Fix event flow: ConfigEvent sets size, FrameEvent sets scale only

- ConfigEvent: ONLY from app.ConfigEvent, sets width/height in State
- FrameEvent: gets scale from gtx.Metric.PxPerDp, sends ScaleEvent only if changed
- ScaleEvent: updates State.Scale
- Renderer reads windowW/windowH from State (SetWindowSize), not gtx.Constraints
- Renderer reads scale from State (SetScale), not gtx.Metric.PxPerDp
- main.go: ConfigEvent calls SetWindowSize, FrameEvent calls SetScale
This commit is contained in:
Greg Pomerantz 2026-05-09 20:26:10 -04:00
parent 68437c32a7
commit 21b4df59a3
2 changed files with 24 additions and 19 deletions

View File

@ -40,6 +40,8 @@ func run(w *app.Window) error {
// Track pixel dimensions from ConfigEvent (for resize handling) // Track pixel dimensions from ConfigEvent (for resize handling)
var pixelW, pixelH int var pixelW, pixelH int
// Track previous scale to detect changes
prevScale := float32(1.0)
// Create logic instance with initial DP size and scale=1.0 // Create logic instance with initial DP size and scale=1.0
logic := editor.NewLogic(initialDPW, initialDPH) logic := editor.NewLogic(initialDPW, initialDPH)
@ -71,24 +73,20 @@ func run(w *app.Window) error {
Width: dpW, Width: dpW,
Height: dpH, Height: dpH,
} }
// Update renderer with window size from State
renderer.SetWindowSize(pixelW, pixelH)
case app.FrameEvent: case app.FrameEvent:
gtx := app.NewContext(&ops, e) gtx := app.NewContext(&ops, e)
newScale := gtx.Metric.PxPerDp
// Get scale from State — this is updated by ScaleEvent // If scale changed, send scale event to logic goroutine
newScale := logic.Scale() if newScale != prevScale {
logic.ConfigChan() <- editor.ScaleEvent{Scale: newScale}
// Convert pixel dimensions to DP using actual scale prevScale = newScale
dpW := ui.ToDp(ui.Px(pixelW), newScale)
dpH := ui.ToDp(ui.Px(pixelH), newScale)
// Send updated config to logic goroutine
logic.ConfigChan() <- editor.ConfigEvent{
Width: dpW,
Height: dpH,
} }
// Update renderer with current scale from State // Update renderer with current scale from State
renderer.SetScale(newScale) renderer.SetScale(logic.Scale())
// Acquire mutex, read frame, draw, release mutex // Acquire mutex, read frame, draw, release mutex
mu.Lock() mu.Lock()

View File

@ -20,6 +20,9 @@ type Renderer struct {
theme Theme theme Theme
shp *text.Shaper shp *text.Shaper
scale float32 // pixels per DP, from State.Scale scale float32 // pixels per DP, from State.Scale
// Window dimensions in physical pixels, from State
windowW int
windowH int
} }
// New creates a new Renderer. // New creates a new Renderer.
@ -32,6 +35,12 @@ func (r *Renderer) SetScale(scale float32) {
r.scale = scale r.scale = scale
} }
// SetWindowSize updates the window dimensions in physical pixels from State.
func (r *Renderer) SetWindowSize(w, h int) {
r.windowW = w
r.windowH = h
}
// toPx converts Dp to physical pixels using the renderer's scale. // toPx converts Dp to physical pixels using the renderer's scale.
func (r *Renderer) toPx(dp Dp) Px { func (r *Renderer) toPx(dp Dp) Px {
return ToPx(dp, r.scale) return ToPx(dp, r.scale)
@ -43,15 +52,13 @@ func (r *Renderer) toDp(px Px) Dp {
} }
// Draw iterates elements and draws each in slice order (back-to-front). // Draw iterates elements and draws each in slice order (back-to-front).
// It captures the initial constraints once at the start, then passes them // Window constraints come from State (set via SetWindowSize), not from gtx.
// to each render function for consistent positioning. // Scale comes from State (set via SetScale), not from gtx.Metric.PxPerDp.
// The scale is set externally via SetScale() from State.Scale.
func (r *Renderer) Draw(gtx layout.Context, elems []Element) { func (r *Renderer) Draw(gtx layout.Context, elems []Element) {
// Capture initial constraints once — before any clips modify them. // Use window dimensions from State — never from gtx.Constraints
// These are in physical pixels and serve as the window bounds for all positioning.
initialConstraints := WindowConstraints{ initialConstraints := WindowConstraints{
Min: gtx.Constraints.Min, Min: image.Point{X: 0, Y: 0},
Max: gtx.Constraints.Max, Max: image.Point{X: r.windowW, Y: r.windowH},
} }
for _, e := range elems { for _, e := range elems {