diff --git a/ui/checkbox.go b/ui/checkbox.go index bab6205..94b099b 100644 --- a/ui/checkbox.go +++ b/ui/checkbox.go @@ -4,9 +4,13 @@ import ( "opslag.de/schobers/geom" ) +type SelectedChangedFn func(ctx Context, c Control, selected bool) + type Checkbox struct { ControlBase + onSelectedChanged SelectedChangedFn + Selected bool Text string } @@ -26,15 +30,21 @@ func (c *Checkbox) desiredSize(ctx Context) geom.PointF32 { if len(c.Text) != 0 { w += pad + font.WidthOf(c.Text) } - icon, _ := ctx.Images().ScaledHeight(c.icon(ctx, false), h) + icon, _ := ctx.Images().ScaledHeight(c.getOrCreateNormalIcon(ctx), h) w += pad + icon.Width() return geom.PtF32(w+pad, pad+h+pad) } -func (c *Checkbox) icon(ctx Context, selected bool) Image { - if selected { +func (c *Checkbox) icon(ctx Context) Image { + if c.Selected { return GetOrCreateIcon(ctx, "ui-default-checkbox-selected", c.selectedIcon) + } else if c.over { + return GetOrCreateIcon(ctx, "ui-default-checkbox-hover", c.hoverIcon) } + return c.getOrCreateNormalIcon(ctx) +} + +func (c *Checkbox) getOrCreateNormalIcon(ctx Context) Image { return GetOrCreateIcon(ctx, "ui-default-checkbox", c.normalIcon) } @@ -47,6 +57,22 @@ func (c *Checkbox) iconBorder() geom.PolygonF32 { ) } +func (c *Checkbox) checkMark() geom.PointsF32 { + return geom.PointsF32{ + geom.PtF32(96, 256), + geom.PtF32(180, 340), + geom.PtF32(340, 150), + } +} + +func (c *Checkbox) hoverIcon() IconPixelTestFn { + border := c.iconBorder() + check := c.checkMark() + return func(pt geom.PointF32) bool { + return (pt.DistanceToPolygon(border) < 48 && !pt.InPolygon(border)) || pt.DistanceToLines(check) < 24 + } +} + func (c *Checkbox) normalIcon() IconPixelTestFn { border := c.iconBorder() return func(pt geom.PointF32) bool { @@ -56,11 +82,7 @@ func (c *Checkbox) normalIcon() IconPixelTestFn { func (c *Checkbox) selectedIcon() IconPixelTestFn { border := c.iconBorder() - check := geom.PointsF32{ - geom.PtF32(84, 256), - geom.PtF32(180, 352), - geom.PtF32(352, 150), - } + check := c.checkMark() return func(pt geom.PointF32) bool { if pt.DistanceToPolygon(border) < 48 || pt.InPolygon(border) { return pt.DistanceToLines(check) > 24 @@ -76,6 +98,10 @@ func (c *Checkbox) Handle(ctx Context, e Event) { case *MouseButtonDownEvent: if e.Button == MouseButtonLeft && c.over { c.Selected = !c.Selected + onSelectedChanged := c.onSelectedChanged + if onSelectedChanged != nil { + onSelectedChanged(ctx, c, c.Selected) + } } } c.ControlBase.Handle(ctx, e) @@ -84,23 +110,25 @@ func (c *Checkbox) Handle(ctx Context, e Event) { } } +func (c *Checkbox) OnSelectedChanged(fn SelectedChangedFn) { + c.onSelectedChanged = fn +} + func (c *Checkbox) Render(ctx Context) { + c.RenderBackground(ctx) + var style = ctx.Style() var palette = style.Palette fore := c.FontColor(ctx) - size := c.desiredSize(ctx) bounds := c.bounds - deltaX, deltaY := bounds.Dx()-size.X, bounds.Dy()-size.Y - bounds.Min.X += .5 * deltaX - bounds.Min.Y += .5 * deltaY var pad = style.Dimensions.TextPadding bounds = bounds.Inset(pad) pos := bounds.Min - icon, _ := ctx.Images().ScaledHeight(c.icon(ctx, c.Selected), bounds.Dy()) + icon, _ := ctx.Images().ScaledHeight(c.icon(ctx), bounds.Dy()) if icon != nil { iconColor := fore - if c.Selected { + if c.Selected && c.Font.Color == nil { iconColor = palette.Primary } ctx.Renderer().DrawImageOptions(icon, geom.PtF32(pos.X, pos.Y+.5*(bounds.Dy()-icon.Height())), DrawOptions{Tint: iconColor})