Generated reference › API — ICoreEssentials/UI/Backends/AppKit/Graphics
kind: generated#api#icoreessentials-ui-backends-appkit-graphics

API — ICoreEssentials/UI/Backends/AppKit/Graphics

The public contract of 4 header(s) under ICoreEssentials/UI/Backends/AppKit/Graphics — 3 class/struct definition(s), 5 declaration(s). Each section shows the header's banner and its public (and protected-virtual) surface exactly as the file writes it.

ICoreAppKitGraphicsObjectAccess.h#

ICoreEssentials/UI/Backends/AppKit/Graphics/ICoreAppKitGraphicsObjectAccess.h

Reaching from a NODE back to the wrapper that owns it, inside the AppKit zone. (The planning row is named in the .cpp, not here.)

The Qt seat needs nothing like this: its Impl IS the toolkit item, so a QGraphicsItem* found in the scene graph is downcast to an Impl and asked for its owner. Here the scene core stores ids, numbers and one opaque tag, and the tag is a node address -- so the step from "the core says item 7" to "the wrapper whose virtuals answer for item 7" needs a registry.

⚠ IT IS A REGISTRY RATHER THAN A FIELD ON THE NODE, AND THAT IS DELIBERATE. ICoreAppKitSceneNode is a plain struct compiled into every translation unit of the item tier, so adding a member to it changes its LAYOUT -- and a layout change is the one edit that links cleanly across a half-updated build and then misbehaves at run time, because no mangled name moves with it. A

Declares no class of its own — see the file.

ICoreAppKitGraphicsView.h#

ICoreEssentials/UI/Backends/AppKit/Graphics/ICoreAppKitGraphicsView.h

Where the portable scene core meets a native view: the core says what to paint and in what order, and this file runs a painter down that list, turns pointer coordinates into scene coordinates, and turns the core's dirty region into repaint requests.

NO OBJECTIVE-C IN THIS HEADER, the rule this zone follows throughout.

⚠ THE SPLIT WITH THE CORE IS A CONTRACT, NOT AN INTERNAL DETAIL. UI/Portable/ICoreSceneCore.{h,cpp} is maintained separately from this file, so the division is written down rather than left to be inferred:

THE CORE OWNS z-order, item flags, hit-testing, hover, drag, transforms, dirty-rect accumulation -- all in SCENE coordinates, with no view, no device pixel ratio and no notion of a screen.

ICoreAppKitGraphicsItemPaint#

ICoreAppKitGraphicsView.h:51 · struct · 0 declaration(s)

-- what the owner is told when it is time to paint one item --------------- The core stores geometry and flags and a tag it never reads; it does not know what an item LOOKS like.

struct ICoreAppKitGraphicsItemPaint {
public:
    ICoreSceneItemId id;

    // The owner's own identity for this item, straight from the core.
    long long tag = 0;

    // The item's own area, origin-relative -- what to draw into.
    ICoreSceneRect contentBounds;

    bool selected = false;

    // True when this item is the one under the pointer. Read from the scene,
    // not remembered here, so it cannot drift out of step with the core.
    bool hovered = false;

    // The scale the item is being drawn AT, view zoom and every ancestor's
    // scale folded together. An owner that draws a hairline or picks a font
    // size needs this; one that draws plain shapes can ignore it.
    double effectiveScale = 1.0;
};
};

ICoreAppKitSceneNode.h#

ICoreEssentials/UI/Backends/AppKit/Graphics/ICoreAppKitSceneNode.h

What a scene-tier wrapper's Impl IS on this backend. (The planning row is named in the .cpp, not here -- a published header's comments are published verbatim by the API generator, so the tree's own working machinery does not belong in one.)

The Qt seat's Impl derives QGraphicsItem: the toolkit object holds the item's position, z value, visibility, parent and children, and the wrapper forwards to it. There is no such object here. ICoreScene is DATA -- ids, structs and vectors -- so an item's state has to live somewhere, and the two candidates are not equivalent:

  • in the core, with the node holding only an id: then an item that is not

