...

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

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

     1  // Copyright 2015 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  // Widget is the base object that all onscreen elements implement.
    24  type Widget interface {
    25  	// Draw is called to inform the widget to draw itself.  A containing
    26  	// Widget will generally call this during the application draw loop.
    27  	Draw()
    28  
    29  	// Resize is called in response to a resize of the View.  Unlike with
    30  	// other events, Resize performed by parents first, and they must
    31  	// then call their children.  This is because the children need to
    32  	// see the updated sizes from the parents before they are called.
    33  	// In general this is done *after* the views have updated.
    34  	Resize()
    35  
    36  	// HandleEvent is called to ask the widget to handle any events.
    37  	// If the widget has consumed the event, it should return true.
    38  	// Generally, events are handled by the lower layers first, that
    39  	// is for example, a button may have a chance to handle an event
    40  	// before the enclosing window or panel.
    41  	//
    42  	// Its expected that Resize events are consumed by the outermost
    43  	// Widget, and the turned into a Resize() call.
    44  	HandleEvent(ev tcell.Event) bool
    45  
    46  	// SetView is used by callers to set the visual context of the
    47  	// Widget.  The Widget should use the View as a context for
    48  	// drawing.
    49  	SetView(view View)
    50  
    51  	// Size returns the size of the widget (content size) as width, height
    52  	// in columns.  Layout managers should attempt to ensure that at least
    53  	// this much space is made available to the View for this Widget.  Extra
    54  	// space may be allocated on as an needed basis.
    55  	Size() (int, int)
    56  
    57  	// Watch is used to register an interest in this widget's events.
    58  	// The handler will receive EventWidget events for this widget.
    59  	// The order of event delivery when there are multiple watchers is
    60  	// not specified, and may change from one event to the next.
    61  	Watch(handler tcell.EventHandler)
    62  
    63  	// Unwatch is used to urnegister an interest in this widget's events.
    64  	Unwatch(handler tcell.EventHandler)
    65  }
    66  
    67  // EventWidget is an event delivered by a specific widget.
    68  type EventWidget interface {
    69  	Widget() Widget
    70  	tcell.Event
    71  }
    72  
    73  type widgetEvent struct {
    74  	widget Widget
    75  	tcell.EventTime
    76  }
    77  
    78  func (wev *widgetEvent) Widget() Widget {
    79  	return wev.widget
    80  }
    81  
    82  func (wev *widgetEvent) SetWidget(widget Widget) {
    83  	wev.widget = widget
    84  }
    85  
    86  // WidgetWatchers provides a common implementation for base Widget Watch and
    87  // Unwatch interfaces, suitable for embedding in more concrete widget
    88  // implementations. This implementation is thread-safe, meaning an embedder can
    89  // expect safety when calling WidgetWatcher methods from separate goroutines.
    90  // In general, the views package does not support thread safety.
    91  type WidgetWatchers struct {
    92  	sync.Mutex
    93  	watchers map[tcell.EventHandler]struct{}
    94  }
    95  
    96  // Watch monitors this WidgetWatcher, causing the handler to be fired
    97  // with EventWidget as they are occur on the watched Widget.
    98  func (ww *WidgetWatchers) Watch(handler tcell.EventHandler) {
    99  	ww.Lock()
   100  	defer ww.Unlock()
   101  	if ww.watchers == nil {
   102  		ww.watchers = make(map[tcell.EventHandler]struct{})
   103  	}
   104  	ww.watchers[handler] = struct{}{}
   105  }
   106  
   107  // Unwatch stops monitoring this WidgetWatcher. The handler will no longer
   108  // be fired for Widget events.
   109  func (ww *WidgetWatchers) Unwatch(handler tcell.EventHandler) {
   110  	ww.Lock()
   111  	defer ww.Unlock()
   112  	if ww.watchers != nil {
   113  		delete(ww.watchers, handler)
   114  	}
   115  }
   116  
   117  // PostEvent delivers the EventWidget to all registered watchers.  It is
   118  // to be called by the Widget implementation.
   119  func (ww *WidgetWatchers) PostEvent(wev EventWidget) {
   120  	ww.Lock()
   121  	watcherCopy := make(map[tcell.EventHandler]struct{}, len(ww.watchers))
   122  	for k := range ww.watchers {
   123  		watcherCopy[k] = struct{}{}
   124  	}
   125  	ww.Unlock()
   126  	for watcher := range watcherCopy {
   127  		// Deliver events to all listeners, ignoring return value.
   128  		watcher.HandleEvent(wev)
   129  	}
   130  }
   131  
   132  // PostEventWidgetContent is called by the Widget when its content is
   133  // changed, delivering EventWidgetContent to all watchers.
   134  func (ww *WidgetWatchers) PostEventWidgetContent(w Widget) {
   135  	ev := &EventWidgetContent{}
   136  	ev.SetWidget(w)
   137  	ev.SetEventNow()
   138  	ww.PostEvent(ev)
   139  }
   140  
   141  // PostEventWidgetResize is called by the Widget when the underlying View
   142  // has resized, delivering EventWidgetResize to all watchers.
   143  func (ww *WidgetWatchers) PostEventWidgetResize(w Widget) {
   144  	ev := &EventWidgetResize{}
   145  	ev.SetWidget(w)
   146  	ev.SetEventNow()
   147  	ww.PostEvent(ev)
   148  }
   149  
   150  // PostEventWidgetMove is called by the Widget when it is moved to a new
   151  // location, delivering EventWidgetMove to all watchers.
   152  func (ww *WidgetWatchers) PostEventWidgetMove(w Widget) {
   153  	ev := &EventWidgetMove{}
   154  	ev.SetWidget(w)
   155  	ev.SetEventNow()
   156  	ww.PostEvent(ev)
   157  }
   158  
   159  // XXX: WidgetExposed, Hidden?
   160  // XXX: WidgetExposed, Hidden?
   161  
   162  // EventWidgetContent is fired whenever a widget's content changes.
   163  type EventWidgetContent struct {
   164  	widgetEvent
   165  }
   166  
   167  // EventWidgetResize is fired whenever a widget is resized.
   168  type EventWidgetResize struct {
   169  	widgetEvent
   170  }
   171  
   172  // EventWidgetMove is fired whenver a widget changes location.
   173  type EventWidgetMove struct {
   174  	widgetEvent
   175  }
   176  

View as plain text