API — ICoreEssentials/UI/Backends/Gtk4/Painting
The public contract of 4 header(s) under ICoreEssentials/UI/Backends/Gtk4/Painting — 5 class/struct definition(s), 22 declaration(s). Each section shows the header's banner and its public (and protected-virtual) surface exactly as the file writes it.
ICoreGtk4PaintAccess.h#
ICoreEssentials/UI/Backends/Gtk4/Painting/ICoreGtk4PaintAccess.h
Backend-internal access to what an ICorePen, ICoreBrush or ICoreGradient actually says.
⚠ THIS HEADER IS WHY THE PAINTER CAN BE WRITTEN AT ALL.
ICorePenandICoreBrushhave almost no getters -- their public surface is constructors, setters andnativeStorage()-- and on the Qt backend the state crosses the seam AS THE NATIVE OBJECT (icoreQt(pen)reinterprets the buffer as aQPen&). So a gtk4ICorePainter::Implhanded anICorePencould not ask it anything, and the only way in,nativeStorage(), holds aQPen-- naming which insideBackends/Gtk4/is exactly what census row R2.4 exists to stop.This backend therefore takes its own side of the seam, as the value tier did for ICoreFont: the buffer holds a pointer to a record THIS backend wrote, and this header is how the painter reads it back. The WinUI board reached the
ICoreGtk4PaintStop#
ICoreGtk4PaintAccess.h:36 · struct · 0 declaration(s)
One stop of a gradient.
struct ICoreGtk4PaintStop {
public:
double position = 0.0; // 0..1
ICoreColor color;
};
};
ICoreGtk4BrushSpec#
ICoreGtk4PaintAccess.h:56 · struct · 0 declaration(s)
struct ICoreGtk4BrushSpec {
public:
ICoreGtk4BrushKind kind = ICoreGtk4BrushKind::None;
ICoreColor color; // Solid
// LinearGradient: the two ends, in the CURRENT TRANSFORM SPACE at the
// moment of the draw -- which is what QLinearGradient means and what
// cairo_pattern_create_linear takes.
double x1 = 0.0, y1 = 0.0, x2 = 0.0, y2 = 0.0;
// RadialGradient: centre and radius. ⚠ ONE radius. `ICoreRadialGradient`
// only ever states one, and cairo's radial pattern takes two CIRCLES (a
// focus and an outer), so the seating passes a degenerate focus at the
// centre rather than inventing an ellipse nothing asked for.
double centerX = 0.0, centerY = 0.0, radius = 0.0;
// ⚠ SORTED BY POSITION. `QGradient::stops()` answers sorted, and cairo
// requires non-decreasing offsets; the order they were SET in is preserved
// by neither.
std::vector<ICoreGtk4PaintStop> stops;
};
};
ICoreGtk4PenSpec#
ICoreGtk4PaintAccess.h:85 · struct · 0 declaration(s)
⚠ A PEN CARRIES A BRUSH, NOT A COLOUR, and that is not over-modelling: ICorePen(const ICoreBrush&, double) exists and its one call site in this tree -- a notification panel's rim -- passes a grad...
struct ICoreGtk4PenSpec {
public:
ICoreGtk4BrushSpec brush;
double width = 0.0;
ICorePenStyle style = ICorePenStyle::Solid;
ICorePenCap cap = ICorePenCap::Square;
ICorePenJoin join = ICorePenJoin::Bevel;
bool cosmetic = false;
};
};
File-scope declarations#
// Which kind of cairo source this brush wants.
//
// ⚠ `None` IS NOT `Solid` WITH ALPHA 0, and the difference is load-bearing:
// `ICoreBrush()` means "do not fill at all" -- fifteen call sites spell a bare
// `ICoreBrush()` to turn filling off before stroking an outline (ICoreBrush.h)
// -- so it means "skip the fill", not "fill with something invisible". A
enum class ICoreGtk4BrushKind {
None = 0,
Solid = 1,
LinearGradient = 2,
RadialGradient = 3,
};
ICoreGtk4PathAccess.h#
ICoreEssentials/UI/Backends/Gtk4/Painting/ICoreGtk4PathAccess.h
ICoreGtk4PathNode#
ICoreGtk4PathAccess.h:49 · struct · 0 declaration(s)
struct ICoreGtk4PathNode {
public:
ICoreGtk4PathOp op = ICoreGtk4PathOp::Built;
// op == Built
std::vector<ICorePathBuilderElement> elements;
// ⚠ THE FILL RULE TRAVELS WITH THE NODE, not with the path handle: a union
// of two paths has a rule of its own, and the painter needs it at the node
// it is filling rather than at the handle it was reached through.
int fillRule = 1; // matches ICoreFillRule: 0 NonZero, 1 EvenOdd
// op == Union
ICoreGtk4PathRef operandA;
ICoreGtk4PathRef operandB;
// op == StrokedRound (operandA is the path being stroked)
double strokeWidth = 0.0;
};
};
File-scope declarations#
// Backend-internal access to what an ICorePainterPath actually contains.
//
// The peer of `ICoreGtk4PaintAccess.h` next door.
// ⚠ NOTHING ABOVE THE BACKEND ZONE MAY INCLUDE THIS.
//
// ⚠ A PATH IS A TREE HERE, NOT A CURVE LIST, and that is this file's one real
enum class ICoreGtk4PathOp {
Built = 0, // the element list is the whole answer
Union = 1, // operandA ∪ operandB
StrokedRound = 2, // the outline of operandA stroked `strokeWidth` across
};
using ICoreGtk4PathRef = std::shared_ptr<const ICoreGtk4PathNode>;
ICoreGtk4RichText.h#
ICoreEssentials/UI/Backends/Gtk4/Painting/ICoreGtk4RichText.h
Declares no class of its own — see the file.
ICoreGtk4TextSelection.h#
ICoreEssentials/UI/Backends/Gtk4/Painting/ICoreGtk4TextSelection.h
ICoreGtk4TextSelection#
ICoreGtk4TextSelection.h:70 · class · pImpl · 22 declaration(s)
Selecting, copying and right-clicking text that THIS TREE PAINTED.
class ICoreGtk4TextSelection {
public:
ICoreGtk4TextSelection();
~ICoreGtk4TextSelection();
ICoreGtk4TextSelection(const ICoreGtk4TextSelection&) = delete;
ICoreGtk4TextSelection& operator=(const ICoreGtk4TextSelection&) = delete;
// ⚠ SET ONCE, BEFORE ANYTHING ELSE IS ASKED. Without it every member below
// answers as though the surface were empty -- which is the correct answer
// for a surface whose seat has not wired this up, and a silent one, so wire
// it in the constructor beside installMenu().
//
// The provider must return a NEW layout (this class unrefs it) laid out
// exactly as the surface's own text is -- same reader, same font, same
// width, same alignment. Null means "nothing to select".
void setLayoutProvider(std::function<PangoLayout*()> provider);
// Where the surface shows that layout, in its own coordinates. Kept here so
// that a scrolled document reports the byte the reader is pointing at without
// every call site passing the same two numbers.
void setOrigin(double x, double y);
// Off means every member below is inert and the surface behaves exactly as
// it did before this class existed. Turning it off drops any selection --
// a highlight nobody can clear is worse than no highlight.
void setEnabled(bool enabled);
[[nodiscard]] bool isEnabled() const;
// ⚠ CALLED FROM THE SEAT'S PAINT, BEFORE THE TEXT GOES DOWN. It returns the
// rectangles to fill BEHIND the glyphs, in the widget's own coordinates, at
// the origin setOrigin() last named.
//
// ⚠ ONE RECTANGLE PER LINE, NOT ONE PER RUN. A multi-line selection is a
// band per line -- full width in the middle, partial at the two ends -- and
// that is what Pango's own per-line x-ranges answer.
[[nodiscard]] std::vector<ICoreRect> bands();
// Whether anything is selected at all. Cheap; no layout needed.
[[nodiscard]] bool hasSelection() const;
// -- the pointer ---------------------------------------------------------
//
// Coordinates are the surface's own; the origin setOrigin() named is
// subtracted here. Each returns true when the surface should repaint.
// ⚠ THE PRESS ANCHORS AND DOES NOT SELECT. A single click in a document
// clears the selection and puts the anchor down; the drag is what selects,
// which is every text surface's behaviour and the reason a stray click does
// not wipe out what the reader was about to copy by widening it.
bool press(double x, double y);
bool drag(double x, double y);
void release();
[[nodiscard]] bool isDragging() const;
// Whole-word on a double click, the whole line on a triple -- the two
// gestures every text surface answers and neither of which a drag can
// express. `pressCount` is GtkGestureClick's n_press.
bool multiClick(double x, double y, int pressCount);
// -- the two commands ----------------------------------------------------
void selectAll();
void clearSelection();
[[nodiscard]] std::string selectedText() const;
// Puts selectedText() on the CLIPBOARD (not the primary selection), which
// is what Ctrl+C and a Copy menu item both mean. A no-op with nothing
// selected -- a copy that cleared the clipboard would lose whatever the
// reader had put there.
void copyToClipboard(GtkWidget* host) const;
// ⚠ THE TWO SHORTCUTS, AND THEY ARE HANDLED HERE RATHER THAN BY A
// GtkShortcutController. A painted surface has no toolkit control to carry
// class bindings, so its seat's own key hook is the only route; answering
// them here keeps the pair identical on every surface that uses this class.
//
// Returns true when the key was consumed. `state` is a GdkModifierType.
bool keyPressed(GtkWidget* host, unsigned int keyval, unsigned int state);
// -- the menu ------------------------------------------------------------
// ⚠⚠ A REAL GtkPopoverMenu OVER A GMenu, WHICH IS WHAT "THE NATIVE CONTEXT
// MENU" MEANS ON THIS TOOLKIT. GTK4 has no `gtk_menu_popup` and no
// window-manager menu to borrow: a popover menu built from a GMenuModel IS
// the platform's menu, and it is what GtkText and GtkLabel raise for their
// own text. So a painted surface using this class gets the same widget, the
// same theming and the same keyboard navigation as the hosted controls next
// door -- rather than something this tree drew to look like one.
//
// Idempotent: the popover and its action group are built on the first call
// and parented to `host`, so they die with it.
void installMenu(GtkWidget* host);
// Raise the menu at a point in `host`'s coordinates. A no-op if
// installMenu() has not been called or selection is off. The Copy item is
// insensitive with nothing selected, which is how a menu says "there is
// nothing to copy" without leaving the reader to find out by pressing it.
void popupAt(GtkWidget* host, double x, double y);
private:
class Impl; // the two-line residue; state lives here
std::unique_ptr<Impl> impl;
};