Add StatusBar to Editor Mode, Iterate on UI Toolkit
* Added `BoxSize()` to Widget that reports the full box size including borders and margin. * The Frame uses the `BoxSize()` of widgets to position them. Reintroduces some padding issues (boxes on the GUI Test stick out of bounds a bit) but is on the right track. * Renamed `Padding` to `Margin` on the Widget object, since the Margin is taken into consideration along with Outline and Border in computing the widget's BoxSize. * Restructured the Label widget to take a Text or TextVariable property and the font settings (render.Text) are in a new `Font` property.
This commit is contained in:
parent
316456ef03
commit
8624a28ea9
|
@ -1,11 +1,13 @@
|
||||||
package balance
|
package balance
|
||||||
|
|
||||||
import "git.kirsle.net/apps/doodle/render"
|
import (
|
||||||
|
"git.kirsle.net/apps/doodle/render"
|
||||||
|
)
|
||||||
|
|
||||||
// Shell related variables.
|
// Shell related variables.
|
||||||
var (
|
var (
|
||||||
// TODO: why not renders transparent
|
// TODO: why not renders transparent
|
||||||
ShellBackgroundColor = render.Color{0, 10, 20, 128}
|
ShellBackgroundColor = render.RGBA(0, 10, 20, 128)
|
||||||
ShellForegroundColor = render.White
|
ShellForegroundColor = render.White
|
||||||
ShellPadding int32 = 8
|
ShellPadding int32 = 8
|
||||||
ShellFontSize = 16
|
ShellFontSize = 16
|
||||||
|
@ -15,3 +17,10 @@ var (
|
||||||
// Ticks that a flashed message persists for.
|
// Ticks that a flashed message persists for.
|
||||||
FlashTTL uint64 = 400
|
FlashTTL uint64 = 400
|
||||||
)
|
)
|
||||||
|
|
||||||
|
// StatusFont is the font for the status bar.
|
||||||
|
var StatusFont = render.Text{
|
||||||
|
Size: 12,
|
||||||
|
Padding: 4,
|
||||||
|
Color: render.Black,
|
||||||
|
}
|
||||||
|
|
|
@ -63,7 +63,8 @@ func (d *Doodle) Run() error {
|
||||||
|
|
||||||
// Set up the default scene.
|
// Set up the default scene.
|
||||||
if d.Scene == nil {
|
if d.Scene == nil {
|
||||||
d.Goto(&GUITestScene{})
|
// d.Goto(&GUITestScene{})
|
||||||
|
d.NewMap()
|
||||||
// d.Goto(&MainScene{})
|
// d.Goto(&MainScene{})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -20,6 +20,8 @@ type EditorScene struct {
|
||||||
Filename string
|
Filename string
|
||||||
Canvas render.Grid
|
Canvas render.Grid
|
||||||
|
|
||||||
|
UI *EditorUI
|
||||||
|
|
||||||
// History of all the pixels placed by the user.
|
// History of all the pixels placed by the user.
|
||||||
pixelHistory []level.Pixel
|
pixelHistory []level.Pixel
|
||||||
lastPixel *level.Pixel // last pixel placed while mouse down and dragging
|
lastPixel *level.Pixel // last pixel placed while mouse down and dragging
|
||||||
|
@ -56,6 +58,8 @@ func (s *EditorScene) Setup(d *Doodle) error {
|
||||||
s.Canvas = nil
|
s.Canvas = nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
s.UI = NewEditorUI(d)
|
||||||
|
|
||||||
d.Flash("Editor Mode. Press 'P' to play this map.")
|
d.Flash("Editor Mode. Press 'P' to play this map.")
|
||||||
|
|
||||||
if s.pixelHistory == nil {
|
if s.pixelHistory == nil {
|
||||||
|
@ -72,6 +76,8 @@ func (s *EditorScene) Setup(d *Doodle) error {
|
||||||
|
|
||||||
// Loop the editor scene.
|
// Loop the editor scene.
|
||||||
func (s *EditorScene) Loop(d *Doodle, ev *events.State) error {
|
func (s *EditorScene) Loop(d *Doodle, ev *events.State) error {
|
||||||
|
s.UI.Loop(ev)
|
||||||
|
|
||||||
// Taking a screenshot?
|
// Taking a screenshot?
|
||||||
if ev.ScreenshotKey.Pressed() {
|
if ev.ScreenshotKey.Pressed() {
|
||||||
log.Info("Taking a screenshot")
|
log.Info("Taking a screenshot")
|
||||||
|
@ -131,6 +137,7 @@ func (s *EditorScene) Loop(d *Doodle, ev *events.State) error {
|
||||||
// Draw the current frame.
|
// Draw the current frame.
|
||||||
func (s *EditorScene) Draw(d *Doodle) error {
|
func (s *EditorScene) Draw(d *Doodle) error {
|
||||||
s.canvas.Draw(d.Engine)
|
s.canvas.Draw(d.Engine)
|
||||||
|
s.UI.Present(d.Engine)
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
116
editor_ui.go
Normal file
116
editor_ui.go
Normal file
|
@ -0,0 +1,116 @@
|
||||||
|
package doodle
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
|
||||||
|
"git.kirsle.net/apps/doodle/balance"
|
||||||
|
"git.kirsle.net/apps/doodle/events"
|
||||||
|
"git.kirsle.net/apps/doodle/render"
|
||||||
|
"git.kirsle.net/apps/doodle/ui"
|
||||||
|
)
|
||||||
|
|
||||||
|
// EditorUI manages the user interface for the Editor Scene.
|
||||||
|
type EditorUI struct {
|
||||||
|
d *Doodle
|
||||||
|
|
||||||
|
// Variables
|
||||||
|
StatusMouseText string
|
||||||
|
|
||||||
|
// Widgets
|
||||||
|
Supervisor *ui.Supervisor
|
||||||
|
StatusBar *ui.Frame
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewEditorUI initializes the Editor UI.
|
||||||
|
func NewEditorUI(d *Doodle) *EditorUI {
|
||||||
|
u := &EditorUI{
|
||||||
|
d: d,
|
||||||
|
Supervisor: ui.NewSupervisor(),
|
||||||
|
StatusMouseText: ".",
|
||||||
|
}
|
||||||
|
u.StatusBar = u.SetupStatusBar(d)
|
||||||
|
return u
|
||||||
|
}
|
||||||
|
|
||||||
|
// Loop to process events and update the UI.
|
||||||
|
func (u *EditorUI) Loop(ev *events.State) {
|
||||||
|
u.StatusMouseText = fmt.Sprintf("Mouse: (%d,%d)",
|
||||||
|
ev.CursorX.Now,
|
||||||
|
ev.CursorY.Now,
|
||||||
|
)
|
||||||
|
u.StatusBar.Compute(u.d.Engine)
|
||||||
|
u.Supervisor.Loop(ev)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Present the UI to the screen.
|
||||||
|
func (u *EditorUI) Present(e render.Engine) {
|
||||||
|
u.StatusBar.Present(e, u.StatusBar.Point())
|
||||||
|
}
|
||||||
|
|
||||||
|
// SetupStatusBar sets up the status bar widget along the bottom of the window.
|
||||||
|
func (u *EditorUI) SetupStatusBar(d *Doodle) *ui.Frame {
|
||||||
|
frame := ui.NewFrame("Status Bar")
|
||||||
|
frame.Configure(ui.Config{
|
||||||
|
BorderStyle: ui.BorderRaised,
|
||||||
|
Background: render.Grey,
|
||||||
|
BorderSize: 2,
|
||||||
|
Width: d.width,
|
||||||
|
})
|
||||||
|
|
||||||
|
cursorLabel := ui.NewLabel(ui.Label{
|
||||||
|
TextVariable: &u.StatusMouseText,
|
||||||
|
Font: balance.StatusFont,
|
||||||
|
})
|
||||||
|
cursorLabel.Configure(ui.Config{
|
||||||
|
Background: render.Grey,
|
||||||
|
BorderStyle: ui.BorderSunken,
|
||||||
|
BorderColor: render.Grey,
|
||||||
|
BorderSize: 1,
|
||||||
|
})
|
||||||
|
cursorLabel.Compute(d.Engine)
|
||||||
|
frame.Pack(cursorLabel, ui.Pack{
|
||||||
|
Anchor: ui.W,
|
||||||
|
})
|
||||||
|
|
||||||
|
filenameLabel := ui.NewLabel(ui.Label{
|
||||||
|
Text: "Filename: untitled.map",
|
||||||
|
Font: balance.StatusFont,
|
||||||
|
})
|
||||||
|
filenameLabel.Configure(ui.Config{
|
||||||
|
Background: render.Grey,
|
||||||
|
BorderStyle: ui.BorderSunken,
|
||||||
|
BorderColor: render.Grey,
|
||||||
|
BorderSize: 1,
|
||||||
|
})
|
||||||
|
filenameLabel.Compute(d.Engine)
|
||||||
|
frame.Pack(filenameLabel, ui.Pack{
|
||||||
|
Anchor: ui.W,
|
||||||
|
})
|
||||||
|
|
||||||
|
extraLabel := ui.NewLabel(ui.Label{
|
||||||
|
Text: "blah",
|
||||||
|
Font: balance.StatusFont,
|
||||||
|
})
|
||||||
|
extraLabel.Configure(ui.Config{
|
||||||
|
Background: render.Grey,
|
||||||
|
BorderStyle: ui.BorderSunken,
|
||||||
|
BorderColor: render.Grey,
|
||||||
|
BorderSize: 1,
|
||||||
|
})
|
||||||
|
extraLabel.Compute(d.Engine)
|
||||||
|
frame.Pack(extraLabel, ui.Pack{
|
||||||
|
Anchor: ui.E,
|
||||||
|
})
|
||||||
|
|
||||||
|
frame.Resize(render.Rect{
|
||||||
|
W: d.width,
|
||||||
|
H: cursorLabel.BoxSize().H + frame.BoxThickness(1),
|
||||||
|
})
|
||||||
|
frame.Compute(d.Engine)
|
||||||
|
frame.MoveTo(render.Point{
|
||||||
|
X: 0,
|
||||||
|
Y: d.height - frame.Size().H,
|
||||||
|
})
|
||||||
|
|
||||||
|
return frame
|
||||||
|
}
|
135
guitest_scene.go
135
guitest_scene.go
|
@ -3,6 +3,7 @@ package doodle
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
|
|
||||||
|
"git.kirsle.net/apps/doodle/balance"
|
||||||
"git.kirsle.net/apps/doodle/events"
|
"git.kirsle.net/apps/doodle/events"
|
||||||
"git.kirsle.net/apps/doodle/render"
|
"git.kirsle.net/apps/doodle/render"
|
||||||
"git.kirsle.net/apps/doodle/ui"
|
"git.kirsle.net/apps/doodle/ui"
|
||||||
|
@ -37,11 +38,13 @@ func (s *GUITestScene) Setup(d *Doodle) error {
|
||||||
})
|
})
|
||||||
|
|
||||||
// Title Bar
|
// Title Bar
|
||||||
titleBar := ui.NewLabel(render.Text{
|
titleBar := ui.NewLabel(ui.Label{
|
||||||
Text: "Widget Toolkit",
|
Text: "Widget Toolkit",
|
||||||
Size: 12,
|
Font: render.Text{
|
||||||
Color: render.White,
|
Size: 12,
|
||||||
Stroke: render.DarkBlue,
|
Color: render.White,
|
||||||
|
Stroke: render.DarkBlue,
|
||||||
|
},
|
||||||
})
|
})
|
||||||
titleBar.Configure(ui.Config{
|
titleBar.Configure(ui.Config{
|
||||||
Background: render.Blue,
|
Background: render.Blue,
|
||||||
|
@ -76,15 +79,17 @@ func (s *GUITestScene) Setup(d *Doodle) error {
|
||||||
|
|
||||||
// Some left frame buttons.
|
// Some left frame buttons.
|
||||||
for _, label := range []string{"New", "Edit", "Play", "Help"} {
|
for _, label := range []string{"New", "Edit", "Play", "Help"} {
|
||||||
btn := ui.NewButton("dummy "+label, ui.NewLabel(render.Text{
|
btn := ui.NewButton("dummy "+label, ui.NewLabel(ui.Label{
|
||||||
Text: label,
|
Text: label,
|
||||||
Size: 12,
|
Font: balance.StatusFont,
|
||||||
Color: render.Black,
|
|
||||||
}))
|
}))
|
||||||
|
btn.Handle("Click", func(p render.Point) {
|
||||||
|
d.Flash("%s clicked", btn)
|
||||||
|
})
|
||||||
s.Supervisor.Add(btn)
|
s.Supervisor.Add(btn)
|
||||||
leftFrame.Pack(btn, ui.Pack{
|
leftFrame.Pack(btn, ui.Pack{
|
||||||
Anchor: ui.N,
|
Anchor: ui.N,
|
||||||
Fill: true,
|
FillX: true,
|
||||||
PadY: 2,
|
PadY: 2,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
@ -98,6 +103,7 @@ func (s *GUITestScene) Setup(d *Doodle) error {
|
||||||
body.Pack(frame, ui.Pack{
|
body.Pack(frame, ui.Pack{
|
||||||
Anchor: ui.W,
|
Anchor: ui.W,
|
||||||
Expand: true,
|
Expand: true,
|
||||||
|
Fill: true,
|
||||||
})
|
})
|
||||||
|
|
||||||
// Right Frame
|
// Right Frame
|
||||||
|
@ -116,19 +122,28 @@ func (s *GUITestScene) Setup(d *Doodle) error {
|
||||||
// A grid of buttons.
|
// A grid of buttons.
|
||||||
for row := 0; row < 3; row++ {
|
for row := 0; row < 3; row++ {
|
||||||
rowFrame := ui.NewFrame(fmt.Sprintf("Row%d", row))
|
rowFrame := ui.NewFrame(fmt.Sprintf("Row%d", row))
|
||||||
|
rowFrame.Configure(ui.Config{
|
||||||
|
Background: render.RGBA(0, uint8((row*20)+120), 0, 255),
|
||||||
|
})
|
||||||
for col := 0; col < 3; col++ {
|
for col := 0; col < 3; col++ {
|
||||||
btn := ui.NewButton("X",
|
(func(row, col int, frame *ui.Frame) {
|
||||||
ui.NewFrame(fmt.Sprintf("Col%d", col)),
|
btn := ui.NewButton(fmt.Sprintf("Grid Button %d:%d", col, row),
|
||||||
)
|
ui.NewFrame(fmt.Sprintf("Col%d", col)),
|
||||||
btn.Configure(ui.Config{
|
)
|
||||||
Height: 20,
|
btn.Configure(ui.Config{
|
||||||
BorderStyle: ui.BorderRaised,
|
Height: 20,
|
||||||
})
|
BorderStyle: ui.BorderRaised,
|
||||||
rowFrame.Pack(btn, ui.Pack{
|
})
|
||||||
Anchor: ui.W,
|
btn.Handle("Click", func(p render.Point) {
|
||||||
Expand: true,
|
d.Flash("%s clicked", btn)
|
||||||
})
|
})
|
||||||
s.Supervisor.Add(btn)
|
rowFrame.Pack(btn, ui.Pack{
|
||||||
|
Anchor: ui.W,
|
||||||
|
Expand: true,
|
||||||
|
FillX: true,
|
||||||
|
})
|
||||||
|
s.Supervisor.Add(btn)
|
||||||
|
})(row, col, rowFrame)
|
||||||
}
|
}
|
||||||
rightFrame.Pack(rowFrame, ui.Pack{
|
rightFrame.Pack(rowFrame, ui.Pack{
|
||||||
Anchor: ui.N,
|
Anchor: ui.N,
|
||||||
|
@ -136,10 +151,12 @@ func (s *GUITestScene) Setup(d *Doodle) error {
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
frame.Pack(ui.NewLabel(render.Text{
|
frame.Pack(ui.NewLabel(ui.Label{
|
||||||
Text: "Hello World!",
|
Text: "Hello World!",
|
||||||
Size: 14,
|
Font: render.Text{
|
||||||
Color: render.Black,
|
Size: 14,
|
||||||
|
Color: render.Black,
|
||||||
|
},
|
||||||
}), ui.Pack{
|
}), ui.Pack{
|
||||||
Anchor: ui.NW,
|
Anchor: ui.NW,
|
||||||
Padding: 2,
|
Padding: 2,
|
||||||
|
@ -147,10 +164,9 @@ func (s *GUITestScene) Setup(d *Doodle) error {
|
||||||
|
|
||||||
cb := ui.NewCheckbox("Overlay",
|
cb := ui.NewCheckbox("Overlay",
|
||||||
&DebugOverlay,
|
&DebugOverlay,
|
||||||
ui.NewLabel(render.Text{
|
ui.NewLabel(ui.Label{
|
||||||
Text: "Toggle Debug Overlay",
|
Text: "Toggle Debug Overlay",
|
||||||
Size: 14,
|
Font: balance.StatusFont,
|
||||||
Color: render.Black,
|
|
||||||
}),
|
}),
|
||||||
)
|
)
|
||||||
frame.Pack(cb, ui.Pack{
|
frame.Pack(cb, ui.Pack{
|
||||||
|
@ -158,18 +174,22 @@ func (s *GUITestScene) Setup(d *Doodle) error {
|
||||||
Padding: 4,
|
Padding: 4,
|
||||||
})
|
})
|
||||||
cb.Supervise(s.Supervisor)
|
cb.Supervise(s.Supervisor)
|
||||||
frame.Pack(ui.NewLabel(render.Text{
|
frame.Pack(ui.NewLabel(ui.Label{
|
||||||
Text: "Like Tk!",
|
Text: "Like Tk!",
|
||||||
Size: 16,
|
Font: render.Text{
|
||||||
Color: render.Red,
|
Size: 16,
|
||||||
|
Color: render.Red,
|
||||||
|
},
|
||||||
}), ui.Pack{
|
}), ui.Pack{
|
||||||
Anchor: ui.SE,
|
Anchor: ui.SE,
|
||||||
Padding: 8,
|
Padding: 8,
|
||||||
})
|
})
|
||||||
frame.Pack(ui.NewLabel(render.Text{
|
frame.Pack(ui.NewLabel(ui.Label{
|
||||||
Text: "Frame widget for pack layouts",
|
Text: "Frame widget for pack layouts",
|
||||||
Size: 14,
|
Font: render.Text{
|
||||||
Color: render.Blue,
|
Size: 14,
|
||||||
|
Color: render.Blue,
|
||||||
|
},
|
||||||
}), ui.Pack{
|
}), ui.Pack{
|
||||||
Anchor: ui.SE,
|
Anchor: ui.SE,
|
||||||
Padding: 8,
|
Padding: 8,
|
||||||
|
@ -184,10 +204,9 @@ func (s *GUITestScene) Setup(d *Doodle) error {
|
||||||
Anchor: ui.N,
|
Anchor: ui.N,
|
||||||
})
|
})
|
||||||
|
|
||||||
button1 := ui.NewButton("Button1", ui.NewLabel(render.Text{
|
button1 := ui.NewButton("Button1", ui.NewLabel(ui.Label{
|
||||||
Text: "New Map",
|
Text: "New Map",
|
||||||
Size: 14,
|
Font: balance.StatusFont,
|
||||||
Color: render.Black,
|
|
||||||
}))
|
}))
|
||||||
button1.SetBackground(render.Blue)
|
button1.SetBackground(render.Blue)
|
||||||
button1.Handle("Click", func(p render.Point) {
|
button1.Handle("Click", func(p render.Point) {
|
||||||
|
@ -196,11 +215,13 @@ func (s *GUITestScene) Setup(d *Doodle) error {
|
||||||
|
|
||||||
log.Info("Button1 bg: %s", button1.Background())
|
log.Info("Button1 bg: %s", button1.Background())
|
||||||
|
|
||||||
button2 := ui.NewButton("Button2", ui.NewLabel(render.Text{
|
button2 := ui.NewButton("Button2", ui.NewLabel(ui.Label{
|
||||||
Text: "New Map",
|
Text: "New Map",
|
||||||
Size: 14,
|
Font: balance.StatusFont,
|
||||||
Color: render.Black,
|
|
||||||
}))
|
}))
|
||||||
|
button2.Handle("Click", func(p render.Point) {
|
||||||
|
d.Flash("Button2 clicked")
|
||||||
|
})
|
||||||
button2.SetText("Load Map")
|
button2.SetText("Load Map")
|
||||||
|
|
||||||
var align = ui.W
|
var align = ui.W
|
||||||
|
@ -230,30 +251,28 @@ func (s *GUITestScene) Draw(d *Doodle) error {
|
||||||
// Clear the canvas and fill it with white.
|
// Clear the canvas and fill it with white.
|
||||||
d.Engine.Clear(render.White)
|
d.Engine.Clear(render.White)
|
||||||
|
|
||||||
label := ui.NewLabel(render.Text{
|
label := ui.NewLabel(ui.Label{
|
||||||
Text: "GUITest Doodle v" + Version,
|
Text: "GUITest Doodle v" + Version,
|
||||||
Size: 26,
|
Font: render.Text{
|
||||||
Color: render.Pink,
|
Size: 26,
|
||||||
Stroke: render.SkyBlue,
|
Color: render.Pink,
|
||||||
Shadow: render.Black,
|
Stroke: render.SkyBlue,
|
||||||
|
Shadow: render.Black,
|
||||||
|
},
|
||||||
})
|
})
|
||||||
label.Compute(d.Engine)
|
label.Compute(d.Engine)
|
||||||
label.MoveTo(render.Point{
|
label.MoveTo(render.Point{
|
||||||
X: (d.width / 2) - (label.Size().W / 2),
|
X: (d.width / 2) - (label.Size().W / 2),
|
||||||
Y: 40,
|
Y: 40,
|
||||||
})
|
})
|
||||||
label.Present(d.Engine)
|
label.Present(d.Engine, label.Point())
|
||||||
|
|
||||||
s.Window.Compute(d.Engine)
|
s.Window.Compute(d.Engine)
|
||||||
s.Window.MoveTo(render.Point{
|
s.Window.MoveTo(render.Point{
|
||||||
X: (d.width / 2) - (s.Window.Size().W / 2),
|
X: (d.width / 2) - (s.Window.Size().W / 2),
|
||||||
Y: 100,
|
Y: 100,
|
||||||
})
|
})
|
||||||
s.Window.Present(d.Engine)
|
s.Window.Present(d.Engine, s.Window.Point())
|
||||||
|
|
||||||
s.Supervisor.Present(d.Engine)
|
|
||||||
|
|
||||||
// os.Exit(1)
|
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
package doodle
|
package doodle
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"git.kirsle.net/apps/doodle/balance"
|
||||||
"git.kirsle.net/apps/doodle/events"
|
"git.kirsle.net/apps/doodle/events"
|
||||||
"git.kirsle.net/apps/doodle/render"
|
"git.kirsle.net/apps/doodle/render"
|
||||||
"git.kirsle.net/apps/doodle/ui"
|
"git.kirsle.net/apps/doodle/ui"
|
||||||
|
@ -23,51 +24,29 @@ func (s *MainScene) Setup(d *Doodle) error {
|
||||||
|
|
||||||
frame := ui.NewFrame("frame")
|
frame := ui.NewFrame("frame")
|
||||||
s.frame = frame
|
s.frame = frame
|
||||||
s.frame.Configure(ui.Config{
|
|
||||||
// Width: 400,
|
|
||||||
// Height: 200,
|
|
||||||
Background: render.Purple,
|
|
||||||
BorderStyle: ui.BorderSolid,
|
|
||||||
BorderSize: 1,
|
|
||||||
BorderColor: render.Blue,
|
|
||||||
})
|
|
||||||
|
|
||||||
button1 := ui.NewButton("Button1", ui.NewLabel(render.Text{
|
button1 := ui.NewButton("Button1", ui.NewLabel(ui.Label{
|
||||||
Text: "New Map",
|
Text: "New Map",
|
||||||
Size: 14,
|
Font: balance.StatusFont,
|
||||||
Color: render.Black,
|
|
||||||
}))
|
}))
|
||||||
// button1.Compute(d.Engine)
|
|
||||||
// button1.MoveTo(render.Point{
|
|
||||||
// X: (d.width / 2) - (button1.Size().W / 2),
|
|
||||||
// Y: 200,
|
|
||||||
// })
|
|
||||||
button1.Handle("Click", func(p render.Point) {
|
button1.Handle("Click", func(p render.Point) {
|
||||||
d.NewMap()
|
d.NewMap()
|
||||||
})
|
})
|
||||||
|
|
||||||
button2 := ui.NewButton("Button2", ui.NewLabel(render.Text{
|
button2 := ui.NewButton("Button2", ui.NewLabel(ui.Label{
|
||||||
Text: "New Map",
|
Text: "New Map",
|
||||||
Size: 14,
|
Font: balance.StatusFont,
|
||||||
Color: render.Black,
|
|
||||||
}))
|
}))
|
||||||
button2.SetText("Load Map")
|
button2.SetText("Load Map")
|
||||||
// button2.Compute(d.Engine)
|
|
||||||
// button2.MoveTo(render.Point{
|
|
||||||
// X: (d.width / 2) - (button2.Size().W / 2),
|
|
||||||
// Y: 260,
|
|
||||||
// })
|
|
||||||
|
|
||||||
var align = ui.E
|
|
||||||
frame.Pack(button1, ui.Pack{
|
frame.Pack(button1, ui.Pack{
|
||||||
Anchor: align,
|
Anchor: ui.N,
|
||||||
Padding: 12,
|
Fill: true,
|
||||||
Fill: true,
|
|
||||||
})
|
})
|
||||||
frame.Pack(button2, ui.Pack{
|
frame.Pack(button2, ui.Pack{
|
||||||
Anchor: align,
|
Anchor: ui.N,
|
||||||
Padding: 12,
|
PadY: 12,
|
||||||
Fill: true,
|
Fill: true,
|
||||||
})
|
})
|
||||||
|
|
||||||
s.Supervisor.Add(button1)
|
s.Supervisor.Add(button1)
|
||||||
|
@ -87,28 +66,28 @@ func (s *MainScene) Draw(d *Doodle) error {
|
||||||
// Clear the canvas and fill it with white.
|
// Clear the canvas and fill it with white.
|
||||||
d.Engine.Clear(render.White)
|
d.Engine.Clear(render.White)
|
||||||
|
|
||||||
label := ui.NewLabel(render.Text{
|
label := ui.NewLabel(ui.Label{
|
||||||
Text: "Doodle v" + Version,
|
Text: "Doodle v" + Version,
|
||||||
Size: 26,
|
Font: render.Text{
|
||||||
Color: render.Pink,
|
Size: 26,
|
||||||
Stroke: render.SkyBlue,
|
Color: render.Pink,
|
||||||
Shadow: render.Black,
|
Stroke: render.SkyBlue,
|
||||||
|
Shadow: render.Black,
|
||||||
|
},
|
||||||
})
|
})
|
||||||
label.Compute(d.Engine)
|
label.Compute(d.Engine)
|
||||||
label.MoveTo(render.Point{
|
label.MoveTo(render.Point{
|
||||||
X: (d.width / 2) - (label.Size().W / 2),
|
X: (d.width / 2) - (label.Size().W / 2),
|
||||||
Y: 120,
|
Y: 120,
|
||||||
})
|
})
|
||||||
label.Present(d.Engine)
|
label.Present(d.Engine, label.Point())
|
||||||
|
|
||||||
s.frame.Compute(d.Engine)
|
s.frame.Compute(d.Engine)
|
||||||
s.frame.MoveTo(render.Point{
|
s.frame.MoveTo(render.Point{
|
||||||
X: (d.width / 2) - (s.frame.Size().W / 2),
|
X: (d.width / 2) - (s.frame.Size().W / 2),
|
||||||
Y: 200,
|
Y: 200,
|
||||||
})
|
})
|
||||||
s.frame.Present(d.Engine)
|
s.frame.Present(d.Engine, s.frame.Point())
|
||||||
|
|
||||||
s.Supervisor.Present(d.Engine)
|
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
|
@ -156,11 +156,12 @@ func (r Rect) IsZero() bool {
|
||||||
|
|
||||||
// Text holds information for drawing text.
|
// Text holds information for drawing text.
|
||||||
type Text struct {
|
type Text struct {
|
||||||
Text string
|
Text string
|
||||||
Size int
|
Size int
|
||||||
Color Color
|
Color Color
|
||||||
Stroke Color // Stroke color (if not zero)
|
Padding int32
|
||||||
Shadow Color // Drop shadow color (if not zero)
|
Stroke Color // Stroke color (if not zero)
|
||||||
|
Shadow Color // Drop shadow color (if not zero)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (t Text) String() string {
|
func (t Text) String() string {
|
||||||
|
|
11
ui/button.go
11
ui/button.go
|
@ -28,7 +28,6 @@ func NewButton(name string, child Widget) *Button {
|
||||||
})
|
})
|
||||||
|
|
||||||
w.Configure(Config{
|
w.Configure(Config{
|
||||||
Padding: 4,
|
|
||||||
BorderSize: 2,
|
BorderSize: 2,
|
||||||
BorderStyle: BorderRaised,
|
BorderStyle: BorderRaised,
|
||||||
OutlineSize: 1,
|
OutlineSize: 1,
|
||||||
|
@ -75,22 +74,21 @@ func (w *Button) Compute(e render.Engine) {
|
||||||
// SetText conveniently sets the button text, for Label children only.
|
// SetText conveniently sets the button text, for Label children only.
|
||||||
func (w *Button) SetText(text string) error {
|
func (w *Button) SetText(text string) error {
|
||||||
if label, ok := w.child.(*Label); ok {
|
if label, ok := w.child.(*Label); ok {
|
||||||
label.Text.Text = text
|
label.Text = text
|
||||||
}
|
}
|
||||||
return errors.New("child is not a Label widget")
|
return errors.New("child is not a Label widget")
|
||||||
}
|
}
|
||||||
|
|
||||||
// Present the button.
|
// Present the button.
|
||||||
func (w *Button) Present(e render.Engine) {
|
func (w *Button) Present(e render.Engine, P render.Point) {
|
||||||
w.Compute(e)
|
w.Compute(e)
|
||||||
var (
|
var (
|
||||||
P = w.Point()
|
|
||||||
S = w.Size()
|
S = w.Size()
|
||||||
ChildSize = w.child.Size()
|
ChildSize = w.child.Size()
|
||||||
)
|
)
|
||||||
|
|
||||||
// Draw the widget's border and everything.
|
// Draw the widget's border and everything.
|
||||||
w.DrawBox(e)
|
w.DrawBox(e, P)
|
||||||
|
|
||||||
// Offset further if we are currently sunken.
|
// Offset further if we are currently sunken.
|
||||||
var clickOffset int32
|
var clickOffset int32
|
||||||
|
@ -112,6 +110,5 @@ func (w *Button) Present(e render.Engine) {
|
||||||
_ = ChildSize
|
_ = ChildSize
|
||||||
|
|
||||||
// Draw the text label inside.
|
// Draw the text label inside.
|
||||||
w.child.MoveTo(moveTo)
|
w.child.Present(e, moveTo)
|
||||||
w.child.Present(e)
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -32,7 +32,6 @@ func NewCheckButton(name string, boolVar *bool, child Widget) *CheckButton {
|
||||||
}
|
}
|
||||||
|
|
||||||
w.Configure(Config{
|
w.Configure(Config{
|
||||||
Padding: 4,
|
|
||||||
BorderSize: 2,
|
BorderSize: 2,
|
||||||
BorderStyle: borderStyle,
|
BorderStyle: borderStyle,
|
||||||
OutlineSize: 1,
|
OutlineSize: 1,
|
||||||
|
|
13
ui/frame.go
13
ui/frame.go
|
@ -46,14 +46,13 @@ func (w *Frame) Compute(e render.Engine) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Present the Frame.
|
// Present the Frame.
|
||||||
func (w *Frame) Present(e render.Engine) {
|
func (w *Frame) Present(e render.Engine, P render.Point) {
|
||||||
var (
|
var (
|
||||||
P = w.Point()
|
|
||||||
S = w.Size()
|
S = w.Size()
|
||||||
)
|
)
|
||||||
|
|
||||||
// Draw the widget's border and everything.
|
// Draw the widget's border and everything.
|
||||||
w.DrawBox(e)
|
w.DrawBox(e, P)
|
||||||
|
|
||||||
// Draw the background color.
|
// Draw the background color.
|
||||||
e.DrawBox(w.Background(), render.Rect{
|
e.DrawBox(w.Background(), render.Rect{
|
||||||
|
@ -65,11 +64,13 @@ func (w *Frame) Present(e render.Engine) {
|
||||||
|
|
||||||
// Draw the widgets.
|
// Draw the widgets.
|
||||||
for _, child := range w.widgets {
|
for _, child := range w.widgets {
|
||||||
|
// child.Compute(e)
|
||||||
p := child.Point()
|
p := child.Point()
|
||||||
child.MoveTo(render.NewPoint(
|
moveTo := render.NewPoint(
|
||||||
P.X+p.X+w.BoxThickness(1),
|
P.X+p.X+w.BoxThickness(1),
|
||||||
P.Y+p.Y+w.BoxThickness(1),
|
P.Y+p.Y+w.BoxThickness(1),
|
||||||
))
|
)
|
||||||
child.Present(e)
|
child.MoveTo(moveTo)
|
||||||
|
child.Present(e, moveTo)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -5,7 +5,7 @@ import "git.kirsle.net/apps/doodle/render"
|
||||||
// computePacked processes all the Pack layout widgets in the Frame.
|
// computePacked processes all the Pack layout widgets in the Frame.
|
||||||
func (w *Frame) computePacked(e render.Engine) {
|
func (w *Frame) computePacked(e render.Engine) {
|
||||||
var (
|
var (
|
||||||
frameSize = w.Size()
|
frameSize = w.BoxSize()
|
||||||
|
|
||||||
// maxWidth and maxHeight are always the computed minimum dimensions
|
// maxWidth and maxHeight are always the computed minimum dimensions
|
||||||
// that the Frame must be to contain all of its children. If the Frame
|
// that the Frame must be to contain all of its children. If the Frame
|
||||||
|
@ -37,7 +37,7 @@ func (w *Frame) computePacked(e render.Engine) {
|
||||||
yDirection = -1 - w.BoxThickness(2) // parent + child BoxThickness(1) = 2
|
yDirection = -1 - w.BoxThickness(2) // parent + child BoxThickness(1) = 2
|
||||||
} else if anchor == E {
|
} else if anchor == E {
|
||||||
x = frameSize.W
|
x = frameSize.W
|
||||||
xDirection = -1 - w.BoxThickness(2)
|
xDirection = -1 // - w.BoxThickness(2)
|
||||||
}
|
}
|
||||||
|
|
||||||
for _, packedWidget := range w.packs[anchor] {
|
for _, packedWidget := range w.packs[anchor] {
|
||||||
|
@ -46,7 +46,7 @@ func (w *Frame) computePacked(e render.Engine) {
|
||||||
child.Compute(e)
|
child.Compute(e)
|
||||||
var (
|
var (
|
||||||
// point = child.Point()
|
// point = child.Point()
|
||||||
size = child.Size()
|
size = child.BoxSize()
|
||||||
yStep = y * yDirection
|
yStep = y * yDirection
|
||||||
xStep = x * xDirection
|
xStep = x * xDirection
|
||||||
)
|
)
|
||||||
|
@ -65,10 +65,7 @@ func (w *Frame) computePacked(e render.Engine) {
|
||||||
x -= size.W + (pack.PadX * 2)
|
x -= size.W + (pack.PadX * 2)
|
||||||
}
|
}
|
||||||
|
|
||||||
child.MoveTo(render.Point{
|
child.MoveTo(render.NewPoint(x, y))
|
||||||
X: x + pack.PadX,
|
|
||||||
Y: y + pack.PadY,
|
|
||||||
})
|
|
||||||
|
|
||||||
if anchor.IsNorth() {
|
if anchor.IsNorth() {
|
||||||
y += size.H + (pack.PadY * 2)
|
y += size.H + (pack.PadY * 2)
|
||||||
|
@ -90,8 +87,8 @@ func (w *Frame) computePacked(e render.Engine) {
|
||||||
if len(expanded) > 0 && !frameSize.IsZero() && frameSize.Bigger(computedSize) {
|
if len(expanded) > 0 && !frameSize.IsZero() && frameSize.Bigger(computedSize) {
|
||||||
// Divy up the size available.
|
// Divy up the size available.
|
||||||
growBy := render.Rect{
|
growBy := render.Rect{
|
||||||
W: ((frameSize.W - computedSize.W) / int32(len(expanded))) - w.BoxThickness(2),
|
W: ((frameSize.W - computedSize.W) / int32(len(expanded))), // - w.BoxThickness(2),
|
||||||
H: ((frameSize.H - computedSize.H) / int32(len(expanded))) - w.BoxThickness(2),
|
H: ((frameSize.H - computedSize.H) / int32(len(expanded))), // - w.BoxThickness(2),
|
||||||
}
|
}
|
||||||
for _, pw := range expanded {
|
for _, pw := range expanded {
|
||||||
pw.widget.ResizeBy(growBy)
|
pw.widget.ResizeBy(growBy)
|
||||||
|
@ -102,10 +99,22 @@ func (w *Frame) computePacked(e render.Engine) {
|
||||||
// If we're not using a fixed Frame size, use the dynamically computed one.
|
// If we're not using a fixed Frame size, use the dynamically computed one.
|
||||||
if !w.FixedSize() {
|
if !w.FixedSize() {
|
||||||
frameSize = render.NewRect(maxWidth, maxHeight)
|
frameSize = render.NewRect(maxWidth, maxHeight)
|
||||||
|
} else {
|
||||||
|
// If either of the sizes were left zero, use the dynamically computed one.
|
||||||
|
if frameSize.W == 0 {
|
||||||
|
frameSize.W = maxWidth
|
||||||
|
}
|
||||||
|
if frameSize.H == 0 {
|
||||||
|
frameSize.H = maxHeight
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Rescan all the widgets in this anchor to re-center them
|
// Rescan all the widgets in this anchor to re-center them
|
||||||
// in their space.
|
// in their space.
|
||||||
|
innerFrameSize := render.NewRect(
|
||||||
|
frameSize.W-w.BoxThickness(2),
|
||||||
|
frameSize.H-w.BoxThickness(2),
|
||||||
|
)
|
||||||
for _, pw := range visited {
|
for _, pw := range visited {
|
||||||
var (
|
var (
|
||||||
child = pw.widget
|
child = pw.widget
|
||||||
|
@ -117,38 +126,42 @@ func (w *Frame) computePacked(e render.Engine) {
|
||||||
moved bool
|
moved bool
|
||||||
)
|
)
|
||||||
|
|
||||||
|
if w.String() == "Frame<Row0; 3 widgets>" {
|
||||||
|
log.Debug("%s>%s: pack.FillX=%d resize=%s innerFrameSize=%s", w, child, pack.FillX, resize, innerFrameSize)
|
||||||
|
}
|
||||||
|
|
||||||
if pack.Anchor.IsNorth() || pack.Anchor.IsSouth() {
|
if pack.Anchor.IsNorth() || pack.Anchor.IsSouth() {
|
||||||
if pack.FillX && resize.W < frameSize.W {
|
if pack.FillX && resize.W < innerFrameSize.W {
|
||||||
resize.W = frameSize.W - w.BoxThickness(2)
|
resize.W = innerFrameSize.W - w.BoxThickness(2)
|
||||||
resized = true
|
resized = true
|
||||||
}
|
}
|
||||||
if resize.W < frameSize.W-w.BoxThickness(4) {
|
if resize.W < innerFrameSize.W-w.BoxThickness(4) {
|
||||||
if pack.Anchor.IsCenter() {
|
if pack.Anchor.IsCenter() {
|
||||||
point.X = (frameSize.W / 2) - (resize.W / 2)
|
point.X = (innerFrameSize.W / 2) - (resize.W / 2)
|
||||||
} else if pack.Anchor.IsWest() {
|
} else if pack.Anchor.IsWest() {
|
||||||
point.X = pack.PadX
|
point.X = pack.PadX
|
||||||
} else if pack.Anchor.IsEast() {
|
} else if pack.Anchor.IsEast() {
|
||||||
point.X = frameSize.W - resize.W - pack.PadX
|
point.X = innerFrameSize.W - resize.W - pack.PadX
|
||||||
}
|
}
|
||||||
|
|
||||||
moved = true
|
moved = true
|
||||||
}
|
}
|
||||||
} else if pack.Anchor.IsWest() || pack.Anchor.IsEast() {
|
} else if pack.Anchor.IsWest() || pack.Anchor.IsEast() {
|
||||||
if pack.FillY && resize.H < frameSize.H {
|
if pack.FillY && resize.H < innerFrameSize.H {
|
||||||
resize.H = frameSize.H - w.BoxThickness(2) // BoxThickness(2) for parent + child
|
resize.H = innerFrameSize.H - w.BoxThickness(2) // BoxThickness(2) for parent + child
|
||||||
// point.Y -= (w.BoxThickness(4) + child.BoxThickness(2))
|
// point.Y -= (w.BoxThickness(4) + child.BoxThickness(2))
|
||||||
moved = true
|
moved = true
|
||||||
resized = true
|
resized = true
|
||||||
}
|
}
|
||||||
|
|
||||||
// Vertically align the widgets.
|
// Vertically align the widgets.
|
||||||
if resize.H < frameSize.H {
|
if resize.H < innerFrameSize.H {
|
||||||
if pack.Anchor.IsMiddle() {
|
if pack.Anchor.IsMiddle() {
|
||||||
point.Y = (frameSize.H / 2) - (resize.H / 2)
|
point.Y = (innerFrameSize.H / 2) - (resize.H / 2) - w.BoxThickness(1)
|
||||||
} else if pack.Anchor.IsNorth() {
|
} else if pack.Anchor.IsNorth() {
|
||||||
point.Y = pack.PadY - w.BoxThickness(4)
|
point.Y = pack.PadY - w.BoxThickness(4)
|
||||||
} else if pack.Anchor.IsSouth() {
|
} else if pack.Anchor.IsSouth() {
|
||||||
point.Y = frameSize.H - resize.H - pack.PadY
|
point.Y = innerFrameSize.H - resize.H - pack.PadY
|
||||||
}
|
}
|
||||||
moved = true
|
moved = true
|
||||||
}
|
}
|
||||||
|
@ -157,6 +170,7 @@ func (w *Frame) computePacked(e render.Engine) {
|
||||||
}
|
}
|
||||||
|
|
||||||
if resized && size != resize {
|
if resized && size != resize {
|
||||||
|
// log.Debug("%s/%s: resize to: %s", w, child, resize)
|
||||||
child.Resize(resize)
|
child.Resize(resize)
|
||||||
child.Compute(e)
|
child.Compute(e)
|
||||||
}
|
}
|
||||||
|
@ -165,9 +179,12 @@ func (w *Frame) computePacked(e render.Engine) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if !w.FixedSize() {
|
// if !w.FixedSize() {
|
||||||
w.Resize(frameSize)
|
w.Resize(render.NewRect(
|
||||||
}
|
frameSize.W-w.BoxThickness(2),
|
||||||
|
frameSize.H-w.BoxThickness(2),
|
||||||
|
))
|
||||||
|
// }
|
||||||
}
|
}
|
||||||
|
|
||||||
// Pack provides configuration fields for Frame.Pack().
|
// Pack provides configuration fields for Frame.Pack().
|
||||||
|
|
51
ui/label.go
51
ui/label.go
|
@ -9,33 +9,48 @@ import (
|
||||||
// Label is a simple text label widget.
|
// Label is a simple text label widget.
|
||||||
type Label struct {
|
type Label struct {
|
||||||
BaseWidget
|
BaseWidget
|
||||||
|
|
||||||
|
// Configurable fields for the constructor.
|
||||||
|
Text string
|
||||||
|
TextVariable *string
|
||||||
|
Font render.Text
|
||||||
|
|
||||||
width int32
|
width int32
|
||||||
height int32
|
height int32
|
||||||
Text render.Text
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// NewLabel creates a new label.
|
// NewLabel creates a new label.
|
||||||
func NewLabel(t render.Text) *Label {
|
func NewLabel(c Label) *Label {
|
||||||
w := &Label{
|
w := &Label{
|
||||||
Text: t,
|
Text: c.Text,
|
||||||
|
TextVariable: c.TextVariable,
|
||||||
|
Font: c.Font,
|
||||||
}
|
}
|
||||||
w.Configure(Config{
|
|
||||||
Padding: 4,
|
|
||||||
})
|
|
||||||
w.IDFunc(func() string {
|
w.IDFunc(func() string {
|
||||||
return fmt.Sprintf("Label<%s>", w.Text.Text)
|
return fmt.Sprintf("Label<%s>", w.text().Text)
|
||||||
})
|
})
|
||||||
return w
|
return w
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// text returns the label's displayed text, coming from the TextVariable if
|
||||||
|
// available or else the Text attribute instead.
|
||||||
|
func (w *Label) text() render.Text {
|
||||||
|
if w.TextVariable != nil {
|
||||||
|
w.Font.Text = *w.TextVariable
|
||||||
|
return w.Font
|
||||||
|
}
|
||||||
|
w.Font.Text = w.Text
|
||||||
|
return w.Font
|
||||||
|
}
|
||||||
|
|
||||||
// Compute the size of the label widget.
|
// Compute the size of the label widget.
|
||||||
func (w *Label) Compute(e render.Engine) {
|
func (w *Label) Compute(e render.Engine) {
|
||||||
rect, _ := e.ComputeTextRect(w.Text)
|
rect, _ := e.ComputeTextRect(w.text())
|
||||||
|
|
||||||
if !w.FixedSize() {
|
if !w.FixedSize() {
|
||||||
w.resizeAuto(render.Rect{
|
w.resizeAuto(render.Rect{
|
||||||
W: rect.W + w.Padding(),
|
W: rect.W + (w.Font.Padding * 2),
|
||||||
H: rect.H + w.Padding(),
|
H: rect.H + (w.Font.Padding * 2),
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -46,14 +61,12 @@ func (w *Label) Compute(e render.Engine) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Present the label widget.
|
// Present the label widget.
|
||||||
func (w *Label) Present(e render.Engine) {
|
func (w *Label) Present(e render.Engine, P render.Point) {
|
||||||
var (
|
border := w.BoxThickness(1)
|
||||||
P = w.Point()
|
|
||||||
border = w.BoxThickness(1)
|
w.DrawBox(e, P)
|
||||||
)
|
e.DrawText(w.text(), render.Point{
|
||||||
w.DrawBox(e)
|
X: P.X + border + w.Font.Padding,
|
||||||
e.DrawText(w.Text, render.Point{
|
Y: P.Y + border + w.Font.Padding,
|
||||||
X: P.X + border,
|
|
||||||
Y: P.Y + border,
|
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
|
@ -20,6 +20,7 @@ type Supervisor struct {
|
||||||
// NewSupervisor creates a supervisor.
|
// NewSupervisor creates a supervisor.
|
||||||
func NewSupervisor() *Supervisor {
|
func NewSupervisor() *Supervisor {
|
||||||
return &Supervisor{
|
return &Supervisor{
|
||||||
|
widgets: []Widget{},
|
||||||
hovering: map[int]interface{}{},
|
hovering: map[int]interface{}{},
|
||||||
clicked: map[int]interface{}{},
|
clicked: map[int]interface{}{},
|
||||||
}
|
}
|
||||||
|
@ -84,8 +85,7 @@ func (s *Supervisor) Present(e render.Engine) {
|
||||||
defer s.lock.RUnlock()
|
defer s.lock.RUnlock()
|
||||||
|
|
||||||
for _, w := range s.widgets {
|
for _, w := range s.widgets {
|
||||||
// w.Present(e)
|
w.Present(e, w.Point())
|
||||||
_ = w
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
60
ui/widget.go
60
ui/widget.go
|
@ -24,8 +24,9 @@ type Widget interface {
|
||||||
Point() render.Point
|
Point() render.Point
|
||||||
MoveTo(render.Point)
|
MoveTo(render.Point)
|
||||||
MoveBy(render.Point)
|
MoveBy(render.Point)
|
||||||
Size() render.Rect // Return the Width and Height of the widget.
|
Size() render.Rect // Return the Width and Height of the widget.
|
||||||
FixedSize() bool // Return whether the size is fixed (true) or automatic (false)
|
FixedSize() bool // Return whether the size is fixed (true) or automatic (false)
|
||||||
|
BoxSize() render.Rect // Return the full size including the border and outline.
|
||||||
Resize(render.Rect)
|
Resize(render.Rect)
|
||||||
ResizeBy(render.Rect)
|
ResizeBy(render.Rect)
|
||||||
|
|
||||||
|
@ -34,11 +35,11 @@ type Widget interface {
|
||||||
|
|
||||||
// Thickness of the padding + border + outline.
|
// Thickness of the padding + border + outline.
|
||||||
BoxThickness(multiplier int32) int32
|
BoxThickness(multiplier int32) int32
|
||||||
DrawBox(render.Engine)
|
DrawBox(render.Engine, render.Point)
|
||||||
|
|
||||||
// Widget configuration getters.
|
// Widget configuration getters.
|
||||||
Padding() int32 // Padding
|
Margin() int32 // Margin away from other widgets
|
||||||
SetPadding(int32) //
|
SetMargin(int32) //
|
||||||
Background() render.Color // Background color
|
Background() render.Color // Background color
|
||||||
SetBackground(render.Color) //
|
SetBackground(render.Color) //
|
||||||
Foreground() render.Color // Foreground color
|
Foreground() render.Color // Foreground color
|
||||||
|
@ -60,7 +61,7 @@ type Widget interface {
|
||||||
Compute(render.Engine)
|
Compute(render.Engine)
|
||||||
|
|
||||||
// Render the final widget onto the drawing engine.
|
// Render the final widget onto the drawing engine.
|
||||||
Present(render.Engine)
|
Present(render.Engine, render.Point)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Config holds common base widget configs for quick configuration.
|
// Config holds common base widget configs for quick configuration.
|
||||||
|
@ -73,9 +74,9 @@ type Config struct {
|
||||||
AutoResize bool
|
AutoResize bool
|
||||||
Width int32
|
Width int32
|
||||||
Height int32
|
Height int32
|
||||||
Padding int32
|
Margin int32
|
||||||
PadX int32
|
MarginX int32
|
||||||
PadY int32
|
MarginY int32
|
||||||
Background render.Color
|
Background render.Color
|
||||||
Foreground render.Color
|
Foreground render.Color
|
||||||
BorderSize int32
|
BorderSize int32
|
||||||
|
@ -94,7 +95,7 @@ type BaseWidget struct {
|
||||||
width int32
|
width int32
|
||||||
height int32
|
height int32
|
||||||
point render.Point
|
point render.Point
|
||||||
padding int32
|
margin int32
|
||||||
background render.Color
|
background render.Color
|
||||||
foreground render.Color
|
foreground render.Color
|
||||||
borderStyle BorderStyle
|
borderStyle BorderStyle
|
||||||
|
@ -142,8 +143,8 @@ func (w *BaseWidget) Configure(c Config) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if c.Padding != 0 {
|
if c.Margin != 0 {
|
||||||
w.padding = c.Padding
|
w.margin = c.Margin
|
||||||
}
|
}
|
||||||
if c.Background != render.Invisible {
|
if c.Background != render.Invisible {
|
||||||
w.background = c.Background
|
w.background = c.Background
|
||||||
|
@ -194,6 +195,15 @@ func (w *BaseWidget) Size() render.Rect {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// BoxSize returns the full rendered size of the widget including its box
|
||||||
|
// thickness (border, padding and outline).
|
||||||
|
func (w *BaseWidget) BoxSize() render.Rect {
|
||||||
|
return render.Rect{
|
||||||
|
W: w.width + w.BoxThickness(2),
|
||||||
|
H: w.height + w.BoxThickness(2),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// FixedSize returns whether the widget's size has been hard-coded by the user
|
// FixedSize returns whether the widget's size has been hard-coded by the user
|
||||||
// (true) or if it automatically resizes based on its contents (false).
|
// (true) or if it automatically resizes based on its contents (false).
|
||||||
func (w *BaseWidget) FixedSize() bool {
|
func (w *BaseWidget) FixedSize() bool {
|
||||||
|
@ -226,13 +236,12 @@ func (w *BaseWidget) BoxThickness(m int32) int32 {
|
||||||
if m == 0 {
|
if m == 0 {
|
||||||
m = 1
|
m = 1
|
||||||
}
|
}
|
||||||
return (w.Padding() * m) + (w.BorderSize() * m) + (w.OutlineSize() * m)
|
return (w.Margin() * m) + (w.BorderSize() * m) + (w.OutlineSize() * m)
|
||||||
}
|
}
|
||||||
|
|
||||||
// DrawBox draws the border and outline.
|
// DrawBox draws the border and outline.
|
||||||
func (w *BaseWidget) DrawBox(e render.Engine) {
|
func (w *BaseWidget) DrawBox(e render.Engine, P render.Point) {
|
||||||
var (
|
var (
|
||||||
P = w.Point()
|
|
||||||
S = w.Size()
|
S = w.Size()
|
||||||
outline = w.OutlineSize()
|
outline = w.OutlineSize()
|
||||||
border = w.BorderSize()
|
border = w.BorderSize()
|
||||||
|
@ -300,25 +309,16 @@ func (w *BaseWidget) DrawBox(e render.Engine) {
|
||||||
if w.Background() != render.Invisible {
|
if w.Background() != render.Invisible {
|
||||||
e.DrawBox(w.Background(), box)
|
e.DrawBox(w.Background(), box)
|
||||||
}
|
}
|
||||||
|
|
||||||
// log.Info("Widget %s background color: %s", w, w.Background())
|
|
||||||
|
|
||||||
// XXX: color effective area
|
|
||||||
// box.X += w.Padding()
|
|
||||||
// box.Y += w.Padding()
|
|
||||||
// box.W -= w.Padding() * 2
|
|
||||||
// box.H -= w.Padding() * 2
|
|
||||||
// e.DrawBox(render.RGBA(0, 255, 255, 153), box)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Padding returns the padding width.
|
// Margin returns the margin width.
|
||||||
func (w *BaseWidget) Padding() int32 {
|
func (w *BaseWidget) Margin() int32 {
|
||||||
return w.padding
|
return w.margin
|
||||||
}
|
}
|
||||||
|
|
||||||
// SetPadding sets the padding width.
|
// SetMargin sets the margin width.
|
||||||
func (w *BaseWidget) SetPadding(v int32) {
|
func (w *BaseWidget) SetMargin(v int32) {
|
||||||
w.padding = v
|
w.margin = v
|
||||||
}
|
}
|
||||||
|
|
||||||
// Background returns the background color.
|
// Background returns the background color.
|
||||||
|
|
Loading…
Reference in New Issue
Block a user