yet in a scene has nowhere to put anything, and setWidth before addItem -- which every construction site in this tree does -- would

ICoreAppKitSceneEvent#

ICoreAppKitSceneNode.h:130 · struct · 0 declaration(s)

struct ICoreAppKitSceneEvent {
public:
    ICoreAppKitSceneEventKind kind = ICoreAppKitSceneEventKind::Pressed;

    // Where the pointer is, in the ITEM's own coordinates and in the scene's.
    // Both, because the wrapper hooks publish both and deriving one from the
    // other at each seat is how the two drift apart.
    ICoreScenePoint itemPoint;
    ICoreScenePoint scenePoint;

    // ⚠⚠ AND WHERE IT IS ON THE SCREEN, WHICH THIS STRUCT DID NOT CARRY AT ALL.
    // The two points above are the only ones the node knew, so every
    // ICoreMouseEvent built from one of these left `globalPos` at its default
    // (0, 0) -- and the one consumer that needs a SCREEN point is the one that
    // shows something at it. ICoreCanvas::contextMenuRequested hands
    // `event.globalPos` straight to ICoreMenu::popupAt, so the canvas menu
    // opened at the top-left corner of the display every time, whatever was
    // right-clicked. Filled by the view, which is the only tier that can map a
    // scene point through its own transform and out to the screen.
    ICoreScenePoint screenPoint;

    int button = 0;              // ICoreMouseButton, as an int

    // ⚠ EVERY BUTTON HELD, WHICH IS NOT `button`. `button` is what caused the
    // event; this is the mask a DRAG reads. ICoreLinkBranchSegment::mouseMoved
    // is the site that pins it: it moves a wire only while
    // `event.buttons & Left` is set, and an unfilled mask makes every segment
    // in the editor unresponsive to a drag.
    unsigned int buttons = 0;    // ICoreMouseButtons

    unsigned int modifiers = 0;  // ICoreKeyModifiers

    // The wheel travel, for WheelScrolled and meaningless for every other kind.
    // In the backend's own units -- POINTS on this one, which is what
    // ICoreGraphicsView.mm fills an ICoreWheelEvent with and says so.
    double deltaX = 0.0;
    double deltaY = 0.0;

    // -- KeyPressed only, and meaningless for every other kind ---------------

    // The key, as an `ICoreKey` cast to int. 0 for a keystroke this platform's
    // table does not name -- which is NOT the same as "nothing happened": most
    // punctuation answers 0 and still produces `keyText`, which is the trap
    // ICoreWidget's seat records at length in its own key hook.
    int key = 0;

    // What the keystroke actually produced, UTF-8. Empty for a bare modifier, a
    // cursor key or a dead key mid-composition.
    //
    // ⚠ std::string, NOT ICoreString, FOR THIS HEADER'S OWN RULE: the banner
    // above ICoreAppKitSceneEvent says every field is a scene-core or standard
    // type, because ICoreString reaches <QString> and a header the whole scene
    // tier includes cannot carry a toolkit. The wrapper seats convert.
    std::string keyText;

    bool autoRepeat = false;
};
};

ICoreAppKitSceneNode#

ICoreAppKitSceneNode.h:187 · struct · 5 declaration(s)

struct ICoreAppKitSceneNode {
public:
    // Null until the item is put into a scene, directly or by being parented
    // to an item that is already in one.
    ICoreScene* scene = nullptr;
    ICoreSceneItemId id{};

    ICoreAppKitSceneNode* parent = nullptr;
    std::vector<ICoreAppKitSceneNode*> children;

    // -- the authoritative state, mirrored into the core on attach and on
    // -- every change while attached.
    double width = 10.0;    // the Qt seat's default, reproduced deliberately:
    double height = 10.0;   // an unsized item is 10x10, not 0x0, so it is
                            // visible while a caller is still wiring it up.
    ICoreScenePoint position{};
    double zValue = 0.0;
    bool visible = true;

