Mercurial > projects > dwt-mac
comparison dwt/widgets/Composite.d @ 0:380af2bdd8e5
Upload of whole dwt tree
author | Jacob Carlborg <doob@me.com> <jacob.carlborg@gmail.com> |
---|---|
date | Sat, 09 Aug 2008 17:00:02 +0200 |
parents | |
children | 649b8e223d5a |
comparison
equal
deleted
inserted
replaced
-1:000000000000 | 0:380af2bdd8e5 |
---|---|
1 /******************************************************************************* | |
2 * Copyright (c) 2000, 2007 IBM Corporation 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.eclipse.org/legal/epl-v10.html | |
7 * | |
8 * Contributors: | |
9 * IBM Corporation - initial API and implementation | |
10 *******************************************************************************/ | |
11 module dwt.widgets.Composite; | |
12 | |
13 import dwt.dwthelper.utils; | |
14 | |
15 | |
16 import dwt.DWT; | |
17 import dwt.DWTException; | |
18 import dwt.graphics.Point; | |
19 import dwt.graphics.Rectangle; | |
20 import dwt.internal.cocoa.NSArray; | |
21 import dwt.internal.cocoa.NSEvent; | |
22 import dwt.internal.cocoa.NSRect; | |
23 import dwt.internal.cocoa.NSView; | |
24 import dwt.internal.cocoa.OS; | |
25 import dwt.internal.cocoa.SWTScrollView; | |
26 import dwt.internal.cocoa.SWTView; | |
27 | |
28 /** | |
29 * Instances of this class are controls which are capable | |
30 * of containing other controls. | |
31 * <dl> | |
32 * <dt><b>Styles:</b></dt> | |
33 * <dd>NO_BACKGROUND, NO_FOCUS, NO_MERGE_PAINTS, NO_REDRAW_RESIZE, NO_RADIO_GROUP, EMBEDDED, DOUBLE_BUFFERED</dd> | |
34 * <dt><b>Events:</b></dt> | |
35 * <dd>(none)</dd> | |
36 * </dl> | |
37 * <p> | |
38 * Note: The <code>NO_BACKGROUND</code>, <code>NO_FOCUS</code>, <code>NO_MERGE_PAINTS</code>, | |
39 * and <code>NO_REDRAW_RESIZE</code> styles are intended for use with <code>Canvas</code>. | |
40 * They can be used with <code>Composite</code> if you are drawing your own, but their | |
41 * behavior is undefined if they are used with subclasses of <code>Composite</code> other | |
42 * than <code>Canvas</code>. | |
43 * </p><p> | |
44 * Note: The <code>CENTER</code> style, although undefined for composites, has the | |
45 * same value as <code>EMBEDDED</code> (which is used to embed widgets from other | |
46 * widget toolkits into DWT). On some operating systems (GTK, Motif), this may cause | |
47 * the children of this composite to be obscured. The <code>EMBEDDED</code> style | |
48 * is for use by other widget toolkits and should normally never be used. | |
49 * </p><p> | |
50 * This class may be subclassed by custom control implementors | |
51 * who are building controls that are constructed from aggregates | |
52 * of other controls. | |
53 * </p> | |
54 * | |
55 * @see Canvas | |
56 */ | |
57 public class Composite extends Scrollable { | |
58 Layout layout; | |
59 Control[] tabList; | |
60 int scrolledVisibleRgn, siblingsVisibleRgn; | |
61 int layoutCount, backgroundMode; | |
62 | |
63 Composite () { | |
64 /* Do nothing */ | |
65 } | |
66 | |
67 /** | |
68 * Constructs a new instance of this class given its parent | |
69 * and a style value describing its behavior and appearance. | |
70 * <p> | |
71 * The style value is either one of the style constants defined in | |
72 * class <code>DWT</code> which is applicable to instances of this | |
73 * class, or must be built by <em>bitwise OR</em>'ing together | |
74 * (that is, using the <code>int</code> "|" operator) two or more | |
75 * of those <code>DWT</code> style constants. The class description | |
76 * lists the style constants that are applicable to the class. | |
77 * Style bits are also inherited from superclasses. | |
78 * </p> | |
79 * | |
80 * @param parent a widget which will be the parent of the new instance (cannot be null) | |
81 * @param style the style of widget to construct | |
82 * | |
83 * @exception IllegalArgumentException <ul> | |
84 * <li>ERROR_NULL_ARGUMENT - if the parent is null</li> | |
85 * </ul> | |
86 * @exception DWTException <ul> | |
87 * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the parent</li> | |
88 * </ul> | |
89 * | |
90 * @see DWT#NO_BACKGROUND | |
91 * @see DWT#NO_FOCUS | |
92 * @see DWT#NO_MERGE_PAINTS | |
93 * @see DWT#NO_REDRAW_RESIZE | |
94 * @see DWT#NO_RADIO_GROUP | |
95 * @see Widget#getStyle | |
96 */ | |
97 public Composite (Composite parent, int style) { | |
98 super (parent, style); | |
99 } | |
100 | |
101 Control [] _getChildren () { | |
102 NSArray views = contentView().subviews(); | |
103 int count = views.count(); | |
104 Control [] children = new Control [count]; | |
105 int j = 0; | |
106 for (int i=0; i<count; i++){ | |
107 int tag = new NSView(views.objectAtIndex(i)).tag(); | |
108 if (tag !is 0 && tag !is -1) { | |
109 Object widget = OS.JNIGetObject(tag); | |
110 if (widget !is null && widget !is this) { | |
111 if (widget instanceof Control) { | |
112 children [j++] = (Control) widget; | |
113 } | |
114 } | |
115 } | |
116 } | |
117 if (j is count) return children; | |
118 Control [] newChildren = new Control [j]; | |
119 System.arraycopy (children, 0, newChildren, 0, j); | |
120 return newChildren; | |
121 } | |
122 | |
123 Control [] _getTabList () { | |
124 if (tabList is null) return null; | |
125 int count = 0; | |
126 for (int i=0; i<tabList.length; i++) { | |
127 if (!tabList [i].isDisposed ()) count++; | |
128 } | |
129 if (count is tabList.length) return tabList; | |
130 Control [] newList = new Control [count]; | |
131 int index = 0; | |
132 for (int i=0; i<tabList.length; i++) { | |
133 if (!tabList [i].isDisposed ()) { | |
134 newList [index++] = tabList [i]; | |
135 } | |
136 } | |
137 tabList = newList; | |
138 return tabList; | |
139 } | |
140 | |
141 bool acceptsFirstResponder () { | |
142 if ((state & CANVAS) !is 0) { | |
143 return ((style & DWT.NO_FOCUS) is 0); | |
144 } | |
145 return super.acceptsFirstResponder (); | |
146 } | |
147 | |
148 | |
149 /** | |
150 * Clears any data that has been cached by a Layout for all widgets that | |
151 * are in the parent hierarchy of the changed control up to and including the | |
152 * receiver. If an ancestor does not have a layout, it is skipped. | |
153 * | |
154 * @param changed an array of controls that changed state and require a recalculation of size | |
155 * | |
156 * @exception IllegalArgumentException <ul> | |
157 * <li>ERROR_INVALID_ARGUMENT - if the changed array is null any of its controls are null or have been disposed</li> | |
158 * <li>ERROR_INVALID_PARENT - if any control in changed is not in the widget tree of the receiver</li> | |
159 * </ul> | |
160 * @exception DWTException <ul> | |
161 * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li> | |
162 * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li> | |
163 * </ul> | |
164 * | |
165 * @since 3.1 | |
166 */ | |
167 public void changed (Control[] changed) { | |
168 checkWidget (); | |
169 if (changed is null) error (DWT.ERROR_INVALID_ARGUMENT); | |
170 for (int i=0; i<changed.length; i++) { | |
171 Control control = changed [i]; | |
172 if (control is null) error (DWT.ERROR_INVALID_ARGUMENT); | |
173 if (control.isDisposed ()) error (DWT.ERROR_INVALID_ARGUMENT); | |
174 bool ancestor = false; | |
175 Composite composite = control.parent; | |
176 while (composite !is null) { | |
177 ancestor = composite is this; | |
178 if (ancestor) break; | |
179 composite = composite.parent; | |
180 } | |
181 if (!ancestor) error (DWT.ERROR_INVALID_PARENT); | |
182 } | |
183 for (int i=0; i<changed.length; i++) { | |
184 Control child = changed [i]; | |
185 Composite composite = child.parent; | |
186 while (child !is this) { | |
187 if (composite.layout is null || !composite.layout.flushCache (child)) { | |
188 composite.state |= LAYOUT_CHANGED; | |
189 } | |
190 child = composite; | |
191 composite = child.parent; | |
192 } | |
193 } | |
194 } | |
195 | |
196 public Point computeSize (int wHint, int hHint, bool changed) { | |
197 checkWidget(); | |
198 Point size; | |
199 if (layout !is null) { | |
200 if ((wHint is DWT.DEFAULT) || (hHint is DWT.DEFAULT)) { | |
201 changed |= (state & LAYOUT_CHANGED) !is 0; | |
202 size = layout.computeSize (this, wHint, hHint, changed); | |
203 state &= ~LAYOUT_CHANGED; | |
204 } else { | |
205 size = new Point (wHint, hHint); | |
206 } | |
207 } else { | |
208 size = minimumSize (wHint, hHint, changed); | |
209 } | |
210 if (size.x is 0) size.x = DEFAULT_WIDTH; | |
211 if (size.y is 0) size.y = DEFAULT_HEIGHT; | |
212 if (wHint !is DWT.DEFAULT) size.x = wHint; | |
213 if (hHint !is DWT.DEFAULT) size.y = hHint; | |
214 Rectangle trim = computeTrim (0, 0, size.x, size.y); | |
215 return new Point (trim.width, trim.height); | |
216 } | |
217 | |
218 protected void checkSubclass () { | |
219 /* Do nothing - Subclassing is allowed */ | |
220 } | |
221 | |
222 Control [] computeTabList () { | |
223 Control result [] = super.computeTabList (); | |
224 if (result.length is 0) return result; | |
225 Control [] list = tabList !is null ? _getTabList () : _getChildren (); | |
226 for (int i=0; i<list.length; i++) { | |
227 Control child = list [i]; | |
228 Control [] childList = child.computeTabList (); | |
229 if (childList.length !is 0) { | |
230 Control [] newResult = new Control [result.length + childList.length]; | |
231 System.arraycopy (result, 0, newResult, 0, result.length); | |
232 System.arraycopy (childList, 0, newResult, result.length, childList.length); | |
233 result = newResult; | |
234 } | |
235 } | |
236 return result; | |
237 } | |
238 | |
239 NSView contentView () { | |
240 return view; | |
241 } | |
242 | |
243 void createHandle () { | |
244 createHandle (parent.contentView()); | |
245 } | |
246 | |
247 void createHandle (NSView parent) { | |
248 state |= CANVAS; | |
249 NSRect rect = new NSRect(); | |
250 if ((style & (DWT.V_SCROLL | DWT.H_SCROLL)) !is 0 || hasBorder ()) { | |
251 SWTScrollView scrollWidget = (SWTScrollView)new SWTScrollView().alloc(); | |
252 scrollWidget.initWithFrame (rect); | |
253 scrollWidget.setDrawsBackground(false); | |
254 if ((style & DWT.H_SCROLL) !is 0) scrollWidget.setHasHorizontalScroller(true); | |
255 if ((style & DWT.V_SCROLL) !is 0) scrollWidget.setHasVerticalScroller(true); | |
256 scrollWidget.setBorderType(hasBorder() ? OS.NSBezelBorder : OS.NSNoBorder); | |
257 scrollWidget.setTag(jniRef); | |
258 scrollView = scrollWidget; | |
259 rect.width = rect.height = 100000; | |
260 } | |
261 SWTView widget = (SWTView)new SWTView().alloc(); | |
262 widget.initWithFrame (rect); | |
263 // widget.setFocusRingType(OS.NSFocusRingTypeExterior); | |
264 widget.setTag(jniRef); | |
265 view = widget; | |
266 if (scrollView !is null) { | |
267 // view.setAutoresizingMask (OS.NSViewWidthSizable | OS.NSViewHeightSizable); | |
268 scrollView.setDocumentView(view); | |
269 if (parent !is null) parent.addSubview_(scrollView); | |
270 } else { | |
271 if (parent !is null) parent.addSubview_(view); | |
272 } | |
273 } | |
274 | |
275 Composite findDeferredControl () { | |
276 return layoutCount > 0 ? this : parent.findDeferredControl (); | |
277 } | |
278 | |
279 Menu [] findMenus (Control control) { | |
280 if (control is this) return new Menu [0]; | |
281 Menu result [] = super.findMenus (control); | |
282 Control [] children = _getChildren (); | |
283 for (int i=0; i<children.length; i++) { | |
284 Control child = children [i]; | |
285 Menu [] menuList = child.findMenus (control); | |
286 if (menuList.length !is 0) { | |
287 Menu [] newResult = new Menu [result.length + menuList.length]; | |
288 System.arraycopy (result, 0, newResult, 0, result.length); | |
289 System.arraycopy (menuList, 0, newResult, result.length, menuList.length); | |
290 result = newResult; | |
291 } | |
292 } | |
293 return result; | |
294 } | |
295 | |
296 void fixChildren (Shell newShell, Shell oldShell, Decorations newDecorations, Decorations oldDecorations, Menu [] menus) { | |
297 super.fixChildren (newShell, oldShell, newDecorations, oldDecorations, menus); | |
298 Control [] children = _getChildren (); | |
299 for (int i=0; i<children.length; i++) { | |
300 children [i].fixChildren (newShell, oldShell, newDecorations, oldDecorations, menus); | |
301 } | |
302 } | |
303 | |
304 void fixTabList (Control control) { | |
305 if (tabList is null) return; | |
306 int count = 0; | |
307 for (int i=0; i<tabList.length; i++) { | |
308 if (tabList [i] is control) count++; | |
309 } | |
310 if (count is 0) return; | |
311 Control [] newList = null; | |
312 int length = tabList.length - count; | |
313 if (length !is 0) { | |
314 newList = new Control [length]; | |
315 int index = 0; | |
316 for (int i=0; i<tabList.length; i++) { | |
317 if (tabList [i] !is control) { | |
318 newList [index++] = tabList [i]; | |
319 } | |
320 } | |
321 } | |
322 tabList = newList; | |
323 } | |
324 | |
325 /** | |
326 * Returns the receiver's background drawing mode. This | |
327 * will be one of the following constants defined in class | |
328 * <code>DWT</code>: | |
329 * <code>INHERIT_NONE</code>, <code>INHERIT_DEFAULT</code>, | |
330 * <code>INHERTIT_FORCE</code>. | |
331 * | |
332 * @return the background mode | |
333 * | |
334 * @exception DWTException <ul> | |
335 * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li> | |
336 * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li> | |
337 * </ul> | |
338 * | |
339 * @see DWT | |
340 * | |
341 * @since 3.2 | |
342 */ | |
343 public int getBackgroundMode () { | |
344 checkWidget (); | |
345 return backgroundMode; | |
346 } | |
347 | |
348 /** | |
349 * Returns a (possibly empty) array containing the receiver's children. | |
350 * Children are returned in the order that they are drawn. The topmost | |
351 * control appears at the beginning of the array. Subsequent controls | |
352 * draw beneath this control and appear later in the array. | |
353 * <p> | |
354 * Note: This is not the actual structure used by the receiver | |
355 * to maintain its list of children, so modifying the array will | |
356 * not affect the receiver. | |
357 * </p> | |
358 * | |
359 * @return an array of children | |
360 * | |
361 * @see Control#moveAbove | |
362 * @see Control#moveBelow | |
363 * | |
364 * @exception DWTException <ul> | |
365 * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li> | |
366 * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li> | |
367 * </ul> | |
368 */ | |
369 public Control [] getChildren () { | |
370 checkWidget(); | |
371 return _getChildren (); | |
372 } | |
373 | |
374 int getChildrenCount () { | |
375 /* | |
376 * NOTE: The current implementation will count | |
377 * non-registered children. | |
378 */ | |
379 // short [] count = new short [1]; | |
380 // OS.CountSubControls (handle, count); | |
381 // return count [0]; | |
382 return 0; | |
383 } | |
384 | |
385 /** | |
386 * Returns layout which is associated with the receiver, or | |
387 * null if one has not been set. | |
388 * | |
389 * @return the receiver's layout or null | |
390 * | |
391 * @exception DWTException <ul> | |
392 * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li> | |
393 * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li> | |
394 * </ul> | |
395 */ | |
396 public Layout getLayout () { | |
397 checkWidget(); | |
398 return layout; | |
399 } | |
400 | |
401 /** | |
402 * Returns <code>true</code> if the receiver has deferred | |
403 * the performing of layout, and <code>false</code> otherwise. | |
404 * | |
405 * @return the receiver's deferred layout state | |
406 * | |
407 * @exception DWTException <ul> | |
408 * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li> | |
409 * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li> | |
410 * </ul> | |
411 * | |
412 * @see #setLayoutDeferred(bool) | |
413 * @see #isLayoutDeferred() | |
414 * | |
415 * @since 3.1 | |
416 */ | |
417 public bool getLayoutDeferred () { | |
418 checkWidget (); | |
419 return layoutCount > 0 ; | |
420 } | |
421 | |
422 /** | |
423 * Gets the (possibly empty) tabbing order for the control. | |
424 * | |
425 * @return tabList the ordered list of controls representing the tab order | |
426 * | |
427 * @exception DWTException <ul> | |
428 * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li> | |
429 * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li> | |
430 * </ul> | |
431 * | |
432 * @see #setTabList | |
433 */ | |
434 public Control [] getTabList () { | |
435 checkWidget (); | |
436 Control [] tabList = _getTabList (); | |
437 if (tabList is null) { | |
438 int count = 0; | |
439 Control [] list =_getChildren (); | |
440 for (int i=0; i<list.length; i++) { | |
441 if (list [i].isTabGroup ()) count++; | |
442 } | |
443 tabList = new Control [count]; | |
444 int index = 0; | |
445 for (int i=0; i<list.length; i++) { | |
446 if (list [i].isTabGroup ()) { | |
447 tabList [index++] = list [i]; | |
448 } | |
449 } | |
450 } | |
451 return tabList; | |
452 } | |
453 | |
454 bool hooksKeys () { | |
455 return hooks (DWT.KeyDown) || hooks (DWT.KeyUp); | |
456 } | |
457 | |
458 /** | |
459 * Returns <code>true</code> if the receiver or any ancestor | |
460 * up to and including the receiver's nearest ancestor shell | |
461 * has deferred the performing of layouts. Otherwise, <code>false</code> | |
462 * is returned. | |
463 * | |
464 * @return the receiver's deferred layout state | |
465 * | |
466 * @exception DWTException <ul> | |
467 * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li> | |
468 * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li> | |
469 * </ul> | |
470 * | |
471 * @see #setLayoutDeferred(bool) | |
472 * @see #getLayoutDeferred() | |
473 * | |
474 * @since 3.1 | |
475 */ | |
476 public bool isLayoutDeferred () { | |
477 checkWidget (); | |
478 return findDeferredControl () !is null; | |
479 } | |
480 | |
481 bool isTabGroup () { | |
482 if ((state & CANVAS) !is 0) return true; | |
483 return super.isTabGroup (); | |
484 } | |
485 | |
486 /** | |
487 * If the receiver has a layout, asks the layout to <em>lay out</em> | |
488 * (that is, set the size and location of) the receiver's children. | |
489 * If the receiver does not have a layout, do nothing. | |
490 * <p> | |
491 * This is equivalent to calling <code>layout(true)</code>. | |
492 * </p> | |
493 * <p> | |
494 * Note: Layout is different from painting. If a child is | |
495 * moved or resized such that an area in the parent is | |
496 * exposed, then the parent will paint. If no child is | |
497 * affected, the parent will not paint. | |
498 * </p> | |
499 * | |
500 * @exception DWTException <ul> | |
501 * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li> | |
502 * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li> | |
503 * </ul> | |
504 */ | |
505 public void layout () { | |
506 checkWidget (); | |
507 layout (true); | |
508 } | |
509 | |
510 /** | |
511 * If the receiver has a layout, asks the layout to <em>lay out</em> | |
512 * (that is, set the size and location of) the receiver's children. | |
513 * If the argument is <code>true</code> the layout must not rely | |
514 * on any information it has cached about the immediate children. If it | |
515 * is <code>false</code> the layout may (potentially) optimize the | |
516 * work it is doing by assuming that none of the receiver's | |
517 * children has changed state since the last layout. | |
518 * If the receiver does not have a layout, do nothing. | |
519 * <p> | |
520 * If a child is resized as a result of a call to layout, the | |
521 * resize event will invoke the layout of the child. The layout | |
522 * will cascade down through all child widgets in the receiver's widget | |
523 * tree until a child is encountered that does not resize. Note that | |
524 * a layout due to a resize will not flush any cached information | |
525 * (same as <code>layout(false)</code>). | |
526 * </p> | |
527 * <p> | |
528 * Note: Layout is different from painting. If a child is | |
529 * moved or resized such that an area in the parent is | |
530 * exposed, then the parent will paint. If no child is | |
531 * affected, the parent will not paint. | |
532 * </p> | |
533 * | |
534 * @param changed <code>true</code> if the layout must flush its caches, and <code>false</code> otherwise | |
535 * | |
536 * @exception DWTException <ul> | |
537 * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li> | |
538 * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li> | |
539 * </ul> | |
540 */ | |
541 public void layout (bool changed) { | |
542 checkWidget (); | |
543 if (layout is null) return; | |
544 layout (changed, false); | |
545 } | |
546 | |
547 /** | |
548 * If the receiver has a layout, asks the layout to <em>lay out</em> | |
549 * (that is, set the size and location of) the receiver's children. | |
550 * If the changed argument is <code>true</code> the layout must not rely | |
551 * on any information it has cached about its children. If it | |
552 * is <code>false</code> the layout may (potentially) optimize the | |
553 * work it is doing by assuming that none of the receiver's | |
554 * children has changed state since the last layout. | |
555 * If the all argument is <code>true</code> the layout will cascade down | |
556 * through all child widgets in the receiver's widget tree, regardless of | |
557 * whether the child has changed size. The changed argument is applied to | |
558 * all layouts. If the all argument is <code>false</code>, the layout will | |
559 * <em>not</em> cascade down through all child widgets in the receiver's widget | |
560 * tree. However, if a child is resized as a result of a call to layout, the | |
561 * resize event will invoke the layout of the child. Note that | |
562 * a layout due to a resize will not flush any cached information | |
563 * (same as <code>layout(false)</code>). | |
564 * </p> | |
565 * <p> | |
566 * Note: Layout is different from painting. If a child is | |
567 * moved or resized such that an area in the parent is | |
568 * exposed, then the parent will paint. If no child is | |
569 * affected, the parent will not paint. | |
570 * </p> | |
571 * | |
572 * @param changed <code>true</code> if the layout must flush its caches, and <code>false</code> otherwise | |
573 * @param all <code>true</code> if all children in the receiver's widget tree should be laid out, and <code>false</code> otherwise | |
574 * | |
575 * @exception DWTException <ul> | |
576 * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li> | |
577 * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li> | |
578 * </ul> | |
579 * | |
580 * @since 3.1 | |
581 */ | |
582 public void layout (bool changed, bool all) { | |
583 checkWidget (); | |
584 if (layout is null && !all) return; | |
585 markLayout (changed, all); | |
586 updateLayout (all); | |
587 } | |
588 | |
589 /** | |
590 * Forces a lay out (that is, sets the size and location) of all widgets that | |
591 * are in the parent hierarchy of the changed control up to and including the | |
592 * receiver. The layouts in the hierarchy must not rely on any information | |
593 * cached about the changed control or any of its ancestors. The layout may | |
594 * (potentially) optimize the work it is doing by assuming that none of the | |
595 * peers of the changed control have changed state since the last layout. | |
596 * If an ancestor does not have a layout, skip it. | |
597 * <p> | |
598 * Note: Layout is different from painting. If a child is | |
599 * moved or resized such that an area in the parent is | |
600 * exposed, then the parent will paint. If no child is | |
601 * affected, the parent will not paint. | |
602 * </p> | |
603 * | |
604 * @param changed a control that has had a state change which requires a recalculation of its size | |
605 * | |
606 * @exception IllegalArgumentException <ul> | |
607 * <li>ERROR_INVALID_ARGUMENT - if the changed array is null any of its controls are null or have been disposed</li> | |
608 * <li>ERROR_INVALID_PARENT - if any control in changed is not in the widget tree of the receiver</li> | |
609 * </ul> | |
610 * @exception DWTException <ul> | |
611 * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li> | |
612 * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li> | |
613 * </ul> | |
614 * | |
615 * @since 3.1 | |
616 */ | |
617 public void layout (Control [] changed) { | |
618 checkWidget (); | |
619 if (changed is null) error (DWT.ERROR_INVALID_ARGUMENT); | |
620 for (int i=0; i<changed.length; i++) { | |
621 Control control = changed [i]; | |
622 if (control is null) error (DWT.ERROR_INVALID_ARGUMENT); | |
623 if (control.isDisposed ()) error (DWT.ERROR_INVALID_ARGUMENT); | |
624 bool ancestor = false; | |
625 Composite composite = control.parent; | |
626 while (composite !is null) { | |
627 ancestor = composite is this; | |
628 if (ancestor) break; | |
629 composite = composite.parent; | |
630 } | |
631 if (!ancestor) error (DWT.ERROR_INVALID_PARENT); | |
632 } | |
633 int updateCount = 0; | |
634 Composite [] update = new Composite [16]; | |
635 for (int i=0; i<changed.length; i++) { | |
636 Control child = changed [i]; | |
637 Composite composite = child.parent; | |
638 while (child !is this) { | |
639 if (composite.layout !is null) { | |
640 composite.state |= LAYOUT_NEEDED; | |
641 if (!composite.layout.flushCache (child)) { | |
642 composite.state |= LAYOUT_CHANGED; | |
643 } | |
644 } | |
645 if (updateCount is update.length) { | |
646 Composite [] newUpdate = new Composite [update.length + 16]; | |
647 System.arraycopy (update, 0, newUpdate, 0, update.length); | |
648 update = newUpdate; | |
649 } | |
650 child = update [updateCount++] = composite; | |
651 composite = child.parent; | |
652 } | |
653 } | |
654 for (int i=updateCount-1; i>=0; i--) { | |
655 update [i].updateLayout (false); | |
656 } | |
657 } | |
658 | |
659 void markLayout (bool changed, bool all) { | |
660 if (layout !is null) { | |
661 state |= LAYOUT_NEEDED; | |
662 if (changed) state |= LAYOUT_CHANGED; | |
663 } | |
664 if (all) { | |
665 Control [] children = _getChildren (); | |
666 for (int i=0; i<children.length; i++) { | |
667 children [i].markLayout (changed, all); | |
668 } | |
669 } | |
670 } | |
671 | |
672 Point minimumSize (int wHint, int Hint, bool changed) { | |
673 Control [] children = _getChildren (); | |
674 int width = 0, height = 0; | |
675 for (int i=0; i<children.length; i++) { | |
676 Rectangle rect = children [i].getBounds (); | |
677 width = Math.max (width, rect.x + rect.width); | |
678 height = Math.max (height, rect.y + rect.height); | |
679 } | |
680 return new Point (width, height); | |
681 } | |
682 | |
683 void releaseChildren (bool destroy) { | |
684 Control [] children = _getChildren (); | |
685 for (int i=0; i<children.length; i++) { | |
686 Control child = children [i]; | |
687 if (child !is null && !child.isDisposed ()) { | |
688 child.release (false); | |
689 } | |
690 } | |
691 super.releaseChildren (destroy); | |
692 } | |
693 | |
694 void releaseWidget () { | |
695 super.releaseWidget (); | |
696 layout = null; | |
697 tabList = null; | |
698 } | |
699 | |
700 void removeControl (Control control) { | |
701 fixTabList (control); | |
702 } | |
703 | |
704 /** | |
705 * Sets the background drawing mode to the argument which should | |
706 * be one of the following constants defined in class <code>DWT</code>: | |
707 * <code>INHERIT_NONE</code>, <code>INHERIT_DEFAULT</code>, | |
708 * <code>INHERIT_FORCE</code>. | |
709 * | |
710 * @param mode the new background mode | |
711 * | |
712 * @exception DWTException <ul> | |
713 * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li> | |
714 * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li> | |
715 * </ul> | |
716 * | |
717 * @see DWT | |
718 * | |
719 * @since 3.2 | |
720 */ | |
721 public void setBackgroundMode (int mode) { | |
722 checkWidget (); | |
723 backgroundMode = mode; | |
724 Control [] children = _getChildren (); | |
725 for (int i = 0; i < children.length; i++) { | |
726 children [i].updateBackgroundMode (); | |
727 } | |
728 } | |
729 | |
730 int setBounds (int x, int y, int width, int height, bool move, bool resize) { | |
731 int result = super.setBounds (x, y, width, height, move, resize); | |
732 if (layout !is null && (result & RESIZED) !is 0) { | |
733 markLayout (false, false); | |
734 updateLayout (false); | |
735 } | |
736 return result; | |
737 } | |
738 | |
739 public bool setFocus () { | |
740 checkWidget (); | |
741 Control [] children = _getChildren (); | |
742 for (int i= 0; i < children.length; i++) { | |
743 if (children [i].setFocus ()) return true; | |
744 } | |
745 return super.setFocus (); | |
746 } | |
747 | |
748 /** | |
749 * Sets the layout which is associated with the receiver to be | |
750 * the argument which may be null. | |
751 * | |
752 * @param layout the receiver's new layout or null | |
753 * | |
754 * @exception DWTException <ul> | |
755 * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li> | |
756 * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li> | |
757 * </ul> | |
758 */ | |
759 public void setLayout (Layout layout) { | |
760 checkWidget(); | |
761 this.layout = layout; | |
762 } | |
763 | |
764 /** | |
765 * If the argument is <code>true</code>, causes subsequent layout | |
766 * operations in the receiver or any of its children to be ignored. | |
767 * No layout of any kind can occur in the receiver or any of its | |
768 * children until the flag is set to false. | |
769 * Layout operations that occurred while the flag was | |
770 * <code>true</code> are remembered and when the flag is set to | |
771 * <code>false</code>, the layout operations are performed in an | |
772 * optimized manner. Nested calls to this method are stacked. | |
773 * | |
774 * @param defer the new defer state | |
775 * | |
776 * @exception DWTException <ul> | |
777 * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li> | |
778 * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li> | |
779 * </ul> | |
780 * | |
781 * @see #layout(bool) | |
782 * @see #layout(Control[]) | |
783 * | |
784 * @since 3.1 | |
785 */ | |
786 public void setLayoutDeferred (bool defer) { | |
787 if (!defer) { | |
788 if (--layoutCount is 0) { | |
789 if ((state & LAYOUT_CHILD) !is 0 || (state & LAYOUT_NEEDED) !is 0) { | |
790 updateLayout (true); | |
791 } | |
792 } | |
793 } else { | |
794 layoutCount++; | |
795 } | |
796 } | |
797 | |
798 | |
799 bool setScrollBarVisible (ScrollBar bar, bool visible) { | |
800 bool changed = super.setScrollBarVisible (bar, visible); | |
801 if (changed && layout !is null) { | |
802 markLayout (false, false); | |
803 updateLayout (false); | |
804 } | |
805 return changed; | |
806 } | |
807 | |
808 bool setTabGroupFocus () { | |
809 if (isTabItem ()) return setTabItemFocus (); | |
810 bool takeFocus = (style & DWT.NO_FOCUS) is 0; | |
811 if ((state & CANVAS) !is 0) takeFocus = hooksKeys (); | |
812 if (takeFocus && setTabItemFocus ()) return true; | |
813 Control [] children = _getChildren (); | |
814 for (int i=0; i<children.length; i++) { | |
815 Control child = children [i]; | |
816 if (child.isTabItem () && child.setTabItemFocus ()) return true; | |
817 } | |
818 return false; | |
819 } | |
820 | |
821 /** | |
822 * Sets the tabbing order for the specified controls to | |
823 * match the order that they occur in the argument list. | |
824 * | |
825 * @param tabList the ordered list of controls representing the tab order or null | |
826 * | |
827 * @exception IllegalArgumentException <ul> | |
828 * <li>ERROR_INVALID_ARGUMENT - if a widget in the tabList is null or has been disposed</li> | |
829 * <li>ERROR_INVALID_PARENT - if widget in the tabList is not in the same widget tree</li> | |
830 * </ul> | |
831 * @exception DWTException <ul> | |
832 * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li> | |
833 * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li> | |
834 * </ul> | |
835 */ | |
836 public void setTabList (Control [] tabList) { | |
837 checkWidget (); | |
838 if (tabList !is null) { | |
839 for (int i=0; i<tabList.length; i++) { | |
840 Control control = tabList [i]; | |
841 if (control is null) error (DWT.ERROR_INVALID_ARGUMENT); | |
842 if (control.isDisposed ()) error (DWT.ERROR_INVALID_ARGUMENT); | |
843 if (control.parent !is this) error (DWT.ERROR_INVALID_PARENT); | |
844 } | |
845 Control [] newList = new Control [tabList.length]; | |
846 System.arraycopy (tabList, 0, newList, 0, tabList.length); | |
847 tabList = newList; | |
848 } | |
849 this.tabList = tabList; | |
850 } | |
851 | |
852 int traversalCode (int key, NSEvent theEvent) { | |
853 if ((state & CANVAS) !is 0) { | |
854 if ((style & DWT.NO_FOCUS) !is 0) return 0; | |
855 if (hooksKeys ()) return 0; | |
856 } | |
857 return super.traversalCode (key, theEvent); | |
858 } | |
859 | |
860 void updateBackgroundMode () { | |
861 super.updateBackgroundMode (); | |
862 Control [] children = _getChildren (); | |
863 for (int i = 0; i < children.length; i++) { | |
864 children [i].updateBackgroundMode (); | |
865 } | |
866 } | |
867 | |
868 void updateLayout (bool all) { | |
869 Composite parent = findDeferredControl (); | |
870 if (parent !is null) { | |
871 parent.state |= LAYOUT_CHILD; | |
872 return; | |
873 } | |
874 if ((state & LAYOUT_NEEDED) !is 0) { | |
875 bool changed = (state & LAYOUT_CHANGED) !is 0; | |
876 state &= ~(LAYOUT_NEEDED | LAYOUT_CHANGED); | |
877 layout.layout (this, changed); | |
878 } | |
879 if (all) { | |
880 state &= ~LAYOUT_CHILD; | |
881 Control [] children = _getChildren (); | |
882 for (int i=0; i<children.length; i++) { | |
883 children [i].updateLayout (all); | |
884 } | |
885 } | |
886 } | |
887 | |
888 } |