...

Source file src/github.com/gdamore/tcell/v2/views/app.go

Documentation: github.com/gdamore/tcell/v2/views

     1  // Copyright 2018 The Tcell Authors
     2  //
     3  // Licensed under the Apache License, Version 2.0 (the "License");
     4  // you may not use file except in compliance with the License.
     5  // You may obtain a copy of the license at
     6  //
     7  //    http://www.apache.org/licenses/LICENSE-2.0
     8  //
     9  // Unless required by applicable law or agreed to in writing, software
    10  // distributed under the License is distributed on an "AS IS" BASIS,
    11  // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    12  // See the License for the specific language governing permissions and
    13  // limitations under the License.
    14  
    15  package views
    16  
    17  import (
    18  	"sync"
    19  
    20  	"github.com/gdamore/tcell/v2"
    21  )
    22  
    23  // Application represents an event-driven application running on a screen.
    24  type Application struct {
    25  	widget Widget
    26  	screen tcell.Screen
    27  	style  tcell.Style
    28  	err    error
    29  	wg     sync.WaitGroup
    30  	paste  bool
    31  }
    32  
    33  // SetRootWidget sets the primary (root, main) Widget to be displayed.
    34  func (app *Application) SetRootWidget(widget Widget) {
    35  	app.widget = widget
    36  }
    37  
    38  // EnablePaste enables or disables pasting support in the application.
    39  // It must be called before Start or Run or else it will have no effect.
    40  func (app *Application) EnablePaste(on bool) {
    41  	app.paste = on
    42  }
    43  
    44  // initialize initializes the application.  It will normally attempt to
    45  // allocate a default screen if one is not already established.
    46  func (app *Application) initialize() error {
    47  	if app.screen == nil {
    48  		if app.screen, app.err = tcell.NewScreen(); app.err != nil {
    49  			return app.err
    50  		}
    51  		app.screen.SetStyle(app.style)
    52  	}
    53  	return nil
    54  }
    55  
    56  // Quit causes the application to shutdown gracefully.  It does not wait
    57  // for the application to exit, but returns immediately.
    58  func (app *Application) Quit() {
    59  	ev := &eventAppQuit{}
    60  	ev.SetEventNow()
    61  	if scr := app.screen; scr != nil {
    62  		go func() { scr.PostEventWait(ev) }()
    63  	}
    64  }
    65  
    66  // Refresh causes the application forcibly redraw everything.  Use this
    67  // to clear up screen corruption, etc.
    68  func (app *Application) Refresh() {
    69  	ev := &eventAppRefresh{}
    70  	ev.SetEventNow()
    71  	if scr := app.screen; scr != nil {
    72  		go func() { scr.PostEventWait(ev) }()
    73  	}
    74  }
    75  
    76  // Update asks the application to draw any screen updates that have not
    77  // been drawn yet.
    78  func (app *Application) Update() {
    79  	ev := &eventAppUpdate{}
    80  	ev.SetEventNow()
    81  	if scr := app.screen; scr != nil {
    82  		go func() { scr.PostEventWait(ev) }()
    83  	}
    84  }
    85  
    86  // PostFunc posts a function to be executed in the context of the
    87  // application's event loop.  Functions that need to update displayed
    88  // state, etc. can do this to avoid holding locks.
    89  func (app *Application) PostFunc(fn func()) {
    90  	ev := &eventAppFunc{fn: fn}
    91  	ev.SetEventNow()
    92  	if scr := app.screen; scr != nil {
    93  		go func() { scr.PostEventWait(ev) }()
    94  	}
    95  }
    96  
    97  // SetScreen sets the screen to use for the application.  This must be
    98  // done before the application starts to run or is initialized.
    99  func (app *Application) SetScreen(scr tcell.Screen) {
   100  	if app.screen == nil {
   101  		app.screen = scr
   102  		app.err = nil
   103  	}
   104  }
   105  
   106  // SetStyle sets the default style (background) to be used for Widgets
   107  // that have not specified any other style.
   108  func (app *Application) SetStyle(style tcell.Style) {
   109  	app.style = style
   110  	if app.screen != nil {
   111  		app.screen.SetStyle(style)
   112  	}
   113  }
   114  
   115  func (app *Application) run() {
   116  
   117  	screen := app.screen
   118  	widget := app.widget
   119  
   120  	if widget == nil {
   121  		app.wg.Done()
   122  		return
   123  	}
   124  	if screen == nil {
   125  		if e := app.initialize(); e != nil {
   126  			app.wg.Done()
   127  			return
   128  		}
   129  		screen = app.screen
   130  	}
   131  	defer func() {
   132  		screen.Fini()
   133  		app.wg.Done()
   134  	}()
   135  	screen.Init()
   136  	screen.EnableMouse()
   137  	if app.paste {
   138  		screen.EnablePaste()
   139  	}
   140  	screen.Clear()
   141  	widget.SetView(screen)
   142  
   143  loop:
   144  	for {
   145  		if widget = app.widget; widget == nil {
   146  			break
   147  		}
   148  		widget.Draw()
   149  		screen.Show()
   150  
   151  		ev := screen.PollEvent()
   152  		switch nev := ev.(type) {
   153  		case *eventAppQuit:
   154  			break loop
   155  		case *eventAppUpdate:
   156  			screen.Show()
   157  		case *eventAppRefresh:
   158  			screen.Sync()
   159  		case *eventAppFunc:
   160  			nev.fn()
   161  		case *tcell.EventResize:
   162  			screen.Sync()
   163  			widget.Resize()
   164  		default:
   165  			widget.HandleEvent(ev)
   166  		}
   167  	}
   168  }
   169  
   170  // Start starts the application loop, initializing the screen
   171  // and starting the Event loop.  The application will run in a goroutine
   172  // until Quit is called.
   173  func (app *Application) Start() {
   174  	app.wg.Add(1)
   175  	go app.run()
   176  }
   177  
   178  // Wait waits until the application finishes.
   179  func (app *Application) Wait() error {
   180  	app.wg.Wait()
   181  	return app.err
   182  }
   183  
   184  // Run runs the application, waiting until the application loop exits.
   185  // It is equivalent to app.Start() followed by app.Wait()
   186  func (app *Application) Run() error {
   187  	app.Start()
   188  	return app.Wait()
   189  }
   190  
   191  type eventAppUpdate struct {
   192  	tcell.EventTime
   193  }
   194  
   195  type eventAppQuit struct {
   196  	tcell.EventTime
   197  }
   198  
   199  type eventAppRefresh struct {
   200  	tcell.EventTime
   201  }
   202  
   203  type eventAppFunc struct {
   204  	tcell.EventTime
   205  	fn func()
   206  }
   207  

View as plain text