2018-07-25 16:03:49 +00:00
|
|
|
package ui
|
|
|
|
|
2018-07-26 04:24:37 +00:00
|
|
|
import (
|
|
|
|
"git.kirsle.net/apps/doodle/render"
|
|
|
|
)
|
|
|
|
|
|
|
|
// BorderStyle options for widget.SetBorderStyle()
|
|
|
|
type BorderStyle string
|
|
|
|
|
|
|
|
// Styles for a widget border.
|
|
|
|
const (
|
|
|
|
BorderSolid BorderStyle = "solid"
|
|
|
|
BorderRaised = "raised"
|
|
|
|
BorderSunken = "sunken"
|
|
|
|
)
|
2018-07-25 16:03:49 +00:00
|
|
|
|
|
|
|
// Widget is a user interface element.
|
|
|
|
type Widget interface {
|
|
|
|
Point() render.Point
|
2018-07-26 02:38:54 +00:00
|
|
|
MoveTo(render.Point)
|
|
|
|
MoveBy(render.Point)
|
2018-07-25 16:03:49 +00:00
|
|
|
Size() render.Rect // Return the Width and Height of the widget.
|
|
|
|
Resize(render.Rect)
|
|
|
|
|
2018-07-26 03:25:02 +00:00
|
|
|
Handle(string, func(render.Point))
|
|
|
|
Event(string, render.Point) // called internally to trigger an event
|
|
|
|
|
2018-07-26 04:24:37 +00:00
|
|
|
// Thickness of the padding + border + outline.
|
|
|
|
BoxThickness(multiplier int32) int32
|
|
|
|
DrawBox(render.Engine)
|
|
|
|
|
|
|
|
// Widget configuration getters.
|
|
|
|
Padding() int32 // Padding
|
|
|
|
SetPadding(int32) //
|
|
|
|
Background() render.Color // Background color
|
|
|
|
SetBackground(render.Color) //
|
|
|
|
Foreground() render.Color // Foreground color
|
|
|
|
SetForeground(render.Color) //
|
|
|
|
BorderStyle() BorderStyle // Border style: none, raised, sunken
|
|
|
|
SetBorderStyle(BorderStyle) //
|
|
|
|
BorderColor() render.Color // Border color (default is Background)
|
|
|
|
SetBorderColor(render.Color) //
|
|
|
|
BorderSize() int32 // Border size (default 0)
|
|
|
|
SetBorderSize(int32) //
|
|
|
|
OutlineColor() render.Color // Outline color (default Invisible)
|
|
|
|
SetOutlineColor(render.Color) //
|
|
|
|
OutlineSize() int32 // Outline size (default 0)
|
|
|
|
SetOutlineSize(int32) //
|
|
|
|
|
2018-07-25 16:03:49 +00:00
|
|
|
// Run any render computations; by the end the widget must know its
|
|
|
|
// Width and Height. For example the Label widget will render itself onto
|
|
|
|
// an SDL Surface and then it will know its bounding box, but not before.
|
|
|
|
Compute(render.Engine)
|
|
|
|
|
|
|
|
// Render the final widget onto the drawing engine.
|
|
|
|
Present(render.Engine)
|
|
|
|
}
|
|
|
|
|
|
|
|
// BaseWidget holds common functionality for all widgets, such as managing
|
|
|
|
// their widths and heights.
|
|
|
|
type BaseWidget struct {
|
2018-07-26 04:24:37 +00:00
|
|
|
width int32
|
|
|
|
height int32
|
|
|
|
point render.Point
|
|
|
|
padding int32
|
|
|
|
background render.Color
|
|
|
|
foreground render.Color
|
|
|
|
borderStyle BorderStyle
|
|
|
|
borderColor render.Color
|
|
|
|
borderSize int32
|
|
|
|
outlineColor render.Color
|
|
|
|
outlineSize int32
|
|
|
|
handlers map[string][]func(render.Point)
|
2018-07-25 16:03:49 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// Point returns the X,Y position of the widget on the window.
|
|
|
|
func (w *BaseWidget) Point() render.Point {
|
|
|
|
return w.point
|
|
|
|
}
|
|
|
|
|
2018-07-26 02:38:54 +00:00
|
|
|
// MoveTo updates the X,Y position to the new point.
|
|
|
|
func (w *BaseWidget) MoveTo(v render.Point) {
|
2018-07-25 16:03:49 +00:00
|
|
|
w.point = v
|
|
|
|
}
|
|
|
|
|
2018-07-26 02:38:54 +00:00
|
|
|
// MoveBy adds the X,Y values to the widget's current position.
|
|
|
|
func (w *BaseWidget) MoveBy(v render.Point) {
|
|
|
|
w.point.X += v.X
|
|
|
|
w.point.Y += v.Y
|
|
|
|
}
|
|
|
|
|
2018-07-25 16:03:49 +00:00
|
|
|
// Size returns the box with W and H attributes containing the size of the
|
|
|
|
// widget. The X,Y attributes of the box are ignored and zero.
|
|
|
|
func (w *BaseWidget) Size() render.Rect {
|
|
|
|
return render.Rect{
|
|
|
|
W: w.width,
|
|
|
|
H: w.height,
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// Resize sets the size of the widget to the .W and .H attributes of a rect.
|
|
|
|
func (w *BaseWidget) Resize(v render.Rect) {
|
|
|
|
w.width = v.W
|
|
|
|
w.height = v.H
|
|
|
|
}
|
2018-07-26 03:25:02 +00:00
|
|
|
|
2018-07-26 04:24:37 +00:00
|
|
|
// BoxThickness returns the full sum of the padding, border and outline.
|
|
|
|
// m = multiplier, i.e., 1 or 2
|
|
|
|
func (w *BaseWidget) BoxThickness(m int32) int32 {
|
|
|
|
if m == 0 {
|
|
|
|
m = 1
|
|
|
|
}
|
|
|
|
return (w.Padding() * m) + (w.BorderSize() * m) + (w.OutlineSize() * m)
|
|
|
|
}
|
|
|
|
|
|
|
|
// DrawBox draws the border and outline.
|
|
|
|
func (w *BaseWidget) DrawBox(e render.Engine) {
|
|
|
|
var (
|
|
|
|
P = w.Point()
|
|
|
|
S = w.Size()
|
|
|
|
outline = w.OutlineSize()
|
|
|
|
border = w.BorderSize()
|
|
|
|
borderColor = w.BorderColor()
|
|
|
|
highlight = borderColor.Add(20, 20, 20, 0)
|
|
|
|
shadow = borderColor.Add(-20, -20, -20, 0)
|
|
|
|
color render.Color
|
|
|
|
box = render.Rect{
|
|
|
|
X: P.X,
|
|
|
|
Y: P.Y,
|
|
|
|
W: S.W,
|
|
|
|
H: S.H,
|
|
|
|
}
|
|
|
|
)
|
|
|
|
|
|
|
|
// Draw the outline layer as the full size of the widget.
|
|
|
|
e.DrawBox(w.OutlineColor(), render.Rect{
|
|
|
|
X: P.X - outline,
|
|
|
|
Y: P.Y - outline,
|
|
|
|
W: S.W + (outline * 2),
|
|
|
|
H: S.H + (outline * 2),
|
|
|
|
})
|
|
|
|
|
|
|
|
// Highlight on the top left edge.
|
|
|
|
if w.BorderStyle() == BorderRaised {
|
|
|
|
color = highlight
|
|
|
|
} else if w.BorderStyle() == BorderSunken {
|
|
|
|
color = shadow
|
|
|
|
} else {
|
|
|
|
color = borderColor
|
|
|
|
}
|
|
|
|
e.DrawBox(color, box)
|
|
|
|
box.W = S.W
|
|
|
|
|
|
|
|
// Shadow on the bottom right edge.
|
|
|
|
box.X += border
|
|
|
|
box.Y += border
|
|
|
|
box.W -= border
|
|
|
|
box.H -= border
|
|
|
|
if w.BorderStyle() == BorderRaised {
|
|
|
|
color = shadow
|
|
|
|
} else if w.BorderStyle() == BorderSunken {
|
|
|
|
color = highlight
|
|
|
|
} else {
|
|
|
|
color = borderColor
|
|
|
|
}
|
|
|
|
e.DrawBox(color.Add(-20, -20, -20, 0), box)
|
|
|
|
|
|
|
|
// Background color of the button.
|
|
|
|
box.W -= border
|
|
|
|
box.H -= border
|
|
|
|
// if w.hovering {
|
|
|
|
// e.DrawBox(render.Yellow, box)
|
|
|
|
// } else {
|
|
|
|
e.DrawBox(color, box)
|
|
|
|
}
|
|
|
|
|
|
|
|
// Padding returns the padding width.
|
|
|
|
func (w *BaseWidget) Padding() int32 {
|
|
|
|
return w.padding
|
|
|
|
}
|
|
|
|
|
|
|
|
// SetPadding sets the padding width.
|
|
|
|
func (w *BaseWidget) SetPadding(v int32) {
|
|
|
|
w.padding = v
|
|
|
|
}
|
|
|
|
|
|
|
|
// Background returns the background color.
|
|
|
|
func (w *BaseWidget) Background() render.Color {
|
|
|
|
return w.background
|
|
|
|
}
|
|
|
|
|
|
|
|
// SetBackground sets the color.
|
|
|
|
func (w *BaseWidget) SetBackground(c render.Color) {
|
|
|
|
w.background = c
|
|
|
|
}
|
|
|
|
|
|
|
|
// Foreground returns the foreground color.
|
|
|
|
func (w *BaseWidget) Foreground() render.Color {
|
|
|
|
return w.foreground
|
|
|
|
}
|
|
|
|
|
|
|
|
// SetForeground sets the color.
|
|
|
|
func (w *BaseWidget) SetForeground(c render.Color) {
|
|
|
|
w.foreground = c
|
|
|
|
}
|
|
|
|
|
|
|
|
// BorderStyle returns the border style.
|
|
|
|
func (w *BaseWidget) BorderStyle() BorderStyle {
|
|
|
|
return w.borderStyle
|
|
|
|
}
|
|
|
|
|
|
|
|
// SetBorderStyle sets the border style.
|
|
|
|
func (w *BaseWidget) SetBorderStyle(v BorderStyle) {
|
|
|
|
w.borderStyle = v
|
|
|
|
}
|
|
|
|
|
|
|
|
// BorderColor returns the border color, or defaults to the background color.
|
|
|
|
func (w *BaseWidget) BorderColor() render.Color {
|
|
|
|
if w.borderColor == render.Invisible {
|
|
|
|
return w.Background()
|
|
|
|
}
|
|
|
|
return w.borderColor
|
|
|
|
}
|
|
|
|
|
|
|
|
// SetBorderColor sets the border color.
|
|
|
|
func (w *BaseWidget) SetBorderColor(c render.Color) {
|
|
|
|
w.borderColor = c
|
|
|
|
}
|
|
|
|
|
|
|
|
// BorderSize returns the border thickness.
|
|
|
|
func (w *BaseWidget) BorderSize() int32 {
|
|
|
|
return w.borderSize
|
|
|
|
}
|
|
|
|
|
|
|
|
// SetBorderSize sets the border thickness.
|
|
|
|
func (w *BaseWidget) SetBorderSize(v int32) {
|
|
|
|
w.borderSize = v
|
|
|
|
}
|
|
|
|
|
|
|
|
// OutlineColor returns the background color.
|
|
|
|
func (w *BaseWidget) OutlineColor() render.Color {
|
|
|
|
return w.outlineColor
|
|
|
|
}
|
|
|
|
|
|
|
|
// SetOutlineColor sets the color.
|
|
|
|
func (w *BaseWidget) SetOutlineColor(c render.Color) {
|
|
|
|
w.outlineColor = c
|
|
|
|
}
|
|
|
|
|
|
|
|
// OutlineSize returns the outline thickness.
|
|
|
|
func (w *BaseWidget) OutlineSize() int32 {
|
|
|
|
return w.outlineSize
|
|
|
|
}
|
|
|
|
|
|
|
|
// SetOutlineSize sets the outline thickness.
|
|
|
|
func (w *BaseWidget) SetOutlineSize(v int32) {
|
|
|
|
w.outlineSize = v
|
|
|
|
}
|
|
|
|
|
2018-07-26 03:25:02 +00:00
|
|
|
// Event is called internally by Doodle to trigger an event.
|
|
|
|
func (w *BaseWidget) Event(name string, p render.Point) {
|
|
|
|
if handlers, ok := w.handlers[name]; ok {
|
|
|
|
for _, fn := range handlers {
|
|
|
|
fn(p)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// Handle an event in the widget.
|
|
|
|
func (w *BaseWidget) Handle(name string, fn func(render.Point)) {
|
|
|
|
if w.handlers == nil {
|
|
|
|
w.handlers = map[string][]func(render.Point){}
|
|
|
|
}
|
|
|
|
|
|
|
|
if _, ok := w.handlers[name]; !ok {
|
|
|
|
w.handlers[name] = []func(render.Point){}
|
|
|
|
}
|
|
|
|
|
|
|
|
w.handlers[name] = append(w.handlers[name], fn)
|
|
|
|
}
|
|
|
|
|
|
|
|
// OnMouseOut should be overridden on widgets who want this event.
|
|
|
|
func (w *BaseWidget) OnMouseOut(render.Point) {}
|