diff options
Diffstat (limited to 'gui/ui/field.go')
| -rw-r--r-- | gui/ui/field.go | 88 |
1 files changed, 88 insertions, 0 deletions
diff --git a/gui/ui/field.go b/gui/ui/field.go new file mode 100644 index 0000000..6872d32 --- /dev/null +++ b/gui/ui/field.go @@ -0,0 +1,88 @@ +package ui + +import "9front/gui/draw" + +// A Field is one line of editable text. +// +// Deliberately small: a cursor at the end, backspace, and ^U to clear. +// There is no selection, no mouse cursor placement and no history, +// because a form that asks for a summary and a time does not need them +// and every one of them is a place to get subtly wrong. A program that +// needs a real editor should hand the job to one. +type Field struct { + Label string + Value string + R draw.Rectangle // set by Draw, used for hit testing +} + +// Draw paints the field and records where it landed in f.R, so the +// caller can make it clickable. It does not register a hit region +// itself: the first matching region wins a click, and a do-nothing one +// here would silently swallow the caller's. +func (u *UI) Draw(f *Field, r draw.Rectangle, focused bool) { + f.R = r + lw := u.F.Width("attendees ") + 8 + u.Text(draw.Point{X: r.Min.X, Y: r.Min.Y + 2}, "ink", f.Label) + + box := draw.Rect(r.Min.X+lw, r.Min.Y, r.Max.X, r.Max.Y) + u.Fill(box, "bg") + c := "rule" + if focused { + c = "border" + } + u.Border(box, c) + + s := f.Value + if focused { + s += "|" + } + // keep the end of the line in view: that is where you are typing + for len(s) > 0 && u.F.Width(s) > box.Dx()-8 { + s = s[1:] + } + u.Text(draw.Point{X: box.Min.X + 4, Y: box.Min.Y + 2}, "ink", s) +} + +// oneLine keeps a paste to the first line: these are one-line fields, +// and a pasted paragraph would silently lose everything after the first +// newline anyway. +func oneLine(s string) string { + for i, r := range s { + if r == '\n' || r == '\r' { + return s[:i] + } + } + return s +} + +// Key applies one typed rune and says whether it changed anything. +func (f *Field) Key(r rune) bool { + switch r { + case '\b', 0x7F: // backspace, del + if f.Value == "" { + return false + } + v := []rune(f.Value) + f.Value = string(v[:len(v)-1]) + return true + case 0x15: // ^U + if f.Value == "" { + return false + } + f.Value = "" + return true + case 0x16, 0x19: // ^V, ^Y: paste + if v, err := draw.Snarfed("/dev"); err == nil { + f.Value += oneLine(v) + return true + } + return false + case '\n', '\r', '\t', 0x1B: + return false // the form deals with these + } + if r < ' ' { + return false + } + f.Value += string(r) + return true +} |
