summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorBrian Mattern <rephorm@rephorm.com>2019-06-04 15:08:02 -0700
committerBrian Mattern <rephorm@rephorm.com>2019-06-04 15:09:09 -0700
commit9c0253ef3193d8259ba12cc51b3c2b694f309485 (patch)
tree26c32294dcb49106c385885e9490ce3b189ca63a
parent84a4bbd440f665a42d8192a8da21427c672032ec (diff)
Factor Entry widget out of proc.
-rw-r--r--src/termui/entry.go132
-rw-r--r--src/widgets/proc.go103
2 files changed, 150 insertions, 85 deletions
diff --git a/src/termui/entry.go b/src/termui/entry.go
new file mode 100644
index 0000000..e0930f7
--- /dev/null
+++ b/src/termui/entry.go
@@ -0,0 +1,132 @@
+package termui
+
+import (
+ "image"
+ "strings"
+ "unicode/utf8"
+
+ "github.com/cjbassi/gotop/src/utils"
+ . "github.com/gizak/termui/v3"
+ rw "github.com/mattn/go-runewidth"
+)
+
+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 TruncateFront(s string, w int, prefix string) string {
+ if rw.StringWidth(s) < w {
+ return s
+ }
+ r := []rune(s)
+ pw := rw.StringWidth(prefix)
+ w -= pw
+ width := 0
+ i := len(r) - 1
+ for ; i >= 0 && width <= w; i-- {
+ cw := rw.RuneWidth(r[i])
+ width += cw
+ if width > w {
+ break
+ }
+ }
+ return prefix + string(r[i+1:len(r)])
+}
+
+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)
+}
diff --git a/src/widgets/proc.go b/src/widgets/proc.go
index a598498..106d970 100644
--- a/src/widgets/proc.go
+++ b/src/widgets/proc.go
@@ -2,28 +2,23 @@ package widgets
import (
"fmt"
- "image"
"log"
"os/exec"
"sort"
"strconv"
"strings"
"time"
- "unicode/utf8"
psCPU "github.com/shirou/gopsutil/cpu"
ui "github.com/cjbassi/gotop/src/termui"
"github.com/cjbassi/gotop/src/utils"
tui "github.com/gizak/termui/v3"
- rw "github.com/mattn/go-runewidth"
)
const (
UP_ARROW = "▲"
DOWN_ARROW = "▼"
- ELLIPSIS = "…"
- CURSOR = " "
)
type ProcSortMethod string
@@ -44,11 +39,11 @@ type Proc struct {
type ProcWidget struct {
*ui.Table
+ entry *ui.Entry
cpuCount int
updateInterval time.Duration
sortMethod ProcSortMethod
filter string
- editingFilter bool
groupedProcs []Proc
ungroupedProcs []Proc
showGroupedProcs bool
@@ -66,7 +61,15 @@ func NewProcWidget() *ProcWidget {
sortMethod: ProcSortCpu,
showGroupedProcs: true,
filter: "",
- editingFilter: false,
+ }
+ self.entry = &ui.Entry{
+ Style: self.TitleStyle,
+ Label: " Filter: ",
+ Value: "foobar",
+ UpdateCallback: func(val string) {
+ self.filter = val
+ self.update()
+ },
}
self.Title = " Processes "
self.ShowCursor = true
@@ -98,91 +101,21 @@ func NewProcWidget() *ProcWidget {
}
func (self *ProcWidget) SetEditingFilter(editing bool) {
- self.editingFilter = editing
- if !editing {
- self.update()
- }
+ self.entry.SetEditing(editing)
}
-// handleEditFilterEvents handles events while editing the proc filter.
-// Returns true if the event was handled.
func (self *ProcWidget) HandleEvent(e tui.Event) bool {
- if !self.editingFilter {
- return false
- }
- if utf8.RuneCountInString(e.ID) == 1 {
- self.filter += e.ID
- self.update()
- return true
- }
- switch e.ID {
- case "<C-c>", "<Escape>":
- self.filter = ""
- self.update()
- self.SetEditingFilter(false)
- case "<Enter>":
- self.SetEditingFilter(false)
- case "<Backspace>":
- if self.filter != "" {
- r := []rune(self.filter)
- self.filter = string(r[:len(r)-1])
- self.update()
- }
- case "<Space>":
- self.filter += " "
- self.update()
- default:
- return false
- }
- return true
+ return self.entry.HandleEvent(e)
}
-func (self *ProcWidget) Draw(buf *tui.Buffer) {
- self.Table.Draw(buf)
- if self.filter != "" || self.editingFilter {
- self.drawFilter(buf)
- }
+func (self *ProcWidget) SetRect(x1, y1, x2, y2 int) {
+ self.Table.SetRect(x1, y1, x2, y2)
+ self.entry.SetRect(x1+2, y2-1, x2-2, y2)
}
-func (self *ProcWidget) drawFilter(buf *tui.Buffer) {
- padding := 2
-
- style := self.TitleStyle
- label := " Filter: "
- if self.editingFilter {
- label += "["
- style = tui.NewStyle(style.Fg, style.Bg, tui.ModifierBold)
- }
- cursorStyle := tui.NewStyle(style.Bg, style.Fg, tui.ModifierClear)
-
- p := image.Pt(self.Min.X+padding, self.Max.Y-1)
- buf.SetString(label, style, p)
- p.X += rw.StringWidth(label)
-
- tail := " "
- if self.editingFilter {
- tail = "] "
- }
-
- maxLen := self.Max.X - p.X - padding - rw.StringWidth(tail)
- if self.editingFilter {
- maxLen -= 1 // for cursor
- }
-
- filter := utils.TruncateFront(self.filter, maxLen, ELLIPSIS)
- buf.SetString(filter, self.TitleStyle, p)
- p.X += rw.StringWidth(filter)
-
- if self.editingFilter {
- buf.SetString(CURSOR, cursorStyle, p)
- p.X += rw.StringWidth(CURSOR)
-
- if remaining := maxLen - rw.StringWidth(filter); remaining > 0 {
- buf.SetString(strings.Repeat(" ", remaining), self.TitleStyle, p)
- p.X += remaining
- }
- }
- buf.SetString(tail, style, p)
+func (self *ProcWidget) Draw(buf *tui.Buffer) {
+ self.Table.Draw(buf)
+ self.entry.Draw(buf)
}
func (self *ProcWidget) filterProcs(procs []Proc) []Proc {