257 lines
6.4 KiB
Go
257 lines
6.4 KiB
Go
|
package ui
|
||
|
|
||
|
import (
|
||
|
"fmt"
|
||
|
"strings"
|
||
|
"time"
|
||
|
|
||
|
"git.bullercodeworks.com/brian/gime/util"
|
||
|
"git.bullercodeworks.com/brian/go-timertxt"
|
||
|
"git.bullercodeworks.com/brian/wandle"
|
||
|
"git.bullercodeworks.com/brian/widdles"
|
||
|
"github.com/nsf/termbox-go"
|
||
|
)
|
||
|
|
||
|
type listTimersScreen struct {
|
||
|
ui *Ui
|
||
|
|
||
|
initialized bool
|
||
|
menu *widdles.TopMenu
|
||
|
scrollbar *widdles.Scrollbar
|
||
|
|
||
|
cursor int
|
||
|
|
||
|
fullList *timertxt.TimerList
|
||
|
timerList *timertxt.TimerList
|
||
|
doneList *timertxt.TimerList
|
||
|
|
||
|
timerFilterList *timertxt.TimerList
|
||
|
doneFilterList *timertxt.TimerList
|
||
|
|
||
|
selected map[int]bool
|
||
|
|
||
|
inputDialog *widdles.InputDialog
|
||
|
filter string
|
||
|
|
||
|
partManager *PartManager
|
||
|
|
||
|
msg string
|
||
|
err error
|
||
|
}
|
||
|
|
||
|
type ListTimersMsg ScreenMsg
|
||
|
|
||
|
func NewListTimersScreen(u *Ui) *listTimersScreen {
|
||
|
w, h := termbox.Size()
|
||
|
s := listTimersScreen{
|
||
|
ui: u,
|
||
|
menu: widdles.NewTopMenu(0, 0, 0),
|
||
|
scrollbar: widdles.NewScrollbar(w-2, 2, 1, h-2),
|
||
|
selected: make(map[int]bool),
|
||
|
inputDialog: widdles.NewInputDialog("", ""),
|
||
|
partManager: NewPartManager("", 0, 0, 0, 0),
|
||
|
}
|
||
|
return &s
|
||
|
}
|
||
|
|
||
|
func (s *listTimersScreen) Init() wandle.Cmd {
|
||
|
if s.initialized {
|
||
|
return nil
|
||
|
}
|
||
|
s.initialized = true
|
||
|
// Set up the top menu
|
||
|
fileMenu := s.menu.NewSubMenu("File")
|
||
|
settingsOption := widdles.NewMenuItem("Settings")
|
||
|
settingsOption.SetCommand(s.ui.GotoScreen(SettingsId))
|
||
|
fileMenu.AddOption(settingsOption)
|
||
|
quitOption := widdles.NewMenuItem("Quit")
|
||
|
quitOption.Hotkey = termbox.KeyCtrlC
|
||
|
quitOption.SetCommand(func() wandle.Msg { return wandle.Quit() })
|
||
|
fileMenu.AddOption(quitOption)
|
||
|
s.menu.Measure()
|
||
|
// Timer Lists
|
||
|
s.timerList, s.doneList = s.ui.program.TimerList, s.ui.program.DoneList
|
||
|
s.fullList = timertxt.NewTimerList()
|
||
|
s.fullList.AddTimers(s.timerList.GetTimerSlice())
|
||
|
s.fullList.AddTimers(s.doneList.GetTimerSlice())
|
||
|
s.timerFilterList, s.doneFilterList = s.timerList, s.doneList
|
||
|
s.timerFilterList.Sort(timertxt.SORT_START_DATE_DESC)
|
||
|
s.doneFilterList.Sort(timertxt.SORT_START_DATE_DESC)
|
||
|
w, h := termbox.Size()
|
||
|
s.partManager.SetX(w / 4)
|
||
|
s.partManager.SetY(h / 4)
|
||
|
s.partManager.SetWidth(w / 2)
|
||
|
s.partManager.SetHeight(h / 2)
|
||
|
|
||
|
return nil
|
||
|
}
|
||
|
|
||
|
func (s *listTimersScreen) Update(msg wandle.Msg) wandle.Cmd {
|
||
|
switch msg := msg.(type) {
|
||
|
case ScreenMsg:
|
||
|
case termbox.Event:
|
||
|
return s.handleTermboxEvent(msg)
|
||
|
}
|
||
|
return nil
|
||
|
}
|
||
|
|
||
|
func (s *listTimersScreen) View(style wandle.Style) {
|
||
|
_, h := termbox.Size()
|
||
|
y := 2
|
||
|
wandle.Print(1, y, style.Bold(true), "Active Timers")
|
||
|
y++
|
||
|
for idx, tmr := range s.timerFilterList.GetTimerSlice() {
|
||
|
if y > h-2 {
|
||
|
break
|
||
|
}
|
||
|
st := style
|
||
|
if s.cursor == idx {
|
||
|
st = st.Invert()
|
||
|
}
|
||
|
if s.selected[idx] {
|
||
|
wandle.Print(1, y, st, "[✔] ")
|
||
|
} else {
|
||
|
wandle.Print(1, y, st, "[ ] ")
|
||
|
}
|
||
|
s.ViewTimer(5, y, st, tmr)
|
||
|
y++
|
||
|
}
|
||
|
y++
|
||
|
wandle.Print(1, y, style.Bold(true), "Done Timers")
|
||
|
y++
|
||
|
for idx, tmr := range s.doneFilterList.GetTimerSlice() {
|
||
|
if y > h-3 {
|
||
|
break
|
||
|
}
|
||
|
st := style
|
||
|
if s.cursor == s.timerFilterList.Size()+idx {
|
||
|
st = st.Invert()
|
||
|
}
|
||
|
if s.selected[s.timerFilterList.Size()+idx] {
|
||
|
wandle.Print(1, y, st, "[✔] ")
|
||
|
} else {
|
||
|
wandle.Print(1, y, st, "[ ] ")
|
||
|
}
|
||
|
s.ViewTimer(5, y, st, tmr)
|
||
|
y++
|
||
|
}
|
||
|
wandle.Print(1, h-1, style, "[p]roject(+), [c]ontext(@), [t]ags(:)")
|
||
|
if len(s.selected) > 0 {
|
||
|
wandle.Print(39, h-1, style, fmt.Sprintf("(%d selected)", len(s.selected)))
|
||
|
}
|
||
|
|
||
|
s.scrollbar.View(style)
|
||
|
if s.menu.IsActive() {
|
||
|
s.menu.View(style)
|
||
|
}
|
||
|
s.partManager.View(style)
|
||
|
}
|
||
|
|
||
|
func (s *listTimersScreen) ViewTimer(x, y int, style wandle.Style, tmr *timertxt.Timer) {
|
||
|
var tags []string
|
||
|
for _, k := range util.SortedTagKeyList(tmr.AdditionalTags) {
|
||
|
tags = append(tags, fmt.Sprintf("%s:%s", k, tmr.AdditionalTags[k]))
|
||
|
}
|
||
|
|
||
|
wandle.Print(x, y, style, fmt.Sprintf("%s %s %s %s %s", tmr.StartDate.Format(time.Stamp), tmr.Duration(), tmr.Contexts, tmr.Projects, strings.Join(tags, "; ")))
|
||
|
}
|
||
|
|
||
|
func (s *listTimersScreen) handleTermboxEvent(msg termbox.Event) wandle.Cmd {
|
||
|
if pmRes := s.partManager.Update(msg); pmRes != nil {
|
||
|
return pmRes
|
||
|
}
|
||
|
if (msg.Type == termbox.EventKey && msg.Key == termbox.KeyEsc) || s.menu.IsActive() {
|
||
|
return s.menu.Update(msg)
|
||
|
}
|
||
|
switch msg.Type {
|
||
|
case termbox.EventKey:
|
||
|
top := s.timerFilterList.Size() + s.doneFilterList.Size() - 2
|
||
|
selected := len(s.selected)
|
||
|
var selTimer *timertxt.Timer
|
||
|
if selected == 0 {
|
||
|
if s.cursor < s.timerFilterList.Size() {
|
||
|
selTimer, s.err = s.timerFilterList.GetTimer(s.cursor)
|
||
|
} else {
|
||
|
selTimer, s.err = s.doneFilterList.GetTimer(s.cursor)
|
||
|
}
|
||
|
}
|
||
|
if msg.Key == termbox.KeyEnter {
|
||
|
// Edit the entry
|
||
|
/*
|
||
|
if s.cursor >= 0 && s.cursor < s.timerFilterList.Size()+s.doneFilterList.Size() {
|
||
|
} else {
|
||
|
}
|
||
|
*/
|
||
|
} else if msg.Key == termbox.KeySpace {
|
||
|
// (un)Select the entry
|
||
|
if v := s.selected[s.cursor]; v {
|
||
|
delete(s.selected, s.cursor)
|
||
|
} else {
|
||
|
s.selected[s.cursor] = true
|
||
|
}
|
||
|
} else if msg.Key == termbox.KeyArrowUp || msg.Ch == 'k' {
|
||
|
if s.cursor > 0 {
|
||
|
s.cursor--
|
||
|
} else {
|
||
|
s.cursor = 0
|
||
|
}
|
||
|
return nil
|
||
|
} else if msg.Key == termbox.KeyArrowDown || msg.Ch == 'j' {
|
||
|
if s.cursor < top {
|
||
|
s.cursor++
|
||
|
} else {
|
||
|
s.cursor = top
|
||
|
}
|
||
|
return nil
|
||
|
} else if msg.Ch == 'G' {
|
||
|
s.cursor = top
|
||
|
} else if msg.Ch == 't' {
|
||
|
// Edit tag(s)
|
||
|
tags := s.fullList.GetTagKeys()
|
||
|
s.partManager.SetOptions(tags)
|
||
|
if selected > 0 {
|
||
|
// TODO
|
||
|
//s.partManager.SetLabel(fmt.Sprintf("Manage Tags on %d Timers", selected))
|
||
|
} else {
|
||
|
s.partManager.SetLabel("Manage Tags for Timer")
|
||
|
s.partManager.SetType("Tag")
|
||
|
}
|
||
|
s.partManager.Show()
|
||
|
} else if msg.Ch == 'p' {
|
||
|
// Edit project(s)
|
||
|
projs := s.fullList.GetProjects()
|
||
|
s.partManager.SetOptions(projs)
|
||
|
if selected > 0 {
|
||
|
// TODO
|
||
|
//s.partManager.SetLabel(fmt.Sprintf("Manage Projects on %d Timers", selected))
|
||
|
} else {
|
||
|
s.partManager.SetLabel("Manage Projects for Timer")
|
||
|
s.partManager.SetType("Project")
|
||
|
s.partManager.SetValue(strings.Join(selTimer.Projects, " "))
|
||
|
}
|
||
|
s.partManager.Show()
|
||
|
} else if msg.Ch == 'c' {
|
||
|
// Edit context(s)
|
||
|
ctxts := s.fullList.GetContexts()
|
||
|
s.partManager.SetOptions(ctxts)
|
||
|
if selected > 0 {
|
||
|
// TODO
|
||
|
//s.partManager.SetLabel(fmt.Sprintf("Manage Contexts on %d Timers", selected))
|
||
|
} else {
|
||
|
s.partManager.SetLabel("Manage Contexts for Timer")
|
||
|
s.partManager.SetType("Context")
|
||
|
s.partManager.SetValue(strings.Join(selTimer.Contexts, " "))
|
||
|
}
|
||
|
s.partManager.Show()
|
||
|
}
|
||
|
}
|
||
|
return nil
|
||
|
}
|
||
|
|
||
|
func (s *listTimersScreen) gotoSettingsScreen() wandle.Msg {
|
||
|
return ScreenMsg{
|
||
|
source: ListTimersId,
|
||
|
command: CmdGotoSettings,
|
||
|
}
|
||
|
}
|