WIP Labels

This commit is contained in:
Noah 2018-07-31 17:18:13 -07:00
parent 11df6cbda9
commit 2e36d9ca85
11 changed files with 750 additions and 51 deletions

View File

@ -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(&MainScene{}) d.Goto(&GUITestScene{})
// d.Goto(&MainScene{})
} }
log.Info("Enter Main Loop") log.Info("Enter Main Loop")

159
guitest_scene.go Normal file
View File

@ -0,0 +1,159 @@
package doodle
import (
"git.kirsle.net/apps/doodle/events"
"git.kirsle.net/apps/doodle/render"
"git.kirsle.net/apps/doodle/ui"
)
// GUITestScene implements the main menu of Doodle.
type GUITestScene struct {
Supervisor *ui.Supervisor
frame *ui.Frame
window *ui.Frame
}
// Name of the scene.
func (s *GUITestScene) Name() string {
return "Main"
}
// Setup the scene.
func (s *GUITestScene) Setup(d *Doodle) error {
s.Supervisor = ui.NewSupervisor()
window := ui.NewFrame()
s.window = window
window.Configure(ui.Config{
Width: 400,
Height: 400,
Background: render.Grey,
BorderStyle: ui.BorderRaised,
BorderSize: 2,
})
titleBar := ui.NewLabel(render.Text{
Text: "Alert",
Size: 12,
Color: render.White,
Stroke: render.Black,
})
titleBar.Configure(ui.Config{
Background: render.Blue,
OutlineSize: 1,
OutlineColor: render.Black,
})
window.Pack(titleBar, ui.Pack{
Anchor: ui.N,
FillX: true,
})
msgFrame := ui.NewFrame()
msgFrame.Configure(ui.Config{
Background: render.Grey,
BorderStyle: ui.BorderRaised,
BorderSize: 1,
})
window.Pack(msgFrame, ui.Pack{
Anchor: ui.N,
Fill: true,
Padding: 4,
})
btnFrame := ui.NewFrame()
btnFrame.Configure(ui.Config{
Background: render.DarkRed,
})
window.Pack(btnFrame, ui.Pack{
Anchor: ui.N,
Padding: 4,
})
msg := ui.NewLabel(render.Text{
Text: "Hello World!",
Size: 14,
Color: render.Black,
})
msgFrame.Pack(msg, ui.Pack{
Anchor: ui.NW,
Padding: 2,
})
button1 := ui.NewButton(*ui.NewLabel(render.Text{
Text: "New Map",
Size: 14,
Color: render.Black,
}))
button1.SetBackground(render.Blue)
button1.Handle("Click", func(p render.Point) {
d.NewMap()
})
log.Info("Button1 bg: %s", button1.Background())
button2 := ui.NewButton(*ui.NewLabel(render.Text{
Text: "New Map",
Size: 14,
Color: render.Black,
}))
button2.SetText("Load Map")
var align = ui.W
btnFrame.Pack(button1, ui.Pack{
Anchor: align,
Padding: 20,
Fill: true,
})
btnFrame.Pack(button2, ui.Pack{
Anchor: align,
Padding: 20,
Fill: true,
})
s.Supervisor.Add(button1)
s.Supervisor.Add(button2)
return nil
}
// Loop the editor scene.
func (s *GUITestScene) Loop(d *Doodle, ev *events.State) error {
s.Supervisor.Loop(ev)
return nil
}
// Draw the pixels on this frame.
func (s *GUITestScene) Draw(d *Doodle) error {
// Clear the canvas and fill it with white.
d.Engine.Clear(render.White)
label := ui.NewLabel(render.Text{
Text: "GUITest Doodle v" + Version,
Size: 26,
Color: render.Pink,
Stroke: render.SkyBlue,
Shadow: render.Black,
})
label.Compute(d.Engine)
label.MoveTo(render.Point{
X: (d.width / 2) - (label.Size().W / 2),
Y: 40,
})
label.Present(d.Engine)
s.window.Compute(d.Engine)
s.window.MoveTo(render.Point{
X: (d.width / 2) - (s.window.Size().W / 2),
Y: 100,
})
s.window.Present(d.Engine)
s.Supervisor.Present(d.Engine)
return nil
}
// Destroy the scene.
func (s *GUITestScene) Destroy() error {
return nil
}

View File

