GraphicApplication: canvas facade with a contract and backends, modifier keys, window types #14

Merged
ilusha merged 3 commits from GraphicApplicationCanvas into master 2026-10-30 11:02:54 +03:00
Collaborator

GraphicApplication: canvas facade with a contract and backends, modifier keys, window types

Split out of the Widgets core refactor (#12). These are the GraphicApplication changes the new Widgets core needs. They touch only GraphicApplication/.

Canvas: facade, contract, backends

The canvas now follows the same structure the platform windows use (backends/contract + implementations beside it, facade on top):

  • src/canvas — Canvas, the drawing facade: origin, clip scopes, composite operation. Portable, links Math and Containers only, no Vulkan.
  • src/canvas/backends/contract — CanvasBackend, the interface every backend implements, plus the drawing vocabulary (Axis, TextAlign, FontFace, TextStyle, ImageHandle, TextMetrics).
  • src/canvas/backends/nanovg — NanoVgCanvasBackend, drawing on a window surface. The canvas's window-surface constructor and beginFrame(frame, windowFrame) / endFrame() are defined here, next to the backend, so the portable facade never names a GPU frame. The application uses Canvas directly.
  • src/canvas/backends/recording — RecordingCanvasBackend, records each command with its surface rect, clip and composite operation, and measures text with a fixed advance, so layout and painting are testable headless.

Also:

  • Canvas::Clip is a public clip scope; clips intersect and restore with the scope. SavedState also restores the composite operation.
  • gradientRect takes an Axis; polyline/polygon take vectors; text takes a string; frame() and debugCross() had no users and are gone.
  • setClip takes std::optional<RectF> instead of a null pointer.

Modifier keys

KeyModifiers (shift, control, alt, super; either side of the keyboard counts) and ModifierTracker, which follows modifier presses in event order. InputState::modifiers() gives the modifiers held at the end of the frame. Losing keyboard focus releases them.

Window vocabulary library

WindowTypes (cursor shapes, clipboard image, window identity and edges) and PlatformInfo move from the backend contract into GraphicApplicationWindowTypes, which needs only Math. Code that names a cursor no longer links the GPU device.

Verification

  • Each commit builds and passes its tests on master (f855ec9): 88 → 103 → 108 → 108.
  • The example runs under Vulkan validation with no errors.
  • Full build: master already fails on 5 files of the old Widgets library, which still uses the removed Graphics API. This PR adds one more file there, ColorPickerWidget.cpp, because of the polygon signature change. That library is replaced by #12; nothing that builds on master stops building.

#12 is stacked on this branch and depends on it.

## GraphicApplication: canvas facade with a contract and backends, modifier keys, window types Split out of the Widgets core refactor (#12). These are the GraphicApplication changes the new Widgets core needs. They touch only `GraphicApplication/`. ### Canvas: facade, contract, backends The canvas now follows the same structure the platform windows use (`backends/contract` + implementations beside it, facade on top): - `src/canvas` — `Canvas`, the drawing facade: origin, clip scopes, composite operation. Portable, links Math and Containers only, no Vulkan. - `src/canvas/backends/contract` — `CanvasBackend`, the interface every backend implements, plus the drawing vocabulary (`Axis`, `TextAlign`, `FontFace`, `TextStyle`, `ImageHandle`, `TextMetrics`). - `src/canvas/backends/nanovg` — `NanoVgCanvasBackend`, drawing on a window surface. The canvas's window-surface constructor and `beginFrame(frame, windowFrame)` / `endFrame()` are defined here, next to the backend, so the portable facade never names a GPU frame. The application uses `Canvas` directly. - `src/canvas/backends/recording` — `RecordingCanvasBackend`, records each command with its surface rect, clip and composite operation, and measures text with a fixed advance, so layout and painting are testable headless. Also: - `Canvas::Clip` is a public clip scope; clips intersect and restore with the scope. `SavedState` also restores the composite operation. - `gradientRect` takes an `Axis`; `polyline`/`polygon` take vectors; `text` takes a string; `frame()` and `debugCross()` had no users and are gone. - `setClip` takes `std::optional<RectF>` instead of a null pointer. ### Modifier keys `KeyModifiers` (shift, control, alt, super; either side of the keyboard counts) and `ModifierTracker`, which follows modifier presses in event order. `InputState::modifiers()` gives the modifiers held at the end of the frame. Losing keyboard focus releases them. ### Window vocabulary library `WindowTypes` (cursor shapes, clipboard image, window identity and edges) and `PlatformInfo` move from the backend contract into `GraphicApplicationWindowTypes`, which needs only Math. Code that names a cursor no longer links the GPU device. ### Verification - Each commit builds and passes its tests on `master` (`f855ec9`): 88 → 103 → 108 → 108. - The example runs under Vulkan validation with no errors. - Full build: `master` already fails on 5 files of the old `Widgets` library, which still uses the removed `Graphics` API. This PR adds one more file there, `ColorPickerWidget.cpp`, because of the `polygon` signature change. That library is replaced by #12; nothing that builds on `master` stops building. #12 is stacked on this branch and depends on it.
agent added 3 commits 2026-10-30 09:20:30 +03:00
Canvas keeps the drawing API and its state (origin, clip stack, composite
operation) and draws through a CanvasBackend. The NanoVG code moves to a
SurfaceCanvas library that owns the backend and brackets GPU frames; the
portable Canvas library no longer needs Vulkan.

- RecordingCanvasBackend records commands with their surface rect and clip,
  and measures text with a fixed advance, so layout and painting are testable
  headless.
- Canvas::Clip is a public clip scope; clips intersect and restore with the
  scope. SavedState now also restores the composite operation.
- gradientRect takes an Axis; polyline/polygon take vectors; text takes a
  string. frame() and debugCross() had no users and are gone.
- TextMetrics is an interface Canvas implements, so layout can measure text
  without a frame.
KeyModifiers (shift, control, alt, super; either side of the keyboard counts)
and a ModifierTracker that follows modifier presses in event order. InputState
keeps one, so consumers read the modifiers held at the end of the frame, and
walk events() with their own tracker when they need per-event modifiers.
Losing keyboard focus releases them.
GraphicApplication: move window vocabulary into its own library
Some checks are pending
Windows / build (pull_request) Waiting to run
CMake on a single platform / build (pull_request) Waiting to run
CMake / build (pull_request) Waiting to run
fe26787119
WindowTypes (cursor shapes, clipboard image, window identity and edges) and
PlatformInfo move from the backend contract into a WindowTypes library that
needs only Math. Code that names a cursor or reads platform facts no longer
links the GPU device and the backend contract.
agent force-pushed GraphicApplicationCanvas from fe26787119 to 1052e3346d 2026-10-30 10:59:55 +03:00 Compare
agent changed title from GraphicApplication: portable canvas with recording backend, modifier keys, window types to GraphicApplication: canvas facade with a contract and backends, modifier keys, window types 2026-10-30 11:00:16 +03:00
agent force-pushed GraphicApplicationCanvas from 1052e3346d to ce1bd316c9 2026-10-30 11:02:12 +03:00 Compare
ilusha merged commit 4cc78257b5 into master 2026-10-30 11:02:54 +03:00
ilusha deleted branch GraphicApplicationCanvas 2026-10-30 11:02:55 +03:00
Sign in to join this conversation.
No reviewers
No labels
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set.

Reference: ilusha/Modules#14
No description provided.