From c91f70ac38c658dd0cdc98350870c487191649e4 Mon Sep 17 00:00:00 2001 From: Brian Buller Date: Fri, 12 Jul 2019 11:27:52 -0500 Subject: [PATCH] Windows loop --- screen.go | 1 + screen_windows.go | 187 ++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 188 insertions(+) create mode 100644 screen_windows.go diff --git a/screen.go b/screen.go index 74b28a9..34448e0 100644 --- a/screen.go +++ b/screen.go @@ -1,3 +1,4 @@ +// +build !windows package termboxScreen import ( diff --git a/screen_windows.go b/screen_windows.go new file mode 100644 index 0000000..350390e --- /dev/null +++ b/screen_windows.go @@ -0,0 +1,187 @@ +// +build windows +package termboxScreen + +import ( + "errors" + "fmt" + "time" + + termbox "github.com/nsf/termbox-go" +) + +const ( + NoRefresh = 0 +) + +type Screen interface { + Id() int + Initialize(Bundle) error + HandleKeyEvent(termbox.Event) int + HandleNoneEvent(termbox.Event) int + DrawScreen() + ResizeScreen() +} + +type Manager struct { + defaultFg termbox.Attribute + defaultBg termbox.Attribute + + screens map[int]Screen + displayScreenId int + events chan termbox.Event + + running bool + refreshRate time.Duration +} + +func NewManager() *Manager { + m := Manager{ + defaultFg: termbox.ColorWhite, + defaultBg: termbox.ColorBlack, + events: make(chan termbox.Event), + screens: make(map[int]Screen), + refreshRate: NoRefresh, + } + if err := termbox.Init(); err != nil { + fmt.Println("Error initializing termbox") + return nil + } + termbox.SetOutputMode(termbox.Output256) + return &m +} + +func (m *Manager) SetDefaultFg(c termbox.Attribute) { m.defaultFg = c } +func (m *Manager) SetDefaultBg(c termbox.Attribute) { m.defaultBg = c } + +// AddScreen adds a screen to the screens map, they're indexed by the value +// returned from the screen's Id() function +func (m *Manager) AddScreen(s Screen) { + m.screens[s.Id()] = s + // If this is the only screen we've added, set it to active + if len(m.screens) == 1 { + m.SetDisplayScreen(s.Id()) + } +} + +// AddAndInitializeScreen adds a screen just like AddScreen, but then +// calls it's 'Initialize' function with a blank bundle +func (m *Manager) AddAndInitializeScreen(s Screen) error { + m.AddScreen(s) + return m.InitializeScreen(s.Id(), Bundle{}) +} + +func (m *Manager) GetScreens() map[int]Screen { + return m.screens +} + +func (m *Manager) SetDisplayScreen(id int) error { + if id == m.displayScreenId { + return nil + } + var ok bool + if _, ok = m.screens[id]; !ok { + return errors.New("Invalid Screen Id") + } + m.displayScreenId = id + return nil +} + +func (m *Manager) InitializeScreen(id int, b Bundle) error { + var ok bool + if _, ok = m.screens[id]; !ok { + return errors.New("Invalid screen id") + } + return m.screens[id].Initialize(b) +} + +func (m *Manager) Loop() error { + if len(m.screens) == 0 { + return errors.New("Loop cannot run without screens") + } + m.running = true + go m.pollUserEvents() + // We always start display the first screen added + m.layoutAndDrawScreen() + for { + event := <-m.events + if event.Type == termbox.EventKey { + if event.Key == termbox.KeyCtrlC { + break + } else { + newScreenIndex := m.handleKeyEvent(event) + if err := m.SetDisplayScreen(newScreenIndex); err != nil { + break + } + m.layoutAndDrawScreen() + } + } else if event.Type == termbox.EventNone { + // Type = EventNone is how we can trigger automatic events + newScreenIndex := m.handleNoneEvent(event) + if err := m.SetDisplayScreen(newScreenIndex); err != nil { + break + } + m.layoutAndDrawScreen() + } else if event.Type == termbox.EventResize { + m.resizeScreen() + m.layoutAndDrawScreen() + } + } + m.running = false + close(m.events) + m.Close() + return nil +} + +func (m *Manager) SendNoneEvent() { + m.SendEvent(termbox.Event{Type: termbox.EventNone}) +} + +func (m *Manager) SendEvent(t termbox.Event) { + m.events <- t +} + +func (m *Manager) Close() { + termbox.Close() +} + +func (m *Manager) pollUserEvents() { + for m.running { + m.SendEvent(termbox.PollEvent()) + } +} + +func (m *Manager) SetRefreshRate(t time.Duration) { + m.refreshRate = t + go m.pollRefreshEvents() +} + +func (m *Manager) pollRefreshEvents() { + if m.refreshRate > time.Microsecond { + for m.running { + time.Sleep(m.refreshRate) + m.SendNoneEvent() + } + } +} + +func (m *Manager) handleKeyEvent(event termbox.Event) int { + return m.screens[m.displayScreenId].HandleKeyEvent(event) +} + +func (m *Manager) handleNoneEvent(event termbox.Event) int { + return m.screens[m.displayScreenId].HandleNoneEvent(event) +} + +func (m *Manager) resizeScreen() { + m.screens[m.displayScreenId].ResizeScreen() +} + +func (m *Manager) drawBackground() { + termbox.Clear(0, m.defaultBg) +} + +func (m *Manager) layoutAndDrawScreen() { + m.drawBackground() + m.screens[m.displayScreenId].DrawScreen() + termbox.Flush() +}