~eliasnaur/gio

f7bc744a24bfdfecf1882d4ccc83e18fa139e5cb — Elias Naur 10 months ago 0f51cb9
widget: add Editor.Filter for filtering unwanted characters

Signed-off-by: Elias Naur <mail@eliasnaur.com>
2 files changed, 48 insertions(+), 5 deletions(-)

M widget/editor.go
M widget/editor_test.go
M widget/editor.go => widget/editor.go +17 -5
@@ 49,6 49,9 @@ type Editor struct {
	InputHint key.InputHint
	// MaxLen limits the editor content to a maximum length. Zero means no limit.
	MaxLen int
	// Filter is the list of characters allowed in the Editor. If Filter is empty,
	// all characters are allowed.
	Filter string

	eventKey     int
	font         text.Font


@@ 1235,12 1238,21 @@ func (e *Editor) replace(start, end int, s string, addHistory bool) int {
	startPos := e.closestPosition(combinedPos{runes: start})
	endPos := e.closestPosition(combinedPos{runes: end})
	startOff := e.runeOffset(startPos.runes)
	sc := utf8.RuneCountInString(s)
	el := e.Len()
	for e.MaxLen > 0 && el+sc > e.MaxLen {
		_, n := utf8.DecodeLastRuneInString(s)
		s = s[:len(s)-n]
		sc--
	var sc int
	idx := 0
	for idx < len(s) {
		if e.MaxLen > 0 && el+sc >= e.MaxLen {
			s = s[:idx]
			break
		}
		_, n := utf8.DecodeRuneInString(s[idx:])
		if e.Filter != "" && !strings.Contains(e.Filter, s[idx:idx+n]) {
			s = s[:idx] + s[idx+n:]
			continue
		}
		idx += n
		sc++
	}
	newEnd := startPos.runes + sc
	replaceSize := endPos.runes - startPos.runes

M widget/editor_test.go => widget/editor_test.go +31 -0
@@ 1036,6 1036,37 @@ func TestEditor_MaxLen(t *testing.T) {
	}
}

func TestEditor_Filter(t *testing.T) {
	e := new(Editor)

	e.Filter = "123456789"
	e.SetText("abcde1234")
	if got, want := e.Text(), "1234"; got != want {
		t.Errorf("editor failed to filter SetText")
	}

	e.SetText("2345678")
	gtx := layout.Context{
		Ops:         new(op.Ops),
		Constraints: layout.Exact(image.Pt(100, 100)),
		Queue: newQueue(
			key.EditEvent{Range: key.Range{Start: 0, End: 0}, Text: "ab1"},
			key.SelectionEvent{Start: 4, End: 4},
		),
	}
	cache := text.NewCache(gofont.Collection())
	fontSize := unit.Sp(10)
	font := text.Font{}
	e.Layout(gtx, cache, font, fontSize, nil)

	if got, want := e.Text(), "12345678"; got != want {
		t.Errorf("editor failed to filter EditEvent")
	}
	if start, end := e.Selection(); start != 2 || end != 2 {
		t.Errorf("editor failed to adjust SelectionEvent")
	}
}

func textWidth(e *Editor, lineNum, colStart, colEnd int) float32 {
	var w fixed.Int26_6
	glyphs := e.lines[lineNum].Layout.Glyphs