@ -9,6 +9,7 @@ import (
// MainScene implements the main menu of Doodle. // MainScene implements the main menu of Doodle.
type MainScene struct { type MainScene struct {
Supervisor *ui.Supervisor Supervisor *ui.Supervisor
frame *ui.Frame
} }
// Name of the scene. // Name of the scene.
@ -20,16 +21,27 @@ func (s *MainScene) Name() string {
func (s *MainScene) Setup(d *Doodle) error { func (s *MainScene) Setup(d *Doodle) error {
s.Supervisor = ui.NewSupervisor() s.Supervisor = ui.NewSupervisor()
frame := ui.NewFrame()
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(*ui.NewLabel(render.Text{ button1 := ui.NewButton(*ui.NewLabel(render.Text{
Text: "New Map", Text: "New Map",
Size: 14, Size: 14,
Color: render.Black, Color: render.Black,
})) }))
button1.Compute(d.Engine) // button1.Compute(d.Engine)
button1.MoveTo(render.Point{ // button1.MoveTo(render.Point{
X: (d.width / 2) - (button1.Size().W / 2), // X: (d.width / 2) - (button1.Size().W / 2),
Y: 200, // Y: 200,
}) // })
button1.Handle("Click", func(p render.Point) { button1.Handle("Click", func(p render.Point) {
d.NewMap() d.NewMap()
}) })
@ -40,10 +52,22 @@ func (s *MainScene) Setup(d *Doodle) error {
Color: render.Black, Color: render.Black,
})) }))
button2.SetText("Load Map") button2.SetText("Load Map")
button2.Compute(d.Engine) // button2.Compute(d.Engine)
button2.MoveTo(render.Point{ // button2.MoveTo(render.Point{
X: (d.width / 2) - (button2.Size().W / 2), // X: (d.width / 2) - (button2.Size().W / 2),
Y: 260, // Y: 260,
// })
var align = ui.E
frame.Pack(button1, ui.Pack{
Anchor: align,
Padding: 12,
Fill: true,
})
frame.Pack(button2, ui.Pack{
Anchor: align,
Padding: 12,
Fill: true,
}) })
s.Supervisor.Add(button1) s.Supervisor.Add(button1)
@ -77,6 +101,13 @@ func (s *MainScene) Draw(d *Doodle) error {
}) })
label.Present(d.Engine) label.Present(d.Engine)
s.frame.Compute(d.Engine)
s.frame.MoveTo(render.Point{
X: (d.width / 2) - (s.frame.Size().W / 2),
Y: 200,
})
s.frame.Present(d.Engine)
s.Supervisor.Present(d.Engine) s.Supervisor.Present(d.Engine)
return nil return nil

View File

@ -89,6 +89,16 @@ func (c Color) Add(r, g, b, a int32) Color {
} }
} }
// Lighten a color value.
func (c Color) Lighten(v int32) Color {
return c.Add(v, v, v, 0)
}
// Darken a color value.
func (c Color) Darken(v int32) Color {
return c.Add(-v, -v, -v, 0)
}
// Point holds an X,Y coordinate value. // Point holds an X,Y coordinate value.
type Point struct { type Point struct {
X int32 X int32

View File

@ -1,6 +1,8 @@
package ui package ui
import ( import (
"fmt"
"git.kirsle.net/apps/doodle/render" "git.kirsle.net/apps/doodle/render"
"git.kirsle.net/apps/doodle/ui/theme" "git.kirsle.net/apps/doodle/ui/theme"
) )
@ -21,12 +23,14 @@ func NewButton(label Label) *Button {
Label: label, Label: label,
} }
w.SetPadding(4) w.Configure(Config{
w.SetBorderSize(2) Padding: 4,
w.SetBorderStyle(BorderRaised) BorderSize: 2,
w.SetOutlineSize(1) BorderStyle: BorderRaised,
w.SetOutlineColor(theme.ButtonOutlineColor) OutlineSize: 1,
w.SetBackground(theme.ButtonBackgroundColor) OutlineColor: theme.ButtonOutlineColor,
Background: theme.ButtonBackgroundColor,
})
w.Handle("MouseOver", func(p render.Point) { w.Handle("MouseOver", func(p render.Point) {
w.hovering = true w.hovering = true
@ -46,6 +50,10 @@ func NewButton(label Label) *Button {
w.SetBorderStyle(BorderRaised) w.SetBorderStyle(BorderRaised)
}) })
w.IDFunc(func() string {
return fmt.Sprintf("Button<%s>", w.Label.Text.Text)
})
return w return w
} }

