text: remove padding from Editor

Before this change, the Editor computed a suitable padding for itself
from its font and text. Varying the padding according to the particular
font and text doesn't seem worth it and interferes with higher level widgets'
ability to overlay hints and the like on top of the editor.

Signed-off-by: Elias Naur <mail@eliasnaur.com>
This commit is contained in:
Elias Naur
2019-10-10 13:48:25 +02:00
parent f35fe407b3
commit dbb62ae0f6
+46 -60
View File
@@ -41,22 +41,20 @@ type Editor struct {
// If not enabled, carriage returns are inserted as newlines in the text. // If not enabled, carriage returns are inserted as newlines in the text.
Submit bool Submit bool
scale int scale int
font editorFont font Font
blinkStart time.Time blinkStart time.Time
focused bool focused bool
rr editBuffer rr editBuffer
maxWidth int maxWidth int
viewSize image.Point viewSize image.Point
valid bool valid bool
lines []Line lines []Line
dims layout.Dimensions dims layout.Dimensions
padTop, padBottom int carWidth fixed.Int26_6
padLeft, padRight int requestFocus bool
carWidth fixed.Int26_6 caretOn bool
requestFocus bool caretScroll bool
caretOn bool
caretScroll bool
// carXOff is the offset to the current caret // carXOff is the offset to the current caret
// position when moving between lines. // position when moving between lines.
@@ -201,17 +199,12 @@ func (e *Editor) layout(gtx *layout.Context, s *Shaper, font Font) {
e.scale = scale e.scale = scale
} }
cs := gtx.Constraints cs := gtx.Constraints
twoDp := gtx.Px(unit.Dp(2))
e.carWidth = fixed.I(gtx.Px(unit.Dp(1))) e.carWidth = fixed.I(gtx.Px(unit.Dp(1)))
e.padLeft, e.padRight = twoDp, twoDp
maxWidth := cs.Width.Max maxWidth := cs.Width.Max
if e.SingleLine { if e.SingleLine {
maxWidth = inf maxWidth = inf
} }
if maxWidth != inf {
maxWidth -= e.padLeft + e.padRight
}
if maxWidth != e.maxWidth { if maxWidth != e.maxWidth {
e.maxWidth = maxWidth e.maxWidth = maxWidth
e.invalidate() e.invalidate()
@@ -232,8 +225,6 @@ func (e *Editor) layout(gtx *layout.Context, s *Shaper, font Font) {
key.InputOp{Key: e, Focus: e.requestFocus}.Add(gtx.Ops) key.InputOp{Key: e, Focus: e.requestFocus}.Add(gtx.Ops)
e.requestFocus = false e.requestFocus = false
baseline := e.padTop + e.dims.Baseline
pointerPadding := gtx.Px(unit.Dp(4)) pointerPadding := gtx.Px(unit.Dp(4))
r := image.Rectangle{Max: e.viewSize} r := image.Rectangle{Max: e.viewSize}
r.Min.X -= pointerPadding r.Min.X -= pointerPadding
@@ -243,7 +234,6 @@ func (e *Editor) layout(gtx *layout.Context, s *Shaper, font Font) {
pointer.RectAreaOp{Rect: r}.Add(gtx.Ops) pointer.RectAreaOp{Rect: r}.Add(gtx.Ops)
e.scroller.Add(gtx.Ops) e.scroller.Add(gtx.Ops)
e.clicker.Add(gtx.Ops) e.clicker.Add(gtx.Ops)
gtx.Dimensions = layout.Dimensions{Size: e.viewSize, Baseline: baseline}
e.caretOn = false e.caretOn = false
if e.focused { if e.focused {
now := gtx.Now() now := gtx.Now()
@@ -257,21 +247,24 @@ func (e *Editor) layout(gtx *layout.Context, s *Shaper, font Font) {
} }
e.caretOn = e.focused && (!blinking || dt%timePerBlink < timePerBlink/2) e.caretOn = e.focused && (!blinking || dt%timePerBlink < timePerBlink/2)
} }
gtx.Dimensions = layout.Dimensions{Size: e.viewSize, Baseline: e.dims.Baseline}
} }
func (e *Editor) draw(gtx *layout.Context, s *Shaper, font Font) { func (e *Editor) draw(gtx *layout.Context, s *Shaper, font Font) {
var stack op.StackOp var stack op.StackOp
stack.Push(gtx.Ops) stack.Push(gtx.Ops)
off := image.Point{ off := image.Point{
X: -e.scrollOff.X + e.padLeft, X: -e.scrollOff.X,
Y: -e.scrollOff.Y + e.padTop, Y: -e.scrollOff.Y,
} }
clip := e.clipRect() clip := textPadding(e.lines)
clip.Max = clip.Max.Add(e.viewSize)
it := lineIterator{ it := lineIterator{
Lines: e.lines, Lines: e.lines,
Clip: clip, Clip: clip,
Alignment: e.Alignment, Alignment: e.Alignment,
Width: e.viewWidth(), Width: e.viewSize.X,
Offset: off, Offset: off,
} }
for { for {
@@ -304,10 +297,20 @@ func (e *Editor) drawCaret(gtx *layout.Context) {
Max: image.Point{X: carX.Ceil() + e.carWidth.Ceil(), Y: carY + carDesc.Ceil()}, Max: image.Point{X: carX.Ceil() + e.carWidth.Ceil(), Y: carY + carDesc.Ceil()},
} }
carRect = carRect.Add(image.Point{ carRect = carRect.Add(image.Point{
X: -e.scrollOff.X + e.padLeft, X: -e.scrollOff.X,
Y: -e.scrollOff.Y + e.padTop, Y: -e.scrollOff.Y,
}) })
carRect = e.clipRect().Intersect(carRect) clip := textPadding(e.lines)
// Account for caret width to each side.
whalf := (e.carWidth / 2).Ceil()
if clip.Max.X < whalf {
clip.Max.X = whalf
}
if clip.Min.X > -whalf {
clip.Min.X = -whalf
}
clip.Max = clip.Max.Add(e.viewSize)
carRect = clip.Intersect(carRect)
if !carRect.Empty() { if !carRect.Empty() {
paint.PaintOp{Rect: toRectF(carRect)}.Add(gtx.Ops) paint.PaintOp{Rect: toRectF(carRect)}.Add(gtx.Ops)
} }
@@ -331,17 +334,11 @@ func (e *Editor) SetText(s string) {
e.prepend(s) e.prepend(s)
} }
func (e *Editor) clipRect() image.Rectangle {
clip := textPadding(e.lines)
clip.Max = clip.Max.Add(e.viewSize)
return clip
}
func (e *Editor) scrollBounds() image.Rectangle { func (e *Editor) scrollBounds() image.Rectangle {
var b image.Rectangle var b image.Rectangle
if e.SingleLine { if e.SingleLine {
if len(e.lines) > 0 { if len(e.lines) > 0 {
b.Min.X = align(e.Alignment, e.lines[0].Width, e.viewWidth()).Floor() b.Min.X = align(e.Alignment, e.lines[0].Width, e.viewSize.X).Floor()
if b.Min.X > 0 { if b.Min.X > 0 {
b.Min.X = 0 b.Min.X = 0
} }
@@ -379,12 +376,12 @@ func (e *Editor) moveCoord(c unit.Converter, pos image.Point) {
for _, l := range e.lines { for _, l := range e.lines {
y += (prevDesc + l.Ascent).Ceil() y += (prevDesc + l.Ascent).Ceil()
prevDesc = l.Descent prevDesc = l.Descent
if y+prevDesc.Ceil() >= pos.Y+e.scrollOff.Y-e.padTop { if y+prevDesc.Ceil() >= pos.Y+e.scrollOff.Y {
break break
} }
carLine++ carLine++
} }
x := fixed.I(pos.X + e.scrollOff.X - e.padLeft) x := fixed.I(pos.X + e.scrollOff.X)
e.moveToLine(x, carLine) e.moveToLine(x, carLine)
} }
@@ -409,18 +406,9 @@ func (e *Editor) layoutText(c unit.Converter, s *Shaper, font Font) {
} }
} }
} }
padTop, padBottom := textPadding(lines)
dims.Size.Y += padTop + padBottom
dims.Size.X += e.padLeft + e.padRight
e.padTop = padTop
e.padBottom = padBottom
e.lines, e.dims = lines, dims e.lines, e.dims = lines, dims
} }
func (e *Editor) viewWidth() int {
return e.viewSize.X - e.padLeft - e.padRight
}
func (e *Editor) layoutCaret() (carLine, carCol int, x fixed.Int26_6, y int) { func (e *Editor) layoutCaret() (carLine, carCol int, x fixed.Int26_6, y int) {
e.adjustScroll() e.adjustScroll()
var idx int var idx int
@@ -446,7 +434,7 @@ loop:
} }
idx += len(l.Text.String) idx += len(l.Text.String)
} }
x += align(e.Alignment, e.lines[carLine].Width, e.viewWidth()) x += align(e.Alignment, e.lines[carLine].Width, e.viewSize.X)
return return
} }
@@ -530,7 +518,7 @@ func (e *Editor) moveToLine(carX fixed.Int26_6, carLine2 int) fixed.Int26_6 {
} }
} }
l2 := e.lines[carLine2] l2 := e.lines[carLine2]
carX2 := align(e.Alignment, l2.Width, e.viewWidth()) carX2 := align(e.Alignment, l2.Width, e.viewSize.X)
// Only move past the end of the last line // Only move past the end of the last line
end := 0 end := 0
if carLine2 < len(e.lines)-1 { if carLine2 < len(e.lines)-1 {
@@ -587,7 +575,7 @@ func (e *Editor) moveEnd() {
e.rr.caret += s e.rr.caret += s
x += adv x += adv
} }
a := align(e.Alignment, l.Width, e.viewWidth()) a := align(e.Alignment, l.Width, e.viewSize.X)
e.carXOff = l.Width + a - x e.carXOff = l.Width + a - x
} }
@@ -595,21 +583,19 @@ func (e *Editor) scrollToCaret() {
carLine, _, x, y := e.layoutCaret() carLine, _, x, y := e.layoutCaret()
l := e.lines[carLine] l := e.lines[carLine]
if e.SingleLine { if e.SingleLine {
minx := (x - e.carWidth/2).Ceil() if d := x.Floor() - e.scrollOff.X; d < 0 {
if d := minx - e.scrollOff.X + e.padLeft; d < 0 {
e.scrollOff.X += d e.scrollOff.X += d
} }
maxx := (x + e.carWidth/2).Ceil() if d := x.Ceil() - (e.scrollOff.X + e.viewSize.X); d > 0 {
if d := maxx - (e.scrollOff.X + e.viewSize.X - e.padRight); d > 0 {
e.scrollOff.X += d e.scrollOff.X += d
} }
} else { } else {
miny := y + l.Bounds.Min.Y.Floor() miny := y - l.Ascent.Ceil()
if d := miny - e.scrollOff.Y + e.padTop; d < 0 { if d := miny - e.scrollOff.Y; d < 0 {
e.scrollOff.Y += d e.scrollOff.Y += d
} }
maxy := y + l.Bounds.Max.Y.Ceil() maxy := y + l.Descent.Ceil()
if d := maxy - (e.scrollOff.Y + e.viewSize.Y - e.padBottom); d > 0 { if d := maxy - (e.scrollOff.Y + e.viewSize.Y); d > 0 {
e.scrollOff.Y += d e.scrollOff.Y += d
} }
} }