Store scale in State, use it everywhere instead of gtx.Metric.PxPerDp

- State.Scale stores the scale factor (default 1.0)
- ScaleEvent applies SetScale() which updates State.Scale
- Logic.Scale() accessor returns current scale
- Renderer.SetScale() updates renderer's scale from State
- main.go: uses logic.Scale() to get scale, calls renderer.SetScale()
- No more references to gtx.Metric.PxPerDp in render.go or main.go
This commit is contained in:
Greg Pomerantz 2026-05-09 20:23:02 -04:00
parent ef31701d87
commit 68437c32a7
4 changed files with 28 additions and 20 deletions

View File

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

View File

@ -31,9 +31,7 @@ func (e ConfigEvent) apply(s *State) {
}
func (e ScaleEvent) apply(s *State) {
// Scale is used by the renderer, not stored in state.
// Layout is already computed in DP, so no recomputation needed.
_ = s.Elems // force use of state
s.SetScale(e.Scale)
}
// InputEvent represents a user input event routed to an element.
@ -98,6 +96,13 @@ func (l *Logic) ScreenSize() (ui.Dp, ui.Dp) {
return l.state.ScreenWidth, l.state.ScreenHeight
}
// Scale returns the current scale factor (pixels per DP).
func (l *Logic) Scale() float32 {
l.mu.Lock()
defer l.mu.Unlock()
return l.state.Scale
}
// Run runs the logic goroutine loop.
func (l *Logic) Run() {
for {
@ -109,8 +114,7 @@ func (l *Logic) Run() {
e.apply(l.state)
l.frameChan <- l.state.Elems
case ScaleEvent:
// Scale is used by the renderer via gtx.Metric.PxPerDp.
// No state change needed — layout is already in DP.
e.apply(l.state)
l.frameChan <- l.state.Elems
}
case <-l.inputChan:

View File

@ -9,19 +9,28 @@ import (
type State struct {
ScreenWidth ui.Dp
ScreenHeight ui.Dp
Scale float32 // pixels per DP, default 1.0
Elems []ui.Element
}
// NewState creates a new State with initial editor layout.
// screenWidth and screenHeight are in device-independent pixels (Dp).
// scale defaults to 1.0 until updated by ScaleEvent.
func NewState(screenWidth, screenHeight ui.Dp) *State {
return &State{
ScreenWidth: screenWidth,
ScreenHeight: screenHeight,
Scale: 1.0,
Elems: EditorLayout(screenWidth, screenHeight),
}
}
// SetScale updates the scale factor and recomputes layout.
func (s *State) SetScale(scale float32) {
s.Scale = scale
s.Elems = EditorLayout(s.ScreenWidth, s.ScreenHeight)
}
// EditorLayout computes regions for the editor page.
// It takes screen dimensions in Dp and returns []Element with regions in Dp.
// This function works exclusively in Dp — no pixel conversions.

View File

@ -19,7 +19,7 @@ import (
type Renderer struct {
theme Theme
shp *text.Shaper
scale float32 // pixels per DP, from gtx.Metric.PxPerDp
scale float32 // pixels per DP, from State.Scale
}
// New creates a new Renderer.
@ -27,9 +27,9 @@ func New(th Theme, shp *text.Shaper) *Renderer {
return &Renderer{theme: th, shp: shp, scale: 1.0}
}
// setScale updates the renderer's scale factor from a layout.Context.
func (r *Renderer) setScale(gtx layout.Context) {
r.scale = gtx.Metric.PxPerDp
// SetScale updates the renderer's scale factor from State.Scale.
func (r *Renderer) SetScale(scale float32) {
r.scale = scale
}
// toPx converts Dp to physical pixels using the renderer's scale.
@ -45,10 +45,8 @@ func (r *Renderer) toDp(px Px) Dp {
// Draw iterates elements and draws each in slice order (back-to-front).
// It captures the initial constraints once at the start, then passes them
// to each render function for consistent positioning.
// The scale is set externally via SetScale() from State.Scale.
func (r *Renderer) Draw(gtx layout.Context, elems []Element) {
// Update scale from the frame context
r.setScale(gtx)
// Capture initial constraints once — before any clips modify them.
// These are in physical pixels and serve as the window bounds for all positioning.
initialConstraints := WindowConstraints{