- Fix render.go: replace broken material.Label with shaper-based text rendering (LayoutString + Shape + glyph iteration) per Gio's paintGlyph - Fix render.go: only apply clip rects at container boundaries; leaf elements have zero-size regions that were clipping all text out - Fix render.go: call r.drawElement recursively for container children so nested containers work and clips are applied correctly - Fix render.go: add drawLineText/drawLine helpers matching Gio's paintGlyph offset calculation (x + first.X, y + first.Y) - Fix element.go: Button.Draw now uses r.drawText instead of duplicate broken material.Label code; Label defaults to black when color is unset - Fix state.go: container children use relative coordinates instead of mixed screen-space/container-relative positions - Fix main.go: ConfigEvent carries raw pixel dimensions only; ScaleEvent carries scale only; layout is computed once per frame using both, eliminating the infinite Invalidate() loop
83 lines
2.4 KiB
Go
83 lines
2.4 KiB
Go
package editor
|
|
|
|
import (
|
|
"fmt"
|
|
"pad/internal/ui"
|
|
)
|
|
|
|
// State holds all application state owned by the logic goroutine.
|
|
type State struct {
|
|
PixelWidth int // raw pixel width from Gio ConfigEvent
|
|
PixelHeight int // raw pixel height from Gio ConfigEvent
|
|
scale float32
|
|
Elems []ui.Element
|
|
}
|
|
|
|
func NewState() *State {
|
|
return &State{scale: 1.0}
|
|
}
|
|
|
|
func (s *State) SetScale(scale float32) {
|
|
s.scale = scale
|
|
}
|
|
|
|
func (s *State) Scale() float32 {
|
|
return s.scale
|
|
}
|
|
|
|
// layout converts stored pixel dimensions to Dp using the current scale
|
|
// and computes the element tree. Called only when a frame is needed.
|
|
func (s *State) layout() []ui.Element {
|
|
dpW := ui.ToDp(ui.Px(s.PixelWidth), s.scale)
|
|
dpH := ui.ToDp(ui.Px(s.PixelHeight), s.scale)
|
|
s.Elems = EditorLayout(dpW, dpH)
|
|
return s.Elems
|
|
}
|
|
|
|
// EditorLayout computes the element tree for the editor page.
|
|
func EditorLayout(screenWidth, screenHeight ui.Dp) []ui.Element {
|
|
margin := ui.Dp(10)
|
|
|
|
// --- Top bar: filename on row 1, icons on row 2 ---
|
|
statusBarRegion := ui.Region{
|
|
X: margin, Y: margin,
|
|
W: screenWidth - margin*2,
|
|
H: ui.Dp(52),
|
|
}
|
|
statusBarW := statusBarRegion.W
|
|
statusBar := ui.NewContainer(
|
|
statusBarRegion,
|
|
ui.Color{R: 230, G: 230, B: 230, A: 255},
|
|
[]ui.Element{
|
|
// Row 1: filename centered (relative to container)
|
|
ui.NewLabel("a very long file name that probably will eventually need to be truncated.txt", 14, ui.Region{X: statusBarW/2 - ui.Dp(40), Y: ui.Dp(2)}),
|
|
// Row 2: cut icon left (relative to container)
|
|
ui.NewIcon("cut", ui.Region{X: ui.Dp(8), Y: ui.Dp(28)}, ui.Dp(16)),
|
|
// Row 2: status icons right (relative to container)
|
|
ui.NewLabel("Ln 47, Col 12", 12, ui.Region{X: statusBarW - ui.Dp(70), Y: ui.Dp(28)}),
|
|
},
|
|
)
|
|
|
|
// --- Bottom bar ---
|
|
bottomBarHeight := ui.Dp(24)
|
|
bottomBarY := screenHeight - margin - bottomBarHeight
|
|
bottomBarRegion := ui.Region{
|
|
X: margin, Y: bottomBarY,
|
|
W: screenWidth - margin*2,
|
|
H: bottomBarHeight,
|
|
}
|
|
bottomBarW := bottomBarRegion.W
|
|
bottomBar := ui.NewContainer(
|
|
bottomBarRegion,
|
|
ui.Color{R: 230, G: 230, B: 230, A: 255},
|
|
[]ui.Element{
|
|
ui.NewLabel("Ln 47, Col 12", 12, ui.Region{X: ui.Dp(8), Y: ui.Dp(2)}),
|
|
ui.NewLabel("1024 / 50000", 12, ui.Region{X: bottomBarW/2 - ui.Dp(40), Y: ui.Dp(2)}),
|
|
ui.NewLabel("Wrap: On", 12, ui.Region{X: bottomBarW - ui.Dp(60), Y: ui.Dp(2)}),
|
|
},
|
|
)
|
|
|
|
fmt.Println("[DEBUG EditorLayout] created", len([]ui.Element{statusBar, bottomBar}), "containers")
|
|
return []ui.Element{statusBar, bottomBar}
|
|
}
|