package ui import ( "opslag.de/schobers/geom" ) type Checkbox struct { ControlBase selectedChanged Events Selected bool Text string } func BuildCheckbox(text string, fn func(c *Checkbox)) *Checkbox { var c = &Checkbox{Text: text} if fn != nil { fn(c) } return c } func (c *Checkbox) desiredSize(ctx Context) geom.PointF32 { pad := c.ActualTextPadding(ctx) font := c.ActualFont(ctx) var w, h float32 = 0, font.Height() if len(c.Text) != 0 { w += pad.Left + font.WidthOf(c.Text) } icon := c.getOrCreateNormalIcon(ctx) _, iconWidth := ScaleToHeight(SizeOfTexture(icon).ToF32(), h) w += pad.Left + iconWidth return geom.PtF32(w+pad.Right, pad.Top+h+pad.Bottom) } func (c *Checkbox) icon(ctx Context) Texture { if c.Selected { return GetOrCreateIcon(ctx, "ui-default-checkbox-selected", c.selectedIcon) } else if c.over && !c.Disabled { return GetOrCreateIcon(ctx, "ui-default-checkbox-hover", c.hoverIcon) } return c.getOrCreateNormalIcon(ctx) } func (c *Checkbox) getOrCreateNormalIcon(ctx Context) Texture { return GetOrCreateIcon(ctx, "ui-default-checkbox", c.normalIcon) } var checkBoxIconBorder = geom.PolF32( geom.PtF32(48, 80), geom.PtF32(400, 80), geom.PtF32(400, 432), geom.PtF32(48, 432), ) var checkBoxCheckMark = geom.PointsF32{ geom.PtF32(96, 256), geom.PtF32(180, 340), geom.PtF32(340, 150), } func (c *Checkbox) hoverIcon(pt geom.PointF32) bool { return (pt.DistanceToPolygon(checkBoxIconBorder) < 48 && !pt.InPolygon(checkBoxIconBorder)) || pt.DistanceToLines(checkBoxCheckMark) < 24 } func (c *Checkbox) normalIcon(pt geom.PointF32) bool { return pt.DistanceToPolygon(checkBoxIconBorder) < 48 && !pt.InPolygon(checkBoxIconBorder) } func (c *Checkbox) selectedIcon(pt geom.PointF32) bool { if pt.DistanceToPolygon(checkBoxIconBorder) < 48 || pt.InPolygon(checkBoxIconBorder) { return pt.DistanceToLines(checkBoxCheckMark) > 24 } return false } func (c *Checkbox) DesiredSize(ctx Context, _ geom.PointF32) geom.PointF32 { return c.desiredSize(ctx) } func (c *Checkbox) Handle(ctx Context, e Event) bool { result := c.ControlBase.Handle(ctx, e) if c.over { if c.Disabled { return true } ctx.Renderer().SetMouseCursor(MouseCursorPointer) } if result { return true } switch e := e.(type) { case *MouseButtonDownEvent: if e.Button == MouseButtonLeft && c.over { c.Selected = !c.Selected return c.selectedChanged.Notify(ctx, c.Selected) } } return false } func (c *Checkbox) SelectedChanged() EventHandler { return &c.selectedChanged } func (c *Checkbox) Render(ctx Context) { c.RenderBackground(ctx) var style = ctx.Style() var palette = style.Palette fore := c.TextColor(ctx) bounds := c.bounds pad := c.ActualTextPadding(ctx) bounds = pad.InsetRect(bounds) boundsH := bounds.Dy() pos := bounds.Min icon := c.icon(ctx) if icon != nil { iconColor := fore if c.Selected { iconColor = c.FontColor(ctx, palette.Primary) } scaledIcon, _ := ctx.Textures().ScaledHeight(icon, boundsH) // try to pre-scale icon if scaledIcon == nil { // let the renderer scale scaledIcon = icon } _, iconWidth := ScaleToHeight(SizeOfTexture(scaledIcon).ToF32(), boundsH) rect := geom.RectRelF32(pos.X, pos.Y, iconWidth, boundsH) ctx.Renderer().DrawTextureOptions(scaledIcon, rect, DrawOptions{Tint: iconColor}) pos.X += iconWidth + pad.Right } if len(c.Text) != 0 { font := c.ActualFont(ctx) ctx.Renderer().Text(font, geom.PtF32(pos.X, pos.Y+.5*(boundsH-font.Height())), fore, c.Text) } }