From 639810fb13a2e1050abef7592ab0a0b2a81fca4b Mon Sep 17 00:00:00 2001 From: Sasha Koshka Date: Fri, 4 Aug 2023 21:59:52 -0400 Subject: [PATCH] Added dot selection visualization --- textbox.go | 72 +++++++++++++++++++++++++++++++++++++++++++++--------- 1 file changed, 61 insertions(+), 11 deletions(-) diff --git a/textbox.go b/textbox.go index 797714c..003ab6d 100644 --- a/textbox.go +++ b/textbox.go @@ -3,6 +3,7 @@ package x import "image" import "image/color" import "golang.org/x/image/font" +import "golang.org/x/image/math/fixed" import "git.tebibyte.media/tomo/tomo" import "git.tebibyte.media/tomo/typeset" import "git.tebibyte.media/tomo/tomo/text" @@ -24,6 +25,7 @@ type textBox struct { selectable bool dot text.Dot + dotColor color.Color drawer typeset.Drawer @@ -98,6 +100,14 @@ func (this *textBox) SetSelectable (selectable bool) { this.selectable = selectable } +func (this *textBox) SetDotColor (c color.Color) { + if this.dotColor == c { return } + this.dotColor = c + if !this.dot.Empty() { + this.invalidateDraw() + } +} + func (this *textBox) Select (dot text.Dot) { if !this.selectable { return } if this.dot == dot { return } @@ -144,24 +154,64 @@ func (this *textBox) Draw (can canvas.Canvas) { this.drawer.Draw(can, this.textColor, this.textOffset()) } +func roundPt (point fixed.Point26_6) image.Point { + return image.Pt(point.X.Round(), point.Y.Round()) +} + +func fixPt (point image.Point) fixed.Point26_6 { + return fixed.P(point.X, point.Y) +} + func (this *textBox) drawDot (can canvas.Canvas) { pen := can.Pen() pen.Fill(color.Transparent) pen.Stroke(this.textColor) pen.StrokeWeight(1) + + bounds := this.InnerBounds() + metrics := this.face.Metrics() + dot := this.dot.Canon() + start := this.drawer.PositionAt(dot.Start).Add(fixPt(this.textOffset())) + end := this.drawer.PositionAt(dot.End ).Add(fixPt(this.textOffset())) + height := this.drawer.LineHeight().Round() + ascent := fixed.Point26_6 { Y: metrics.Descent } + descent := fixed.Point26_6 { Y: metrics.Ascent } - // TODO draw dot - if this.dot.Empty() { - metrics := this.face.Metrics() - position := this.drawer.PositionAt(this.dot.Start) - roundPos := - image.Pt(position.X.Round(), position.Y.Round()). - Add(this.textOffset()) - pen.Path ( - roundPos.Add(image.Pt(0, metrics.Descent.Round())), - roundPos.Sub(image.Pt(0, metrics.Ascent.Round()))) - } else { + switch { + case dot.Empty(): + pen.Path(roundPt(start.Add(ascent)), roundPt(start.Sub(descent))) + case start.Y == end.Y: + pen.Fill(this.dotColor) + pen.StrokeWeight(0) + pen.Rectangle(image.Rectangle { + Min: roundPt(start.Add(ascent)), + Max: roundPt(end.Sub(descent)), + }) + + default: + pen.Fill(this.dotColor) + pen.StrokeWeight(0) + + rect := image.Rectangle { + Min: roundPt(start.Add(ascent)), + Max: roundPt(start.Sub(descent)), + } + rect.Max.X = bounds.Max.X + pen.Rectangle(rect) + if end.Y - start.Y > fixed.I(height) { + rect.Min.X = bounds.Min.X + rect.Min.Y = roundPt(start.Sub(descent)).Y + height + rect.Max.X = bounds.Max.X + rect.Max.Y = roundPt(end.Add(ascent)).Y - height + pen.Rectangle(rect) + } + rect = image.Rectangle { + Min: roundPt(end.Add(ascent)), + Max: roundPt(end.Sub(descent)), + } + rect.Min.X = bounds.Min.X + pen.Rectangle(rect) } }