325
ui/frame.go Normal file
View File

@ -0,0 +1,325 @@
package ui
import (
"fmt"
"time"
"git.kirsle.net/apps/doodle/render"
)
// Frame is a widget that contains other widgets.
type Frame struct {
BaseWidget
packs map[Anchor][]packedWidget
widgets []Widget
}
// NewFrame creates a new Frame.
func NewFrame() *Frame {
return &Frame{
packs: map[Anchor][]packedWidget{},
widgets: []Widget{},
}
}
func (w *Frame) String() string {
return fmt.Sprintf("Frame<%d widgets>",
len(w.widgets),
)
}
// Compute the size of the Frame.
func (w *Frame) Compute(e render.Engine) {
var (
frameSize = w.Size()
maxWidth int32
maxHeight int32
visited = []packedWidget{}
)
// Initialize the dimensions?
if w.FixedSize() {
maxWidth = frameSize.W
maxHeight = frameSize.H
}
for anchor := AnchorMin; anchor <= AnchorMax; anchor++ {
if _, ok := w.packs[anchor]; !ok {
continue
}
var (
x int32
y int32
yDirection int32 = 1
xDirection int32 = 1
)
if anchor.IsSouth() {
y = frameSize.H
yDirection = -1 - w.BoxThickness(1)
} else if anchor == E {
x = frameSize.W
xDirection = -1
}
for _, packedWidget := range w.packs[anchor] {
child := packedWidget.widget
pack := packedWidget.pack
child.Compute(e)
var (
// point = child.Point()
size = child.Size()
yStep = y * yDirection
xStep = x * xDirection
)
if !w.FixedSize() {
log.Warn("not fixed")
if xStep+size.W+(pack.PadX*2) > maxWidth {
var old = maxWidth
maxWidth = xStep + size.W + (pack.PadX * 2)
log.Error("%s %s Upgrading maxWidth %d -> %d (size %s) xstep %d",
w,
child,
old,
maxWidth,
size,
xStep,
)
time.Sleep(5)
}
if yStep+size.H+(pack.PadY*2) > maxHeight {
maxHeight = yStep + size.H + (pack.PadY * 2)
}
}
if anchor.IsSouth() {
y -= size.H + (pack.PadY * 2)
}
if anchor.IsEast() {
x -= size.W + (pack.PadX * 2)
}
child.MoveTo(render.Point{
X: x + pack.PadX,
Y: y + pack.PadY,
})
if anchor.IsNorth() {
y += size.H + (pack.PadY * 2)
}
if anchor == W {
x += size.W + (pack.PadX * 2)
}
visited = append(visited, packedWidget)
}
}
// Rescan all the widgets in this anchor to re-center them
// in their space.
for _, pw := range visited {
var (
child = pw.widget
pack = pw.pack
point = child.Point()
size = child.Size()
resized bool
moved bool
)
if pack.Anchor.IsNorth() || pack.Anchor.IsSouth() {
if pack.FillX && size.W < maxWidth {
size.W = maxWidth - w.BoxThickness(2)
resized = true
}
if size.W < maxWidth {
if pack.Anchor.IsCenter() {
point.X = (maxWidth / 2) - (size.W / 2)
} else if pack.Anchor.IsWest() {
point.X = pack.PadX
} else if pack.Anchor.IsEast() {
point.X = maxWidth - size.W - pack.PadX
}
moved = true
}
} else if pack.Anchor.IsWest() || pack.Anchor.IsEast() {
if pack.FillY && size.H < maxHeight {
size.H = maxHeight - w.BoxThickness(2)
resized = true
}
if size.H < maxHeight {
if pack.Anchor.IsMiddle() {
point.Y = (maxHeight / 2) - (size.H / 2)
} else if pack.Anchor.IsNorth() {
point.Y = pack.PadY
} else if pack.Anchor.IsSouth() {
point.Y = maxHeight - size.H - pack.PadY
}
moved = true
}
} else {
log.Error("unsupported pack.Anchor")
}
if resized {
child.Resize(size)
}
if moved {
child.MoveTo(point)
}
}
if !w.FixedSize() {
w.Resize(render.Rect{
W: maxWidth + w.BoxThickness(2),
H: maxHeight + w.BoxThickness(2),
})
}
}
// Present the Frame.
func (w *Frame) Present(e render.Engine) {
var (
P = w.Point()
S = w.Size()
)
// Draw the widget's border and everything.
w.DrawBox(e)
// Draw the background color.
e.DrawBox(w.Background(), render.Rect{
X: P.X + w.BoxThickness(1),
Y: P.Y + w.BoxThickness(1),
W: S.W - w.BoxThickness(2),
H: S.H - w.BoxThickness(2),
})
// Draw the widgets.
for _, child := range w.widgets {
p := child.Point()
child.MoveTo(render.NewPoint(
P.X+p.X+w.BoxThickness(1),
P.Y+p.Y+w.BoxThickness(1),
))
child.Present(e)
}
}
// Pack provides configuration fields for Frame.Pack().
type Pack struct {
// Side of the parent to anchor the position to, like N, SE, W. Default
// is Center.
Anchor Anchor
// If the widget is smaller than its allocated space, grow the widget
// to fill its space in the Frame.
Fill bool
FillX bool
FillY bool
Padding int32 // Equal padding on X and Y.
PadX int32
PadY int32
// Expand bool // Widget should grow to fill any remaining space.
}
// Anchor is a cardinal direction.
type Anchor uint8
// Anchor values.
const (
Center Anchor = iota
N
NE
E
SE
S
SW
W
NW
)
// Range of Anchor values.
const (
AnchorMin = Center
AnchorMax = NW
)
// IsNorth returns if the anchor is N, NE or NW.
func (a Anchor) IsNorth() bool {
return a == N || a == NE || a == NW
}
// IsSouth returns if the anchor is S, SE or SW.
func (a Anchor) IsSouth() bool {
return a == S || a == SE || a == SW
}
// IsEast returns if the anchor is E, NE or SE.
func (a Anchor) IsEast() bool {
return a == E || a == NE || a == SE
}
// IsWest returns if the anchor is W, NW or SW.
func (a Anchor) IsWest() bool {
return a == W || a == NW || a == SW
}
// IsCenter returns if the anchor is Center, N or S, to determine
// whether to align text as centered for North/South anchors.
func (a Anchor) IsCenter() bool {
return a == Center || a == N || a == S
}
// IsMiddle returns if the anchor is Center, E or W, to determine
// whether to align text as middled for East/West anchors.
func (a Anchor) IsMiddle() bool {
return a == Center || a == W || a == E
}
// Pack a widget along a side of the frame.
func (w *Frame) Pack(child Widget, config ...Pack) {
var C Pack
if len(config) > 0 {
C = config[0]
}
// Initialize the pack list for this anchor?
if _, ok := w.packs[C.Anchor]; !ok {
w.packs[C.Anchor] = []packedWidget{}
}
// Padding: if the user only provided Padding add it to both
// the X and Y value. If the user additionally provided the X
// and Y value, it will add to the base padding as you'd expect.
C.PadX += C.Padding
C.PadY += C.Padding
w.packs[C.Anchor] = append(w.packs[C.Anchor], packedWidget{
widget: child,
pack: C,
})
w.widgets = append(w.widgets, child)
}
type packLayout struct {
widgets []packedWidget
}
type packedWidget struct {
widget Widget
pack Pack
fill uint8
}
// packedWidget.fill values
const (
fillNone uint8 = iota
fillX
fillY
fillBoth
)

