diff options
author | Ben Burwell <ben@benburwell.com> | 2019-12-20 13:21:32 -0500 |
---|---|---|
committer | Drew DeVault <sir@cmpwn.com> | 2019-12-21 09:23:20 -0500 |
commit | bcd03c4c4a94e73b2545bf5dfc404082a674c76e (patch) | |
tree | 8366af84dfd9011d20794f2a7556e7d6fc71b7db /lib/ui/ui.go | |
parent | ef4c2f61d8c599ac25b4f465ffa3bea9ca6ce1a3 (diff) | |
download | aerc-bcd03c4c4a94e73b2545bf5dfc404082a674c76e.tar.gz |
Add popovers
A popover is a special UI element which can be layered over the rest of
the UI (i.e. it is painted last) and can fall anywhere on the screen,
not just with the bounds of its parent's viewport/context. With these
special abilities comes the restriction that only one popover may be
visible on screen at once.
Popovers are requested from the UI context passed to Draw calls and
specify the anchor point and the desired dimensions. The popover is then
fit to the available space and placed relative to the anchor point.
Diffstat (limited to 'lib/ui/ui.go')
-rw-r--r-- | lib/ui/ui.go | 26 |
1 files changed, 23 insertions, 3 deletions
diff --git a/lib/ui/ui.go b/lib/ui/ui.go index 01d12dc4..16b176d5 100644 --- a/lib/ui/ui.go +++ b/lib/ui/ui.go @@ -11,6 +11,7 @@ type UI struct { exit atomic.Value // bool ctx *Context screen tcell.Screen + popover *Popover tcEvents chan tcell.Event invalid int32 // access via atomic @@ -34,11 +35,11 @@ func Initialize(content DrawableInteractiveBeeper) (*UI, error) { state := UI{ Content: content, - ctx: NewContext(width, height, screen), screen: screen, tcEvents: make(chan tcell.Event, 10), } + state.ctx = NewContext(width, height, screen, state.onPopover) state.exit.Store(false) go func() { @@ -57,6 +58,10 @@ func Initialize(content DrawableInteractiveBeeper) (*UI, error) { return &state, nil } +func (state *UI) onPopover(p *Popover) { + state.popover = p +} + func (state *UI) ShouldExit() bool { return state.exit.Load().(bool) } @@ -78,17 +83,32 @@ func (state *UI) Tick() bool { case *tcell.EventResize: state.screen.Clear() width, height := event.Size() - state.ctx = NewContext(width, height, state.screen) + state.ctx = NewContext(width, height, state.screen, state.onPopover) state.Content.Invalidate() } - state.Content.Event(event) + // if we have a popover, and it can handle the event, it does so + if state.popover == nil || !state.popover.Event(event) { + // otherwise, we send the event to the main content + state.Content.Event(event) + } more = true default: } wasInvalid := atomic.SwapInt32(&state.invalid, 0) if wasInvalid != 0 { + if state.popover != nil { + // if the previous frame had a popover, rerender the entire display + state.Content.Invalidate() + atomic.StoreInt32(&state.invalid, 0) + } + // reset popover for the next Draw + state.popover = nil state.Content.Draw(state.ctx) + if state.popover != nil { + // if the Draw resulted in a popover, draw it + state.popover.Draw(state.ctx) + } state.screen.Show() more = true } |