From 64fa922ec013079f8f0c90fc9e93c56db3611d30 Mon Sep 17 00:00:00 2001 From: Tulir Asokan Date: Sun, 22 Apr 2018 21:25:06 +0300 Subject: Switch to dep --- vendor/maunium.net/go/tview/application.go | 408 +++++++++++++++++++++++++++++ 1 file changed, 408 insertions(+) create mode 100644 vendor/maunium.net/go/tview/application.go (limited to 'vendor/maunium.net/go/tview/application.go') diff --git a/vendor/maunium.net/go/tview/application.go b/vendor/maunium.net/go/tview/application.go new file mode 100644 index 0000000..f3d6328 --- /dev/null +++ b/vendor/maunium.net/go/tview/application.go @@ -0,0 +1,408 @@ +package tview + +import ( + "fmt" + "os" + "sync" + + "maunium.net/go/tcell" +) + +// Application represents the top node of an application. +// +// It is not strictly required to use this class as none of the other classes +// depend on it. However, it provides useful tools to set up an application and +// plays nicely with all widgets. +type Application struct { + sync.RWMutex + + // The application's screen. + screen tcell.Screen + + // The primitive which currently has the keyboard focus. + focus Primitive + + // The root primitive to be seen on the screen. + root Primitive + + // Whether or not the application resizes the root primitive. + rootFullscreen bool + + // An optional capture function which receives a key event and returns the + // event to be forwarded to the default input handler (nil if nothing should + // be forwarded). + inputCapture func(event *tcell.EventKey) *tcell.EventKey + + // An optional capture function which receives a mouse event and returns the + // event to be forwarded to the default input handler (nil if nothing should + // be forwarded). + mouseCapture func(event *tcell.EventMouse) *tcell.EventMouse + + // An optional callback function which is invoked just before the root + // primitive is drawn. + beforeDraw func(screen tcell.Screen) bool + + // An optional callback function which is invoked after the root primitive + // was drawn. + afterDraw func(screen tcell.Screen) + + // If this value is true, the application has entered suspended mode. + suspended bool +} + +// NewApplication creates and returns a new application. +func NewApplication() *Application { + return &Application{} +} + +// SetInputCapture sets a function which captures all key events before they are +// forwarded to the key event handler of the primitive which currently has +// focus. This function can then choose to forward that key event (or a +// different one) by returning it or stop the key event processing by returning +// nil. +// +// Note that this also affects the default event handling of the application +// itself: Such a handler can intercept the Ctrl-C event which closes the +// applicatoon. +func (a *Application) SetInputCapture(capture func(event *tcell.EventKey) *tcell.EventKey) *Application { + a.inputCapture = capture + return a +} + +// GetInputCapture returns the function installed with SetInputCapture() or nil +// if no such function has been installed. +func (a *Application) GetInputCapture() func(event *tcell.EventKey) *tcell.EventKey { + return a.inputCapture +} + +// SetMouseCapture sets a function which captures all mouse events before they are +// forwarded to the mouse event handler of the primitive which currently has +// focus. This function can then choose to forward that mouse event (or a +// different one) by returning it or stop the key event processing by returning +// nil. +func (a *Application) SetMouseCapture(capture func(event *tcell.EventMouse) *tcell.EventMouse) *Application { + a.mouseCapture = capture + return a +} + +// GetMouseCapture returns the function installed with SetMouseCapture() or nil +// if no such function has been installed. +func (a *Application) GetMouseCapture() func(event *tcell.EventMouse) *tcell.EventMouse { + return a.mouseCapture +} + +func (a *Application) GetScreen() tcell.Screen { + return a.screen +} + +// Run starts the application and thus the event loop. This function returns +// when Stop() was called. +func (a *Application) Run() error { + var err error + a.Lock() + + // Make a screen. + a.screen, err = tcell.NewScreen() + if err != nil { + a.Unlock() + return err + } + if err = a.screen.Init(); err != nil { + a.Unlock() + return err + } + a.screen.EnableMouse() + + // Draw the screen for the first time. + a.Unlock() + a.Draw() + + // Start event loop. + for { + a.Lock() + screen := a.screen + if a.suspended { + a.suspended = false // Clear previous suspended flag. + } + a.Unlock() + if screen == nil { + break + } + + // Wait for next event. + event := a.screen.PollEvent() + if event == nil { + a.Lock() + if a.suspended { + // This screen was renewed due to suspended mode. + a.suspended = false + a.Unlock() + continue // Resume. + } + a.Unlock() + + // The screen was finalized. Exit the loop. + break + } + + switch event := event.(type) { + case *tcell.EventKey: + a.RLock() + p := a.focus + a.RUnlock() + + // Intercept keys. + if a.inputCapture != nil { + event = a.inputCapture(event) + if event == nil { + break // Don't forward event. + } + } + + // Pass other key events to the currently focused primitive. + if p != nil { + if handler := p.InputHandler(); handler != nil { + handler(event, func(p Primitive) { + a.SetFocus(p) + }) + a.Draw() + } + } + case *tcell.EventMouse: + a.RLock() + p := a.focus + a.RUnlock() + + // Intercept keys. + if a.mouseCapture != nil { + event = a.mouseCapture(event) + if event == nil { + break // Don't forward event. + } + } + + // Pass other key events to the currently focused primitive. + if p != nil { + if handler := p.MouseHandler(); handler != nil { + handler(event, func(p Primitive) { + a.SetFocus(p) + }) + //a.Draw() + } + } + case *tcell.EventResize: + a.Lock() + screen := a.screen + a.Unlock() + screen.Clear() + a.Draw() + } + } + + return nil +} + +// Stop stops the application, causing Run() to return. +func (a *Application) Stop() { + a.RLock() + defer a.RUnlock() + if a.screen == nil { + return + } + a.screen.Fini() + a.screen = nil +} + +// Suspend temporarily suspends the application by exiting terminal UI mode and +// invoking the provided function "f". When "f" returns, terminal UI mode is +// entered again and the application resumes. +// +// A return value of true indicates that the application was suspended and "f" +// was called. If false is returned, the application was already suspended, +// terminal UI mode was not exited, and "f" was not called. +func (a *Application) Suspend(f func()) bool { + a.Lock() + + if a.suspended || a.screen == nil { + // Application is already suspended. + a.Unlock() + return false + } + + // Enter suspended mode. + a.suspended = true + a.Unlock() + a.Stop() + + // Deal with panics during suspended mode. Exit the program. + defer func() { + if p := recover(); p != nil { + fmt.Println(p) + os.Exit(1) + } + }() + + // Wait for "f" to return. + f() + + // Make a new screen and redraw. + a.Lock() + var err error + a.screen, err = tcell.NewScreen() + if err != nil { + a.Unlock() + panic(err) + } + if err = a.screen.Init(); err != nil { + a.Unlock() + panic(err) + } + a.Unlock() + a.Draw() + + // Continue application loop. + return true +} + +// Draw refreshes the screen. It calls the Draw() function of the application's +// root primitive and then syncs the screen buffer. +func (a *Application) Draw() *Application { + a.RLock() + screen := a.screen + root := a.root + fullscreen := a.rootFullscreen + before := a.beforeDraw + after := a.afterDraw + a.RUnlock() + + // Maybe we're not ready yet or not anymore. + if screen == nil || root == nil { + return a + } + + // Resize if requested. + if fullscreen && root != nil { + width, height := screen.Size() + root.SetRect(0, 0, width, height) + } + + // Call before handler if there is one. + if before != nil { + if before(screen) { + screen.Show() + return a + } + } + + // Draw all primitives. + root.Draw(screen) + + // Call after handler if there is one. + if after != nil { + after(screen) + } + + // Sync screen. + screen.Show() + + return a +} + +// SetBeforeDrawFunc installs a callback function which is invoked just before +// the root primitive is drawn during screen updates. If the function returns +// true, drawing will not continue, i.e. the root primitive will not be drawn +// (and an after-draw-handler will not be called). +// +// Note that the screen is not cleared by the application. To clear the screen, +// you may call screen.Clear(). +// +// Provide nil to uninstall the callback function. +func (a *Application) SetBeforeDrawFunc(handler func(screen tcell.Screen) bool) *Application { + a.beforeDraw = handler + return a +} + +// GetBeforeDrawFunc returns the callback function installed with +// SetBeforeDrawFunc() or nil if none has been installed. +func (a *Application) GetBeforeDrawFunc() func(screen tcell.Screen) bool { + return a.beforeDraw +} + +// SetAfterDrawFunc installs a callback function which is invoked after the root +// primitive was drawn during screen updates. +// +// Provide nil to uninstall the callback function. +func (a *Application) SetAfterDrawFunc(handler func(screen tcell.Screen)) *Application { + a.afterDraw = handler + return a +} + +// GetAfterDrawFunc returns the callback function installed with +// SetAfterDrawFunc() or nil if none has been installed. +func (a *Application) GetAfterDrawFunc() func(screen tcell.Screen) { + return a.afterDraw +} + +// SetRoot sets the root primitive for this application. If "fullscreen" is set +// to true, the root primitive's position will be changed to fill the screen. +// +// This function must be called at least once or nothing will be displayed when +// the application starts. +// +// It also calls SetFocus() on the primitive. +func (a *Application) SetRoot(root Primitive, fullscreen bool) *Application { + a.Lock() + a.root = root + a.rootFullscreen = fullscreen + if a.screen != nil { + a.screen.Clear() + } + a.Unlock() + + a.SetFocus(root) + + return a +} + +// ResizeToFullScreen resizes the given primitive such that it fills the entire +// screen. +func (a *Application) ResizeToFullScreen(p Primitive) *Application { + a.RLock() + width, height := a.screen.Size() + a.RUnlock() + p.SetRect(0, 0, width, height) + return a +} + +// SetFocus sets the focus on a new primitive. All key events will be redirected +// to that primitive. Callers must ensure that the primitive will handle key +// events. +// +// Blur() will be called on the previously focused primitive. Focus() will be +// called on the new primitive. +func (a *Application) SetFocus(p Primitive) *Application { + a.Lock() + if a.focus != nil { + a.focus.Blur() + } + a.focus = p + if a.screen != nil { + a.screen.HideCursor() + } + a.Unlock() + if p != nil { + p.Focus(func(p Primitive) { + a.SetFocus(p) + }) + } + + return a +} + +// GetFocus returns the primitive which has the current focus. If none has it, +// nil is returned. +func (a *Application) GetFocus() Primitive { + a.RLock() + defer a.RUnlock() + return a.focus +} -- cgit v1.2.3