1 /*******************************************************************************
2 * Copyright (c) 2000, 2018 IBM Corporation and others.
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/
9 * SPDX-License-Identifier: EPL-2.0
12 * IBM Corporation - initial API and implementation
13 *******************************************************************************/
14 package org.eclipse.swt.widgets;
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.*;
23 * Instances of this class support the layout of selectable
26 * The item children that may be added to instances of this class
27 * must be of type <code>ExpandItem</code>.
30 * <dt><b>Styles:</b></dt>
32 * <dt><b>Events:</b></dt>
33 * <dd>Expand, Collapse</dd>
36 * IMPORTANT: This class is <em>not</em> intended to be subclassed.
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>
48 * @noextend This class is not intended to be subclassed by clients.
50 public class ExpandBar extends Composite {
60 * Constructs a new instance of this class given its parent
61 * and a style value describing its behavior and appearance.
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.
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
75 * @exception IllegalArgumentException <ul>
76 * <li>ERROR_NULL_ARGUMENT - if the parent is null</li>
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>
84 * @see Widget#checkSubclass
85 * @see Widget#getStyle
87 public ExpandBar (Composite parent, int style) {
88 super (parent, checkStyle (style));
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>
97 * @param listener the listener which should be notified
99 * @exception IllegalArgumentException <ul>
100 * <li>ERROR_NULL_ARGUMENT - if the listener is null</li>
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>
107 * @see ExpandListener
108 * @see #removeExpandListener
110 public void addExpandListener (ExpandListener listener) {
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);
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);
125 protected void checkSubclass () {
126 if (!isValidSubclass ()) error (SWT.ERROR_INVALID_SUBCLASS);
129 static int checkStyle (int style) {
130 style &= ~SWT.H_SCROLL;
131 return style | SWT.NO_BACKGROUND;
134 @Override Point computeSizeInPixels (int wHint, int hHint, boolean changed) {
135 int height = 0, width = 0;
136 if (wHint == SWT.DEFAULT || hHint == SWT.DEFAULT) {
138 long hDC = OS.GetDC (handle);
140 if (isAppThemed ()) {
141 hTheme = display.hExplorerBarTheme ();
143 long hCurrentFont = 0, oldFont = 0;
146 hCurrentFont = hFont;
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);
155 if (hCurrentFont != 0) {
156 oldFont = OS.SelectObject (hDC, hCurrentFont);
160 for (int i = 0; i < itemCount; i++) {
161 ExpandItem item = items [i];
162 height += item.getHeaderHeightInPixels ();
163 if (item.expanded) height += item.height;
165 width = Math.max (width, item.getPreferredWidth (hTheme, hDC));
167 if (hCurrentFont != 0) {
168 OS.SelectObject (hDC, oldFont);
169 if (hCurrentFont != hFont) OS.DeleteObject (hCurrentFont);
171 OS.ReleaseDC (handle, hDC);
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);
183 void createHandle () {
184 super.createHandle ();
186 state |= TRACK_MOUSE;
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);
196 System.arraycopy (items, index, items, index + 1, itemCount - index);
197 items [index] = item;
199 if (focusItem == null) focusItem = item;
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);
208 void createWidget () {
209 super.createWidget ();
210 items = new ExpandItem [4];
211 if (!isAppThemed ()) {
212 backgroundMode = SWT.INHERIT_DEFAULT;
217 int defaultBackground() {
218 if (!isAppThemed ()) {
219 return OS.GetSysColor (OS.COLOR_WINDOW);
221 return super.defaultBackground();
224 void destroyItem (ExpandItem item) {
226 while (index < itemCount) {
227 if (items [index] == item) break;
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);
240 System.arraycopy (items, index + 1, items, index, --itemCount - index);
241 items [itemCount] = null;
243 layoutItems (index, true);
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);
254 void drawWidget (GC gc, RECT clipRect) {
256 if (isAppThemed ()) {
257 hTheme = display.hExplorerBarTheme ();
260 RECT rect = new RECT ();
261 OS.GetClientRect (handle, rect);
262 OS.DrawThemeBackground (hTheme, gc.handle, OS.EBP_HEADERBACKGROUND, 0, rect, clipRect);
264 drawBackground (gc.handle);
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;
271 long hCurrentFont = 0, oldFont = 0;
274 hCurrentFont = hFont;
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);
283 if (hCurrentFont != 0) {
284 oldFont = OS.SelectObject (gc.handle, hCurrentFont);
286 if (foreground != -1) {
287 OS.SetTextColor (gc.handle, foreground);
290 for (int i = 0; i < itemCount; i++) {
291 ExpandItem item = items[i];
292 item.drawItem (gc, hTheme, clipRect, item == focusItem && drawFocus);
294 if (hCurrentFont != 0) {
295 OS.SelectObject (gc.handle, oldFont);
296 if (hCurrentFont != hFont) OS.DeleteObject (hCurrentFont);
301 Control findBackgroundControl () {
302 Control control = super.findBackgroundControl ();
303 if (!isAppThemed ()) {
304 if (control == null) control = this;
310 Control findThemeControl () {
311 return isAppThemed () ? this : super.findThemeControl ();
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);
325 * Returns the item at the given, zero-relative index in the
326 * receiver. Throws an exception if the index is out of range.
328 * @param index the index of the item to return
329 * @return the item at the given index
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>
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>
339 public ExpandItem getItem (int index) {
341 if (!(0 <= index && index < itemCount)) error (SWT.ERROR_INVALID_RANGE);
342 return items [index];
346 * Returns the number of items contained in the receiver.
348 * @return the number of items
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>
355 public int getItemCount () {
361 * Returns an array of <code>ExpandItem</code>s which are the items
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.
369 * @return the items in the receiver
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>
376 public ExpandItem [] getItems () {
378 ExpandItem [] result = new ExpandItem [itemCount];
379 System.arraycopy (items, 0, result, 0, itemCount);
384 * Returns the receiver's spacing.
386 * @return the spacing
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>
393 public int getSpacing () {
395 return DPIUtil.autoScaleDown(getSpacingInPixels ());
398 int getSpacingInPixels () {
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.
408 * @param item the search item
409 * @return the index of the item
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>
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>
420 public int indexOf (ExpandItem item) {
422 if (item == null) error (SWT.ERROR_NULL_ARGUMENT);
423 for (int i = 0; i < itemCount; i++) {
424 if (items [i] == item) return i;
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 ();
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;
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;
451 if (setScrollbar) setScrollbar ();
455 void releaseChildren (boolean destroy) {
457 for (int i=0; i<items.length; i++) {
458 ExpandItem item = items [i];
459 if (item != null && !item.isDisposed ()) {
460 item.release (false);
466 super.releaseChildren (destroy);
470 * Removes the listener from the collection of listeners who will
471 * be notified when items in the receiver are expanded or collapsed.
473 * @param listener the listener which should no longer be notified
475 * @exception IllegalArgumentException <ul>
476 * <li>ERROR_NULL_ARGUMENT - if the listener is null</li>
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>
483 * @see ExpandListener
484 * @see #addExpandListener
486 public void removeExpandListener (ExpandListener listener) {
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);
495 void reskinChildren (int flags) {
497 for (int i=0; i<items.length; i++) {
498 ExpandItem item = items [i];
499 if (item != null ) item.reskin (flags);
502 super.reskinChildren (flags);
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);
513 public void setFont (Font font) {
514 super.setFont (font);
515 hFont = font != null ? font.handle : 0;
516 layoutItems (0, true);
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);
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;
536 //claim bottom free space
537 if (yCurrentScroll > 0 && height > maxHeight) {
538 yCurrentScroll = Math.max (0, yCurrentScroll + maxHeight - height);
539 layoutItems (0, false);
541 maxHeight += yCurrentScroll;
543 SCROLLINFO info = new SCROLLINFO ();
544 info.cbSize = SCROLLINFO.sizeof;
545 info.fMask = OS.SIF_RANGE | OS.SIF_PAGE | OS.SIF_POS;
547 info.nMax = maxHeight;
549 info.nPos = Math.min (yCurrentScroll, info.nMax);
550 if (info.nPage != 0) info.nPage++;
551 OS.SetScrollInfo (handle, OS.SB_VERT, info, true);
555 * Sets the receiver's spacing. Spacing specifies the number of points allocated around
558 * @param spacing the spacing around each item
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>
565 public void setSpacing (int spacing) {
567 setSpacingInPixels(DPIUtil.autoScaleUp(spacing));
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);
581 layoutItems (0, true);
582 OS.InvalidateRect (handle, null, true);
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);
598 void showItem (ExpandItem item) {
599 Control control = item.control;
600 if (control != null && !control.isDisposed ()) {
601 control.setVisible (item.expanded);
604 int index = indexOf (item);
605 layoutItems (index + 1, true);
608 void showFocus (boolean up) {
609 RECT rect = new RECT();
610 OS.GetClientRect (handle, rect);
611 int height = rect.bottom - rect.top;
614 if (focusItem.y < 0) {
615 updateY = Math.min (yCurrentScroll, -focusItem.y);
618 int itemHeight = focusItem.y + getBandHeight ();
619 if (focusItem.expanded) {
620 if (height >= getBandHeight () + focusItem.height) {
621 itemHeight += focusItem.height;
624 if (itemHeight > height) {
625 updateY = height - itemHeight;
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);
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;
645 TCHAR windowClass () {
646 return display.windowClass;
651 return display.windowProc;
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) {
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);
669 int focusIndex = indexOf (focusItem);
670 if (focusIndex > 0) {
671 focusItem.redraw (true);
672 focusItem = items [focusIndex - 1];
673 focusItem.redraw (true);
680 int focusIndex = indexOf (focusItem);
681 if (focusIndex < itemCount - 1) {
682 focusItem.redraw (true);
683 focusItem = items [focusIndex + 1];
684 focusItem.redraw (true);
695 LRESULT WM_KILLFOCUS (long wParam, long lParam) {
696 LRESULT result = super.WM_KILLFOCUS (wParam, lParam);
697 if (focusItem != null) focusItem.redraw (true);
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);
713 focusItem.redraw (true);
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);
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);
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];
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) {
772 LRESULT WM_MOUSEWHEEL (long wParam, long lParam) {
773 return wmScrollWheel (true, wParam, lParam);
777 LRESULT WM_PAINT (long wParam, long lParam) {
778 if ((state & DISPOSE_SENT) != 0) return LRESULT.ZERO;
780 PAINTSTRUCT ps = new PAINTSTRUCT ();
781 GCData data = new GCData ();
784 GC gc = new_GC (data);
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 ();
795 event.setBoundsInPixels(new Rectangle(rect.left, rect.top, width, height));
796 sendEvent (SWT.Paint, event);
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);
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];
828 long hCursor = OS.LoadCursor (0, OS.IDC_HAND);
829 OS.SetCursor (hCursor);
838 LRESULT WM_SETFOCUS (long wParam, long lParam) {
839 LRESULT result = super.WM_SETFOCUS (wParam, lParam);
840 if (focusItem != null) focusItem.redraw (true);
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);
855 OS.InvalidateRect (handle, null, true);
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;
870 for (int i = 0; i < itemCount; i++) {
871 items [i].y += updateY;