276 lines
6.4 KiB
Go
276 lines
6.4 KiB
Go
package ui
|
|
|
|
import (
|
|
"image/color"
|
|
|
|
"opslag.de/schobers/geom"
|
|
)
|
|
|
|
type ControlClickedArgs struct {
|
|
Position geom.PointF32
|
|
Button MouseButton
|
|
}
|
|
|
|
type ControlClickedEventHandler interface {
|
|
AddHandler(func(Context, ControlClickedArgs)) uint
|
|
}
|
|
|
|
type ControlClickedEvents struct {
|
|
Events
|
|
}
|
|
|
|
func (e *ControlClickedEvents) AddHandler(handler func(Context, ControlClickedArgs)) uint {
|
|
return e.Events.AddHandler(func(ctx Context, state interface{}) {
|
|
args := state.(ControlClickedArgs)
|
|
handler(ctx, args)
|
|
})
|
|
}
|
|
|
|
type DragEndedArgs struct {
|
|
Start geom.PointF32
|
|
End geom.PointF32
|
|
}
|
|
|
|
type DragEndedEventHandler interface {
|
|
AddHandler(func(Context, DragEndedArgs)) uint
|
|
}
|
|
|
|
type DragEndedEvents struct {
|
|
Events
|
|
}
|
|
|
|
func (e *DragEndedEvents) AddHandler(handler func(Context, DragEndedArgs)) uint {
|
|
return e.Events.AddHandler(func(ctx Context, state interface{}) {
|
|
args := state.(DragEndedArgs)
|
|
handler(ctx, args)
|
|
})
|
|
}
|
|
|
|
type DragMovedArgs struct {
|
|
Start geom.PointF32
|
|
Current geom.PointF32
|
|
}
|
|
|
|
type DragMovedEventHandler interface {
|
|
AddHandler(func(Context, DragMovedArgs)) uint
|
|
}
|
|
|
|
type DragMovedEvents struct {
|
|
Events
|
|
}
|
|
|
|
func (e *DragMovedEvents) AddHandler(handler func(Context, DragMovedArgs)) uint {
|
|
return e.Events.AddHandler(func(ctx Context, state interface{}) {
|
|
args := state.(DragMovedArgs)
|
|
handler(ctx, args)
|
|
})
|
|
}
|
|
|
|
type DragStartedArgs struct {
|
|
Start geom.PointF32
|
|
}
|
|
|
|
type DragStartedEventHandler interface {
|
|
AddHandler(func(Context, DragStartedArgs)) uint
|
|
}
|
|
|
|
type DragStartedEvents struct {
|
|
Events
|
|
}
|
|
|
|
func (e *DragStartedEvents) AddHandler(handler func(Context, DragStartedArgs)) uint {
|
|
return e.Events.AddHandler(func(ctx Context, state interface{}) {
|
|
args := state.(DragStartedArgs)
|
|
handler(ctx, args)
|
|
})
|
|
}
|
|
|
|
var _ Control = &ControlBase{}
|
|
|
|
type ControlBase struct {
|
|
bounds geom.RectangleF32
|
|
offset geom.PointF32
|
|
parent Control
|
|
drag Dragable
|
|
over bool
|
|
pressed bool
|
|
|
|
clicked ControlClickedEvents
|
|
dragEnded DragEndedEvents
|
|
dragMoved DragMovedEvents
|
|
dragStarted DragStartedEvents
|
|
|
|
Background color.Color
|
|
Font FontStyle
|
|
TextAlignment HorizontalAlignment
|
|
|
|
Disabled bool
|
|
|
|
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) ControlClicked() ControlClickedEventHandler { return &c.clicked }
|
|
|
|
func (c *ControlBase) DesiredSize(Context) geom.PointF32 { return geom.ZeroPtF32 }
|
|
|
|
func (c *ControlBase) Disable() { c.Disabled = true }
|
|
|
|
func (c *ControlBase) DragEnded() DragEndedEventHandler { return &c.dragEnded }
|
|
|
|
func (c *ControlBase) DragMoved() DragMovedEventHandler { return &c.dragMoved }
|
|
|
|
func (c *ControlBase) DragStarted() DragStartedEventHandler { return &c.dragStarted }
|
|
|
|
func (c *ControlBase) Enable() { c.Disabled = false }
|
|
|
|
func (c *ControlBase) Handle(ctx Context, e Event) bool { return c.HandleNotify(ctx, e, c) }
|
|
|
|
func (c *ControlBase) HandleNotify(ctx Context, e Event, notifier Notifier) bool {
|
|
defer func() {
|
|
if c.Tooltip != "" && c.over {
|
|
ctx.ShowTooltip(c.Tooltip)
|
|
}
|
|
}()
|
|
|
|
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)
|
|
return notifier.Notify(ctx, DragMovedArgs{Start: start, Current: move})
|
|
}
|
|
var start = c.ToControlPosition(e.Pos())
|
|
c.drag.Start(start)
|
|
return notifier.Notify(ctx, DragStartedArgs{Start: start})
|
|
}
|
|
case *MouseLeaveEvent:
|
|
c.over = false
|
|
case *MouseButtonDownEvent:
|
|
c.over = over(e.MouseEvent)
|
|
if c.over && e.Button == MouseButtonLeft {
|
|
c.pressed = true
|
|
return notifier.Notify(ctx, ControlClickedArgs{Position: e.Pos(), Button: e.Button})
|
|
}
|
|
case *MouseButtonUpEvent:
|
|
if e.Button == MouseButtonLeft {
|
|
c.pressed = false
|
|
if start, ok := c.drag.IsDragging(); ok {
|
|
var end = c.ToControlPosition(e.Pos())
|
|
c.drag.Cancel()
|
|
return notifier.Notify(ctx, DragEndedArgs{Start: start, End: end})
|
|
}
|
|
}
|
|
}
|
|
return false
|
|
}
|
|
|
|
func (c *ControlBase) FontColor(ctx Context, color color.Color) color.Color {
|
|
if c.Disabled {
|
|
return ctx.Style().Palette.TextOnDisabled
|
|
}
|
|
var text = c.Font.Color
|
|
if text == nil {
|
|
text = color
|
|
}
|
|
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) IsDisabled() bool { return c.Disabled }
|
|
|
|
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) IsPressed() bool { return c.pressed }
|
|
|
|
func (c *ControlBase) Notify(ctx Context, state interface{}) bool {
|
|
switch state.(type) {
|
|
case ControlClickedArgs:
|
|
return c.clicked.Notify(ctx, state)
|
|
case DragEndedArgs:
|
|
return c.dragEnded.Notify(ctx, state)
|
|
case DragMovedArgs:
|
|
return c.dragMoved.Notify(ctx, state)
|
|
case DragStartedArgs:
|
|
return c.dragStarted.Notify(ctx, state)
|
|
default:
|
|
return false
|
|
}
|
|
}
|
|
|
|
func (c *ControlBase) Parent() Control { return c.parent }
|
|
|
|
func (c *ControlBase) Offset() geom.PointF32 { return c.offset }
|
|
|
|
func (c *ControlBase) OutlineColor(ctx Context) color.Color {
|
|
return c.FontColor(ctx, ctx.Style().Palette.Primary)
|
|
}
|
|
|
|
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) {
|
|
c.RenderOutlineDefault(ctx, nil)
|
|
}
|
|
|
|
func (c *ControlBase) RenderOutlineDefault(ctx Context, color color.Color) {
|
|
style := ctx.Style()
|
|
width := style.Dimensions.OutlineWidth
|
|
if color == nil {
|
|
color = c.OutlineColor(ctx)
|
|
}
|
|
ctx.Renderer().Rectangle(c.bounds.Inset(.5*width), color, width)
|
|
}
|
|
|
|
func (c *ControlBase) TextColor(ctx Context) color.Color {
|
|
return c.FontColor(ctx, ctx.Style().Palette.Text)
|
|
}
|
|
|
|
func (c *ControlBase) ToControlPosition(p geom.PointF32) geom.PointF32 { return p.Sub(c.offset) }
|