comparison mde/gui/WMScreen.d @ 131:9cff74f68b84

Major revisions to popup handling. Buttons can close menus now, plus some smaller impovements. Removed Widget module. Moved Widget.AWidget to AChildWidget.AChildWidget and Widget.AParentWidget to AParentWidget.AParentWidget. Removed ASingleParentWidget to improve code sharing. AChildWidget doesn't implement IParentWidget like AWidget did. New IPopupParentWidget extending IParentWidget for the WM and some widgets to handle popups. Cut old popup management code. New underMouse() function replacing highlight(); called on all widgets. Separate menu-popup and button widgets aren't needed for menus now. Functions returning content widgets have been moved to their own module. Cleaned up jobs.txt. Switched to 80 line length for Ddoc.
author Diggory Hardy <diggory.hardy@gmail.com>
date Wed, 21 Jan 2009 13:01:40 +0000
parents 41582439a42b
children 264028f4115a
comparison
equal deleted inserted replaced
130:c5c38eaadb64 131:9cff74f68b84
11 See the GNU General Public License for more details. 11 See the GNU General Public License for more details.
12 12
13 You should have received a copy of the GNU General Public License 13 You should have received a copy of the GNU General Public License
14 along with this program. If not, see <http://www.gnu.org/licenses/>. */ 14 along with this program. If not, see <http://www.gnu.org/licenses/>. */
15 15
16 /************************************************************************************************* 16 /******************************************************************************
17 * A gui manager class using mde.setup.Screen and mde.input.Input. 17 * A gui manager class using mde.setup.Screen and mde.input.Input.
18 * 18 *
19 * This is the module to use externally to create a graphical user interface (likely also with 19 * This is the module to use externally to create a graphical user interface
20 * content modules). 20 * (likely also with content modules).
21 *************************************************************************************************/ 21 *****************************************************************************/
22 module mde.gui.WMScreen; 22 module mde.gui.WMScreen;
23 23
24 import mde.gui.WidgetManager; 24 import mde.gui.WidgetManager;
25 import mde.gui.widget.Ifaces; 25 import mde.gui.widget.Ifaces;
26 import mde.gui.renderer.createRenderer; 26 import mde.gui.renderer.createRenderer;
32 private Logger logger; 32 private Logger logger;
33 static this () { 33 static this () {
34 logger = Log.getLogger ("mde.gui.WMScreen"); 34 logger = Log.getLogger ("mde.gui.WMScreen");
35 } 35 }
36 36
37 /************************************************************************************************* 37 /******************************************************************************
38 * The widget manager. 38 * The widget manager.
39 * 39 *
40 * This provides a layer on top of WidgetLoader, handling input and rendering. Other functionality 40 * This provides a layer on top of WidgetLoader, handling input and rendering.
41 * is contained in the super class, to simplify supporting new input/graphics libraries. 41 * Other functionality is contained in the super class, to simplify supporting
42 * new input/graphics libraries.
42 * 43 *
43 * Currently mouse coordinates are passed to widgets untranslated. It may make sense to translate 44 * Currently mouse coordinates are passed to widgets untranslated. It may make
44 * them and possibly drop events for some uses, such as if the gui is drawn to a texture. 45 * sense to translate them and possibly drop events for some uses, such as if
46 * the gui is drawn to a texture.
45 * 47 *
46 * Aside from the IWidgetManager methods, this class should be thread-safe. 48 * Public non IWidget* methods should be thread-safe.
47 *************************************************************************************************/ 49 *****************************************************************************/
48 scope class WMScreen : AWidgetManager, Screen.IDrawable { 50 scope class WMScreen : AWidgetManager, Screen.IDrawable {
49 /** Construct a new widget manager. 51 /** Construct a new widget manager.
50 * 52 *
51 * Must be run after static this. 53 * Must be run after static this.
52 * 54 *
66 /** Draw the gui. */ 68 /** Draw the gui. */
67 void draw() { 69 void draw() {
68 synchronized(mutex) { 70 synchronized(mutex) {
69 if (child) 71 if (child)
70 child.draw; 72 child.draw;
71 foreach (popup; popups) 73 if (childIPPW)
72 popup.widget.draw(); 74 childIPPW.drawPopup;
73 } 75 }
74 } 76 }
75 77
76 /** For mouse click events. 78 /** For mouse click events.
77 * 79 *
83 scope(exit) mutex.unlock; 85 scope(exit) mutex.unlock;
84 if (child is null) return; 86 if (child is null) return;
85 87
86 wdabs cx = cast(wdabs) usx, cy = cast(wdabs) usy; 88 wdabs cx = cast(wdabs) usx, cy = cast(wdabs) usy;
87 89
88 // 1. Callbacks have the highest priority recieving events (e.g. a button release) 90 // Callbacks have the highest priority receiving events (e.g. a button release)
89 foreach (dg; clickCallbacks) 91 foreach (dg; clickCallbacks)
90 if (dg (cx, cy, b, state)) return; 92 if (dg (cx, cy, b, state)) return;
91 93
92 // 2. Then pop-ups: close from top, depending on click pos 94 // Update underMouse to get the widget clicked on
93 // Note: assumes each evaluated popup's parent is not under another still open popup. 95 updateUnderMouse (cx, cy, state);
94 // Also assumes popup's parent doesn't have other children in its box.
95 size_t removeTo = popups.length;
96 bool eventDone; // don't pass clickEvent
97 IChildWidget widg; // widget clicked on
98 foreach_reverse (i,popup; popups) with (popup) {
99 if (cx < x || cx >= x + w ||
100 cy < y || cy >= y + h) { // on popup
101 if (parent.onSelf (cx, cy)) {
102 if (parent.popupParentClick()) removeTo = i;
103 eventDone = true;
104 break;
105 } else {
106 removeTo = i;
107 parent.popupClose;
108 }
109 } else {
110 widg = widget.getWidget (cast(wdabs)cx,cast(wdabs)cy);
111 break;
112 }
113 }
114 if (removeTo < popups.length) {
115 requestRedraw;
116 popups = popups[0..removeTo];
117 }
118 if (eventDone)
119 return;
120 96
121 // 3. Then the main widget tree 97 // Disable keyboard input if on another widget:
122 debug assert (cx < child.width && cy < child.height, "WidgetManager: child doesn't cover whole area (code error)"); 98 if (keyFocus && keyFocus !is underMouse) {
123 if (widg is null)
124 widg = child.getWidget (cast(wdabs)cx,cast(wdabs)cy);
125 if (keyFocus && keyFocus !is widg) {
126 keyFocus.keyFocusLost; 99 keyFocus.keyFocusLost;
127 keyFocus = null; 100 keyFocus = null;
128 imde.input.setLetterCallback (null); 101 imde.input.setLetterCallback (null);
129 } 102 }
130 if (widg !is null) { 103 // Finally, post the actual event:
131 if (widg.clickEvent (cast(wdabs)cx,cast(wdabs)cy,b,state) & 1) { 104 if (underMouse.clickEvent (cast(wdabs)cx,cast(wdabs)cy,b,state) & 1) {
132 keyFocus = widg; 105 // keyboard input requested
133 imde.input.setLetterCallback (&widg.keyEvent); 106 keyFocus = underMouse;
134 } 107 imde.input.setLetterCallback (&underMouse.keyEvent);
135 } 108 }
136 } 109 }
137 110
138 /** For mouse motion events. 111 /** For mouse motion events.
139 * 112 *
140 * Sends the event on to all motion callbacks. */ 113 * Sends the event on to all motion callbacks. */
144 mutex.lock; 117 mutex.lock;
145 scope(exit) mutex.unlock; 118 scope(exit) mutex.unlock;
146 wdabs cx = cast(wdabs) scx, cy = cast(wdabs) scy; 119 wdabs cx = cast(wdabs) scx, cy = cast(wdabs) scy;
147 foreach (dg; motionCallbacks) 120 foreach (dg; motionCallbacks)
148 dg (cx, cy); 121 dg (cx, cy);
149 122
150 IChildWidget ohighlighted = highlighted; 123 updateUnderMouse (cx, cy, false);
151 foreach_reverse (popup; popups) with (popup) {
152 if (cx >= x && cx < x+w && cy >= y && cy < y+h) {
153 highlighted = widget.getWidget (cx,cy);
154 goto foundPopup;
155 }
156 }
157 highlighted = null; // not over a popup
158 foundPopup:
159 if (ohighlighted != highlighted) {
160 if (ohighlighted)
161 ohighlighted.highlight (false);
162 if (highlighted)
163 highlighted.highlight (true);
164 requestRedraw;
165 }
166 } 124 }
167 125
168 126
169 void sizeEvent (int nw, int nh) { // IDrawable function 127 void sizeEvent (int nw, int nh) { // IDrawable function
170 mutex.lock; 128 mutex.lock;
193 * Note: sizeEvent should be called with window size before this. */ 151 * Note: sizeEvent should be called with window size before this. */
194 final override void createRootWidget () { 152 final override void createRootWidget () {
195 // The renderer needs to be created on the first load, but not after this. 153 // The renderer needs to be created on the first load, but not after this.
196 if (rend is null) 154 if (rend is null)
197 rend = createRenderer (rendName); 155 rend = createRenderer (rendName);
198 popups = null;
199 156
200 debug (mdeWidgets) logger.trace ("Creating root widget..."); 157 debug (mdeWidgets) logger.trace ("Creating root widget...");
201 child = makeWidget (this, "root"); 158 child = makeWidget (this, "root");
202 debug (mdeWidgets) logger.trace ("Setting up root widget..."); 159 debug (mdeWidgets) logger.trace ("Setting up root widget...");
203 child.setup (0, 3); 160 child.setup (0, 3);