]> gerrit.simantics Code Review - simantics/platform.git/blob - bundles/org.eclipse.swt.win32.win32.x86_64/src/org/eclipse/swt/widgets/ExpandBar.java
Remove invalid SHA-256-Digests
[simantics/platform.git] / bundles / org.eclipse.swt.win32.win32.x86_64 / src / org / eclipse / swt / widgets / ExpandBar.java
1 /*******************************************************************************
2  * Copyright (c) 2000, 2018 IBM Corporation and others.
3  *
4  * This program and the accompanying materials
5  * are made available under the terms of the Eclipse Public License 2.0
6  * which accompanies this distribution, and is available at
7  * https://www.eclipse.org/legal/epl-2.0/
8  *
9  * SPDX-License-Identifier: EPL-2.0
10  *
11  * Contributors:
12  *     IBM Corporation - initial API and implementation
13  *******************************************************************************/
14 package org.eclipse.swt.widgets;
15
16 import org.eclipse.swt.*;
17 import org.eclipse.swt.events.*;
18 import org.eclipse.swt.graphics.*;
19 import org.eclipse.swt.internal.*;
20 import org.eclipse.swt.internal.win32.*;
21
22 /**
23  * Instances of this class support the layout of selectable
24  * expand bar items.
25  * <p>
26  * The item children that may be added to instances of this class
27  * must be of type <code>ExpandItem</code>.
28  * </p>
29  * <dl>
30  * <dt><b>Styles:</b></dt>
31  * <dd>V_SCROLL</dd>
32  * <dt><b>Events:</b></dt>
33  * <dd>Expand, Collapse</dd>
34  * </dl>
35  * <p>
36  * IMPORTANT: This class is <em>not</em> intended to be subclassed.
37  * </p>
38  *
39  * @see ExpandItem
40  * @see ExpandEvent
41  * @see ExpandListener
42  * @see ExpandAdapter
43  * @see <a href="http://www.eclipse.org/swt/snippets/#expandbar">ExpandBar snippets</a>
44  * @see <a href="http://www.eclipse.org/swt/examples.php">SWT Example: ControlExample</a>
45  * @see <a href="http://www.eclipse.org/swt/">Sample code and further information</a>
46  *
47  * @since 3.2
48  * @noextend This class is not intended to be subclassed by clients.
49  */
50 public class ExpandBar extends Composite {
51         ExpandItem[] items;
52         int itemCount;
53         ExpandItem focusItem;
54         int spacing = 4;
55         int yCurrentScroll;
56         long hFont;
57
58
59 /**
60  * Constructs a new instance of this class given its parent
61  * and a style value describing its behavior and appearance.
62  * <p>
63  * The style value is either one of the style constants defined in
64  * class <code>SWT</code> which is applicable to instances of this
65  * class, or must be built by <em>bitwise OR</em>'ing together
66  * (that is, using the <code>int</code> "|" operator) two or more
67  * of those <code>SWT</code> style constants. The class description
68  * lists the style constants that are applicable to the class.
69  * Style bits are also inherited from superclasses.
70  * </p>
71  *
72  * @param parent a composite control which will be the parent of the new instance (cannot be null)
73  * @param style the style of control to construct
74  *
75  * @exception IllegalArgumentException <ul>
76  *    <li>ERROR_NULL_ARGUMENT - if the parent is null</li>
77  * </ul>
78  * @exception SWTException <ul>
79  *    <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the parent</li>
80  *    <li>ERROR_INVALID_SUBCLASS - if this class is not an allowed subclass</li>
81  * </ul>
82  *
83  * @see SWT#V_SCROLL
84  * @see Widget#checkSubclass
85  * @see Widget#getStyle
86  */
87 public ExpandBar (Composite parent, int style) {
88         super (parent, checkStyle (style));
89 }
90
91 /**
92  * Adds the listener to the collection of listeners who will
93  * be notified when an item in the receiver is expanded or collapsed
94  * by sending it one of the messages defined in the <code>ExpandListener</code>
95  * interface.
96  *
97  * @param listener the listener which should be notified
98  *
99  * @exception IllegalArgumentException <ul>
100  *    <li>ERROR_NULL_ARGUMENT - if the listener is null</li>
101  * </ul>
102  * @exception SWTException <ul>
103  *    <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
104  *    <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
105  * </ul>
106  *
107  * @see ExpandListener
108  * @see #removeExpandListener
109  */
110 public void addExpandListener (ExpandListener listener) {
111         checkWidget ();
112         if (listener == null) error (SWT.ERROR_NULL_ARGUMENT);
113         TypedListener typedListener = new TypedListener (listener);
114         addListener (SWT.Expand, typedListener);
115         addListener (SWT.Collapse, typedListener);
116 }
117
118 @Override
119 long callWindowProc (long hwnd, int msg, long wParam, long lParam) {
120         if (handle == 0) return 0;
121         return OS.DefWindowProc (hwnd, msg, wParam, lParam);
122 }
123
124 @Override
125 protected void checkSubclass () {
126         if (!isValidSubclass ()) error (SWT.ERROR_INVALID_SUBCLASS);
127 }
128
129 static int checkStyle (int style) {
130         style &= ~SWT.H_SCROLL;
131         return style | SWT.NO_BACKGROUND;
132 }
133
134 @Override Point computeSizeInPixels (int wHint, int hHint, boolean changed) {
135         int height = 0, width = 0;
136         if (wHint == SWT.DEFAULT || hHint == SWT.DEFAULT) {
137                 if (itemCount > 0) {
138                         long hDC = OS.GetDC (handle);
139                         long hTheme = 0;
140                         if (isAppThemed ()) {
141                                 hTheme = display.hExplorerBarTheme ();
142                         }
143                         long hCurrentFont = 0, oldFont = 0;
144                         if (hTheme == 0) {
145                                 if (hFont != 0) {
146                                         hCurrentFont = hFont;
147                                 } else {
148                                         NONCLIENTMETRICS info = new NONCLIENTMETRICS ();
149                                         info.cbSize = NONCLIENTMETRICS.sizeof;
150                                         if (OS.SystemParametersInfo (OS.SPI_GETNONCLIENTMETRICS, 0, info, 0)) {
151                                                 LOGFONT logFont = info.lfCaptionFont;
152                                                 hCurrentFont = OS.CreateFontIndirect (logFont);
153                                         }
154                                 }
155                                 if (hCurrentFont != 0) {
156                                         oldFont = OS.SelectObject (hDC, hCurrentFont);
157                                 }
158                         }
159                         height += spacing;
160                         for (int i = 0; i < itemCount; i++) {
161                                 ExpandItem item = items [i];
162                                 height += item.getHeaderHeightInPixels ();
163                                 if (item.expanded) height += item.height;
164                                 height += spacing;
165                                 width = Math.max (width, item.getPreferredWidth (hTheme, hDC));
166                         }
167                         if (hCurrentFont != 0) {
168                                 OS.SelectObject (hDC, oldFont);
169                                 if (hCurrentFont != hFont) OS.DeleteObject (hCurrentFont);
170                         }
171                         OS.ReleaseDC (handle, hDC);
172                 }
173         }
174         if (width == 0) width = DEFAULT_WIDTH;
175         if (height == 0) height = DEFAULT_HEIGHT;
176         if (wHint != SWT.DEFAULT) width = wHint;
177         if (hHint != SWT.DEFAULT) height = hHint;
178         Rectangle trim = computeTrimInPixels (0, 0, width, height);
179         return new Point (trim.width, trim.height);
180 }
181
182 @Override
183 void createHandle () {
184         super.createHandle ();
185         state &= ~CANVAS;
186         state |= TRACK_MOUSE;
187 }
188
189 void createItem (ExpandItem item, int style, int index) {
190         if (!(0 <= index && index <= itemCount)) error (SWT.ERROR_INVALID_RANGE);
191         if (itemCount == items.length) {
192                 ExpandItem [] newItems = new ExpandItem [itemCount + 4];
193                 System.arraycopy (items, 0, newItems, 0, items.length);
194                 items = newItems;
195         }
196         System.arraycopy (items, index, items, index + 1, itemCount - index);
197         items [index] = item;
198         itemCount++;
199         if (focusItem == null) focusItem = item;
200
201         RECT rect = new RECT ();
202         OS.GetWindowRect (handle, rect);
203         item.width = Math.max (0, rect.right - rect.left - spacing * 2);
204         layoutItems (index, true);
205 }
206
207 @Override
208 void createWidget () {
209         super.createWidget ();
210         items = new ExpandItem [4];
211         if (!isAppThemed ()) {
212                 backgroundMode = SWT.INHERIT_DEFAULT;
213         }
214 }
215
216 @Override
217 int defaultBackground() {
218         if (!isAppThemed ()) {
219                 return OS.GetSysColor (OS.COLOR_WINDOW);
220         }
221         return super.defaultBackground();
222 }
223
224 void destroyItem (ExpandItem item) {
225         int index = 0;
226         while (index < itemCount) {
227                 if (items [index] == item) break;
228                 index++;
229         }
230         if (index == itemCount) return;
231         if (item == focusItem) {
232                 int focusIndex = index > 0 ? index - 1 : 1;
233                 if (focusIndex < itemCount) {
234                         focusItem = items [focusIndex];
235                         focusItem.redraw (true);
236                 } else {
237                         focusItem = null;
238                 }
239         }
240         System.arraycopy (items, index + 1, items, index, --itemCount - index);
241         items [itemCount] = null;
242         item.redraw (true);
243         layoutItems (index, true);
244 }
245
246 @Override
247 void drawThemeBackground (long hDC, long hwnd, RECT rect) {
248         RECT rect2 = new RECT ();
249         OS.GetClientRect (handle, rect2);
250         OS.MapWindowPoints (handle, hwnd, rect2, 2);
251         OS.DrawThemeBackground (display.hExplorerBarTheme (), hDC, OS.EBP_NORMALGROUPBACKGROUND, 0, rect2, null);
252 }
253
254 void drawWidget (GC gc, RECT clipRect) {
255         long hTheme = 0;
256         if (isAppThemed ()) {
257                 hTheme = display.hExplorerBarTheme ();
258         }
259         if (hTheme != 0) {
260                 RECT rect = new RECT ();
261                 OS.GetClientRect (handle, rect);
262                 OS.DrawThemeBackground (hTheme, gc.handle, OS.EBP_HEADERBACKGROUND, 0, rect, clipRect);
263         } else {
264                 drawBackground (gc.handle);
265         }
266         boolean drawFocus = false;
267         if (handle == OS.GetFocus ()) {
268                 int uiState = (int)OS.SendMessage (handle, OS.WM_QUERYUISTATE, 0, 0);
269                 drawFocus = (uiState & OS.UISF_HIDEFOCUS) == 0;
270         }
271         long hCurrentFont = 0, oldFont = 0;
272         if (hTheme == 0) {
273                 if (hFont != 0) {
274                         hCurrentFont = hFont;
275                 } else {
276                         NONCLIENTMETRICS info = new NONCLIENTMETRICS ();
277                         info.cbSize = NONCLIENTMETRICS.sizeof;
278                         if (OS.SystemParametersInfo (OS.SPI_GETNONCLIENTMETRICS, 0, info, 0)) {
279                                 LOGFONT logFont = info.lfCaptionFont;
280                                 hCurrentFont = OS.CreateFontIndirect (logFont);
281                         }
282                 }
283                 if (hCurrentFont != 0) {
284                         oldFont = OS.SelectObject (gc.handle, hCurrentFont);
285                 }
286                 if (foreground != -1) {
287                         OS.SetTextColor (gc.handle, foreground);
288                 }
289         }
290         for (int i = 0; i < itemCount; i++) {
291                 ExpandItem item = items[i];
292                 item.drawItem (gc, hTheme, clipRect, item == focusItem && drawFocus);
293         }
294         if (hCurrentFont != 0) {
295                 OS.SelectObject (gc.handle, oldFont);
296                 if (hCurrentFont != hFont) OS.DeleteObject (hCurrentFont);
297         }
298 }
299
300 @Override
301 Control findBackgroundControl () {
302         Control control = super.findBackgroundControl ();
303         if (!isAppThemed ()) {
304                 if (control == null) control = this;
305         }
306         return control;
307 }
308
309 @Override
310 Control findThemeControl () {
311         return isAppThemed () ? this : super.findThemeControl ();
312 }
313
314 int getBandHeight () {
315         long hDC = OS.GetDC (handle);
316         long oldHFont = OS.SelectObject (hDC, hFont == 0 ? defaultFont () : hFont);
317         TEXTMETRIC lptm = new TEXTMETRIC ();
318         OS.GetTextMetrics (hDC, lptm);
319         OS.SelectObject (hDC, oldHFont);
320         OS.ReleaseDC (handle, hDC);
321         return Math.max (ExpandItem.CHEVRON_SIZE, lptm.tmHeight + 4);
322 }
323
324 /**
325  * Returns the item at the given, zero-relative index in the
326  * receiver. Throws an exception if the index is out of range.
327  *
328  * @param index the index of the item to return
329  * @return the item at the given index
330  *
331  * @exception IllegalArgumentException <ul>
332  *    <li>ERROR_INVALID_RANGE - if the index is not between 0 and the number of elements in the list minus 1 (inclusive)</li>
333  * </ul>
334  * @exception SWTException <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 public ExpandItem getItem (int index) {
340         checkWidget ();
341         if (!(0 <= index && index < itemCount)) error (SWT.ERROR_INVALID_RANGE);
342         return items [index];
343 }
344
345 /**
346  * Returns the number of items contained in the receiver.
347  *
348  * @return the number of items
349  *
350  * @exception SWTException <ul>
351  *    <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
352  *    <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
353  * </ul>
354  */
355 public int getItemCount () {
356         checkWidget ();
357         return itemCount;
358 }
359
360 /**
361  * Returns an array of <code>ExpandItem</code>s which are the items
362  * in the receiver.
363  * <p>
364  * Note: This is not the actual structure used by the receiver
365  * to maintain its list of items, so modifying the array will
366  * not affect the receiver.
367  * </p>
368  *
369  * @return the items in the receiver
370  *
371  * @exception SWTException <ul>
372  *    <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
373  *    <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
374  * </ul>
375  */
376 public ExpandItem [] getItems () {
377         checkWidget ();
378         ExpandItem [] result = new ExpandItem [itemCount];
379         System.arraycopy (items, 0, result, 0, itemCount);
380         return result;
381 }
382
383 /**
384  * Returns the receiver's spacing.
385  *
386  * @return the spacing
387  *
388  * @exception SWTException <ul>
389  *    <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
390  *    <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
391  * </ul>
392  */
393 public int getSpacing () {
394         checkWidget ();
395         return DPIUtil.autoScaleDown(getSpacingInPixels ());
396 }
397
398 int getSpacingInPixels () {
399         return spacing;
400 }
401
402 /**
403  * Searches the receiver's list starting at the first item
404  * (index 0) until an item is found that is equal to the
405  * argument, and returns the index of that item. If no item
406  * is found, returns -1.
407  *
408  * @param item the search item
409  * @return the index of the item
410  *
411  * @exception IllegalArgumentException <ul>
412  *    <li>ERROR_NULL_ARGUMENT - if the item is null</li>
413  *    <li>ERROR_INVALID_ARGUMENT - if the item has been disposed</li>
414  * </ul>
415  * @exception SWTException <ul>
416  *    <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
417  *    <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
418  * </ul>
419  */
420 public int indexOf (ExpandItem item) {
421         checkWidget ();
422         if (item == null) error (SWT.ERROR_NULL_ARGUMENT);
423         for (int i = 0; i < itemCount; i++) {
424                 if (items [i] == item) return i;
425         }
426         return -1;
427 }
428
429 boolean isAppThemed () {
430         if (background != -1) return false;
431         if (foreground != -1) return false;
432         if (hFont != 0) return false;
433         return OS.IsAppThemed ();
434 }
435
436 void layoutItems (int index, boolean setScrollbar) {
437         if (index < itemCount) {
438                 int y = spacing - yCurrentScroll;
439                 for (int i = 0; i < index; i++) {
440                         ExpandItem item = items [i];
441                         if (item.expanded) y += item.height;
442                         y += item.getHeaderHeightInPixels () + spacing;
443                 }
444                 for (int i = index; i < itemCount; i++) {
445                         ExpandItem item = items [i];
446                         item.setBoundsInPixels (spacing, y, 0, 0, true, false);
447                         if (item.expanded) y += item.height;
448                         y += item.getHeaderHeightInPixels () + spacing;
449                 }
450         }
451         if (setScrollbar) setScrollbar ();
452 }
453
454 @Override
455 void releaseChildren (boolean destroy) {
456         if (items != null) {
457                 for (int i=0; i<items.length; i++) {
458                         ExpandItem item = items [i];
459                         if (item != null && !item.isDisposed ()) {
460                                 item.release (false);
461                         }
462                 }
463                 items = null;
464         }
465         focusItem = null;
466         super.releaseChildren (destroy);
467 }
468
469 /**
470  * Removes the listener from the collection of listeners who will
471  * be notified when items in the receiver are expanded or collapsed.
472  *
473  * @param listener the listener which should no longer be notified
474  *
475  * @exception IllegalArgumentException <ul>
476  *    <li>ERROR_NULL_ARGUMENT - if the listener is null</li>
477  * </ul>
478  * @exception SWTException <ul>
479  *    <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
480  *    <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
481  * </ul>
482  *
483  * @see ExpandListener
484  * @see #addExpandListener
485  */
486 public void removeExpandListener (ExpandListener listener) {
487         checkWidget ();
488         if (listener == null) error (SWT.ERROR_NULL_ARGUMENT);
489         if (eventTable == null) return;
490         eventTable.unhook (SWT.Expand, listener);
491         eventTable.unhook (SWT.Collapse, listener);
492 }
493
494 @Override
495 void reskinChildren (int flags) {
496         if (items != null) {
497                 for (int i=0; i<items.length; i++) {
498                         ExpandItem item = items [i];
499                         if (item != null ) item.reskin (flags);
500                 }
501         }
502         super.reskinChildren (flags);
503 }
504
505 @Override
506 void setBackgroundPixel (int pixel) {
507         super.setBackgroundPixel (pixel);
508         int flags = OS.RDW_ERASE | OS.RDW_FRAME | OS.RDW_INVALIDATE | OS.RDW_ALLCHILDREN;
509         OS.RedrawWindow (handle, null, 0, flags);
510 }
511
512 @Override
513 public void setFont (Font font) {
514         super.setFont (font);
515         hFont = font != null ? font.handle : 0;
516         layoutItems (0, true);
517 }
518
519 @Override
520 void setForegroundPixel (int pixel) {
521         super.setForegroundPixel (pixel);
522         int flags = OS.RDW_ERASE | OS.RDW_FRAME | OS.RDW_INVALIDATE | OS.RDW_ALLCHILDREN;
523         OS.RedrawWindow (handle, null, 0, flags);
524 }
525
526 void setScrollbar () {
527         if (itemCount == 0) return;
528         if ((style & SWT.V_SCROLL) == 0) return;
529         RECT rect = new RECT();
530         OS.GetClientRect (handle, rect);
531         int height = rect.bottom - rect.top;
532         ExpandItem item = items [itemCount - 1];
533         int maxHeight = item.y + getBandHeight () + spacing;
534         if (item.expanded) maxHeight += item.height;
535
536         //claim bottom free space
537         if (yCurrentScroll > 0 && height > maxHeight) {
538                 yCurrentScroll = Math.max (0, yCurrentScroll + maxHeight - height);
539                 layoutItems (0, false);
540         }
541         maxHeight += yCurrentScroll;
542
543         SCROLLINFO info = new SCROLLINFO ();
544         info.cbSize = SCROLLINFO.sizeof;
545         info.fMask = OS.SIF_RANGE | OS.SIF_PAGE | OS.SIF_POS;
546         info.nMin = 0;
547         info.nMax = maxHeight;
548         info.nPage = height;
549         info.nPos = Math.min (yCurrentScroll, info.nMax);
550         if (info.nPage != 0) info.nPage++;
551         OS.SetScrollInfo (handle, OS.SB_VERT, info, true);
552 }
553
554 /**
555  * Sets the receiver's spacing. Spacing specifies the number of points allocated around
556  * each item.
557  *
558  * @param spacing the spacing around each item
559  *
560  * @exception SWTException <ul>
561  *    <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
562  *    <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
563  * </ul>
564  */
565 public void setSpacing (int spacing) {
566         checkWidget ();
567         setSpacingInPixels(DPIUtil.autoScaleUp(spacing));
568 }
569
570 void setSpacingInPixels (int spacing) {
571         if (spacing < 0) return;
572         if (spacing == this.spacing) return;
573         this.spacing = spacing;
574         RECT rect = new RECT ();
575         OS.GetClientRect (handle, rect);
576         int width = Math.max (0, (rect.right - rect.left) - spacing * 2);
577         for (int i = 0; i < itemCount; i++) {
578                 ExpandItem item = items[i];
579                 if (item.width != width) item.setBoundsInPixels (0, 0, width, item.height, false, true);
580         }
581         layoutItems (0, true);
582         OS.InvalidateRect (handle, null, true);
583 }
584
585 @Override
586 boolean updateTextDirection(int textDirection) {
587         if (super.updateTextDirection(textDirection)) {
588                 for (int i = 0, n = items.length; i < n; i++) {
589                         if (items[i] != null) {
590                                 items[i].updateTextDirection(textDirection == AUTO_TEXT_DIRECTION ? AUTO_TEXT_DIRECTION : style & SWT.FLIP_TEXT_DIRECTION);
591                         }
592                 }
593                 return true;
594         }
595         return false;
596 }
597
598 void showItem (ExpandItem item) {
599         Control control = item.control;
600         if (control != null && !control.isDisposed ()) {
601                 control.setVisible (item.expanded);
602         }
603         item.redraw (true);
604         int index = indexOf (item);
605         layoutItems (index + 1, true);
606 }
607
608 void showFocus (boolean up) {
609         RECT rect = new RECT();
610         OS.GetClientRect (handle, rect);
611         int height = rect.bottom - rect.top;
612         int updateY = 0;
613         if (up) {
614                 if (focusItem.y < 0) {
615                         updateY = Math.min (yCurrentScroll, -focusItem.y);
616                 }
617         } else {
618                 int itemHeight = focusItem.y + getBandHeight ();
619                 if (focusItem.expanded) {
620                         if (height >= getBandHeight () + focusItem.height) {
621                                 itemHeight += focusItem.height;
622                         }
623                 }
624                 if (itemHeight > height) {
625                         updateY = height - itemHeight;
626                 }
627         }
628         if (updateY != 0) {
629                 yCurrentScroll = Math.max (0, yCurrentScroll - updateY);
630                 if ((style & SWT.V_SCROLL) != 0) {
631                         SCROLLINFO info = new SCROLLINFO ();
632                         info.cbSize = SCROLLINFO.sizeof;
633                         info.fMask = OS.SIF_POS;
634                         info.nPos = yCurrentScroll;
635                         OS.SetScrollInfo (handle, OS.SB_VERT, info, true);
636                 }
637                 OS.ScrollWindowEx (handle, 0, updateY, null, null, 0, null, OS.SW_SCROLLCHILDREN | OS.SW_INVALIDATE);
638                 for (int i = 0; i < itemCount; i++) {
639                         items [i].y += updateY;
640                 }
641         }
642 }
643
644 @Override
645 TCHAR windowClass () {
646         return display.windowClass;
647 }
648
649 @Override
650 long windowProc () {
651         return display.windowProc;
652 }
653
654 @Override
655 LRESULT WM_KEYDOWN (long wParam, long lParam) {
656         LRESULT result = super.WM_KEYDOWN (wParam, lParam);
657         if (result != null) return result;
658         if (focusItem == null) return result;
659         switch ((int)wParam) {
660                 case OS.VK_SPACE:
661                 case OS.VK_RETURN:
662                         Event event = new Event ();
663                         event.item = focusItem;
664                         sendEvent (focusItem.expanded ? SWT.Collapse : SWT.Expand, event);
665                         focusItem.expanded = !focusItem.expanded;
666                         showItem (focusItem);
667                         return LRESULT.ZERO;
668                 case OS.VK_UP: {
669                         int focusIndex = indexOf (focusItem);
670                         if (focusIndex > 0) {
671                                 focusItem.redraw (true);
672                                 focusItem = items [focusIndex - 1];
673                                 focusItem.redraw (true);
674                                 showFocus (true);
675                                 return LRESULT.ZERO;
676                         }
677                         break;
678                 }
679                 case OS.VK_DOWN: {
680                         int focusIndex = indexOf (focusItem);
681                         if (focusIndex < itemCount - 1) {
682                                 focusItem.redraw (true);
683                                 focusItem = items [focusIndex + 1];
684                                 focusItem.redraw (true);
685                                 showFocus (false);
686                                 return LRESULT.ZERO;
687                         }
688                         break;
689                 }
690         }
691         return result;
692 }
693
694 @Override
695 LRESULT WM_KILLFOCUS (long wParam, long lParam) {
696         LRESULT result = super.WM_KILLFOCUS (wParam, lParam);
697         if (focusItem != null) focusItem.redraw (true);
698         return result;
699 }
700
701 @Override
702 LRESULT WM_LBUTTONDOWN (long wParam, long lParam) {
703         LRESULT result = super.WM_LBUTTONDOWN (wParam, lParam);
704         if (result == LRESULT.ZERO) return result;
705         int x = OS.GET_X_LPARAM (lParam);
706         int y = OS.GET_Y_LPARAM (lParam);
707         for (int i = 0; i < itemCount; i++) {
708                 ExpandItem item = items[i];
709                 boolean hover = item.isHover (x, y);
710                 if (hover && focusItem != item) {
711                         focusItem.redraw (true);
712                         focusItem = item;
713                         focusItem.redraw (true);
714                         forceFocus ();
715                         break;
716                 }
717         }
718         return result;
719 }
720
721 @Override
722 LRESULT WM_LBUTTONUP (long wParam, long lParam) {
723         LRESULT result = super.WM_LBUTTONUP (wParam, lParam);
724         if (result == LRESULT.ZERO) return result;
725         if (focusItem == null) return result;
726         int x = OS.GET_X_LPARAM (lParam);
727         int y = OS.GET_Y_LPARAM (lParam);
728         boolean hover = focusItem.isHover (x, y);
729         if (hover) {
730                 Event event = new Event ();
731                 event.item = focusItem;
732                 sendEvent (focusItem.expanded ? SWT.Collapse : SWT.Expand, event);
733                 focusItem.expanded = !focusItem.expanded;
734                 showItem (focusItem);
735         }
736         return result;
737 }
738
739 @Override
740 LRESULT WM_MOUSELEAVE (long wParam, long lParam) {
741         LRESULT result = super.WM_MOUSELEAVE (wParam, lParam);
742         if (result != null) return result;
743         for (int i = 0; i < itemCount; i++) {
744                 ExpandItem item = items [i];
745                 if (item.hover) {
746                         item.hover = false;
747                         item.redraw (false);
748                         break;
749                 }
750         }
751         return result;
752 }
753
754 @Override
755 LRESULT WM_MOUSEMOVE (long wParam, long lParam) {
756         LRESULT result = super.WM_MOUSEMOVE (wParam, lParam);
757         if (result == LRESULT.ZERO) return result;
758         int x = OS.GET_X_LPARAM (lParam);
759         int y = OS.GET_Y_LPARAM (lParam);
760         for (int i = 0; i < itemCount; i++) {
761                 ExpandItem item = items [i];
762                 boolean hover = item.isHover (x, y);
763                 if (item.hover != hover) {
764                         item.hover = hover;
765                         item.redraw (false);
766                 }
767         }
768         return result;
769 }
770
771 @Override
772 LRESULT WM_MOUSEWHEEL (long wParam, long lParam) {
773         return wmScrollWheel (true, wParam, lParam);
774 }
775
776 @Override
777 LRESULT WM_PAINT (long wParam, long lParam) {
778         if ((state & DISPOSE_SENT) != 0) return LRESULT.ZERO;
779
780         PAINTSTRUCT ps = new PAINTSTRUCT ();
781         GCData data = new GCData ();
782         data.ps = ps;
783         data.hwnd = handle;
784         GC gc = new_GC (data);
785         if (gc != null) {
786                 int width = ps.right - ps.left;
787                 int height = ps.bottom - ps.top;
788                 if (width != 0 && height != 0) {
789                         RECT rect = new RECT ();
790                         OS.SetRect (rect, ps.left, ps.top, ps.right, ps.bottom);
791                         drawWidget (gc, rect);
792                         if (hooks (SWT.Paint) || filters (SWT.Paint)) {
793                                 Event event = new Event ();
794                                 event.gc = gc;
795                                 event.setBoundsInPixels(new Rectangle(rect.left, rect.top, width, height));
796                                 sendEvent (SWT.Paint, event);
797                                 event.gc = null;
798                         }
799                 }
800                 gc.dispose ();
801         }
802         return LRESULT.ZERO;
803 }
804
805 @Override
806 LRESULT WM_PRINTCLIENT (long wParam, long lParam) {
807         LRESULT result = super.WM_PRINTCLIENT (wParam, lParam);
808         RECT rect = new RECT ();
809         OS.GetClientRect (handle, rect);
810         GCData data = new GCData ();
811         data.device = display;
812         data.foreground = getForegroundPixel ();
813         GC gc = GC.win32_new (wParam, data);
814         drawWidget (gc, rect);
815         gc.dispose ();
816         return result;
817 }
818
819 @Override
820 LRESULT WM_SETCURSOR (long wParam, long lParam) {
821         LRESULT result = super.WM_SETCURSOR (wParam, lParam);
822         if (result != null) return result;
823         int hitTest = (short) OS.LOWORD (lParam);
824         if (hitTest == OS.HTCLIENT) {
825                 for (int i = 0; i < itemCount; i++) {
826                         ExpandItem item = items [i];
827                         if (item.hover) {
828                                 long hCursor = OS.LoadCursor (0, OS.IDC_HAND);
829                                 OS.SetCursor (hCursor);
830                                 return LRESULT.ONE;
831                         }
832                 }
833         }
834         return result;
835 }
836
837 @Override
838 LRESULT WM_SETFOCUS (long wParam, long lParam) {
839         LRESULT result = super.WM_SETFOCUS (wParam, lParam);
840         if (focusItem != null) focusItem.redraw (true);
841         return result;
842 }
843
844 @Override
845 LRESULT WM_SIZE (long wParam, long lParam) {
846         LRESULT result = super.WM_SIZE (wParam, lParam);
847         RECT rect = new RECT ();
848         OS.GetClientRect (handle, rect);
849         int width = Math.max (0, (rect.right - rect.left) - spacing * 2);
850         for (int i = 0; i < itemCount; i++) {
851                 ExpandItem item = items[i];
852                 if (item.width != width) item.setBoundsInPixels (0, 0, width, item.height, false, true);
853         }
854         setScrollbar ();
855         OS.InvalidateRect (handle, null, true);
856         return result;
857 }
858
859 @Override
860 LRESULT wmScroll (ScrollBar bar, boolean update, long hwnd, int msg, long wParam, long lParam) {
861         LRESULT result = super.wmScroll (bar, true, hwnd, msg, wParam, lParam);
862         SCROLLINFO info = new SCROLLINFO ();
863         info.cbSize = SCROLLINFO.sizeof;
864         info.fMask = OS.SIF_POS;
865         OS.GetScrollInfo (handle, OS.SB_VERT, info);
866         int updateY = yCurrentScroll - info.nPos;
867         OS.ScrollWindowEx (handle, 0, updateY, null, null, 0, null, OS.SW_SCROLLCHILDREN | OS.SW_INVALIDATE);
868         yCurrentScroll = info.nPos;
869         if (updateY != 0) {
870                 for (int i = 0; i < itemCount; i++) {
871                         items [i].y += updateY;
872                 }
873         }
874         return result;
875 }
876 }