Mercurial > projects > dwt-addons
comparison dwtx/novocode/ishell/DesktopForm.d @ 188:e3780acbbf80
Added ported sources from Novocode, thanks to WasserDragoon
author | Frank Benoit <benoit@tionex.de> |
---|---|
date | Sun, 26 Oct 2008 14:54:39 +0100 |
parents | |
children | df4e66472aff |
comparison
equal
deleted
inserted
replaced
187:293a2f22f944 | 188:e3780acbbf80 |
---|---|
1 /******************************************************************************* | |
2 * Copyright (c) 2005 Stefan Zeiger and others. | |
3 * All rights reserved. This program and the accompanying materials | |
4 * are made available under the terms of the Eclipse Public License v1.0 | |
5 * which accompanies this distribution, and is available at | |
6 * http://www.novocode.com/legal/epl-v10.html | |
7 * | |
8 * Contributors: | |
9 * Stefan Zeiger (szeiger@novocode.com) - initial API and implementation | |
10 *******************************************************************************/ | |
11 | |
12 module dwtx.novocode.ishell.DesktopForm; | |
13 | |
14 import dwt.DWT; | |
15 import dwt.graphics.Color; | |
16 import dwt.graphics.Rectangle; | |
17 import dwt.widgets.Composite; | |
18 import dwt.widgets.Control; | |
19 import dwt.widgets.Display; | |
20 import dwt.widgets.Event; | |
21 import dwt.widgets.Listener; | |
22 import dwt.widgets.Shell; | |
23 | |
24 import dwtx.novocode.ishell.internal.DesktopListener; | |
25 import dwtx.novocode.ishell.InternalShell; | |
26 | |
27 import tango.core.Array; | |
28 | |
29 | |
30 /** | |
31 * A desktop which manages internal shells. | |
32 * | |
33 * @author Stefan Zeiger (szeiger@novocode.com) | |
34 * @since Jan 21, 2005 | |
35 * @version $Id: DesktopForm.java 344 2005-07-09 22:37:51 +0000 (Sat, 09 Jul 2005) szeiger $ | |
36 */ | |
37 | |
38 class DesktopForm : Composite | |
39 { | |
40 private static const InternalShell[] EMPTY_INTERNALSHELL_ARRAY/** = new InternalShell[0]*/; | |
41 private static const int FIRST_SHELL_LOCATION = 32; | |
42 private static const int SHELL_LOCATION_OFFSET = 16; | |
43 | |
44 private InternalShell activeShell; | |
45 private DesktopListener[] desktopListeners; | |
46 private InternalShell[] allShells; | |
47 private InternalShell[] visibleShells; | |
48 private int nextShellLocation = FIRST_SHELL_LOCATION; | |
49 private bool showMaximizedTitle; | |
50 private bool autoMaximize = true; | |
51 private bool enableCtrlTab = true; | |
52 private bool allowDeactivate; | |
53 private Shell shell; | |
54 private InternalShell ishell; | |
55 private Listener mouseDownFilter, focusInFilter, traverseFilter; | |
56 | |
57 | |
58 this(Composite parent, int style) | |
59 { | |
60 super(parent, style); | |
61 Display display = getDisplay(); | |
62 shell = getShell(); | |
63 | |
64 Color bg = display.getSystemColor(DWT.COLOR_TITLE_INACTIVE_BACKGROUND); | |
65 setBackground(bg); | |
66 int brightness = bg.getRed() + bg.getGreen() + bg.getBlue(); | |
67 setForeground(display.getSystemColor(brightness > 400 ? DWT.COLOR_BLACK : DWT.COLOR_WHITE)); | |
68 | |
69 addListener(DWT.Resize, dgListener(&onResize)); | |
70 | |
71 mouseDownFilter = dgListener(&onMouseDownFilter); | |
72 focusInFilter = dgListener(&onFocusInFilter); | |
73 traverseFilter = dgListener(&onTraverseFilter); | |
74 | |
75 display.addFilter(DWT.MouseDown, mouseDownFilter); | |
76 display.addFilter(DWT.FocusIn, focusInFilter); | |
77 display.addFilter(DWT.Traverse, traverseFilter); | |
78 | |
79 addListener(DWT.Dispose, dgListener(&onDispose)); | |
80 } | |
81 | |
82 | |
83 private void onResize(Event event) | |
84 { | |
85 Rectangle ca = getClientArea(); | |
86 foreach(c; getChildren()) | |
87 { | |
88 if(cast(InternalShell)c !is null) | |
89 (cast(InternalShell)c).desktopResized(ca); | |
90 } | |
91 } | |
92 | |
93 | |
94 private void onMouseDownFilter(Event event) | |
95 { | |
96 if(!(cast(Control)event.widget !is null)) return; | |
97 Control c = cast(Control)event.widget; | |
98 if(c.getShell() !is shell) return; | |
99 bool[] desktopHit = new bool[1]; | |
100 InternalShell ishell = getInternalShell(c, desktopHit); | |
101 if(desktopHit[0] && allowDeactivate) activate(null); | |
102 if(ishell is null) return; | |
103 activate(ishell); | |
104 } | |
105 | |
106 | |
107 private void onFocusInFilter(Event event) | |
108 { | |
109 if(!(cast(Control)event.widget !is null)) return; | |
110 Control c = cast(Control)event.widget; | |
111 if(c.getShell() !is shell) return; | |
112 bool[] desktopHit = new bool[1]; | |
113 ishell = getInternalShell(c, desktopHit); | |
114 if(desktopHit[0] && allowDeactivate) activate(null); | |
115 if(ishell is null) return; | |
116 ishell.focusControl = c; | |
117 } | |
118 | |
119 | |
120 private void onTraverseFilter(Event event) | |
121 { | |
122 if(!enableCtrlTab) return; | |
123 if(!event.doit) return; // don't steal traverse event if a control wants to handle it directly | |
124 if((event.stateMask & DWT.CTRL) is 0) return; | |
125 if(event.detail !is DWT.TRAVERSE_TAB_NEXT && event.detail !is DWT.TRAVERSE_TAB_PREVIOUS) return; | |
126 if(!(cast(Control)event.widget !is null)) return; | |
127 Control c = cast(Control)event.widget; | |
128 if(c.getShell() !is shell) return; | |
129 bool[] desktopHit = new bool[1]; | |
130 InternalShell ishell = getInternalShell(c, desktopHit); | |
131 if(ishell !is null || desktopHit[0]) | |
132 { | |
133 if(event.detail is DWT.TRAVERSE_TAB_NEXT) activateNextShell(); | |
134 else activatePreviousShell(); | |
135 event.doit = false; | |
136 } | |
137 } | |
138 | |
139 | |
140 private void onDispose(Event event) | |
141 { | |
142 display.removeFilter(DWT.MouseDown, mouseDownFilter); | |
143 display.removeFilter(DWT.FocusIn, focusInFilter); | |
144 display.removeFilter(DWT.Traverse, traverseFilter); | |
145 } | |
146 | |
147 | |
148 void manage(InternalShell ishell) | |
149 { | |
150 Rectangle bounds = getBounds(); | |
151 if(nextShellLocation > bounds.height-100 || nextShellLocation > bounds.width-100) | |
152 nextShellLocation = FIRST_SHELL_LOCATION; | |
153 ishell.setLocation(bounds.x+nextShellLocation, bounds.y+nextShellLocation); | |
154 nextShellLocation += SHELL_LOCATION_OFFSET; | |
155 | |
156 ishell.addListener(DWT.Dispose, dgListener(&onIshellDispose)); | |
157 allShells ~= ishell; | |
158 if(ishell.isVisible()) visibleShells ~= ishell; | |
159 notifyDesktopListenersCreate(ishell); | |
160 } | |
161 | |
162 | |
163 private void onIshellDispose(Event event) | |
164 { | |
165 allShells.remove(ishell); | |
166 visibleShells.remove(ishell); | |
167 if(ishell is activeShell) | |
168 { | |
169 activateTopmostVisibleShellExcept(ishell); | |
170 if(autoMaximize && !hasVisibleMaximizedShell()) | |
171 setAllVisibleMaximized(false); | |
172 } | |
173 notifyDesktopListenersDispose(ishell); | |
174 } | |
175 | |
176 | |
177 private InternalShell activateTopmostVisibleShellExcept(InternalShell except) | |
178 { | |
179 Control[] children = getChildren(); | |
180 for(int i=0; i<children.length; i++) | |
181 { | |
182 Control c = children[i]; | |
183 if(c is except) continue; | |
184 if(cast(InternalShell)c !is null && c.isVisible()) | |
185 { | |
186 InternalShell ishell = cast(InternalShell)c; | |
187 activate(ishell); | |
188 return ishell; | |
189 } | |
190 } | |
191 activeShell = null; | |
192 notifyDesktopListenersActivate(null); | |
193 return null; | |
194 } | |
195 | |
196 | |
197 void activate(InternalShell ishell) | |
198 { | |
199 if(ishell is activeShell) return; | |
200 checkWidget(); | |
201 if(ishell !is null) | |
202 { | |
203 if(!ishell.isVisible()) ishell.setVisible(true); | |
204 if((ishell.getStyle() & DWT.ON_TOP) !is 0) | |
205 ishell.moveAbove(null); | |
206 else | |
207 { | |
208 InternalShell firstRegular = getTopmostRegularShell(); | |
209 if(firstRegular !is null && firstRegular !is ishell) ishell.moveAbove(firstRegular); | |
210 else | |
211 { | |
212 Control[] children = getChildren(); | |
213 if(children.length > 0) ishell.moveAbove(children[0]); | |
214 } | |
215 } | |
216 } | |
217 InternalShell oldActiveShell = activeShell; | |
218 activeShell = ishell; | |
219 if(oldActiveShell !is null) oldActiveShell.redrawDecorationsAfterActivityChange(); | |
220 if(ishell !is null) | |
221 { | |
222 if(activeShell.isVisible()) activeShell.redrawDecorationsAfterActivityChange(); | |
223 setTabList(/**new Control[] { activeShell }*/[ activeShell ]); | |
224 activeShell.setFocus(); | |
225 } | |
226 else | |
227 { | |
228 setTabList(/**new Control[] {}*/[]); | |
229 forceFocus(); | |
230 } | |
231 notifyDesktopListenersActivate(ishell); | |
232 } | |
233 | |
234 | |
235 private InternalShell getTopmostRegularShell() | |
236 { | |
237 foreach(c; getChildren()) | |
238 { | |
239 if(!(cast(InternalShell)c !is null)) continue; | |
240 if((c.getStyle() & DWT.ON_TOP) is 0) return cast(InternalShell)c; | |
241 } | |
242 return null; | |
243 } | |
244 | |
245 | |
246 private InternalShell getBottommostOnTopShell() | |
247 { | |
248 Control[] ch = getChildren(); | |
249 for(int i=ch.length-1; i>=0; i--) | |
250 { | |
251 Control c = ch[i]; | |
252 if(!(cast(InternalShell)c !is null)) continue; | |
253 if((c.getStyle() & DWT.ON_TOP) !is 0) return cast(InternalShell)c; | |
254 } | |
255 return null; | |
256 } | |
257 | |
258 | |
259 void shellVisibilityChanged(InternalShell ishell, bool visible) | |
260 { | |
261 if(visible) | |
262 { | |
263 if(!contains(visibleShells, ishell)) | |
264 { | |
265 visibleShells ~= ishell; | |
266 if(autoMaximize && !ishell.getMaximized() && (ishell.getStyle() & DWT.MAX) !is 0 && hasVisibleMaximizedShell()) | |
267 ishell.setMaximizedWithoutNotification(true); | |
268 } | |
269 if(ishell.getMaximized()) | |
270 ishell.desktopResized(getClientArea()); | |
271 } | |
272 else | |
273 { | |
274 visibleShells.remove(ishell); | |
275 if(ishell is activeShell) | |
276 { | |
277 activateTopmostVisibleShellExcept(ishell); | |
278 if(autoMaximize && !hasVisibleMaximizedShell()) | |
279 setAllVisibleMaximized(false); | |
280 } | |
281 } | |
282 } | |
283 | |
284 | |
285 private InternalShell getInternalShell(Control c, bool[] desktopHit) | |
286 { | |
287 while(c !is null && c !is /**DesktopForm.*/this) | |
288 { | |
289 if(cast(InternalShell)c !is null && (cast(InternalShell)c).getParent() is this) | |
290 return cast(InternalShell)c; | |
291 c = c.getParent(); | |
292 } | |
293 if(desktopHit !is null && c is /**DesktopForm.*/this) desktopHit[0] = true; | |
294 return null; | |
295 } | |
296 | |
297 | |
298 public InternalShell getActiveShell() | |
299 { | |
300 return activeShell; | |
301 } | |
302 | |
303 | |
304 public InternalShell[] getVisibleShells() | |
305 { | |
306 checkWidget(); | |
307 return visibleShells; | |
308 } | |
309 | |
310 | |
311 public InternalShell[] getShells() | |
312 { | |
313 checkWidget(); | |
314 return allShells; | |
315 } | |
316 | |
317 | |
318 public void setShowMaximizedTitle(bool b) | |
319 { | |
320 checkWidget(); | |
321 showMaximizedTitle = b; | |
322 Rectangle ca = getClientArea(); | |
323 foreach(c; getChildren()) | |
324 { | |
325 if(cast(InternalShell)c !is null) | |
326 (cast(InternalShell)c).desktopResized(ca); | |
327 } | |
328 } | |
329 | |
330 | |
331 public bool getShowMaximizedTitle() | |
332 { | |
333 checkWidget(); | |
334 return showMaximizedTitle; | |
335 } | |
336 | |
337 | |
338 public void setAutoMaximize(bool b) | |
339 { | |
340 checkWidget(); | |
341 autoMaximize = b; | |
342 bool hasMax = false; | |
343 foreach(ins; visibleShells) | |
344 { | |
345 if(ins.getMaximized()) | |
346 { | |
347 hasMax = true; | |
348 break; | |
349 } | |
350 } | |
351 if(hasMax) | |
352 { | |
353 // Maximize all shells | |
354 foreach(ins; visibleShells) | |
355 { | |
356 if((ins.getStyle() & DWT.MAX) !is 0) ins.setMaximized(true); | |
357 } | |
358 } | |
359 } | |
360 | |
361 | |
362 public bool getAutoMaximize() | |
363 { | |
364 checkWidget(); | |
365 return autoMaximize; | |
366 } | |
367 | |
368 | |
369 public void setEnableCtrlTab(bool b) | |
370 { | |
371 checkWidget(); | |
372 this.enableCtrlTab = b; | |
373 } | |
374 | |
375 | |
376 public bool getEnableCtrlTab() | |
377 { | |
378 return enableCtrlTab; | |
379 } | |
380 | |
381 | |
382 public void setAllowDeactivate(bool b) | |
383 { | |
384 checkWidget(); | |
385 this.allowDeactivate = b; | |
386 if(!allowDeactivate && activeShell is null) | |
387 activateTopmostVisibleShellExcept(null); | |
388 } | |
389 | |
390 | |
391 public bool getAllowDeactivate() | |
392 { | |
393 return allowDeactivate; | |
394 } | |
395 | |
396 | |
397 void shellMaximizedOrRestored(InternalShell ishell, bool maximized) | |
398 { | |
399 setAllVisibleMaximized(maximized); | |
400 } | |
401 | |
402 | |
403 private void setAllVisibleMaximized(bool maximized) | |
404 { | |
405 if(autoMaximize) // maximize or restore all shells | |
406 { | |
407 foreach(c; getChildren()) | |
408 { | |
409 if(cast(InternalShell)c !is null) | |
410 { | |
411 InternalShell ishell = cast(InternalShell)c; | |
412 if((ishell.getStyle() & DWT.MAX) !is 0 && ishell.isVisible()) | |
413 (cast(InternalShell)c).setMaximizedWithoutNotification(maximized); | |
414 } | |
415 } | |
416 } | |
417 } | |
418 | |
419 | |
420 private void activateNextShell() | |
421 { | |
422 if(activeShell is null) | |
423 { | |
424 activateTopmostVisibleShellExcept(null); | |
425 return; | |
426 } | |
427 if(visibleShells.length < 2) return; | |
428 InternalShell topReg = getTopmostRegularShell(); | |
429 InternalShell botTop = getBottommostOnTopShell(); | |
430 if((activeShell.getStyle() & DWT.ON_TOP) !is 0) | |
431 { | |
432 activeShell.moveBelow(botTop); | |
433 if(topReg !is null) activate(topReg); | |
434 else activateTopmostVisibleShellExcept(null); | |
435 } | |
436 else | |
437 { | |
438 activeShell.moveBelow(null); | |
439 activateTopmostVisibleShellExcept(null); | |
440 } | |
441 } | |
442 | |
443 | |
444 private void activatePreviousShell() | |
445 { | |
446 if(activeShell is null) | |
447 { | |
448 activateTopmostVisibleShellExcept(null); | |
449 return; | |
450 } | |
451 if(visibleShells.length < 2) return; | |
452 InternalShell topReg = getTopmostRegularShell(); | |
453 InternalShell botTop = getBottommostOnTopShell(); | |
454 if(activeShell is topReg && botTop !is null) activate(botTop); | |
455 else | |
456 { | |
457 Control[] ch = getChildren(); | |
458 for(int i=ch.length-1; i>=0; i--) | |
459 { | |
460 if(cast(InternalShell)ch[i] !is null && ch[i].isVisible()) | |
461 { | |
462 activate(cast(InternalShell)ch[i]); | |
463 break; | |
464 } | |
465 } | |
466 } | |
467 } | |
468 | |
469 | |
470 public void addDesktopListener(DesktopListener l) | |
471 { | |
472 desktopListeners ~= l; | |
473 } | |
474 | |
475 | |
476 public void removeDesktopListener(DesktopListener l) | |
477 { | |
478 desktopListeners.remove(l); | |
479 } | |
480 | |
481 | |
482 private void notifyDesktopListenersCreate(InternalShell ishell) | |
483 { | |
484 Event event = new Event(); | |
485 event.widget = ishell; | |
486 foreach(l; desktopListeners) l.shellCreated(event); | |
487 } | |
488 | |
489 | |
490 private void notifyDesktopListenersDispose(InternalShell ishell) | |
491 { | |
492 Event event = new Event(); | |
493 event.widget = ishell; | |
494 foreach(l; desktopListeners) l.shellDisposed(event); | |
495 } | |
496 | |
497 | |
498 private void notifyDesktopListenersActivate(InternalShell ishell) | |
499 { | |
500 Event event = new Event(); | |
501 event.widget = ishell; | |
502 foreach(l; desktopListeners) l.shellActivated(event); | |
503 } | |
504 | |
505 | |
506 private bool hasVisibleMaximizedShell() | |
507 { | |
508 foreach(ins; visibleShells) | |
509 if(ins.getMaximized()) return true; | |
510 return false; | |
511 } | |
512 } |