summaryrefslogtreecommitdiffstats
path: root/termui/entry.go
blob: 6a43c5b953e17db0a1966a0a24b67375d94df6a7 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
package termui

import (
	"image"
	"strings"
	"unicode/utf8"

	. "github.com/gizak/termui/v3"
	rw "github.com/mattn/go-runewidth"
	"github.com/xxxserxxx/gotop/v4/utils"
)

const (
	ELLIPSIS = "…"
	CURSOR   = " "
)

type Entry struct {
	Block

	Style Style

	Label          string
	Value          string
	ShowWhenEmpty  bool
	UpdateCallback func(string)

	editing bool
}

func (self *Entry) SetEditing(editing bool) {
	self.editing = editing
}

func (self *Entry) update() {
	if self.UpdateCallback != nil {
		self.UpdateCallback(self.Value)
	}
}

// HandleEvent handles input events if the entry is being edited.
// Returns true if the event was handled.
func (self *Entry) HandleEvent(e Event) bool {
	if !self.editing {
		return false
	}
	if utf8.RuneCountInString(e.ID) == 1 {
		self.Value += e.ID
		self.update()
		return true
	}
	switch e.ID {
	case "<C-c>", "<Escape>":
		self.Value = ""
		self.editing = false
		self.update()
	case "<Enter>":
		self.editing = false
	case "<Backspace>":
		if self.Value != "" {
			r := []rune(self.Value)
			self.Value = string(r[:len(r)-1])
			self.update()
		}
	case "<Space>":
		self.Value += " "
		self.update()
	default:
		return false
	}
	return true
}

func (self *Entry) Draw(buf *Buffer) {
	if self.Value == "" && !self.editing && !self.ShowWhenEmpty {
		return
	}

	style := self.Style
	label := self.Label
	if self.editing {
		label += "["
		style = NewStyle(style.Fg, style.Bg, ModifierBold)
	}
	cursorStyle := NewStyle(style.Bg, style.Fg, ModifierClear)

	p := image.Pt(self.Min.X, self.Min.Y)
	buf.SetString(label, style, p)
	p.X += rw.StringWidth(label)

	tail := " "
	if self.editing {
		tail = "] "
	}

	maxLen := self.Max.X - p.X - rw.StringWidth(tail)
	if self.editing {
		maxLen -= 1 // for cursor
	}
	value := utils.TruncateFront(self.Value, maxLen, ELLIPSIS)
	buf.SetString(value, self.Style, p)
	p.X += rw.StringWidth(value)

	if self.editing {
		buf.SetString(CURSOR, cursorStyle, p)
		p.X += rw.StringWidth(CURSOR)
		if remaining := maxLen - rw.StringWidth(value); remaining > 0 {
			buf.SetString(strings.Repeat(" ", remaining), self.TitleStyle, p)
			p.X += remaining
		}
	}
	buf.SetString(tail, style, p)
}