diff --git a/widget/buffer.go b/widget/buffer.go index 22e84517..74cacdf8 100644 --- a/widget/buffer.go +++ b/widget/buffer.go @@ -35,20 +35,19 @@ func (e *editBuffer) Changed() bool { return c } -func (e *editBuffer) deleteRuneForward() { +func (e *editBuffer) deleteRunes(runes int) { e.moveGap(0) - _, s := utf8.DecodeRune(e.text[e.gapend:]) - e.gapend += s - e.changed = e.changed || s > 0 - e.dump() -} - -func (e *editBuffer) deleteRune() { - e.moveGap(0) - _, s := utf8.DecodeLastRune(e.text[:e.gapstart]) - e.gapstart -= s - e.caret -= s - e.changed = e.changed || s > 0 + for ; runes < 0 && e.gapstart > 0; runes++ { + _, s := utf8.DecodeLastRune(e.text[:e.gapstart]) + e.gapstart -= s + e.caret -= s + e.changed = e.changed || s > 0 + } + for ; runes > 0 && e.gapend < len(e.text); runes-- { + _, s := utf8.DecodeRune(e.text[e.gapend:]) + e.gapend += s + e.changed = e.changed || s > 0 + } e.dump() } @@ -141,15 +140,15 @@ func (e *editBuffer) dump() { } } -func (e *editBuffer) moveLeft() { - _, s := e.runeBefore(e.caret) - e.caret -= s - e.dump() -} - -func (e *editBuffer) moveRight() { - _, s := e.runeAt(e.caret) - e.caret += s +func (e *editBuffer) move(runes int) { + for ; runes < 0 && e.caret > 0; runes++ { + _, s := e.runeBefore(e.caret) + e.caret -= s + } + for ; runes > 0 && e.caret < len(e.text); runes-- { + _, s := e.runeAt(e.caret) + e.caret += s + } e.dump() } diff --git a/widget/editor.go b/widget/editor.go index 8b7b07d2..7ba8d3c8 100644 --- a/widget/editor.go +++ b/widget/editor.go @@ -175,6 +175,38 @@ func (e *Editor) processKey(gtx *layout.Context) { } } +func (e *Editor) command(k key.Event) bool { + switch k.Name { + case key.NameReturn, key.NameEnter: + e.append("\n") + case key.NameDeleteBackward: + e.Delete(-1) + case key.NameDeleteForward: + e.Delete(1) + case key.NameUpArrow: + line, _, carX, _ := e.layoutCaret() + e.carXOff = e.moveToLine(carX+e.carXOff, line-1) + case key.NameDownArrow: + line, _, carX, _ := e.layoutCaret() + e.carXOff = e.moveToLine(carX+e.carXOff, line+1) + case key.NameLeftArrow: + e.Move(-1) + case key.NameRightArrow: + e.Move(1) + case key.NamePageUp: + e.movePages(-1) + case key.NamePageDown: + e.movePages(+1) + case key.NameHome: + e.moveStart() + case key.NameEnd: + e.moveEnd() + default: + return false + } + return true +} + // Focus requests the input focus for the Editor. func (e *Editor) Focus() { e.requestFocus = true @@ -451,15 +483,18 @@ func (e *Editor) invalidate() { e.valid = false } -func (e *Editor) deleteRune() { - e.rr.deleteRune() +// Delete runes from the caret position. The sign of runes specifies the +// direction to delete: positive is forward, negative is backward. +func (e *Editor) Delete(runes int) { + e.rr.deleteRunes(runes) e.carXOff = 0 e.invalidate() } -func (e *Editor) deleteRuneForward() { - e.rr.deleteRuneForward() - e.carXOff = 0 +// Insert inserts text at the caret, moving the caret forward. +func (e *Editor) Insert(s string) { + e.append(s) + e.caretScroll = true e.invalidate() } @@ -549,13 +584,10 @@ func (e *Editor) moveToLine(carX fixed.Int26_6, carLine2 int) fixed.Int26_6 { return carX - carX2 } -func (e *Editor) moveLeft() { - e.rr.moveLeft() - e.carXOff = 0 -} - -func (e *Editor) moveRight() { - e.rr.moveRight() +// Move the caret: positive distance moves forward, negative distance moves +// backward. +func (e *Editor) Move(distance int) { + e.rr.move(distance) e.carXOff = 0 } @@ -612,37 +644,5 @@ func (e *Editor) scrollToCaret() { } } -func (e *Editor) command(k key.Event) bool { - switch k.Name { - case key.NameReturn, key.NameEnter: - e.append("\n") - case key.NameDeleteBackward: - e.deleteRune() - case key.NameDeleteForward: - e.deleteRuneForward() - case key.NameUpArrow: - line, _, carX, _ := e.layoutCaret() - e.carXOff = e.moveToLine(carX+e.carXOff, line-1) - case key.NameDownArrow: - line, _, carX, _ := e.layoutCaret() - e.carXOff = e.moveToLine(carX+e.carXOff, line+1) - case key.NameLeftArrow: - e.moveLeft() - case key.NameRightArrow: - e.moveRight() - case key.NamePageUp: - e.movePages(-1) - case key.NamePageDown: - e.movePages(+1) - case key.NameHome: - e.moveStart() - case key.NameEnd: - e.moveEnd() - default: - return false - } - return true -} - func (s ChangeEvent) isEditorEvent() {} func (s SubmitEvent) isEditorEvent() {}