diff --git a/cmd/pad/main.go b/cmd/pad/main.go index 2aaf14b..812babb 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 - // Create logic instance with initial DP size + // Create logic instance with initial DP size and scale=1.0 logic := editor.NewLogic(initialDPW, initialDPH) // Shared state protected by mutex @@ -60,21 +60,29 @@ func run(w *app.Window) error { case app.DestroyEvent: return e.Err case app.ConfigEvent: - // Store pixel dimensions for later conversion + // Store pixel dimensions from ConfigEvent pixelW = e.Config.Size.X pixelH = e.Config.Size.Y - // Use initial DP size until we get the scale from FrameEvent + // Convert to DP using current scale (starts at 1.0) + dpW := ui.ToDp(ui.Px(pixelW), 1.0) + dpH := ui.ToDp(ui.Px(pixelH), 1.0) + // Send config event to logic goroutine (in DP) logic.ConfigChan() <- editor.ConfigEvent{ - Width: initialDPW, - Height: initialDPH, + Width: dpW, + Height: dpH, } case app.FrameEvent: gtx := app.NewContext(&ops, e) - scale := gtx.Metric.PxPerDp + newScale := gtx.Metric.PxPerDp + + // If scale changed, send scale event to logic goroutine + if newScale != 1.0 { + logic.ScaleChan() <- editor.ScaleEvent{Scale: newScale} + } // Convert pixel dimensions to DP using actual scale - dpW := ui.ToDp(ui.Px(pixelW), scale) - dpH := ui.ToDp(ui.Px(pixelH), scale) + dpW := ui.ToDp(ui.Px(pixelW), newScale) + dpH := ui.ToDp(ui.Px(pixelH), newScale) // Send updated config to logic goroutine logic.ConfigChan() <- editor.ConfigEvent{ diff --git a/internal/editor/logic.go b/internal/editor/logic.go index 7ad170d..7006a9b 100644 --- a/internal/editor/logic.go +++ b/internal/editor/logic.go @@ -1,6 +1,8 @@ package editor import ( + "sync" + "pad/internal/ui" ) @@ -11,6 +13,11 @@ type ConfigEvent struct { Height ui.Dp } +// ScaleEvent represents a metric change (HiDPI scale factor). +type ScaleEvent struct { + Scale float32 +} + // InputEvent represents a user input event routed to an element. type InputEvent struct { ElementID string @@ -25,19 +32,22 @@ type ResultEvent struct { // Logic runs the logic goroutine and provides channels for communication. type Logic struct { - state *State + state *State configChan chan ConfigEvent + scaleChan chan ScaleEvent frameChan chan []ui.Element inputChan chan []InputEvent resultChan chan ResultEvent + mu sync.Mutex } // NewLogic creates a new Logic instance. // screenWidth and screenHeight are in device-independent pixels (Dp). func NewLogic(screenWidth, screenHeight ui.Dp) *Logic { return &Logic{ - state: NewState(screenWidth, screenHeight), + state: NewState(screenWidth, screenHeight), configChan: make(chan ConfigEvent), + scaleChan: make(chan ScaleEvent), frameChan: make(chan []ui.Element), inputChan: make(chan []InputEvent), resultChan: make(chan ResultEvent), @@ -49,6 +59,11 @@ func (l *Logic) ConfigChan() chan<- ConfigEvent { 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 @@ -64,6 +79,22 @@ func (l *Logic) ResultChan() <-chan ResultEvent { return l.resultChan } +// ScreenSize returns the current screen dimensions in Dp. +func (l *Logic) ScreenSize() (ui.Dp, ui.Dp) { + l.mu.Lock() + defer l.mu.Unlock() + 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 { diff --git a/internal/ui/render.go b/internal/ui/render.go index 08469f8..beaf971 100644 --- a/internal/ui/render.go +++ b/internal/ui/render.go @@ -231,7 +231,7 @@ func (r *Renderer) drawBottomBar(gtx layout.Context, bb BottomBar, constraints W // Right: Word wrap button wordWrapXPx := regXPx + barW - r.toPx(Dp(80)) wordWrapXDp := r.toDp(wordWrapXPx) - r.drawText(gtx, r.shp, "W:"+boolToString(bb.WordWrap), r.theme.FontSize, wordWrapXDp, drawY, color.NRGBA{R: 0, G: 0, B: 0, A: 255}) + r.drawText(gtx, r.shp, "Wrap:"+boolToString(bb.WordWrap), r.theme.FontSize, wordWrapXDp, drawY, color.NRGBA{R: 0, G: 0, B: 0, A: 255}) } func (r *Renderer) drawButton(gtx layout.Context, btn Button, _ WindowConstraints) {