diff --git a/cmd/pad/main.go b/cmd/pad/main.go index 8dd7c05..bea9fd6 100644 --- a/cmd/pad/main.go +++ b/cmd/pad/main.go @@ -41,7 +41,7 @@ func run(w *app.Window) error { // Track pixel dimensions from ConfigEvent (for resize handling) var pixelW, pixelH int // Track previous scale to detect changes - prevScale := float32(1.0) + scale := float32(1.0) // Create logic instance with initial DP size and scale=1.0 logic := editor.NewLogic(initialDPW, initialDPH) @@ -78,9 +78,9 @@ func run(w *app.Window) error { newScale := gtx.Metric.PxPerDp // If scale changed, send scale event to logic goroutine - if newScale != prevScale { - logic.ScaleChan() <- editor.ScaleEvent{Scale: newScale} - prevScale = newScale + if newScale != scale { + logic.ConfigChan() <- editor.ScaleEvent{Scale: newScale} + scale = newScale } // Convert pixel dimensions to DP using actual scale diff --git a/internal/editor/logic.go b/internal/editor/logic.go index 7006a9b..2fe12bd 100644 --- a/internal/editor/logic.go +++ b/internal/editor/logic.go @@ -18,6 +18,24 @@ type ScaleEvent struct { Scale float32 } +// ConfigUpdate is a common interface for all configuration updates. +// Both ConfigEvent and ScaleEvent implement this interface. +type ConfigUpdate interface { + apply(*State) +} + +func (e ConfigEvent) apply(s *State) { + s.ScreenWidth = e.Width + s.ScreenHeight = e.Height + s.Elems = EditorLayout(e.Width, e.Height) +} + +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 +} + // InputEvent represents a user input event routed to an element. type InputEvent struct { ElementID string @@ -33,8 +51,7 @@ type ResultEvent struct { // Logic runs the logic goroutine and provides channels for communication. type Logic struct { state *State - configChan chan ConfigEvent - scaleChan chan ScaleEvent + configChan chan ConfigUpdate frameChan chan []ui.Element inputChan chan []InputEvent resultChan chan ResultEvent @@ -45,25 +62,20 @@ type Logic struct { // screenWidth and screenHeight are in device-independent pixels (Dp). func NewLogic(screenWidth, screenHeight ui.Dp) *Logic { return &Logic{ - state: NewState(screenWidth, screenHeight), - configChan: make(chan ConfigEvent), - scaleChan: make(chan ScaleEvent), + state: NewState(screenWidth, screenHeight), + configChan: make(chan ConfigUpdate), frameChan: make(chan []ui.Element), inputChan: make(chan []InputEvent), resultChan: make(chan ResultEvent), } } -// ConfigChan returns the config channel for the logic goroutine. -func (l *Logic) ConfigChan() chan<- ConfigEvent { +// ConfigChan returns the unified config channel for the logic goroutine. +// Accepts ConfigEvent (size) and ScaleEvent (scale factor). +func (l *Logic) ConfigChan() chan<- ConfigUpdate { return l.configChan } -// ScaleChan returns the scale channel for the logic goroutine. -func (l *Logic) ScaleChan() chan<- ScaleEvent { - return l.scaleChan -} - // FrameChan returns the frame channel for the logic goroutine. func (l *Logic) FrameChan() <-chan []ui.Element { return l.frameChan @@ -86,25 +98,21 @@ func (l *Logic) ScreenSize() (ui.Dp, ui.Dp) { return l.state.ScreenWidth, l.state.ScreenHeight } -// SetScale updates the scale factor and recomputes layout. -func (l *Logic) SetScale(scale float32) { - l.mu.Lock() - defer l.mu.Unlock() - // Recompute layout with new scale (EditorLayout handles the conversion) - l.state.Elems = EditorLayout(l.state.ScreenWidth, l.state.ScreenHeight) - l.frameChan <- l.state.Elems -} - // Run runs the logic goroutine loop. func (l *Logic) Run() { for { select { - case cfg := <-l.configChan: - // Update screen size and recompute layout - l.state.ScreenWidth = cfg.Width - l.state.ScreenHeight = cfg.Height - l.state.Elems = EditorLayout(cfg.Width, cfg.Height) - l.frameChan <- l.state.Elems + case update := <-l.configChan: + // Type switch to differentiate ConfigEvent vs ScaleEvent + switch e := update.(type) { + case ConfigEvent: + 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. + l.frameChan <- l.state.Elems + } case <-l.inputChan: // Process input (not implemented in mockup) l.frameChan <- l.state.Elems