View File

@ -1,6 +1,10 @@
package ui package ui
import "git.kirsle.net/apps/doodle/render" import (
"fmt"
"git.kirsle.net/apps/doodle/render"
)
// Label is a simple text label widget. // Label is a simple text label widget.
type Label struct { type Label struct {
@ -12,20 +16,40 @@ type Label struct {
// NewLabel creates a new label. // NewLabel creates a new label.
func NewLabel(t render.Text) *Label { func NewLabel(t render.Text) *Label {
return &Label{ w := &Label{
Text: t, Text: t,
} }
w.Configure(Config{
Padding: 4,
})
w.IDFunc(func() string {
return fmt.Sprintf("Label<%s>", w.Text.Text)
})
return w
} }
// 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, err := e.ComputeTextRect(w.Text) rect, _ := e.ComputeTextRect(w.Text)
w.Resize(rect) w.Resize(render.Rect{
_ = rect W: rect.W + w.Padding(),
_ = err H: rect.H + w.Padding(),
})
w.MoveTo(render.Point{
X: rect.X + w.BoxThickness(1),
Y: rect.Y + w.BoxThickness(1),
})
} }
// Present the label widget. // Present the label widget.
func (w *Label) Present(e render.Engine) { func (w *Label) Present(e render.Engine) {
e.DrawText(w.Text, w.Point()) var (
P = w.Point()
border = w.BoxThickness(1)
)
w.DrawBox(e)
e.DrawText(w.Text, render.Point{
X: P.X + border,
Y: P.Y + border,
})
} }

14
ui/log.go Normal file
View File

@ -0,0 +1,14 @@
package ui
import "github.com/kirsle/golog"
var log *golog.Logger
func init() {
log = golog.GetLogger("ui")
log.Configure(&golog.Config{
Level: golog.DebugLevel,
Theme: golog.DarkTheme,
Colors: golog.ExtendedColor,
})
}

View File

@ -84,7 +84,8 @@ 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
} }
} }

