shithub: xui

Download patch

ref: a8bb4e36f51179ad6b544d2236600b88aab371d2
parent: 00d144fb31327e3e7181f669c58d6fdbe0c9485e
author: Philip Silva <philip.silva@protonmail.com>
date: Thu Jun 26 12:56:25 EDT 2025

field click

--- a/button/button.go
+++ b/button/button.go
@@ -44,7 +44,7 @@
 	b.x = x
 
 	var err error
-	b.textImg, err = font.String(text)
+	b.textImg, err = font.String(text, nil)
 	if err != nil {
 		panic(err.Error())
 	}
--- a/field/field.go
+++ b/field/field.go
@@ -6,6 +6,7 @@
 	//"fmt"
 	"image"
 	"log"
+	"slices"
 	"sync"
 	"github.com/psilva261/xui"
 	"github.com/psilva261/xui/events"
@@ -38,6 +39,9 @@
 	// Position of the cursor
 	Pos int
 
+	// Offsets of the characters
+	Offsets []int
+
 	textImg *memdraw.Image
 	borderImg *memdraw.Image
 	hoverImg *memdraw.Image
@@ -69,10 +73,14 @@
 
 	switch tev := ev.(type) {
 	case mouse.Event:
-		if tev.Type == mouse.Enter {
+		switch tev.Type {
+		case mouse.Enter:
 			f.hover = true
-		} else if tev.Type == mouse.Leave {
+		case mouse.Leave:
 			f.hover = false
+		case mouse.Click:
+			f.Pos, _ = slices.BinarySearch(f.Offsets, tev.Point.X)
+			f.updateTextImgs()
 		}
 
 		if f.cb != nil {
@@ -79,11 +87,11 @@
 			f.cb(tev, f.cbUserData)
 		}
 	case keyboard.Event:
-		log.Printf("key pressed: %+v %d % x", tev, tev, tev)
+		//log.Printf("key pressed: %+v %d % x", tev, tev, tev)
 
 		switch tev.Key {
 		case Backspace:
-			if f.Pos > 0 && len(f.Text) > 0 {
+			if f.Pos > 0 && f.Pos <= len(f.Text) && len(f.Text) > 0 {
 				f.Text = f.Text[:f.Pos-1] + f.Text[f.Pos:]
 			}
 			f.Pos -= 1
@@ -96,8 +104,8 @@
 		case draw.KeyRight:
 			f.Pos += 1
 		default:
-			f.Text += string([]byte{byte(tev.Key)})
-			f.Pos = len(f.Text)
+			f.Text = f.Text[:f.Pos]+string([]byte{byte(tev.Key)})+f.Text[f.Pos:]
+			f.Pos += 1
 		}
 		if f.Pos < 0 {
 			f.Pos = 0
@@ -127,10 +135,9 @@
 }
 
 func (f *Field) updateTextImgs() {
-
 	var err error
-	//log.Printf("updateTextImgs: call font.String")
-	f.textImg, err = font.String(f.Text)
+
+	f.textImg, err = font.String(f.Text, &f.Offsets)
 	if err != nil {
 		panic(err.Error())
 	}
@@ -157,9 +164,13 @@
 	f.hoverImg.Draw(rr, f.textImg, image.ZP, color.EmptyMask, image.ZP, draw.SoverD)
 	geom.DrawRoundedBorder(f.hoverImg, f.Rectangle, f.Colorset.Hover.Border)
 
-	textPart, err := font.String(f.Text[:f.Pos])
+	pos := f.Pos
+	if pos+1 >= len(f.Offsets) {
+		pos = len(f.Offsets)-1
+	}
+	textPartR := draw.Rect(0, 0, f.Offsets[pos], f.textImg.R.Dy())
 	if err == nil {
-		geom.DrawCursor(f.hoverImg, r, textPart.R, f.Colorset.Hover.Border)
+		geom.DrawCursor(f.hoverImg, r, textPartR, f.Colorset.Hover.Border)
 	} else {
 		log.Printf("font string sub text: %v", err)
 	}
--- a/field/field_test.go
+++ b/field/field_test.go
@@ -4,6 +4,7 @@
 	"9fans.net/go/draw"
 	"9fans.net/go/draw/memdraw"
 	"github.com/psilva261/xui/events/keyboard"
+	"github.com/psilva261/xui/events/mouse"
 	"github.com/psilva261/xui/xuitest"
 	"image"
 	"testing"
@@ -32,6 +33,20 @@
 	}
 	if f.Pos != 1 {
 		t.Fatalf("Pos=%d", f.Pos)
+	}
+}
+
+func TestEventClick(t *testing.T) {
+	f := newField(t)
+	f.Text = "abcdefghijklmn"
+	f.Pos = 13
+	f.Offsets = []int{0, 19, 40, 57, 78, 96, 108, 129, 150, 159, 169, 189, 198, 229, 250}
+	f.Event(mouse.Event{
+		Type: mouse.Click,
+		Point: image.Pt(82,423),
+	})
+	if f.Pos != 5 {
+		t.Fatalf("%v", f.Pos)
 	}
 }
 
--- a/font/font.go
+++ b/font/font.go
@@ -34,7 +34,7 @@
 	return
 }
 
-func String(text string) (textImg *memdraw.Image, err error) {
+func String(text string, offsets *[]int) (textImg *memdraw.Image, err error) {
 	face, err := Open("")
 	if err != nil {
 		return nil, fmt.Errorf("open font: %w", err)
@@ -42,10 +42,16 @@
 	ascent := face.Metrics().Ascent.Ceil()
 
 	w := 0
-	for _, r := range text {
+	if offsets != nil && len(*offsets) <= len(text) {
+		*offsets = append(*offsets, make([]int, len(text)-len(*offsets)+1)...)
+	}
+	for i, r := range text {
 		bounds, adv, _ := face.GlyphBounds(r)
 		_ = bounds
 		w += adv.Ceil()
+		if offsets != nil {
+			(*offsets)[i+1] = w
+		}
 	}
 	r := image.Rect(0, 0, w, 2*ascent)
 	if r.Dx() == 0 {
@@ -64,7 +70,7 @@
 	}
 	d.DrawString(text)
 
-	log.Printf("String: dst.Bounds()=%+v", dst.Bounds())
+	//log.Printf("String: dst.Bounds()=%+v", dst.Bounds())
 
 	textImg, err = memdraw.AllocImage(dst.Bounds(), draw.ABGR32)
 	if err != nil {
--- a/font/font_test.go
+++ b/font/font_test.go
@@ -35,7 +35,7 @@
 }
 
 func testString(t *testing.T, text string) (map[color.Color]int, image.Rectangle) {
-	img, err := String(text)
+	img, err := String(text, nil)
 	if err != nil {
 		t.Fail()
 	}
--- a/label/label.go
+++ b/label/label.go
@@ -27,7 +27,7 @@
 	l.Text = text
 
 	var err error
-	l.textImg, err = font.String(text)
+	l.textImg, err = font.String(text, nil)
 	if err != nil {
 		panic(err.Error())
 	}
--