From c0586c1d8f84cdf80b3f7b98f83ebb6c44b0b290 Mon Sep 17 00:00:00 2001 From: Sander Schobers Date: Mon, 19 Jul 2021 07:58:46 +0200 Subject: [PATCH] Added overridable text padding. --- ui/button.go | 20 ++++++++++---------- ui/checkbox.go | 18 +++++++++--------- ui/controlbase.go | 7 ++++++- ui/label.go | 10 +++++----- ui/length.go | 45 +++++++++++++++++++++++++++++++++++++++++++++ ui/paragraph.go | 20 ++++++++++---------- ui/textbox.go | 17 +++++++---------- 7 files changed, 92 insertions(+), 45 deletions(-) diff --git a/ui/button.go b/ui/button.go index b188978..b865295 100644 --- a/ui/button.go +++ b/ui/button.go @@ -40,30 +40,30 @@ func BuildIconButton(icon, text string, fn func(b *Button)) *Button { } func (b *Button) desiredSize(ctx Context) geom.PointF32 { - var pad = ctx.Style().Dimensions.TextPadding - var font = b.Font_(ctx) + var pad = b.ActualTextPadding(ctx) + var font = b.ActualFont(ctx) var w, h float32 = 0, font.Height() icon, iconW, iconH := b.icon(ctx) if len(b.Text) == 0 { if icon != nil && iconH > 0 { - w = pad + iconW + pad + w = pad.Left + iconW + pad.Right h = iconH } } else { - w += pad + font.WidthOf(b.Text) + pad + w += pad.Left + font.WidthOf(b.Text) + pad.Right if icon != nil && iconH > 0 { if b.IconHeight == 0 { iconW = iconW * h / iconH // iconH = h } - w += iconW + pad + w += iconW + pad.Right } } if w == 0 { return geom.ZeroPtF32 } - return geom.PtF32(w, pad+h+pad) + return geom.PtF32(w, pad.Top+h+pad.Bottom) } func (b *Button) icon(ctx Context) (Texture, float32, float32) { @@ -203,8 +203,8 @@ func (b *Button) Render(ctx Context) { bounds.Min.X += .5 * deltaX bounds.Min.Y += .5 * deltaY - var pad = style.Dimensions.TextPadding - bounds = bounds.Inset(pad) + pad := b.ActualTextPadding(ctx) + bounds = pad.InsetRect(bounds) boundsH := bounds.Dy() pos := bounds.Min icon, iconW, iconH := b.icon(ctx) @@ -222,10 +222,10 @@ func (b *Button) Render(ctx Context) { iconOffsetY = .5 * (boundsH - iconH) } ctx.Renderer().DrawTextureOptions(icon, geom.RectRelF32(pos.X, pos.Y+iconOffsetY, iconW, iconH), DrawOptions{Tint: textColor}) - pos.X += iconW + pad + pos.X += iconW + pad.Right } if len(b.Text) != 0 { - font := b.Font_(ctx) + font := b.ActualFont(ctx) ctx.Renderer().Text(font, geom.PtF32(pos.X, pos.Y+.5*(boundsH-font.Height())), textColor, b.Text) } diff --git a/ui/checkbox.go b/ui/checkbox.go index 69675dc..f20f48d 100644 --- a/ui/checkbox.go +++ b/ui/checkbox.go @@ -22,16 +22,16 @@ func BuildCheckbox(text string, fn func(c *Checkbox)) *Checkbox { } func (c *Checkbox) desiredSize(ctx Context) geom.PointF32 { - var pad = ctx.Style().Dimensions.TextPadding - font := c.Font_(ctx) + pad := c.ActualTextPadding(ctx) + font := c.ActualFont(ctx) var w, h float32 = 0, font.Height() if len(c.Text) != 0 { - w += pad + font.WidthOf(c.Text) + w += pad.Left + font.WidthOf(c.Text) } icon := c.getOrCreateNormalIcon(ctx) _, iconWidth := ScaleToHeight(SizeOfTexture(icon).ToF32(), h) - w += pad + iconWidth - return geom.PtF32(w+pad, pad+h+pad) + w += pad.Left + iconWidth + return geom.PtF32(w+pad.Right, pad.Top+h+pad.Bottom) } func (c *Checkbox) icon(ctx Context) Texture { @@ -108,8 +108,8 @@ func (c *Checkbox) Render(ctx Context) { fore := c.TextColor(ctx) bounds := c.bounds - var pad = style.Dimensions.TextPadding - bounds = bounds.Inset(pad) + pad := c.ActualTextPadding(ctx) + bounds = pad.InsetRect(bounds) boundsH := bounds.Dy() pos := bounds.Min icon := c.icon(ctx) @@ -125,10 +125,10 @@ func (c *Checkbox) Render(ctx Context) { _, 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 + pos.X += iconWidth + pad.Right } if len(c.Text) != 0 { - font := c.Font_(ctx) + font := c.ActualFont(ctx) ctx.Renderer().Text(font, geom.PtF32(pos.X, pos.Y+.5*(boundsH-font.Height())), fore, c.Text) } } diff --git a/ui/controlbase.go b/ui/controlbase.go index 7493caf..97e11e7 100644 --- a/ui/controlbase.go +++ b/ui/controlbase.go @@ -103,6 +103,7 @@ type ControlBase struct { Background color.Color Font FontStyle TextAlignment HorizontalAlignment + TextPadding SideLengths Disabled bool @@ -188,11 +189,15 @@ func (c *ControlBase) HandleNotify(ctx Context, e Event, notifier Notifier) bool return false } -func (c *ControlBase) Font_(ctx Context) Font { +func (c *ControlBase) ActualFont(ctx Context) Font { name := c.FontName(ctx) return ctx.Fonts().Font(name) } +func (c *ControlBase) ActualTextPadding(ctx Context) Sides { + return c.TextPadding.Zero(ctx.Style().Dimensions.TextPadding) +} + func (c *ControlBase) FontColor(ctx Context, color color.Color) color.Color { if c.Disabled { return ctx.Style().Palette.TextOnDisabled diff --git a/ui/label.go b/ui/label.go index 40a3fb1..05d52fc 100644 --- a/ui/label.go +++ b/ui/label.go @@ -28,11 +28,11 @@ func (l *Label) hashDesiredSize(ctx Context) string { } func (l *Label) desiredSize(ctx Context) interface{} { - font := l.Font_(ctx) + font := l.ActualFont(ctx) width := font.WidthOf(l.Text) height := font.Height() - pad := ctx.Style().Dimensions.TextPadding - return geom.PtF32(width+pad*2, height+pad*2) + pad := l.ActualTextPadding(ctx) + return geom.PtF32(pad.Left+width+pad.Right, pad.Top+height+pad.Bottom) } func (l *Label) DesiredSize(ctx Context, _ geom.PointF32) geom.PointF32 { @@ -40,8 +40,8 @@ func (l *Label) DesiredSize(ctx Context, _ geom.PointF32) geom.PointF32 { } func (l *Label) getLabelTopLeft(ctx Context) geom.PointF32 { - pad := ctx.Style().Dimensions.TextPadding - bounds := l.bounds.Inset(pad) + pad := l.ActualTextPadding(ctx) + bounds := pad.InsetRect(l.bounds) switch l.TextAlignment { case AlignRight: return geom.PtF32(bounds.Max.X, bounds.Min.Y) diff --git a/ui/length.go b/ui/length.go index b1bba29..dda5b75 100644 --- a/ui/length.go +++ b/ui/length.go @@ -24,9 +24,54 @@ func Fixed(l float32) *Length { return &Length{l} } func Infinite() *Length { return &Length{geom.NaN32()} } +func ZL() *Length { return &Length{0} } + type SideLengths struct { Left *Length Top *Length Right *Length Bottom *Length } + +func (l SideLengths) InsetRect(r geom.RectangleF32) geom.RectangleF32 { + return Sides{ + Left: l.Left.Value(), + Top: l.Top.Value(), + Right: l.Right.Value(), + Bottom: l.Bottom.Value(), + }.InsetRect(r) +} + +func (l SideLengths) Zero(value float32) Sides { + return Sides{ + Left: l.Left.Zero(value), + Top: l.Top.Zero(value), + Right: l.Right.Zero(value), + Bottom: l.Bottom.Zero(value), + } +} + +type Sides struct { + Left float32 + Top float32 + Right float32 + Bottom float32 +} + +func (s Sides) InsetRect(r geom.RectangleF32) geom.RectangleF32 { + if r.Dx() < (s.Left + s.Right) { + r.Min.X += r.Dx() * s.Left / (s.Left + s.Right) + r.Max.X = r.Min.X + } else { + r.Min.X += s.Left + r.Max.X -= s.Right + } + if r.Dy() < (s.Top + s.Bottom) { + r.Min.Y += r.Dy() * s.Top / (s.Top + s.Bottom) + r.Max.Y = r.Min.Y + } else { + r.Min.Y += s.Top + r.Max.Y -= s.Bottom + } + return r +} diff --git a/ui/paragraph.go b/ui/paragraph.go index 9f63199..902347e 100644 --- a/ui/paragraph.go +++ b/ui/paragraph.go @@ -26,11 +26,11 @@ func BuildParagraph(text string, fn func(*Paragraph)) *Paragraph { func fastFormatFloat32(f float32) string { return strconv.FormatFloat(float64(f), 'b', 32, 32) } func (p *Paragraph) desiredSize(ctx Context) interface{} { - font := p.Font_(ctx) + font := p.ActualFont(ctx) - pad := ctx.Style().Dimensions.TextPadding - lines := p.splitInLines(ctx, p.width-2*pad) - return geom.PtF32(p.width, float32(len(lines))*font.Height()+2*pad) + pad := p.ActualTextPadding(ctx) + lines := p.splitInLines(ctx, p.width-pad.Left-pad.Right) + return geom.PtF32(p.width, float32(len(lines))*font.Height()+pad.Top+pad.Bottom) } func (p *Paragraph) hashTextArranged(ctx Context) string { @@ -42,7 +42,7 @@ func (p *Paragraph) hashTextDesired(ctx Context) string { } func (p *Paragraph) splitInLines(ctx Context, width float32) []string { - font := p.Font_(ctx) + font := p.ActualFont(ctx) spaces := func(s string) []int { // creates a slice with indices where spaces can be found in string s var spaces []int @@ -91,8 +91,8 @@ func (p *Paragraph) splitInLines(ctx Context, width float32) []string { } func (p *Paragraph) updateLines(ctx Context) interface{} { - pad := ctx.Style().Dimensions.TextPadding - return p.splitInLines(ctx, p.Bounds().Dx()-2*pad) + pad := p.ActualTextPadding(ctx) + return p.splitInLines(ctx, p.Bounds().Dx()-pad.Left-pad.Right) } func (p *Paragraph) DesiredSize(ctx Context, size geom.PointF32) geom.PointF32 { @@ -104,14 +104,14 @@ func (p *Paragraph) DesiredSize(ctx Context, size geom.PointF32) geom.PointF32 { func (p *Paragraph) Render(ctx Context) { p.RenderBackground(ctx) - pad := ctx.Style().Dimensions.TextPadding - width := p.Bounds().Dx() - 2*pad + pad := p.ActualTextPadding(ctx) + width := p.Bounds().Dx() - pad.Left - pad.Right lines := p.lines.GetContext(ctx, p.updateLines, p.hashTextArranged).([]string) fontColor := p.TextColor(ctx) fontName := p.FontName(ctx) fontHeight := ctx.Fonts().Font(fontName).Height() - bounds := p.bounds.Inset(pad) + bounds := pad.InsetRect(p.bounds) left := bounds.Min.X switch p.TextAlignment { diff --git a/ui/textbox.go b/ui/textbox.go index 76f1347..d02e95c 100644 --- a/ui/textbox.go +++ b/ui/textbox.go @@ -49,21 +49,18 @@ func BuildTextBox(fn func(*TextBox)) *TextBox { return b } -func (b *TextBox) pad(ctx Context) float32 { - return ctx.Style().Dimensions.TextPadding -} - func (b *TextBox) Arrange(ctx Context, bounds geom.RectangleF32, offset geom.PointF32, parent Control) { b.ControlBase.Arrange(ctx, bounds, offset, parent) - b.box.Arrange(ctx, bounds.Inset(b.pad(ctx)), offset, b) + pad := b.ActualTextPadding(ctx) + b.box.Arrange(ctx, pad.InsetRect(bounds), offset, b) } func (b *TextBox) DesiredSize(ctx Context, _ geom.PointF32) geom.PointF32 { - font := b.Font_(ctx) + font := b.ActualFont(ctx) var width = font.WidthOf(b.Text) var height = font.Height() - var pad = b.pad(ctx) - return geom.PtF32(width+pad*2, height+pad*2) + pad := b.ActualTextPadding(ctx) + return geom.PtF32(pad.Left+width+pad.Right, pad.Top+height+pad.Bottom) } func (b *TextBox) TextChanged() *Events { return &b.textChanged } @@ -71,7 +68,7 @@ func (b *TextBox) TextChanged() *Events { return &b.textChanged } func (b *TextBox) mousePosToCaretPos(ctx Context, e MouseEvent) int { p := b.ToControlPosition(e.Pos()) offset := p.X - b.box.bounds.Min.X - f := b.Font_(ctx) + f := b.ActualFont(ctx) var carets = [3]int{0, 0, len(b.Text)} var offsets = [3]float32{0, 0, f.WidthOf(b.Text)} var updateCenter = func() { @@ -262,7 +259,7 @@ func (b *TextBox) Render(ctx Context) { back = ctx.Style().Palette.Background } renderer.Clear(back) - font := b.Font_(ctx) + font := b.ActualFont(ctx) if b.Selection.Start != b.Selection.End { left, right := font.WidthOf(b.Text[:b.Selection.Start]), font.WidthOf(b.Text[:b.Selection.End]) renderer.FillRectangle(geom.RectF32(left, 0, right, size.Y), style.Palette.PrimaryHighlight)