View File

@ -7,4 +7,6 @@ var (
ButtonBackgroundColor = render.RGBA(200, 200, 200, 255) ButtonBackgroundColor = render.RGBA(200, 200, 200, 255)
ButtonHoverColor = render.RGBA(200, 255, 255, 255) ButtonHoverColor = render.RGBA(200, 255, 255, 255)
ButtonOutlineColor = render.Black ButtonOutlineColor = render.Black
BorderColorOffset int32 = 40
) )

View File

@ -2,6 +2,7 @@ package ui
import ( import (
"git.kirsle.net/apps/doodle/render" "git.kirsle.net/apps/doodle/render"
"git.kirsle.net/apps/doodle/ui/theme"
) )
// BorderStyle options for widget.SetBorderStyle() // BorderStyle options for widget.SetBorderStyle()
@ -16,10 +17,14 @@ const (
// Widget is a user interface element. // Widget is a user interface element.
type Widget interface { type Widget interface {
ID() string // Get the widget's string ID.
IDFunc(func() string) // Set a function that returns the widget's ID.
String() string
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)
Resize(render.Rect) Resize(render.Rect)
Handle(string, func(render.Point)) Handle(string, func(render.Point))
@ -56,9 +61,34 @@ type Widget interface {
Present(render.Engine) Present(render.Engine)
} }
// Config holds common base widget configs for quick configuration.
type Config struct {
// Size management. If you provide a non-zero value for Width and Height,
// the widget will be resized and the "fixedSize" flag is set, meaning it
// will not re-compute its size dynamically. To set the size while also
// keeping the auto-resize property, pass AutoResize=true too. This is
// mainly used internally when widgets are calculating their automatic sizes.
AutoResize bool
Width int32
Height int32
Padding int32
PadX int32
PadY int32
Background render.Color
Foreground render.Color
BorderSize int32
BorderStyle BorderStyle
BorderColor render.Color
OutlineSize int32
OutlineColor render.Color
}
// BaseWidget holds common functionality for all widgets, such as managing // BaseWidget holds common functionality for all widgets, such as managing
// their widths and heights. // their widths and heights.
type BaseWidget struct { type BaseWidget struct {
id string
idFunc func() string
fixedSize bool
width int32 width int32
height int32 height int32
point render.Point point render.Point
@ -73,6 +103,66 @@ type BaseWidget struct {
handlers map[string][]func(render.Point) handlers map[string][]func(render.Point)
} }
// SetID sets a string name for your widget, helpful for debugging purposes.
func (w *BaseWidget) SetID(id string) {
w.id = id
}
// ID returns the ID that the widget calls itself by.
func (w *BaseWidget) ID() string {
if w.idFunc == nil {
w.IDFunc(func() string {
return "Widget<Untitled>"
})
}
return w.idFunc()
}
// IDFunc sets an ID function.
func (w *BaseWidget) IDFunc(fn func() string) {
w.idFunc = fn
}
func (w *BaseWidget) String() string {
return w.ID()
}
// Configure the base widget with all the common properties at once. Any
// property left as the zero value will not update the widget.
func (w *BaseWidget) Configure(c Config) {
if c.Width != 0 && c.Height != 0 {
w.fixedSize = !c.AutoResize
w.width = c.Width
w.height = c.Height
}
if c.Padding != 0 {
w.padding = c.Padding
}
if c.Background != render.Invisible {
w.background = c.Background
}
if c.Foreground != render.Invisible {
w.foreground = c.Foreground
}
if c.BorderColor != render.Invisible {
w.borderColor = c.BorderColor
}
if c.OutlineColor != render.Invisible {
w.outlineColor = c.OutlineColor
}
if c.BorderSize != 0 {
w.borderSize = c.BorderSize
}
if c.BorderStyle != BorderSolid {
w.borderStyle = c.BorderStyle
}
if c.OutlineSize != 0 {
w.outlineSize = c.OutlineSize
}
}
// Point returns the X,Y position of the widget on the window. // Point returns the X,Y position of the widget on the window.
func (w *BaseWidget) Point() render.Point { func (w *BaseWidget) Point() render.Point {
return w.point return w.point
@ -98,8 +188,21 @@ func (w *BaseWidget) Size() render.Rect {
} }
} }
// 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).
func (w *BaseWidget) FixedSize() bool {
return w.fixedSize
}
// Resize sets the size of the widget to the .W and .H attributes of a rect. // Resize sets the size of the widget to the .W and .H attributes of a rect.
func (w *BaseWidget) Resize(v render.Rect) { func (w *BaseWidget) Resize(v render.Rect) {
w.fixedSize = true
w.width = v.W
w.height = v.H
}
// resizeAuto sets the size of the widget but doesn't set the fixedSize flag.
func (w *BaseWidget) resizeAuto(v render.Rect) {
w.width = v.W w.width = v.W
w.height = v.H w.height = v.H
} }
@ -121,8 +224,8 @@ func (w *BaseWidget) DrawBox(e render.Engine) {
outline = w.OutlineSize() outline = w.OutlineSize()
border = w.BorderSize() border = w.BorderSize()
borderColor = w.BorderColor() borderColor = w.BorderColor()
highlight = borderColor.Add(20, 20, 20, 0) highlight = borderColor.Lighten(theme.BorderColorOffset)
shadow = borderColor.Add(-20, -20, -20, 0) shadow = borderColor.Darken(theme.BorderColorOffset)
color render.Color color render.Color
box = render.Rect{ box = render.Rect{
X: P.X, X: P.X,
@ -132,46 +235,67 @@ func (w *BaseWidget) DrawBox(e render.Engine) {
} }
) )
if borderColor == render.Invisible {
borderColor = render.Red
}
// Draw the outline layer as the full size of the widget. // Draw the outline layer as the full size of the widget.
e.DrawBox(w.OutlineColor(), render.Rect{ if outline > 0 && w.OutlineColor() != render.Invisible {
X: P.X - outline, e.DrawBox(w.OutlineColor(), render.Rect{
Y: P.Y - outline, X: P.X,
W: S.W + (outline * 2), Y: P.Y,
H: S.H + (outline * 2), W: S.W,
}) H: S.H,
})
}
box.X += outline
box.Y += outline
box.W -= outline * 2
box.H -= outline * 2
// Highlight on the top left edge. // Highlight on the top left edge.
if w.BorderStyle() == BorderRaised { if border > 0 {
color = highlight if w.BorderStyle() == BorderRaised {
} else if w.BorderStyle() == BorderSunken { color = highlight
color = shadow } else if w.BorderStyle() == BorderSunken {
} else { color = shadow
color = borderColor } else {
color = borderColor
}
e.DrawBox(color, box)
} }
e.DrawBox(color, box)
box.W = S.W
// Shadow on the bottom right edge. // Shadow on the bottom right edge.
box.X += border box.X += border
box.Y += border box.Y += border
box.W -= border box.W -= border
box.H -= border box.H -= border
if w.BorderStyle() == BorderRaised { if w.BorderSize() > 0 {
color = shadow if w.BorderStyle() == BorderRaised {
} else if w.BorderStyle() == BorderSunken { color = shadow
color = highlight } else if w.BorderStyle() == BorderSunken {
} else { color = highlight
color = borderColor } else {
color = borderColor
}
e.DrawBox(color, box)
} }
e.DrawBox(color.Add(-20, -20, -20, 0), box)
// Background color of the button. // Background color of the button.
box.W -= border box.W -= border
box.H -= border box.H -= border
// if w.hovering { if w.Background() != render.Invisible {
// e.DrawBox(render.Yellow, box) e.DrawBox(w.Background(), box)
// } else { }
e.DrawBox(color, 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. // Padding returns the padding width.