Add layout components 001-020 with demos and behavior tests
This commit is contained in:
29 files changed
+2110
-9
No files matched your search
+117
@@ -0,0 +1,117 @@
|
||||
package layout
|
||||
|
||||
import (
|
||||
"log/slog"
|
||||
|
||||
"github.com/egoist/mygo/ui"
|
||||
|
||||
"git.zacharyzhang.com/ZacharyZhang-NY/8bitMyGoUI/pixel"
|
||||
)
|
||||
|
||||
const gripW = 6
|
||||
|
||||
type SplitOptions struct {
|
||||
// Vertical stacks the panes top and bottom.
|
||||
Vertical bool
|
||||
// Min is the smallest pane in dots; zero means 24.
|
||||
Min int
|
||||
Label string
|
||||
Disabled bool
|
||||
}
|
||||
|
||||
type SplitResult struct {
|
||||
Element *ui.Element
|
||||
Changed bool
|
||||
}
|
||||
|
||||
// Split shows two panes and a grip moving *size dots.
|
||||
func Split(c *ui.Context, size *int, o SplitOptions, first, second func()) SplitResult {
|
||||
k := pixel.K(c)
|
||||
least := orDef("Split Min", o.Min, 24)
|
||||
var e *ui.Element
|
||||
var total float32
|
||||
back, fwd := ui.KeyLeft, ui.KeyRight
|
||||
if o.Vertical {
|
||||
e = ui.Column(c)
|
||||
total, back, fwd = e.Bounds().H, ui.KeyUp, ui.KeyDown
|
||||
} else {
|
||||
e = ui.Row(c)
|
||||
total = e.Bounds().W
|
||||
}
|
||||
limit := func(n int) int {
|
||||
if total > 0 {
|
||||
n = min(n, int(total/k.Dot())-gripW-least)
|
||||
}
|
||||
return max(n, least)
|
||||
}
|
||||
start := *size
|
||||
e.AlignItems(ui.Stretch).Children(func() {
|
||||
pane := ui.Box(c).Clip().Children(first)
|
||||
shell, base, st := pixel.Shell(c, func() *ui.Element {
|
||||
cur := ui.CursorResizeEW
|
||||
if o.Vertical {
|
||||
cur = ui.CursorResizeNS
|
||||
}
|
||||
return ui.Box(c).Focusable().Role(ui.RoleSplitter).Label(label(k, o.Label, "resize")).Disabled(o.Disabled).Cursor(cur)
|
||||
})
|
||||
if dx, dy, ok := drag(k, base); ok {
|
||||
if o.Vertical {
|
||||
dx = dy
|
||||
}
|
||||
*size += dx
|
||||
}
|
||||
if !o.Disabled && base.Shortcut(0, back) {
|
||||
*size -= 4
|
||||
}
|
||||
if !o.Disabled && base.Shortcut(0, fwd) {
|
||||
*size += 4
|
||||
}
|
||||
*size = limit(*size)
|
||||
if o.Vertical {
|
||||
pane.FillWidth().Height(k.D(*size))
|
||||
shell.FillWidth().Height(k.D(gripW))
|
||||
} else {
|
||||
pane.FillHeight().Width(k.D(*size))
|
||||
shell.FillHeight().Width(k.D(gripW))
|
||||
}
|
||||
shell.Draw(func(p *ui.Painter, r ui.Rect) { grip(k.Canvas(p, r), st, o.Vertical) })
|
||||
ui.Box(c).Grow(1).Clip().Children(second)
|
||||
})
|
||||
e.Draw(func(p *ui.Painter, r ui.Rect) {
|
||||
now := r.W
|
||||
if o.Vertical {
|
||||
now = r.H
|
||||
}
|
||||
if now != total {
|
||||
c.Invalidate()
|
||||
}
|
||||
})
|
||||
res := SplitResult{Element: e, Changed: *size != start}
|
||||
if res.Changed {
|
||||
slog.Debug("8bit: split moved", "size", *size)
|
||||
}
|
||||
return res
|
||||
}
|
||||
|
||||
// grip is a bar with three bumps across its length.
|
||||
func grip(g pixel.Canvas, st pixel.State, vertical bool) {
|
||||
fill := pixel.Face
|
||||
if st.Hover || st.Press {
|
||||
fill = pixel.Lit
|
||||
}
|
||||
g.Rect(0, 0, g.W, g.H, fill)
|
||||
for i := -1; i <= 1; i++ {
|
||||
x, y := g.W/2-1, g.H/2-1+i*4
|
||||
if vertical {
|
||||
x, y = g.W/2-1+i*4, g.H/2-1
|
||||
}
|
||||
g.Dot(x, y, pixel.Lit)
|
||||
g.Dot(x+1, y+1, pixel.Shade)
|
||||
}
|
||||
if st.Disabled {
|
||||
g.Checker(0, 0, g.W, g.H, pixel.Face)
|
||||
}
|
||||
if st.Focus {
|
||||
g.FocusMark(0, 0, g.W, g.H)
|
||||
}
|
||||
}
|
||||
Reference in new issue
Block a user