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 }