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