comparison dynamin/gui/window.d @ 55:c138461bf845

Add focusing and other changes that are related like descendantAdded/Removed events, Window.activated event, and updating List. Window.state was also added, even though focusing does not depend on it.
author Jordan Miner <jminer7@gmail.com>
date Sat, 08 Aug 2009 15:42:27 -0500
parents 3738a2d0bac3
children 84beb40c1665
comparison
equal deleted inserted replaced
54:3738a2d0bac3 55:c138461bf845
35 import dynamin.gui.container; 35 import dynamin.gui.container;
36 import dynamin.gui.events; 36 import dynamin.gui.events;
37 import tango.io.Stdout; 37 import tango.io.Stdout;
38 import tango.core.Exception; 38 import tango.core.Exception;
39 import tango.core.Thread; 39 import tango.core.Thread;
40 import tango.text.Util;
40 41
41 /// 42 ///
42 static class Application { 43 static class Application {
43 static: 44 static:
44 mixin ApplicationBackend; 45 mixin ApplicationBackend;
107 /// Specifies being at the bottom-right corner. 108 /// Specifies being at the bottom-right corner.
108 BottomRight 109 BottomRight
109 } 110 }
110 111
111 /** 112 /**
113 * The different states a window may be in. It may not be in more than one of
114 * these states at a time.
115 */
116 enum WindowState {
117 /**
118 * Specifies that the window is neither minimized or maximized.
119 */
120 Normal,
121 /**
122 * Specifies that the window is only visible as an icon and/or text on
123 * the taskbar or dock.
124 */
125 Minimized,
126 /**
127 * Specifies that the window covers the screen in at least one direction.
128 */
129 Maximized
130 }
131
132 /**
112 * The different types of borders that a window may have. 133 * The different types of borders that a window may have.
113 * These do not affect whether the window is resizable-- 134 * These do not affect whether the window is resizable--
114 * use Window.resizable for that. 135 * use Window.resizable for that.
115 */ 136 */
116 enum WindowBorderStyle { 137 enum WindowBorderStyle {
152 } 173 }
153 protected: 174 protected:
154 mixin WindowBackend; 175 mixin WindowBackend;
155 BorderSize _borderSize; 176 BorderSize _borderSize;
156 Window _owner; 177 Window _owner;
178 package bool _active;
179 package WindowState _state;
157 WindowBorderStyle _borderStyle; 180 WindowBorderStyle _borderStyle;
158 bool _resizable = true; 181 bool _resizable = true;
159 Panel _content; 182 Panel _content;
183 bool _showFocus;
184 // _focusedControl might not be focused at the current time (that is
185 // getFocusedControl()), but will at least be focused when this
186 // window is active
160 Control _focusedControl; 187 Control _focusedControl;
161 package Control focusedControl() { return _focusedControl; } 188 package Control focusedControl() { return _focusedControl; }
162 package void focusedControl(Control c) { 189 package void focusedControl(Control c) {
163 _focusedControl = c; 190 _focusedControl = c;
191 if(active)
192 setFocusedControl(_focusedControl);
164 } 193 }
165 override void dispatchPainting(PaintingEventArgs e) { 194 override void dispatchPainting(PaintingEventArgs e) {
166 Theme.current.Window_paint(this, e.graphics); 195 Theme.current.Window_paint(this, e.graphics);
167 super.dispatchPainting(e); 196 super.dispatchPainting(e);
168 } 197 }
198 override void whenDescendantAdded(HierarchyEventArgs e) {
199 super.whenDescendantAdded(e);
200 if(focusedControl is null && e.descendant.focusable) {
201 // && e.descendant.enabled) {
202 focusedControl = e.descendant;
203 }
204 }
205
206 //{{{ focusing
207 public override bool showFocus() { return _showFocus; }
208 override void whenKeyDown(KeyEventArgs e) {
209 if(e.key == Key.Tab) {
210 getNextFocusable().focus();
211 _showFocus = true;
212 }
213 }
214
215 // will not return null
216 Control getNextFocusable() {
217 Control foc = focusedControl;
218
219 Control[32] buffer;
220 auto des = getFocusableDescendants(buffer);
221 if(des.length == 0)
222 return this;
223 else if(des.length == 1)
224 return des[0];
225
226 int focI = locate(des, foc);
227
228 // look _after_ this control for one with the same tab index
229 foreach(c; des[focI+1..$])
230 if(c.tabIndex == foc.tabIndex)
231 return c;
232
233 // if none are found, look for the next largest tab index
234 // from the beginning of the array
235 Control smallest;
236 Control nextLargest;
237 foreach(c; des) {
238 if(c.tabIndex > foc.tabIndex)
239 if(nextLargest is null || c.tabIndex < nextLargest.tabIndex)
240 nextLargest = c;
241 if(smallest is null || c.tabIndex < smallest.tabIndex)
242 smallest = c;
243 }
244
245 if(nextLargest)
246 return nextLargest;
247 else
248 return smallest;
249 }
250
251 // will not return null
252 Control getPreviousFocusable() {
253 return null;
254 }
255 //}}}
256
169 public: 257 public:
258 /// Override this method in a subclass to handle the activated event.
259 protected void whenActivated(EventArgs e) {
260 setFocusedControl(_focusedControl is null ? content : _focusedControl);
261 }
262 /// This event occurs after this window is activated.
263 Event!(whenActivated) activated;
264
265 /// Override this method in a subclass to handle the deactivated event.
266 protected void whenDeactivated(EventArgs e) {
267 setFocusedControl(null);
268 }
269 /// This event occurs after this window is deactivated.
270 Event!(whenDeactivated) deactivated;
271
272 /**
273 *
274 */
170 this() { 275 this() {
171 _children = new ControlList(); 276 activated.mainHandler = &whenActivated;
277 deactivated.mainHandler = &whenDeactivated;
278
172 content = new Panel; 279 content = new Panel;
173 280
174 _visible = false; 281 _visible = false;
175 _minSize = Size(0, 0); 282 _minSize = Size(0, 0);
176 _maxSize = Size(0, 0); 283 _maxSize = Size(0, 0);
181 this(string text) { 288 this(string text) {
182 this(); 289 this();
183 this.text = text; 290 this.text = text;
184 } 291 }
185 292
293 /**
294 *
295 */
296 Panel content() {
297 return _content;
298 }
299 /// ditto
186 void content(Panel panel) { 300 void content(Panel panel) {
187 if(panel is null) 301 if(panel is null)
188 throw new IllegalArgumentException("content must not be null"); 302 throw new IllegalArgumentException("content must not be null");
189 // TODO: remove handlers 303 // TODO: remove handlers
190 super.remove(panel); 304 super.remove(panel);
226 _content._location = Point(_borderSize.left, _borderSize.top); 340 _content._location = Point(_borderSize.left, _borderSize.top);
227 ignoreResize = true; 341 ignoreResize = true;
228 _content.size = _size-_borderSize; 342 _content.size = _size-_borderSize;
229 ignoreResize = false; 343 ignoreResize = false;
230 } 344 }
231 Panel content() {
232 return _content;
233 }
234 345
235 /** 346 /**
236 * If the handle has not yet been created, calling this will cause it to be. 347 * If the handle has not yet been created, calling this will cause it to be.
237 * Under the Windows backend, returns a HWND. 348 * Under the Windows backend, returns a HWND.
238 * Under the X backend, returns a Window. 349 * Under the X backend, returns a Window.
288 399
289 alias Control.visible visible; 400 alias Control.visible visible;
290 void visible(bool b) { 401 void visible(bool b) {
291 _visible = b; 402 _visible = b;
292 backend_visible = b; 403 backend_visible = b;
404 }
405
406 /**
407 *
408 */
409 bool active() { return _active; }
410 /**
411 *
412 */
413 void activate() {
414 if(!handleCreated)
415 return;
416 backend_activate();
417 }
418
419 /**
420 * Gets or sets whether the window's state is normal, minimized, or
421 * maximized.
422 */
423 WindowState state() { return _state; }
424 /// ditto
425 void state(WindowState s) {
426 _state = s;
427 if(!handleCreated)
428 return;
429 backend_state = s;
293 } 430 }
294 431
295 /** 432 /**
296 * Gets or sets what border this window will have around its contents. 433 * Gets or sets what border this window will have around its contents.
297 * The default is WindowBorderStyle.Normal. 434 * The default is WindowBorderStyle.Normal.