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, } }