Mercurial > projects > dynamin
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. |