    ICoreColor fillColor = ICoreColor::transparent();
    ICoreColor borderColor = ICoreColor::transparent();

    // ⚠⚠ OPACITY IS ON THE NODE, NOT ONLY IN THE WRAPPER'S Impl, AND THAT IS
    // WHAT MAKES IT INHERITABLE. `ICoreScene` is data and models no opacity at
    // all, so each item's paint closure applies its own -- which is correct for
    // one item and WRONG for a subtree, because the other toolkit's
    // QGraphicsItem multiplies a child's opacity by its parent's unless the
    // child sets ItemIgnoresParentOpacity.
    //
    // The tree depends on the inheriting form and says so out loud:
    // ICoreBlockView::setCommentedOutStyle sets 0.4 with the comment "opacity
    // propagates to all child items (frame, ports, labels), so the whole block
    // dims as one when commented out". It did not. A commented-out block kept a
    // full-strength frame, ports, name label and face label with a ghost behind
    // them -- which reads as "commenting out is half-broken" rather than as a
    // missing multiply (A10.18).
    //
    // Stored here rather than walked through the registry because the paint
    // closure has the node and the node has its `parent`: the effective value
    // is one walk up the chain, with no lookup and no knowledge of which
    // wrapper class any ancestor is.
    double opacity = 1.0;

    // The wrapper's own virtuals, reached without knowing which wrapper class
    // this is. Set once by the Impl that owns the node.
    //
    // ⚠ contentBounds IS A CALLBACK RATHER THAN A CACHED RECT because it is
    // VIRTUAL on the wrapper and subclasses override it to state their size --
    // the Qt seat calls it from boundingRect() for the same reason. Caching it
    // here would freeze a subclass's answer at whatever it was when the node
    // was built, which for a subclass sized after construction is 10x10.
    std::function<ICoreSceneRect()> contentBounds;
    std::function<void(ICorePainter&)> paint;

    // ⚠ THE ITEM'S EVENT HOOKS, AND WITHOUT THIS NOTHING ON THIS BACKEND EVER
    // CALLED ONE. The scene core resolves which item a press or a hover
    // belongs to, and the view seat hands that result out -- but nothing turned
    // it into a call on the item wrapper's `mousePressed()` / `pointerEntered()`
    // family, so every item's hook surface was dead while every geometry check
    // passed. It is the exact twin of the paint hook A4.1 left unwired, on the
    // input side.
    //
    // Set once by the Impl that owns the node, like `paint`, and reached
    // without knowing which wrapper class this is. Returns true when the
    // wrapper handled the event.
    std::function<bool(const ICoreAppKitSceneEvent&)> event;
};
};

File-scope declarations#

// What a wrapper is told when the pointer reaches its item.
// 
// ⚠ EVERY FIELD IS A SCENE-CORE TYPE AND NOT AN ICoreMouseEvent, WHICH IS A
// BUILD FACT RATHER THAN A PREFERENCE. `ICoreMouseEvent` reaches `ICorePoint`,
// which includes `<QPoint>`; putting one in this header would pull Qt into
// every translation unit that includes it, which is the trap the drop tier hit
enum class ICoreAppKitSceneEventKind {
    Pressed,
    Moved,
    Released,
    PointerEntered,

    // ⚠ MOVEMENT INSIDE THE ITEM ALREADY HOVERED, WHICH IS NOT `Moved`. `Moved`
    // is the DRAG hook: it fires only while a grab is open, and it goes to the
    // item that took the grab whatever the pointer is over. This one fires with
    // no button down and goes to the item under the pointer, which is the pair
    // Qt spells hoverMoveEvent/mouseMoveEvent and the pair the wrapper tier
    // already publishes as pointerMoved()/mouseMoved(). Without it an item
    // hears a position from the pointer exactly once -- see
    // ICoreAppKitGraphicsView::setPointerMovedHook.
    PointerMoved,

    PointerLeft,

