zntg/ui/controlbase.go

177 lines
3.8 KiB
Go

package ui
import (
"image/color"
"opslag.de/schobers/geom"
)
type ClickFn func(pos geom.PointF32, btn MouseButton)
type DragEndFn func(start, end geom.PointF32)
type DragMoveFn func(start, move geom.PointF32)
type DragStartFn func(start geom.PointF32)
type MouseEnterFn func()
type MouseLeaveFn func()
var _ Control = &ControlBase{}
type ControlBase struct {
bounds geom.RectangleF32
offset geom.PointF32
parent Control
drag Dragable
over bool
pressed bool
onClick ClickFn
onDragEnd DragEndFn
onDragMove DragMoveFn
onDragStart DragStartFn
Background color.Color
Font FontStyle
TextAlignment HorizontalAlignment
Tooltip string
}
func (c *ControlBase) Arrange(ctx Context, bounds geom.RectangleF32, offset geom.PointF32, parent Control) {
c.bounds = bounds
c.offset = offset
c.parent = parent
}
func (c *ControlBase) Bounds() geom.RectangleF32 { return c.bounds }
func (c *ControlBase) DesiredSize(Context) geom.PointF32 { return geom.ZeroPtF32 }
func (c *ControlBase) Handle(ctx Context, e Event) {
var over = func(e MouseEvent) bool {
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
}
switch e := e.(type) {
case *MouseMoveEvent:
c.over = over(e.MouseEvent)
if c.pressed {
if start, ok := c.drag.IsDragging(); ok {
var move = c.ToControlPosition(e.Pos())
c.drag.Move(move)
if c.onDragMove != nil {
c.onDragMove(start, move)
}
} else {
var start = c.ToControlPosition(e.Pos())
c.drag.Start(start)
if c.onDragStart != nil {
c.onDragStart(start)
}
}
}
case *MouseLeaveEvent:
c.over = false
case *MouseButtonDownEvent:
c.over = over(e.MouseEvent)
if c.over && e.Button == MouseButtonLeft {
c.pressed = true
}
case *MouseButtonUpEvent:
if e.Button == MouseButtonLeft {
if start, ok := c.drag.IsDragging(); ok {
var end = c.ToControlPosition(e.Pos())
c.drag.Cancel()
if c.onDragEnd != nil {
c.onDragEnd(start, end)
}
}
if c.pressed {
if c.onClick != nil {
c.onClick(c.ToControlPosition(e.Pos()), e.Button)
}
}
c.pressed = false
}
}
if c.Tooltip != "" && c.over {
ctx.ShowTooltip(c.Tooltip)
}
}
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
}
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)
}
func (c *ControlBase) IsOver() bool { return c.over }
func (c *ControlBase) Parent() Control { return c.parent }
func (c *ControlBase) IsPressed() bool { return c.pressed }
func (c *ControlBase) Offset() geom.PointF32 { return c.offset }
func (c *ControlBase) OnClick(fn ClickFn) { c.onClick = fn }
func (c *ControlBase) OnDragStart(fn DragStartFn) {
c.onDragStart = fn
}
func (c *ControlBase) OnDragMove(fn DragMoveFn) {
c.onDragMove = fn
}
func (c *ControlBase) OnDragEnd(fn DragEndFn) { c.onDragEnd = fn }
func (c *ControlBase) Render(Context) {}
func (c *ControlBase) RenderBackground(ctx Context) {
if c.Background != nil {
ctx.Renderer().FillRectangle(c.bounds, c.Background)
}
}
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)
}
func (c *ControlBase) ToControlPosition(p geom.PointF32) geom.PointF32 { return p.Sub(c.offset) }