summaryrefslogtreecommitdiff
path: root/gui/ui/field.go
diff options
context:
space:
mode:
Diffstat (limited to 'gui/ui/field.go')
-rw-r--r--gui/ui/field.go88
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
+}