ref: 00d144fb31327e3e7181f669c58d6fdbe0c9485e
parent: 0c44bd66e976d09c7aad8c6081d8b590832cea46
author: Philip Silva <philip.silva@protonmail.com>
date: Thu Jun 5 13:59:03 EDT 2025
field cursor
--- a/cmd/hello/hello.go
+++ b/cmd/hello/hello.go
@@ -80,7 +80,7 @@
}, nil)
btn.Margin = x.Space(5, 10)
- fl := field.New(x, image.ZP, " ", x.Rect(0,0, 150, 50))
+ fl := field.New(x, image.ZP, "", x.Rect(0,0, 150, 50))
fl.Margin = x.Space(5, 10)
b2 := box.New([]element.Interface{
l,
--- a/field/field.go
+++ b/field/field.go
@@ -35,6 +35,9 @@
Text string
color.Colorset
+ // Position of the cursor
+ Pos int
+
textImg *memdraw.Image
borderImg *memdraw.Image
hoverImg *memdraw.Image
@@ -76,16 +79,32 @@
f.cb(tev, f.cbUserData)
}
case keyboard.Event:
- log.Printf("key pressed: %+v", tev)
+ log.Printf("key pressed: %+v %d % x", tev, tev, tev)
switch tev.Key {
case Backspace:
- if len(f.Text) > 0 {
- f.Text = f.Text[:len(f.Text)-1]
+ if f.Pos > 0 && len(f.Text) > 0 {
+ f.Text = f.Text[:f.Pos-1] + f.Text[f.Pos:]
}
+ f.Pos -= 1
+ case draw.KeyDelete:
+ if f.Pos < len(f.Text) {
+ f.Text = f.Text[:f.Pos] + f.Text[f.Pos+1:]
+ }
+ case draw.KeyLeft:
+ f.Pos -= 1
+ case draw.KeyRight:
+ f.Pos += 1
default:
f.Text += string([]byte{byte(tev.Key)})
+ f.Pos = len(f.Text)
}
+ if f.Pos < 0 {
+ f.Pos = 0
+ }
+ if f.Pos > len(f.Text) {
+ f.Pos = len(f.Text)
+ }
//log.Printf("event: call updateTextImgs")
f.updateTextImgs()
}
@@ -138,7 +157,12 @@
f.hoverImg.Draw(rr, f.textImg, image.ZP, color.EmptyMask, image.ZP, draw.SoverD)
geom.DrawRoundedBorder(f.hoverImg, f.Rectangle, f.Colorset.Hover.Border)
- geom.DrawCursor(f.hoverImg, r, f.textImg, f.Colorset.Hover.Border)
+ textPart, err := font.String(f.Text[:f.Pos])
+ if err == nil {
+ geom.DrawCursor(f.hoverImg, r, textPart.R, f.Colorset.Hover.Border)
+ } else {
+ log.Printf("font string sub text: %v", err)
+ }
}
func (f Field) Focus() {
--- a/field/field_test.go
+++ b/field/field_test.go
@@ -9,17 +9,34 @@
"testing"
)
-func TestRender(t *testing.T) {
+var rField = image.Rect(0, 0, 300, 100)
+
+func newField(t *testing.T) *Field {
memdraw.Init()
rScreen := image.Rect(0, 0, 800, 600)
- rField := image.Rect(0, 0, 300, 100)
img, err := memdraw.AllocImage(rScreen, draw.ABGR32)
if err != nil {
t.Fail()
}
memdraw.FillColor(img, draw.White)
- f := New(&xuitest.Xui{}, image.ZP, "", rField)
+ return New(&xuitest.Xui{}, image.ZP, "", rField)
+}
+func TestEvent(t *testing.T) {
+ f := newField(t)
+ f.Text = "Text"
+ f.Pos = 2
+ f.Event(keyboard.Event{Key: Backspace})
+ if f.Text != "Txt" {
+ t.Fatalf("Text=%s", f.Text)
+ }
+ if f.Pos != 1 {
+ t.Fatalf("Pos=%d", f.Pos)
+ }
+}
+
+func TestRender(t *testing.T) {
+ f := newField(t)
for i := 0; i < 20; i++ {
f.Event(keyboard.Event{Key: 'a'})
img := f.Render()
@@ -32,4 +49,4 @@
t.Fatalf("bbox outside field rect")
}
}
-}
\ No newline at end of file
+}
--- a/internal/geom/lines.go
+++ b/internal/geom/lines.go
@@ -48,9 +48,9 @@
memdraw.Line(img, image.Pt(x1-radius, y0), image.Pt(x0+radius, y0), 0, 0, 0, color, image.ZP, draw.SoverD)
}
-func DrawCursor(dst *memdraw.Image, bounds image.Rectangle, text *memdraw.Image, color *memdraw.Image) {
- h := text.R.Dy()/2
- p1 := text.R.Max.Add(image.Pt(h/5, -h/2))
+func DrawCursor(dst *memdraw.Image, bounds, textR image.Rectangle, color *memdraw.Image) {
+ h := textR.Dy()/2
+ p1 := textR.Max.Add(image.Pt(h/5, -h/2))
p0 := p1.Add(image.Pt(0, -h))
if p0.X >= bounds.Dx() {
return
--
⑨