2019-03-05 20:52:18 +00:00
|
|
|
package ui
|
|
|
|
|
|
|
|
import (
|
|
|
|
"image/color"
|
|
|
|
|
|
|
|
"opslag.de/schobers/geom"
|
|
|
|
)
|
|
|
|
|
|
|
|
type ClickFn func(ctx Context, c Control, pos geom.PointF32, btn MouseButton)
|
|
|
|
type DragEndFn func(ctx Context, c Control, start, end geom.PointF32)
|
|
|
|
type DragMoveFn func(ctx Context, c Control, start, move geom.PointF32)
|
|
|
|
type DragStartFn func(ctx Context, c Control, start geom.PointF32)
|
|
|
|
type MouseEnterFn func(ctx Context, c Control)
|
|
|
|
type MouseLeaveFn func(ctx Context, c Control)
|
|
|
|
|
|
|
|
var _ Control = &ControlBase{}
|
|
|
|
|
|
|
|
type ControlBase struct {
|
|
|
|
bounds geom.RectangleF32
|
|
|
|
offset geom.PointF32
|
2019-04-11 21:38:32 +00:00
|
|
|
parent Control
|
2019-03-05 20:52:18 +00:00
|
|
|
dragStart *geom.PointF32
|
|
|
|
over bool
|
|
|
|
pressed bool
|
|
|
|
|
|
|
|
onClick ClickFn
|
|
|
|
onDragEnd DragEndFn
|
|
|
|
onDragMove DragMoveFn
|
|
|
|
onDragStart DragStartFn
|
|
|
|
|
|
|
|
Background color.Color
|
2019-03-12 18:43:52 +00:00
|
|
|
Font FontStyle
|
2019-03-05 20:52:18 +00:00
|
|
|
}
|
|
|
|
|
2019-04-11 21:38:32 +00:00
|
|
|
func (c *ControlBase) Arrange(ctx Context, bounds geom.RectangleF32, offset geom.PointF32, parent Control) {
|
2019-03-05 20:52:18 +00:00
|
|
|
c.bounds = bounds
|
|
|
|
c.offset = offset
|
2019-04-11 21:38:32 +00:00
|
|
|
c.parent = parent
|
2019-03-05 20:52:18 +00:00
|
|
|
}
|
|
|
|
|
2019-04-11 21:38:32 +00:00
|
|
|
func (c *ControlBase) Bounds() geom.RectangleF32 { return c.bounds }
|
2019-03-05 20:52:18 +00:00
|
|
|
|
2019-04-11 21:38:32 +00:00
|
|
|
func (c *ControlBase) DesiredSize(Context) geom.PointF32 { return geom.ZeroPtF32 }
|
2019-04-10 19:23:56 +00:00
|
|
|
|
2019-03-05 20:52:18 +00:00
|
|
|
func (c *ControlBase) Handle(ctx Context, e Event) {
|
|
|
|
var over = func(e MouseEvent) bool {
|
2019-04-11 21:38:32 +00:00
|
|
|
pos := e.Pos()
|
|
|
|
if !c.IsInBounds(pos) {
|
|
|
|
return false
|
|
|
|
}
|
|
|
|
parent := c.Parent()
|
|
|
|
for parent != nil {
|
|
|
|
if !parent.IsInBounds(pos) {
|
|
|
|
return false
|
|
|
|
}
|
|
|
|
parent = parent.Parent()
|
|
|
|
}
|
|
|
|
return true
|
2019-03-05 20:52:18 +00:00
|
|
|
}
|
|
|
|
switch e := e.(type) {
|
|
|
|
case *MouseMoveEvent:
|
2019-04-11 21:38:32 +00:00
|
|
|
c.over = over(e.MouseEvent)
|
2019-03-05 20:52:18 +00:00
|
|
|
if c.pressed {
|
|
|
|
if c.dragStart == nil {
|
2019-04-11 21:38:32 +00:00
|
|
|
var start = c.ToControlPosition(e.Pos())
|
2019-03-05 20:52:18 +00:00
|
|
|
c.dragStart = &start
|
|
|
|
if c.onDragStart != nil {
|
|
|
|
c.onDragStart(ctx, c, start)
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
var start = *c.dragStart
|
2019-04-11 21:38:32 +00:00
|
|
|
var move = c.ToControlPosition(e.Pos())
|
2019-03-05 20:52:18 +00:00
|
|
|
if c.onDragMove != nil {
|
|
|
|
c.onDragMove(ctx, c, start, move)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
case *MouseButtonDownEvent:
|
2019-04-11 21:38:32 +00:00
|
|
|
c.over = over(e.MouseEvent)
|
|
|
|
if c.over && e.Button == MouseButtonLeft {
|
2019-03-05 20:52:18 +00:00
|
|
|
c.pressed = true
|
|
|
|
}
|
|
|
|
case *MouseButtonUpEvent:
|
2019-04-10 19:23:56 +00:00
|
|
|
if e.Button == MouseButtonLeft {
|
2019-03-05 20:52:18 +00:00
|
|
|
if c.dragStart != nil {
|
|
|
|
var start = *c.dragStart
|
2019-04-11 21:38:32 +00:00
|
|
|
var end = c.ToControlPosition(e.Pos())
|
2019-03-05 20:52:18 +00:00
|
|
|
c.dragStart = nil
|
|
|
|
if c.onDragEnd != nil {
|
|
|
|
c.onDragEnd(ctx, c, start, end)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if c.pressed {
|
|
|
|
if c.onClick != nil {
|
2019-04-11 21:38:32 +00:00
|
|
|
c.onClick(ctx, c, c.ToControlPosition(e.Pos()), e.Button)
|
2019-03-05 20:52:18 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
c.pressed = false
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-03-12 18:43:52 +00:00
|
|
|
func (c *ControlBase) FontColor(ctx Context) color.Color {
|
|
|
|
var text = c.Font.Color
|
|
|
|
if text == nil {
|
|
|
|
text = ctx.Style().Palette.Text
|
|
|
|
}
|
|
|
|
return text
|
|
|
|
}
|
|
|
|
|
|
|
|
func (c *ControlBase) FontName(ctx Context) string {
|
|
|
|
var name = c.Font.Name
|
|
|
|
if len(name) == 0 {
|
|
|
|
name = ctx.Style().Fonts.Default
|
|
|
|
}
|
|
|
|
return name
|
|
|
|
}
|
|
|
|
|
2019-04-11 21:38:32 +00:00
|
|
|
func (c *ControlBase) IsInBounds(p geom.PointF32) bool {
|
|
|
|
bounds := c.bounds
|
|
|
|
if bounds.Min.X < 0 {
|
|
|
|
bounds.Min.X = 0
|
|
|
|
}
|
|
|
|
if bounds.Min.Y < 0 {
|
|
|
|
bounds.Min.Y = 0
|
|
|
|
}
|
|
|
|
return c.ToControlPosition(p).In(c.bounds)
|
|
|
|
}
|
|
|
|
|
2019-03-05 20:52:18 +00:00
|
|
|
func (c *ControlBase) IsOver() bool { return c.over }
|
|
|
|
|
2019-04-11 21:38:32 +00:00
|
|
|
func (c *ControlBase) Parent() Control { return c.parent }
|
|
|
|
|
2019-03-05 20:52:18 +00:00
|
|
|
func (c *ControlBase) IsPressed() bool { return c.pressed }
|
|
|
|
|
2019-03-05 21:42:57 +00:00
|
|
|
func (c *ControlBase) Offset() geom.PointF32 { return c.offset }
|
|
|
|
|
2019-04-11 21:38:32 +00:00
|
|
|
func (c *ControlBase) OnClick(fn ClickFn) { c.onClick = fn }
|
2019-03-05 20:52:18 +00:00
|
|
|
|
|
|
|
func (c *ControlBase) OnDragStart(fn DragStartFn) {
|
|
|
|
c.onDragStart = fn
|
|
|
|
}
|
|
|
|
|
|
|
|
func (c *ControlBase) OnDragMove(fn DragMoveFn) {
|
|
|
|
c.onDragMove = fn
|
|
|
|
}
|
|
|
|
|
2019-04-11 21:38:32 +00:00
|
|
|
func (c *ControlBase) OnDragEnd(fn DragEndFn) { c.onDragEnd = fn }
|
|
|
|
|
2019-04-11 21:27:25 +00:00
|
|
|
func (c *ControlBase) Render(Context) {}
|
2019-03-05 20:52:18 +00:00
|
|
|
|
|
|
|
func (c *ControlBase) RenderBackground(ctx Context) {
|
|
|
|
if c.Background != nil {
|
|
|
|
ctx.Renderer().FillRectangle(c.bounds, c.Background)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-04-11 21:27:25 +00:00
|
|
|
func (c *ControlBase) RenderOutline(ctx Context) {
|
|
|
|
style := ctx.Style()
|
|
|
|
width := style.Dimensions.OutlineWidth
|
|
|
|
color := style.Palette.Primary
|
|
|
|
if c.Font.Color != nil {
|
|
|
|
color = c.Font.Color
|
|
|
|
}
|
|
|
|
ctx.Renderer().Rectangle(c.bounds.Inset(.5*width), color, width)
|
2019-03-05 20:52:18 +00:00
|
|
|
}
|
2019-04-11 21:38:32 +00:00
|
|
|
|
|
|
|
func (c *ControlBase) ToControlPosition(p geom.PointF32) geom.PointF32 { return p.Sub(c.offset) }
|