eframe: Add App::transform_primitives and App::post_platform_output hooks#8138
Open
Le-Syl21 wants to merge 1 commit into
Open
eframe: Add App::transform_primitives and App::post_platform_output hooks#8138Le-Syl21 wants to merge 1 commit into
App::transform_primitives and App::post_platform_output hooks#8138Le-Syl21 wants to merge 1 commit into
Conversation
|
Preview is being built... Preview will be available at https://egui-pr-preview.github.io/pr/8138-eframe-app-hooks View snapshot changes at kitdiff |
f71c217 to
a6f27a9
Compare
…t` hooks Two new optional methods on the `App` trait give integrations a place to inspect or transform the per-frame egui pipeline output before it reaches the platform. - `transform_primitives(&mut self, ctx, &mut Vec<ClippedPrimitive>)` runs after `Context::tessellate` and before the painter (glow / wgpu) submits draw calls. The primitives can be rewritten, replaced, or stripped. - `post_platform_output(&mut self, ctx, &mut PlatformOutput)` runs after `Context::run_ui` and before the integration consumes platform output (cursor icon dispatch, IME state, clipboard writes, accessibility updates). The output can be inspected or mutated in place. Both hooks default to no-op, so existing apps are unaffected. Use cases: - viewport-level transforms applied uniformly to the whole frame (rotation, mirroring, custom projections) without touching individual widgets - debugging / instrumentation: dump primitive counts, log overdraw, inject debug overlays - custom render passes that need access to the final primitive list - capturing the cursor icon for a custom software cursor - intercepting clipboard writes / cursor commands for kiosk or embedded scenarios The hooks are wired into both the glow and wgpu native integrations. Web (wasm32) is not currently affected — the hooks could be wired in a follow-up if there is demand. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
a6f27a9 to
6539302
Compare
5 tasks
Le-Syl21
added a commit
to Le-Syl21/PinReady
that referenced
this pull request
Apr 30, 2026
The full-rotation egui fork (~3000 lines diff) is replaced by:
- the standalone `egui-rotate` crate (rotation logic + software cursor)
- a slim Le-Syl21/egui fork on `pinready-deps` (~150 lines diff total):
* eframe::App::transform_primitives + post_platform_output hooks
(pending upstream as PR emilk/egui#8138)
* ViewportBuilder::with_monitor (no PR yet)
* Key::ShiftLeft/Right + IntlBackslash physical key variants
(pending upstream as PR emilk/egui#8127)
App-side changes:
- new fields: `rotation`, `cursor: SoftwareCursor`, `last_cursor_icon`
- `set_rotation()` setter called once at construction from main
- `enable_kiosk_cursor` now also configures `cursor.set_scale(3.0)`
+ `cursor.set_lock(true)`
- implement `raw_input_hook` → cursor.process_input (rotates input,
captures cursor)
- implement `transform_primitives` → egui_rotate::transform_clipped_primitives
(rotates output back to physical screen space)
- implement `post_platform_output` → captures cursor icon for next
frame's draw, suppresses OS cursor when captured
- draw the software cursor at the top of `fn ui` on a Foreground layer
Secondary viewports (BG / DMD / Topper) drop their `with_rotation(None)`
and `set_viewport_rotation(None)` — the rotation only applies to the
root, gated by `ctx.viewport_id() != ROOT` in every hook.
Build, clippy clean. Visual validation pending on the cabinet.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Le-Syl21
added a commit
to Le-Syl21/PinReady
that referenced
this pull request
Apr 30, 2026
… labels
Architectural refactor of the egui dependency surface.
The previous full-rotation egui fork (~3000 lines diff) is split into:
- The standalone `egui-rotate` crate (rotation logic + software cursor),
published on crates.io: https://crates.io/crates/egui-rotate
- A slim Le-Syl21/egui fork on `pinready-deps` (~150 lines diff total),
pending three independent upstream PRs:
* eframe::App::transform_primitives + post_platform_output hooks
(emilk/egui#8138)
* ViewportBuilder::with_monitor / ViewportCommand::SetMonitor
(emilk/egui#8140)
* Key::ShiftLeft/Right + IntlBackslash physical key variants
(emilk/egui#8127)
- Localized SDL key labels via the `sdl-keybridge` crate, replacing
PinReady's hand-curated `key_*` rust-i18n entries.
User-visible changes:
- Wizard input page: key labels now localized in the user's UI language
via sdl-keybridge (e.g. "Alt Gauche" instead of "Left Alt" in French).
- Cabinet mode: cursor I-beam in TextEdits now renders perpendicular to
rotated text (was parallel before — fixed in egui-rotate 0.1.2).
- No behavior change for desktop / wizard mode.
App-side changes (internal):
- new fields on `App`: `rotation`, `cursor: SoftwareCursor`,
`last_cursor_icon`
- `set_rotation()` setter called from `main` at construction
- `enable_kiosk_cursor()` now configures `cursor.set_scale(3.0)` +
`cursor.set_lock(true)`
- implements `eframe::App::raw_input_hook` (input rotation + cursor capture),
`transform_primitives` (output rotation, ROOT viewport only via
explicit viewport_id parameter), and `post_platform_output` (cursor
icon capture + suppression)
- software cursor drawn at the top of `fn ui` on a Foreground layer
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
emilk
reviewed
May 12, 2026
Comment on lines
+10
to
+15
| ## Unreleased | ||
|
|
||
| ### ⭐ Added | ||
| * Add `App::transform_primitives` and `App::post_platform_output` hooks to inspect/transform tessellated primitives and platform output before they are dispatched. | ||
|
|
||
|
|
Owner
There was a problem hiding this comment.
revert: we generate the changelog on release
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Adds two optional methods on the
Apptrait that give integrations a place to inspect or transform the per-frame egui pipeline output before it reaches the platform.Both default to no-op, so existing apps are unaffected.
Where they fire
transform_primitivesContext::tessellatepaint_and_update_texturespost_platform_outputContext::run_uireturnsegui_winit.handle_platform_outputconsumes itWired into both
glow_integrationandwgpu_integration. Web (wasm32) is not touched in this PR — could be a follow-up if there's interest.Use cases
These are general-purpose hooks, not tied to any specific feature. Examples that motivated them:
egui-rotateuses these hooks to integrate cleanly with eframe; without them it can only target custom winit/glow integrations.PlatformOutput::cursor_iconto drive a custom cursor (where the OS cursor is hidden, e.g. cabinet displays where the OS cursor cannot be rotated).Why not a single hook?
The two hooks fire at different points in the pipeline (tessellate→paint vs. run_ui→handle_platform_output) and target different data (primitives vs. platform output). Coalescing them would either add a hook that fires earlier than needed for one of the use cases, or split the work into one hook with two unrelated parameters.
Why not extend
Contextinstead?These are integration-time concerns (post-tessellation, pre-paint; post-run, pre-OS-dispatch). They don't fit the egui
ContextAPI, which is mid-pass. TheApptrait is the natural place: it's already whereraw_input_hooklives for the symmetric input side.Test plan
cargo build -p eframecleancargo clippy -p eframe --all-features -- -D warningscleancargo fmt -p eframe --checkcleancargo test -p eframe --libpassesegui-rotateintegration through these hooks on a real eframe app, verify rotation + cursor work — done locally on my pinball cabinet launcher (PinReady), can share details if usefulBackground
This is a smaller, more general follow-up to #8113, which tried to integrate viewport rotation directly into egui+eframe and was declined as too niche / too much surface to maintain. That feedback was fair. The follow-up published the rotation logic as a standalone crate (
egui-rotate) which works fine with custom integrations (winit + glow / wgpu / SDL3 directly). However it cannot integrate witheframebecause eframe owns the tessellate→paint pipeline with no hook in between.These two hooks fix that — and stay generic. They're not specific to rotation; the doc-comments describe the broader use cases.
If preferred, I'm happy to:
pre_paint/pre_handle_output?)transform_primitivesand droppost_platform_output(the cursor icon use case can be worked around with a fixed icon)🤖 Drafted with Claude Code