    // ⚠ OFFERED DOWN THE STACK, NOT TO THE TOPMOST ALONE, which is the rule
    // that makes it worth having at all: the item that DRAWS at a point is
    // routinely not the item that scrolls it. Over an ICoreGraphicsScrollPane
    // the topmost hit is the content, which publishes no wheelScrolled(), while
    // the hook lives on the scrollable area two levels up. The view walks the
    // stack topmost-first and stops at the first item whose hook answers true.
    WheelScrolled,

    // ⚠⚠ THE SECOND PRESS OF A DOUBLE CLICK, WHICH REPLACES THE PRESS RATHER
    // THAN FOLLOWING IT -- the other toolkit's rule, and the portable view core
    // states the same one (ICoreSceneViewCore.cpp: *"THE DOUBLE CLICK REPLACES
    // THE PRESS, IT DOES NOT FOLLOW IT"*). Until this enumerator existed
    // `ICoreGraphicsObject::mouseDoubleClicked()` -- a published virtual with
    // five overrides in the editor -- was a definition nothing on this backend
    // ever reached, so the canvas's auto-inserter never opened, a block could
    // not be opened into its subsystem by double click, and a scope block could
    // not be raised into its chart window.
    DoubleClicked,

    // ⚠⚠ A RIGHT PRESS, OFFERED DOWN THE STACK EXACTLY AS A WHEEL NOTCH IS.
    // The item that DRAWS at a point is routinely not the item that owns the
    // menu there: a port's description label declines and the block frame
    // underneath opens the block's config pane (ICorePortViewDescriptionLabel's
    // own comment says so), and empty canvas is the canvas item several levels
    // down. So the view walks the hit stack topmost-first and stops at the
    // first item whose `contextMenuRequested()` answers true, which is what
    // QGraphicsScene::contextMenuEvent does.
    //
    // ⚠ IT IS RAISED IN ADDITION TO THE PRESS, NOT INSTEAD OF IT, and that is
    // the other toolkit's behaviour rather than a convenience: the editor's
    // handlers depend on the right press having already run the selection
    // logic (ICoreBlockViewFrame::contextMenuRequested -- *"The block is
    // already selected by then: the right press ran the selection logic in
    // mousePressEvent() above"*).
    ContextMenu,

    // ⚠⚠ A KEYSTROKE, GOING TO THE SCENE'S FOCUS ITEM -- AND THE ABSENCE OF
    // THIS ENUMERATOR IS WHY NOTHING ON A CANVAS COULD BE TYPED INTO.
    // `ICoreGraphicsText::keyPressed` and `keyPressHandled` are published
    // virtuals with a real override in the editor
    // (ICoreCanvasAreaViewTitleBarLabel, which vetoes Return so a title cannot
    // grow a second line) -- and until this kind existed the scene dispatched
    // no key at all, so both were definitions nothing ever reached. An
    // in-canvas label could take the focus, draw its focus ring, and then
    // ignore the keyboard entirely (A10.19; the debt is A4.2's editing half).
    //
    // ⚠ IT DOES NOT GO DOWN THE HIT STACK. A key has no position: it belongs to
    // whatever holds `ICoreScene::focusItem` and to nothing else, which is the
    // other toolkit's rule too.
    KeyPressed,
};

ICoreAppKitSceneRender.h#

ICoreEssentials/UI/Backends/AppKit/Graphics/ICoreAppKitSceneRender.h

Run a whole scene down a painter: the body ICoreGraphicsScene::renderTo has had since A4.2, lifted out so a SECOND caller does not become a second copy of it (A7.4).

⚠ WHY IT MOVED. The chart tier needs the same operation from the other end: ICoreChartBase's three export routes render THE SCENE THE CHART SITS IN, and they reach it from an item rather than from a scene wrapper. The other toolkit answers both with one call (QGraphicsScene::render); here the walk is ours, so the choice was a shared body or a duplicated one -- and a duplicated draw loop is the shape that ends with two backends disagreeing about clipping in a way nothing reports.

source is in scene coordinates and target in the painter's. The source is stretched onto the target EXACTLY -- no letterbox -- which is the

Declares no class of its own — see the file.