Mercurial > projects > mde
comparison mde/gui/widget/AChildWidget.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 | mde/gui/widget/Widget.d@c5c38eaadb64 |
children | 9f035cd139c6 |
comparison
equal
deleted
inserted
replaced
130:c5c38eaadb64 | 131:9cff74f68b84 |
---|---|
1 /* LICENSE BLOCK | |
2 Part of mde: a Modular D game-oriented Engine | |
3 Copyright © 2007-2008 Diggory Hardy | |
4 | |
5 This program is free software: you can redistribute it and/or modify it under the terms | |
6 of the GNU General Public License as published by the Free Software Foundation, either | |
7 version 2 of the License, or (at your option) any later version. | |
8 | |
9 This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; | |
10 without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. | |
11 See the GNU General Public License for more details. | |
12 | |
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/>. */ | |
15 | |
16 /****************************************************************************** | |
17 * Contains the AChildWidget class, intended for IChildWidgets to inherit. | |
18 * | |
19 * Abstract widget classes have an 'A' prepended to the name, similar to the | |
20 * 'I' convention for interfaces. | |
21 *****************************************************************************/ | |
22 module mde.gui.widget.AChildWidget; | |
23 | |
24 public import mde.gui.widget.Ifaces; | |
25 import mde.content.Content; | |
26 import mde.gui.exception; | |
27 | |
28 debug { | |
29 import tango.util.log.Log : Log, Logger; | |
30 private Logger logger; | |
31 static this () { | |
32 logger = Log.getLogger ("mde.gui.widget.AChildWidget"); | |
33 } | |
34 } | |
35 | |
36 /****************************************************************************** | |
37 * An abstract base widget class for IChildWidgets. | |
38 * | |
39 * This abstract class, and the more concrete FixedWidget and ScalableWidget | |
40 * classes provides useful basic implementations for widgets. | |
41 *****************************************************************************/ | |
42 abstract class AChildWidget : IChildWidget | |
43 { | |
44 //BEGIN Load and save | |
45 // Base this() for child Widgets. | |
46 protected this (IWidgetManager mgr, IParentWidget parent, widgetID id) { | |
47 this.mgr = mgr; | |
48 this.parent = parent; | |
49 this.id = id; | |
50 } | |
51 | |
52 // Widgets need to do their initialization either in this() or setup(). | |
53 override bool setup (uint,uint) { | |
54 return false; | |
55 } | |
56 | |
57 // Don't save any data: fine for many widgets. | |
58 override bool saveChanges () { | |
59 return false; | |
60 } | |
61 //END Load and save | |
62 | |
63 //BEGIN Size and position | |
64 // default to not resizable | |
65 override bool isWSizable () { | |
66 return false; | |
67 } | |
68 override bool isHSizable () { | |
69 return false; | |
70 } | |
71 | |
72 /* Return minimal/fixed size. */ | |
73 override wdim minWidth () { | |
74 return mw; | |
75 } | |
76 override wdim minHeight () { | |
77 return mh; | |
78 } | |
79 | |
80 override wdim width () { | |
81 return w; | |
82 } | |
83 override wdim height() { | |
84 return h; | |
85 } | |
86 | |
87 override wdabs xPos () { | |
88 return x; | |
89 } | |
90 override wdabs yPos () { | |
91 return y; | |
92 } | |
93 | |
94 /* Set size: minimal size is (mw,mh). Note that both resizable and fixed widgets should allow | |
95 * enlarging, so in both cases this is a correct implementation. */ | |
96 override void setWidth (wdim nw, int) { | |
97 debug if (nw < mw) logger.warn ("Widget width set below minimal size"); | |
98 w = (nw >= mw ? nw : mw); | |
99 } | |
100 override void setHeight (wdim nh, int) { | |
101 debug if (nh < mh) logger.warn ("Widget height set below minimal size"); | |
102 h = (nh >= mh ? nh : mh); | |
103 } | |
104 | |
105 override void setPosition (wdim nx, wdim ny) { | |
106 x = nx; | |
107 y = ny; | |
108 } | |
109 //END Size and position | |
110 | |
111 //BEGIN Events | |
112 /* This method is only called when the location is over this widget; hence for all widgets | |
113 * without children this method is valid. */ | |
114 override IChildWidget getWidget (wdim cx, wdim cy) { | |
115 debug assert (cx >= x && cx < x + w && cy >= y && cy < y + h, "getWidget: not on widget (code error)"); | |
116 return this; | |
117 } | |
118 | |
119 // Should be valid for any widget. | |
120 override bool onSelf (wdabs cx, wdabs cy) { | |
121 return cx >= x && cx < x + w && cy >= y && cy < y + h; | |
122 } | |
123 | |
124 /* Dummy event method (suitable for all widgets which don't respond to events). */ | |
125 override int clickEvent (wdabs cx, wdabs cy, ubyte b, bool state) { | |
126 return 0; | |
127 } | |
128 | |
129 /* Dummy functions: suitable for widgets with no text input. */ | |
130 override void keyEvent (ushort, char[]) {} | |
131 override void keyFocusLost () {} | |
132 | |
133 // Called when mouse moves over or off this | |
134 override void underMouse (bool state) {} | |
135 | |
136 // Only useful to widgets creating popups. | |
137 override void popupClose () {} | |
138 override bool popupParentClick () { | |
139 return true; | |
140 } | |
141 //END Events | |
142 | |
143 /* Basic draw method: draw the background (all widgets should do this). */ | |
144 override void draw () { | |
145 mgr.renderer.drawWidgetBack (x,y, w,h); | |
146 } | |
147 | |
148 // Debug function to print size info. Intended to be correct not optimal. | |
149 debug override void logWidgetSize () { | |
150 logger.trace ("size: {,4},{,4}; minimal: {,4},{,4}; sizable: {},{} - {,-50} {}", this.width, this.height, this.minWidth, this.minHeight, cast(int)this.isWSizable, cast(int)this.isHSizable, this, id); | |
151 } | |
152 | |
153 protected: | |
154 /************************************************************************** | |
155 * Widgets may use W*Check as a utility to check for existance of data. Its use is encouraged, | |
156 * so that the checks can easily be updated should WidgetData be changed. | |
157 * | |
158 * Variants: | |
159 * WDCheck checks the exact length of integer and string data. | |
160 * WDCCheck checks data as WDCheck and that the content passed is valid. | |
161 * WDCMinCheck does the same as WDCCheck, but allows more data than required (used by some | |
162 * generic widgets). | |
163 * | |
164 * Params: | |
165 * data = the WidgetData to check lengths of | |
166 * n_ints = number of integers wanted | |
167 * n_strings= number of strings (default 0 since not all widgets use strings) | |
168 *************************************************************************/ | |
169 void WDCheck (WidgetData data, size_t n_ints, size_t n_strings = 0) { | |
170 if (data.ints.length != n_ints || | |
171 data.strings.length != n_strings) | |
172 throw new WidgetDataException (this); | |
173 } | |
174 /** ditto */ | |
175 void WDCCheck (WidgetData data, size_t n_ints, size_t n_strings, IContent c) { | |
176 if (data.ints.length != n_ints || | |
177 data.strings.length != n_strings) | |
178 throw new WidgetDataException (this); | |
179 if (c is null) | |
180 throw new ContentException (this); | |
181 } | |
182 /** ditto */ | |
183 void WDCMinCheck (WidgetData data, size_t n_ints, size_t n_strings, IContent c) { | |
184 if (data.ints.length < n_ints || | |
185 data.strings.length < n_strings) | |
186 throw new WidgetDataException (this); | |
187 if (c is null) | |
188 throw new ContentException (this); | |
189 } | |
190 | |
191 IWidgetManager mgr; // the enclosing window | |
192 IParentWidget parent; // the parent widget | |
193 wdim x, y; // position | |
194 widgetID id; // The widget's ID, used for saving data | |
195 wdim w, h; // size | |
196 wdim mw = 0, mh = 0; // minimal or fixed size, depending on whether the widget is | |
197 // resizible; both types of widgets should actually be expandable. | |
198 } | |
199 | |
200 /** A base for fixed-size widgets taking their size from the creation data. */ | |
201 class FixedWidget : AChildWidget { | |
202 // Check data.length is at least 3 before calling! | |
203 /** Constructor for a fixed-size [blank] widget. | |
204 * | |
205 * Widget uses the initialisation data: | |
206 * [widgetID, w, h] | |
207 * where w, h is the fixed size. */ | |
208 this (IWidgetManager mgr, IParentWidget parent, widgetID id, WidgetData data) { | |
209 super (mgr, parent, id); | |
210 w = mw = cast(wdim) data.ints[1]; | |
211 h = mh = cast(wdim) data.ints[2]; | |
212 } | |
213 } | |
214 | |
215 /** A base for resizable widgets. */ | |
216 class SizableWidget : AChildWidget { | |
217 // Check data.length is at least 1 before calling! | |
218 /// Constructor for a completely resizable [blank] widget. | |
219 this (IWidgetManager mgr, IParentWidget parent, widgetID id) { | |
220 super (mgr, parent, id); | |
221 } | |
222 | |
223 override bool isWSizable () { | |
224 return true; | |
225 } | |
226 override bool isHSizable () { | |
227 return true; | |
228 } | |
229 } | |
230 | |
231 /** For pressable buttons. | |
232 * | |
233 * Overriding classes should implement this() (setting the size), draw() and activated(). */ | |
234 abstract class AButtonWidget : AChildWidget | |
235 { | |
236 protected this (IWidgetManager mgr, IParentWidget parent, widgetID id) { | |
237 super (mgr, parent, id); | |
238 parentIPPW = parent.getParentIPPW; | |
239 } | |
240 | |
241 /// May be over-ridden. Pushed is true if the button has been pushed and not released. | |
242 override void draw () { | |
243 mgr.renderer.drawButton (x,y, w,h, pushed); | |
244 } | |
245 | |
246 /// Handles the down-click | |
247 override int clickEvent (wdabs, wdabs, ubyte b, bool state) { | |
248 if (b != 1) return 0; | |
249 if (state) { | |
250 pushed = true; | |
251 mgr.requestRedraw; | |
252 mgr.addClickCallback (&clickWhilePushed); | |
253 mgr.addMotionCallback (&motionWhilePushed); | |
254 } | |
255 if (parentIPPW.menuActive) { | |
256 parentIPPW.menuDone; | |
257 activated; | |
258 } | |
259 return 0; | |
260 } | |
261 | |
262 /// When menuActive, highlight on mouse-over | |
263 override void underMouse (bool state) { | |
264 if (!parentIPPW.menuActive) return; | |
265 pushed = state; | |
266 mgr.requestRedraw; | |
267 } | |
268 | |
269 /// Called when a mouse click event occurs while held; handles up-click | |
270 bool clickWhilePushed (wdabs cx, wdabs cy, ubyte b, bool state) { | |
271 if (b == 1 && state == false) { | |
272 if (cx >= x && cx < x+w && cy >= y && cy < y+h) { // button event | |
273 parentIPPW.menuDone; | |
274 activated(); | |
275 } | |
276 | |
277 pushed = false; | |
278 mgr.requestRedraw; | |
279 mgr.removeCallbacks (cast(void*) this); | |
280 | |
281 return true; | |
282 } | |
283 return false; | |
284 } | |
285 /// Called when a mouse motion event occurs while held; handles pushing in/out on hover | |
286 void motionWhilePushed (wdabs cx, wdabs cy) { | |
287 bool oldPushed = pushed; | |
288 if (cx >= x && cx < x+w && cy >= y && cy < y+h) pushed = true; | |
289 else pushed = false; | |
290 if (oldPushed != pushed) | |
291 mgr.requestRedraw; | |
292 } | |
293 | |
294 /// The action triggered when the button is clicked... | |
295 void activated (); | |
296 | |
297 protected: | |
298 bool pushed = false; /// True if button is pushed in (visually) | |
299 IPopupParentWidget parentIPPW; | |
300 } |