xref: /reactos/dll/win32/comctl32/rebar.c (revision 0c2cdcae)
1 /*
2  * Rebar control
3  *
4  * Copyright 1998, 1999 Eric Kohl
5  * Copyright 2007, 2008 Mikolaj Zalewski
6  *
7  * This library is free software; you can redistribute it and/or
8  * modify it under the terms of the GNU Lesser General Public
9  * License as published by the Free Software Foundation; either
10  * version 2.1 of the License, or (at your option) any later version.
11  *
12  * This library is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
15  * Lesser General Public License for more details.
16  *
17  * You should have received a copy of the GNU Lesser General Public
18  * License along with this library; if not, write to the Free Software
19  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
20  *
21  * NOTES
22  *
23  * This code was audited for completeness against the documented features
24  * of Comctl32.dll version 6.0 on Oct. 19, 2004, by Robert Shearman.
25  *
26  * Unless otherwise noted, we believe this code to be complete, as per
27  * the specification mentioned above.
28  * If you discover missing features or bugs please note them below.
29  *
30  * TODO
31  *   Styles:
32  *   - RBS_DBLCLKTOGGLE
33  *   - RBS_FIXEDORDER
34  *   - RBS_REGISTERDROP
35  *   - RBS_TOOLTIPS
36  *   Messages:
37  *   - RB_BEGINDRAG
38  *   - RB_DRAGMOVE
39  *   - RB_ENDDRAG
40  *   - RB_GETBANDMARGINS
41  *   - RB_GETCOLORSCHEME
42  *   - RB_GETDROPTARGET
43  *   - RB_GETPALETTE
44  *   - RB_SETCOLORSCHEME
45  *   - RB_SETPALETTE
46  *   - RB_SETTOOLTIPS
47  *   - WM_CHARTOITEM
48  *   - WM_LBUTTONDBLCLK
49  *   - WM_PALETTECHANGED
50  *   - WM_QUERYNEWPALETTE
51  *   - WM_RBUTTONDOWN
52  *   - WM_RBUTTONUP
53  *   - WM_VKEYTOITEM
54  *   - WM_WININICHANGE
55  *   Notifications:
56  *   - NM_HCHITTEST
57  *   - NM_RELEASEDCAPTURE
58  *   - RBN_AUTOBREAK
59  *   - RBN_GETOBJECT
60  *   - RBN_MINMAX
61  *   Band styles:
62  *   - RBBS_FIXEDBMP
63  *   Native uses (on each draw!!) SM_CYBORDER (or SM_CXBORDER for CCS_VERT)
64  *   to set the size of the separator width (the value SEP_WIDTH_SIZE
65  *   in here). Should be fixed!!
66  */
67 
68 /*
69  * Testing: set to 1 to make background brush *always* green
70  */
71 #define GLATESTING 0
72 
73 /*
74  * 3. REBAR_MoveChildWindows should have a loop because more than
75  *    one pass (together with the RBN_CHILDSIZEs) is made on
76  *    at least RB_INSERTBAND
77  */
78 
79 #include <assert.h>
80 #include <stdarg.h>
81 #include <stdlib.h>
82 #include <string.h>
83 
84 #include "windef.h"
85 #include "winbase.h"
86 #include "wingdi.h"
87 #include "winuser.h"
88 #include "winnls.h"
89 #include "commctrl.h"
90 #include "comctl32.h"
91 #include "uxtheme.h"
92 #include "vssym32.h"
93 #include "wine/debug.h"
94 
95 WINE_DEFAULT_DEBUG_CHANNEL(rebar);
96 
97 typedef struct
98 {
99     UINT    fStyle;
100     UINT    fMask;
101     COLORREF  clrFore;
102     COLORREF  clrBack;
103     INT     iImage;
104     HWND    hwndChild;
105     UINT    cxMinChild;     /* valid if _CHILDSIZE */
106     UINT    cyMinChild;     /* valid if _CHILDSIZE */
107     UINT    cx;             /* valid if _SIZE */
108     HBITMAP hbmBack;
109     UINT    wID;
110     UINT    cyChild;        /* valid if _CHILDSIZE */
111     UINT    cyMaxChild;     /* valid if _CHILDSIZE */
112     UINT    cyIntegral;     /* valid if _CHILDSIZE */
113     UINT    cxIdeal;
114     LPARAM    lParam;
115     UINT    cxHeader;
116 
117     INT     cxEffective;    /* current cx for band */
118     UINT    cyHeader;       /* the height of the header */
119     UINT    cxMinBand;      /* minimum cx for band */
120     UINT    cyMinBand;      /* minimum cy for band */
121 
122     UINT    cyRowSoFar;     /* for RBS_VARHEIGHT - the height of the row if it would break on this band (set by _Layout) */
123     INT     iRow;           /* zero-based index of the row this band assigned to */
124     UINT    fStatus;        /* status flags, reset only by _Validate */
125     UINT    fDraw;          /* drawing flags, reset only by _Layout */
126     UINT    uCDret;         /* last return from NM_CUSTOMDRAW */
127     RECT    rcBand;         /* calculated band rectangle - coordinates swapped for CCS_VERT */
128     RECT    rcGripper;      /* calculated gripper rectangle */
129     RECT    rcCapImage;     /* calculated caption image rectangle */
130     RECT    rcCapText;      /* calculated caption text rectangle */
131     RECT    rcChild;        /* calculated child rectangle */
132     RECT    rcChevron;      /* calculated chevron rectangle */
133 
134     LPWSTR    lpText;
135     HWND    hwndPrevParent;
136 } REBAR_BAND;
137 
138 /* has a value of: 0, CCS_TOP, CCS_NOMOVEY, CCS_BOTTOM */
139 #define CCS_LAYOUT_MASK 0x3
140 
141 /* fStatus flags */
142 #define HAS_GRIPPER    0x00000001
143 #define HAS_IMAGE      0x00000002
144 #define HAS_TEXT       0x00000004
145 
146 /* fDraw flags */
147 #define DRAW_GRIPPER    0x00000001
148 #define DRAW_IMAGE      0x00000002
149 #define DRAW_TEXT       0x00000004
150 #define DRAW_CHEVRONHOT 0x00000040
151 #define DRAW_CHEVRONPUSHED 0x00000080
152 #define NTF_INVALIDATE  0x01000000
153 
154 typedef struct
155 {
156     COLORREF   clrBk;       /* background color */
157     COLORREF   clrText;     /* text color */
158     COLORREF   clrBtnText;  /* system color for BTNTEXT */
159     COLORREF   clrBtnFace;  /* system color for BTNFACE */
160     HIMAGELIST himl;        /* handle to imagelist */
161     UINT     uNumBands;   /* # of bands in rebar (first=0, last=uNumBands-1 */
162     UINT     uNumRows;    /* # of rows of bands (first=1, last=uNumRows */
163     HWND     hwndSelf;    /* handle of REBAR window itself */
164     HWND     hwndToolTip; /* handle to the tool tip control */
165     HWND     hwndNotify;  /* notification window (parent) */
166     HFONT    hDefaultFont;
167     HFONT    hFont;       /* handle to the rebar's font */
168     SIZE     imageSize;   /* image size (image list) */
169     DWORD    dwStyle;     /* window style */
170     DWORD    orgStyle;    /* original style (dwStyle may change) */
171     SIZE     calcSize;    /* calculated rebar size - coordinates swapped for CCS_VERT */
172     BOOL     bUnicode;    /* TRUE if parent wants notify in W format */
173     BOOL     DoRedraw;    /* TRUE to actually draw bands */
174     UINT     fStatus;     /* Status flags (see below)  */
175     HCURSOR  hcurArrow;   /* handle to the arrow cursor */
176     HCURSOR  hcurHorz;    /* handle to the EW cursor */
177     HCURSOR  hcurVert;    /* handle to the NS cursor */
178     HCURSOR  hcurDrag;    /* handle to the drag cursor */
179     INT      iVersion;    /* version number */
180     POINT    dragStart;   /* x,y of button down */
181     POINT    dragNow;     /* x,y of this MouseMove */
182     INT      iOldBand;    /* last band that had the mouse cursor over it */
183     INT      ihitoffset;  /* offset of hotspot from gripper.left */
184     INT      ichevronhotBand; /* last band that had a hot chevron */
185     INT      iGrabbedBand;/* band number of band whose gripper was grabbed */
186 
187     HDPA     bands;       /* pointer to the array of rebar bands */
188 } REBAR_INFO;
189 
190 /* fStatus flags */
191 #define BEGIN_DRAG_ISSUED   0x00000001
192 #define SELF_RESIZE         0x00000002
193 #define BAND_NEEDS_REDRAW   0x00000020
194 
195 /* used by Windows to mark that the header size has been set by the user and shouldn't be changed */
196 #define RBBS_UNDOC_FIXEDHEADER 0x40000000
197 
198 /* ----   REBAR layout constants. Mostly determined by        ---- */
199 /* ----   experiment on WIN 98.                               ---- */
200 
201 /* Width (or height) of separators between bands (either horz. or  */
202 /* vert.). True only if RBS_BANDBORDERS is set                     */
203 #define SEP_WIDTH_SIZE  2
204 #define SEP_WIDTH       ((infoPtr->dwStyle & RBS_BANDBORDERS) ? SEP_WIDTH_SIZE : 0)
205 
206 /* Blank (background color) space between Gripper (if present)     */
207 /* and next item (image, text, or window). Always present          */
208 #define REBAR_ALWAYS_SPACE  4
209 
210 /* Blank (background color) space after Image (if present).        */
211 #define REBAR_POST_IMAGE  2
212 
213 /* Blank (background color) space after Text (if present).         */
214 #define REBAR_POST_TEXT  4
215 
216 /* Height of vertical gripper in a CCS_VERT rebar.                 */
217 #define GRIPPER_HEIGHT  16
218 
219 /* Blank (background color) space before Gripper (if present).     */
220 #define REBAR_PRE_GRIPPER   2
221 
222 /* Width (of normal vertical gripper) or height (of horz. gripper) */
223 /* if present.                                                     */
224 #define GRIPPER_WIDTH  3
225 
226 /* Width of the chevron button if present */
227 #define CHEVRON_WIDTH  10
228 
229 /* the gap between the child and the next band */
230 #define REBAR_POST_CHILD 4
231 
232 /* Height of divider for Rebar if not disabled (CCS_NODIVIDER)     */
233 /* either top or bottom                                            */
234 #define REBAR_DIVIDER  2
235 
236 /* height of a rebar without a child */
237 #define REBAR_NO_CHILD_HEIGHT 4
238 
239 /* minimum vertical height of a normal bar                        */
240 /*   or minimum width of a CCS_VERT bar - from experiment on Win2k */
241 #define REBAR_MINSIZE  23
242 
243 /* This is the increment that is used over the band height         */
244 #define REBARSPACE(a)     ((a->fStyle & RBBS_CHILDEDGE) ? 2*REBAR_DIVIDER : 0)
245 
246 /* ----   End of REBAR layout constants.                      ---- */
247 
248 #define RB_GETBANDINFO_OLD (WM_USER+5) /* obsoleted after IE3, but we have to support it anyway */
249 
250 /*  The following define determines if a given band is hidden      */
251 #define HIDDENBAND(a)  (((a)->fStyle & RBBS_HIDDEN) ||   \
252                         ((infoPtr->dwStyle & CCS_VERT) &&         \
253                          ((a)->fStyle & RBBS_NOVERT)))
254 
255 #define REBAR_GetInfoPtr(wndPtr) ((REBAR_INFO *)GetWindowLongPtrW (hwnd, 0))
256 
257 static LRESULT REBAR_NotifyFormat(REBAR_INFO *infoPtr, LPARAM lParam);
258 static void REBAR_AutoSize(REBAR_INFO *infoPtr, BOOL needsLayout);
259 
260 /* no index check here */
261 static inline REBAR_BAND* REBAR_GetBand(const REBAR_INFO *infoPtr, INT i)
262 {
263     assert(i >= 0 && i < infoPtr->uNumBands);
264     return DPA_GetPtr(infoPtr->bands, i);
265 }
266 
267 /* "constant values" retrieved when DLL was initialized    */
268 /* FIXME we do this when the classes are registered.       */
269 static UINT mindragx = 0;
270 static UINT mindragy = 0;
271 
272 static const char * const band_stylename[] = {
273     "RBBS_BREAK",              /* 0001 */
274     "RBBS_FIXEDSIZE",          /* 0002 */
275     "RBBS_CHILDEDGE",          /* 0004 */
276     "RBBS_HIDDEN",             /* 0008 */
277     "RBBS_NOVERT",             /* 0010 */
278     "RBBS_FIXEDBMP",           /* 0020 */
279     "RBBS_VARIABLEHEIGHT",     /* 0040 */
280     "RBBS_GRIPPERALWAYS",      /* 0080 */
281     "RBBS_NOGRIPPER",          /* 0100 */
282     "RBBS_USECHEVRON",         /* 0200 */
283     "RBBS_HIDETITLE",          /* 0400 */
284     "RBBS_TOPALIGN",           /* 0800 */
285     NULL };
286 
287 static const char * const band_maskname[] = {
288     "RBBIM_STYLE",         /*    0x00000001 */
289     "RBBIM_COLORS",        /*    0x00000002 */
290     "RBBIM_TEXT",          /*    0x00000004 */
291     "RBBIM_IMAGE",         /*    0x00000008 */
292     "RBBIM_CHILD",         /*    0x00000010 */
293     "RBBIM_CHILDSIZE",     /*    0x00000020 */
294     "RBBIM_SIZE",          /*    0x00000040 */
295     "RBBIM_BACKGROUND",    /*    0x00000080 */
296     "RBBIM_ID",            /*    0x00000100 */
297     "RBBIM_IDEALSIZE",     /*    0x00000200 */
298     "RBBIM_LPARAM",        /*    0x00000400 */
299     "RBBIM_HEADERSIZE",    /*    0x00000800 */
300     "RBBIM_CHEVRONLOCATION", /*  0x00001000 */
301     "RBBIM_CHEVRONSTATE",  /*    0x00002000 */
302     NULL };
303 
304 
305 static const WCHAR themeClass[] = { 'R','e','b','a','r',0 };
306 
307 static CHAR *
308 REBAR_FmtStyle(char *buffer, UINT style)
309 {
310     INT i = 0;
311 
312     *buffer = 0;
313     while (band_stylename[i]) {
314 	if (style & (1<<i)) {
315 	    if (*buffer) strcat(buffer, " | ");
316 	    strcat(buffer, band_stylename[i]);
317 	}
318 	i++;
319     }
320     return buffer;
321 }
322 
323 
324 static CHAR *
325 REBAR_FmtMask(char *buffer, UINT mask)
326 {
327     INT i = 0;
328 
329     *buffer = 0;
330     while (band_maskname[i]) {
331 	if (mask & (1<<i)) {
332 	    if (*buffer) strcat(buffer, " | ");
333 	    strcat(buffer, band_maskname[i]);
334 	}
335 	i++;
336     }
337     return buffer;
338 }
339 
340 
341 static VOID
342 REBAR_DumpBandInfo(const REBARBANDINFOW *pB)
343 {
344     char buff[300];
345 
346     if( !TRACE_ON(rebar) ) return;
347     TRACE("band info: ");
348     if (pB->fMask & RBBIM_ID)
349         TRACE("ID=%u, ", pB->wID);
350     TRACE("size=%u, child=%p", pB->cbSize, pB->hwndChild);
351     if (pB->fMask & RBBIM_COLORS)
352         TRACE(", clrF=0x%06x, clrB=0x%06x", pB->clrFore, pB->clrBack);
353     TRACE("\n");
354 
355     TRACE("band info: mask=0x%08x (%s)\n", pB->fMask, REBAR_FmtMask(buff, pB->fMask));
356     if (pB->fMask & RBBIM_STYLE)
357 	TRACE("band info: style=0x%08x (%s)\n", pB->fStyle, REBAR_FmtStyle(buff, pB->fStyle));
358     if (pB->fMask & (RBBIM_SIZE | RBBIM_IDEALSIZE | RBBIM_HEADERSIZE | RBBIM_LPARAM )) {
359 	TRACE("band info:");
360 	if (pB->fMask & RBBIM_SIZE)
361 	    TRACE(" cx=%u", pB->cx);
362 	if (pB->fMask & RBBIM_IDEALSIZE)
363 	    TRACE(" xIdeal=%u", pB->cxIdeal);
364 	if (pB->fMask & RBBIM_HEADERSIZE)
365 	    TRACE(" xHeader=%u", pB->cxHeader);
366 	if (pB->fMask & RBBIM_LPARAM)
367 	    TRACE(" lParam=0x%08lx", pB->lParam);
368 	TRACE("\n");
369     }
370     if (pB->fMask & RBBIM_CHILDSIZE)
371 	TRACE("band info: xMin=%u, yMin=%u, yChild=%u, yMax=%u, yIntgl=%u\n",
372 	      pB->cxMinChild,
373 	      pB->cyMinChild, pB->cyChild, pB->cyMaxChild, pB->cyIntegral);
374 }
375 
376 static VOID
377 REBAR_DumpBand (const REBAR_INFO *iP)
378 {
379     char buff[300];
380     REBAR_BAND *pB;
381     UINT i;
382 
383     if(! TRACE_ON(rebar) ) return;
384 
385     TRACE("hwnd=%p: color=%08x/%08x, bands=%u, rows=%u, cSize=%d,%d\n",
386 	  iP->hwndSelf, iP->clrText, iP->clrBk, iP->uNumBands, iP->uNumRows,
387 	  iP->calcSize.cx, iP->calcSize.cy);
388     TRACE("hwnd=%p: flags=%08x, dragStart=%d,%d, dragNow=%d,%d, iGrabbedBand=%d\n",
389 	  iP->hwndSelf, iP->fStatus, iP->dragStart.x, iP->dragStart.y,
390 	  iP->dragNow.x, iP->dragNow.y,
391 	  iP->iGrabbedBand);
392     TRACE("hwnd=%p: style=%08x, notify in Unicode=%s, redraw=%s\n",
393           iP->hwndSelf, iP->dwStyle, (iP->bUnicode)?"TRUE":"FALSE",
394           (iP->DoRedraw)?"TRUE":"FALSE");
395     for (i = 0; i < iP->uNumBands; i++) {
396 	pB = REBAR_GetBand(iP, i);
397 	TRACE("band # %u:", i);
398 	if (pB->fMask & RBBIM_ID)
399 	    TRACE(" ID=%u", pB->wID);
400 	if (pB->fMask & RBBIM_CHILD)
401 	    TRACE(" child=%p", pB->hwndChild);
402 	if (pB->fMask & RBBIM_COLORS)
403             TRACE(" clrF=0x%06x clrB=0x%06x", pB->clrFore, pB->clrBack);
404 	TRACE("\n");
405 	TRACE("band # %u: mask=0x%08x (%s)\n", i, pB->fMask, REBAR_FmtMask(buff, pB->fMask));
406 	if (pB->fMask & RBBIM_STYLE)
407 	    TRACE("band # %u: style=0x%08x (%s)\n", i, pB->fStyle, REBAR_FmtStyle(buff, pB->fStyle));
408 	TRACE("band # %u: xHeader=%u",
409 	      i, pB->cxHeader);
410 	if (pB->fMask & (RBBIM_SIZE | RBBIM_IDEALSIZE | RBBIM_LPARAM )) {
411 	    if (pB->fMask & RBBIM_SIZE)
412 		TRACE(" cx=%u", pB->cx);
413 	    if (pB->fMask & RBBIM_IDEALSIZE)
414 		TRACE(" xIdeal=%u", pB->cxIdeal);
415 	    if (pB->fMask & RBBIM_LPARAM)
416 		TRACE(" lParam=0x%08lx", pB->lParam);
417 	}
418 	TRACE("\n");
419 	if (RBBIM_CHILDSIZE)
420 	    TRACE("band # %u: xMin=%u, yMin=%u, yChild=%u, yMax=%u, yIntgl=%u\n",
421 		  i, pB->cxMinChild, pB->cyMinChild, pB->cyChild, pB->cyMaxChild, pB->cyIntegral);
422 	if (pB->fMask & RBBIM_TEXT)
423 	    TRACE("band # %u: text=%s\n",
424 		  i, (pB->lpText) ? debugstr_w(pB->lpText) : "(null)");
425         TRACE("band # %u: cxMinBand=%u, cxEffective=%u, cyMinBand=%u\n",
426               i, pB->cxMinBand, pB->cxEffective, pB->cyMinBand);
427         TRACE("band # %u: fStatus=%08x, fDraw=%08x, Band=(%s), Grip=(%s)\n",
428               i, pB->fStatus, pB->fDraw, wine_dbgstr_rect(&pB->rcBand),
429               wine_dbgstr_rect(&pB->rcGripper));
430         TRACE("band # %u: Img=(%s), Txt=(%s), Child=(%s)\n",
431               i, wine_dbgstr_rect(&pB->rcCapImage),
432               wine_dbgstr_rect(&pB->rcCapText), wine_dbgstr_rect(&pB->rcChild));
433     }
434 
435 }
436 
437 /* dest can be equal to src */
438 static void translate_rect(const REBAR_INFO *infoPtr, RECT *dest, const RECT *src)
439 {
440     if (infoPtr->dwStyle & CCS_VERT) {
441         int tmp;
442         tmp = src->left;
443         dest->left = src->top;
444         dest->top = tmp;
445 
446         tmp = src->right;
447         dest->right = src->bottom;
448         dest->bottom = tmp;
449     } else {
450         *dest = *src;
451     }
452 }
453 
454 static int get_rect_cx(const REBAR_INFO *infoPtr, const RECT *lpRect)
455 {
456     if (infoPtr->dwStyle & CCS_VERT)
457         return lpRect->bottom - lpRect->top;
458     return lpRect->right - lpRect->left;
459 }
460 
461 static int get_rect_cy(const REBAR_INFO *infoPtr, const RECT *lpRect)
462 {
463     if (infoPtr->dwStyle & CCS_VERT)
464         return lpRect->right - lpRect->left;
465     return lpRect->bottom - lpRect->top;
466 }
467 
468 static int round_child_height(const REBAR_BAND *lpBand, int cyHeight)
469 {
470     int cy = 0;
471     if (lpBand->cyIntegral == 0)
472         return cyHeight;
473     cy = max(cyHeight - (int)lpBand->cyMinChild, 0);
474     cy = lpBand->cyMinChild + (cy/lpBand->cyIntegral) * lpBand->cyIntegral;
475     cy = min(cy, lpBand->cyMaxChild);
476     return cy;
477 }
478 
479 static void update_min_band_height(const REBAR_INFO *infoPtr, REBAR_BAND *lpBand)
480 {
481     lpBand->cyMinBand = max(lpBand->cyHeader,
482         (lpBand->hwndChild ? lpBand->cyChild + REBARSPACE(lpBand) : REBAR_NO_CHILD_HEIGHT));
483 }
484 
485 static void
486 REBAR_DrawChevron (HDC hdc, INT left, INT top, INT colorRef)
487 {
488     INT x, y;
489     HPEN hPen, hOldPen;
490 
491     if (!(hPen = CreatePen( PS_SOLID, 1, GetSysColor( colorRef )))) return;
492     hOldPen = SelectObject ( hdc, hPen );
493     x = left + 2;
494     y = top;
495     MoveToEx (hdc, x, y, NULL);
496     LineTo (hdc, x+5, y++); x++;
497     MoveToEx (hdc, x, y, NULL);
498     LineTo (hdc, x+3, y++); x++;
499     MoveToEx (hdc, x, y, NULL);
500     LineTo (hdc, x+1, y);
501     SelectObject( hdc, hOldPen );
502     DeleteObject( hPen );
503 }
504 
505 static HWND
506 REBAR_GetNotifyParent (const REBAR_INFO *infoPtr)
507 {
508     HWND parent, owner;
509 
510     parent = infoPtr->hwndNotify;
511     if (!parent) {
512         parent = GetParent (infoPtr->hwndSelf);
513 	owner = GetWindow (infoPtr->hwndSelf, GW_OWNER);
514 	if (owner) parent = owner;
515     }
516     return parent;
517 }
518 
519 
520 static INT
521 REBAR_Notify (NMHDR *nmhdr, const REBAR_INFO *infoPtr, UINT code)
522 {
523     HWND parent;
524 
525     parent = REBAR_GetNotifyParent (infoPtr);
526     nmhdr->idFrom = GetDlgCtrlID (infoPtr->hwndSelf);
527     nmhdr->hwndFrom = infoPtr->hwndSelf;
528     nmhdr->code = code;
529 
530     TRACE("window %p, code=%08x, via %s\n", parent, code, (infoPtr->bUnicode)?"Unicode":"ANSI");
531 
532     return SendMessageW(parent, WM_NOTIFY, nmhdr->idFrom, (LPARAM)nmhdr);
533 }
534 
535 static INT
536 REBAR_Notify_NMREBAR (const REBAR_INFO *infoPtr, UINT uBand, UINT code)
537 {
538     NMREBAR notify_rebar;
539 
540     notify_rebar.dwMask = 0;
541     if (uBand != -1) {
542 	REBAR_BAND *lpBand = REBAR_GetBand(infoPtr, uBand);
543 
544 	if (lpBand->fMask & RBBIM_ID) {
545 	    notify_rebar.dwMask |= RBNM_ID;
546 	    notify_rebar.wID = lpBand->wID;
547 	}
548 	if (lpBand->fMask & RBBIM_LPARAM) {
549 	    notify_rebar.dwMask |= RBNM_LPARAM;
550 	    notify_rebar.lParam = lpBand->lParam;
551 	}
552 	if (lpBand->fMask & RBBIM_STYLE) {
553 	    notify_rebar.dwMask |= RBNM_STYLE;
554 	    notify_rebar.fStyle = lpBand->fStyle;
555 	}
556     }
557     notify_rebar.uBand = uBand;
558     return REBAR_Notify ((NMHDR *)&notify_rebar, infoPtr, code);
559 }
560 
561 static VOID
562 REBAR_DrawBand (HDC hdc, const REBAR_INFO *infoPtr, REBAR_BAND *lpBand)
563 {
564     HFONT hOldFont = 0;
565     INT oldBkMode = 0;
566     NMCUSTOMDRAW nmcd;
567     HTHEME theme = GetWindowTheme (infoPtr->hwndSelf);
568     RECT rcBand;
569 
570     translate_rect(infoPtr, &rcBand, &lpBand->rcBand);
571 
572     if (lpBand->fDraw & DRAW_TEXT) {
573 	hOldFont = SelectObject (hdc, infoPtr->hFont);
574 	oldBkMode = SetBkMode (hdc, TRANSPARENT);
575     }
576 
577     /* should test for CDRF_NOTIFYITEMDRAW here */
578     nmcd.dwDrawStage = CDDS_ITEMPREPAINT;
579     nmcd.hdc = hdc;
580     nmcd.rc = rcBand;
581     nmcd.rc.right = lpBand->rcCapText.right;
582     nmcd.rc.bottom = lpBand->rcCapText.bottom;
583     nmcd.dwItemSpec = lpBand->wID;
584     nmcd.uItemState = 0;
585     nmcd.lItemlParam = lpBand->lParam;
586     lpBand->uCDret = REBAR_Notify ((NMHDR *)&nmcd, infoPtr, NM_CUSTOMDRAW);
587     if (lpBand->uCDret == CDRF_SKIPDEFAULT) {
588 	if (oldBkMode != TRANSPARENT)
589 	    SetBkMode (hdc, oldBkMode);
590 	SelectObject (hdc, hOldFont);
591 	return;
592     }
593 
594     /* draw gripper */
595     if (lpBand->fDraw & DRAW_GRIPPER)
596     {
597         if (theme)
598         {
599             RECT rcGripper = lpBand->rcGripper;
600             int partId = (infoPtr->dwStyle & CCS_VERT) ? RP_GRIPPERVERT : RP_GRIPPER;
601             GetThemeBackgroundExtent (theme, hdc, partId, 0, &rcGripper, &rcGripper);
602             OffsetRect (&rcGripper, lpBand->rcGripper.left - rcGripper.left,
603                 lpBand->rcGripper.top - rcGripper.top);
604             DrawThemeBackground (theme, hdc, partId, 0, &rcGripper, NULL);
605         }
606         else
607             DrawEdge (hdc, &lpBand->rcGripper, BDR_RAISEDINNER, BF_RECT | BF_MIDDLE);
608     }
609 
610     /* draw caption image */
611     if (lpBand->fDraw & DRAW_IMAGE) {
612 	POINT pt;
613 
614 	/* center image */
615 	pt.y = (lpBand->rcCapImage.bottom + lpBand->rcCapImage.top - infoPtr->imageSize.cy)/2;
616 	pt.x = (lpBand->rcCapImage.right + lpBand->rcCapImage.left - infoPtr->imageSize.cx)/2;
617 
618 	ImageList_Draw (infoPtr->himl, lpBand->iImage, hdc,
619 			pt.x, pt.y,
620 			ILD_TRANSPARENT);
621     }
622 
623     /* draw caption text */
624     if (lpBand->fDraw & DRAW_TEXT) {
625 	/* need to handle CDRF_NEWFONT here */
626 	INT oldBkMode = SetBkMode (hdc, TRANSPARENT);
627 	COLORREF oldcolor = CLR_NONE;
628 	COLORREF new;
629 	if (lpBand->clrFore != CLR_NONE) {
630 	    new = (lpBand->clrFore == CLR_DEFAULT) ? infoPtr->clrBtnText :
631 		    lpBand->clrFore;
632 	    oldcolor = SetTextColor (hdc, new);
633 	}
634 
635 #ifdef __REACTOS__
636     if (!theme)
637     {
638         DrawTextW (hdc, lpBand->lpText, -1, &lpBand->rcCapText, DT_CENTER | DT_VCENTER | DT_SINGLELINE);
639     }
640     else
641     {
642         DrawThemeText(theme, hdc, 0, 0, lpBand->lpText, -1, DT_CENTER | DT_VCENTER | DT_SINGLELINE, 0, &lpBand->rcCapText);
643     }
644 #else
645 	DrawTextW (hdc, lpBand->lpText, -1, &lpBand->rcCapText,
646 		   DT_CENTER | DT_VCENTER | DT_SINGLELINE);
647 #endif
648 
649 	if (oldBkMode != TRANSPARENT)
650 	    SetBkMode (hdc, oldBkMode);
651 	if (lpBand->clrFore != CLR_NONE)
652 	    SetTextColor (hdc, oldcolor);
653 	SelectObject (hdc, hOldFont);
654     }
655 
656     if (!IsRectEmpty(&lpBand->rcChevron))
657     {
658         if (theme)
659         {
660             int stateId;
661             if (lpBand->fDraw & DRAW_CHEVRONPUSHED)
662                 stateId = CHEVS_PRESSED;
663             else if (lpBand->fDraw & DRAW_CHEVRONHOT)
664                 stateId = CHEVS_HOT;
665             else
666                 stateId = CHEVS_NORMAL;
667             DrawThemeBackground (theme, hdc, RP_CHEVRON, stateId, &lpBand->rcChevron, NULL);
668         }
669         else
670         {
671             if (lpBand->fDraw & DRAW_CHEVRONPUSHED)
672             {
673                 DrawEdge(hdc, &lpBand->rcChevron, BDR_SUNKENOUTER, BF_RECT | BF_MIDDLE);
674                 REBAR_DrawChevron(hdc, lpBand->rcChevron.left+1, lpBand->rcChevron.top + 11, COLOR_WINDOWFRAME);
675             }
676             else if (lpBand->fDraw & DRAW_CHEVRONHOT)
677             {
678                 DrawEdge(hdc, &lpBand->rcChevron, BDR_RAISEDINNER, BF_RECT | BF_MIDDLE);
679                 REBAR_DrawChevron(hdc, lpBand->rcChevron.left, lpBand->rcChevron.top + 10, COLOR_WINDOWFRAME);
680             }
681             else
682                 REBAR_DrawChevron(hdc, lpBand->rcChevron.left, lpBand->rcChevron.top + 10, COLOR_WINDOWFRAME);
683         }
684     }
685 
686     if (lpBand->uCDret == (CDRF_NOTIFYPOSTPAINT | CDRF_NOTIFYITEMDRAW)) {
687 	nmcd.dwDrawStage = CDDS_ITEMPOSTPAINT;
688 	nmcd.hdc = hdc;
689 	nmcd.rc = rcBand;
690 	nmcd.rc.right = lpBand->rcCapText.right;
691 	nmcd.rc.bottom = lpBand->rcCapText.bottom;
692 	nmcd.dwItemSpec = lpBand->wID;
693 	nmcd.uItemState = 0;
694 	nmcd.lItemlParam = lpBand->lParam;
695 	lpBand->uCDret = REBAR_Notify ((NMHDR *)&nmcd, infoPtr, NM_CUSTOMDRAW);
696     }
697 }
698 
699 
700 static VOID
701 REBAR_Refresh (const REBAR_INFO *infoPtr, HDC hdc)
702 {
703     REBAR_BAND *lpBand;
704     UINT i;
705 
706     if (!infoPtr->DoRedraw) return;
707 
708     for (i = 0; i < infoPtr->uNumBands; i++) {
709 	lpBand = REBAR_GetBand(infoPtr, i);
710 
711 	if (HIDDENBAND(lpBand)) continue;
712 
713 	/* now draw the band */
714 	TRACE("[%p] drawing band %i, flags=%08x\n",
715 	      infoPtr->hwndSelf, i, lpBand->fDraw);
716 	REBAR_DrawBand (hdc, infoPtr, lpBand);
717     }
718 }
719 
720 
721 static void
722 REBAR_CalcHorzBand (const REBAR_INFO *infoPtr, UINT rstart, UINT rend)
723      /* Function: this routine initializes all the rectangles in */
724      /*  each band in a row to fit in the adjusted rcBand rect.  */
725      /* *** Supports only Horizontal bars. ***                   */
726 {
727     REBAR_BAND *lpBand;
728     UINT i, xoff;
729     RECT work;
730 
731     for(i=rstart; i<rend; i++){
732       lpBand = REBAR_GetBand(infoPtr, i);
733       if (HIDDENBAND(lpBand)) {
734           SetRect (&lpBand->rcChild,
735 		   lpBand->rcBand.right, lpBand->rcBand.top,
736 		   lpBand->rcBand.right, lpBand->rcBand.bottom);
737 	  continue;
738       }
739 
740       /* set initial gripper rectangle */
741       SetRect (&lpBand->rcGripper, lpBand->rcBand.left, lpBand->rcBand.top,
742 	       lpBand->rcBand.left, lpBand->rcBand.bottom);
743 
744       /* calculate gripper rectangle */
745       if ( lpBand->fStatus & HAS_GRIPPER) {
746 	  lpBand->fDraw |= DRAW_GRIPPER;
747 	  lpBand->rcGripper.left   += REBAR_PRE_GRIPPER;
748 	  lpBand->rcGripper.right  = lpBand->rcGripper.left + GRIPPER_WIDTH;
749           InflateRect(&lpBand->rcGripper, 0, -2);
750 
751 	  SetRect (&lpBand->rcCapImage,
752 		   lpBand->rcGripper.right+REBAR_ALWAYS_SPACE, lpBand->rcBand.top,
753 		   lpBand->rcGripper.right+REBAR_ALWAYS_SPACE, lpBand->rcBand.bottom);
754       }
755       else {  /* no gripper will be drawn */
756 	  xoff = 0;
757 	  if (lpBand->fStatus & (HAS_IMAGE | HAS_TEXT))
758 	      /* if no gripper but either image or text, then leave space */
759 	      xoff = REBAR_ALWAYS_SPACE;
760 	  SetRect (&lpBand->rcCapImage,
761 		   lpBand->rcBand.left+xoff, lpBand->rcBand.top,
762 		   lpBand->rcBand.left+xoff, lpBand->rcBand.bottom);
763       }
764 
765       /* image is visible */
766       if (lpBand->fStatus & HAS_IMAGE) {
767 	  lpBand->fDraw |= DRAW_IMAGE;
768 	  lpBand->rcCapImage.right  += infoPtr->imageSize.cx;
769 	  lpBand->rcCapImage.bottom = lpBand->rcCapImage.top + infoPtr->imageSize.cy;
770 
771 	  /* set initial caption text rectangle */
772 	  SetRect (&lpBand->rcCapText,
773 		   lpBand->rcCapImage.right+REBAR_POST_IMAGE, lpBand->rcBand.top+1,
774 		   lpBand->rcBand.left+lpBand->cxHeader, lpBand->rcBand.bottom-1);
775       }
776       else {
777 	  /* set initial caption text rectangle */
778 	  SetRect (&lpBand->rcCapText, lpBand->rcCapImage.right, lpBand->rcBand.top+1,
779 		   lpBand->rcBand.left+lpBand->cxHeader, lpBand->rcBand.bottom-1);
780       }
781 
782       /* text is visible */
783       if ((lpBand->fStatus & HAS_TEXT) && !(lpBand->fStyle & RBBS_HIDETITLE)) {
784 	  lpBand->fDraw |= DRAW_TEXT;
785 	  lpBand->rcCapText.right = max(lpBand->rcCapText.left,
786 					lpBand->rcCapText.right-REBAR_POST_TEXT);
787       }
788 
789       /* set initial child window rectangle if there is a child */
790       if (lpBand->hwndChild) {
791 
792           lpBand->rcChild.left  = lpBand->rcBand.left + lpBand->cxHeader;
793           lpBand->rcChild.right = lpBand->rcBand.right - REBAR_POST_CHILD;
794 
795           if (lpBand->cyChild > 0) {
796 
797               UINT yoff = (lpBand->rcBand.bottom - lpBand->rcBand.top - lpBand->cyChild) / 2;
798 
799               /* center child if height is known */
800               lpBand->rcChild.top = lpBand->rcBand.top + yoff;
801               lpBand->rcChild.bottom = lpBand->rcBand.top + yoff + lpBand->cyChild;
802           }
803           else {
804               lpBand->rcChild.top = lpBand->rcBand.top;
805               lpBand->rcChild.bottom = lpBand->rcBand.bottom;
806           }
807 
808 	  if ((lpBand->fStyle & RBBS_USECHEVRON) && (lpBand->rcChild.right - lpBand->rcChild.left < lpBand->cxIdeal))
809 	  {
810 	      lpBand->rcChild.right -= CHEVRON_WIDTH;
811 	      SetRect(&lpBand->rcChevron, lpBand->rcChild.right,
812 	              lpBand->rcChild.top, lpBand->rcChild.right + CHEVRON_WIDTH,
813 	              lpBand->rcChild.bottom);
814 	  }
815       }
816       else {
817           SetRect (&lpBand->rcChild,
818 		   lpBand->rcBand.left+lpBand->cxHeader, lpBand->rcBand.top,
819 		   lpBand->rcBand.right, lpBand->rcBand.bottom);
820       }
821 
822       /* flag if notify required and invalidate rectangle */
823       if (lpBand->fDraw & NTF_INVALIDATE) {
824 	  lpBand->fDraw &= ~NTF_INVALIDATE;
825 	  work = lpBand->rcBand;
826 	  work.right += SEP_WIDTH;
827 	  work.bottom += SEP_WIDTH;
828 	  TRACE("invalidating %s\n", wine_dbgstr_rect(&work));
829 	  InvalidateRect(infoPtr->hwndSelf, &work, TRUE);
830 	  if (lpBand->hwndChild) InvalidateRect(lpBand->hwndChild, NULL, TRUE);
831       }
832 
833     }
834 
835 }
836 
837 
838 static VOID
839 REBAR_CalcVertBand (const REBAR_INFO *infoPtr, UINT rstart, UINT rend)
840      /* Function: this routine initializes all the rectangles in */
841      /*  each band in a row to fit in the adjusted rcBand rect.  */
842      /* *** Supports only Vertical bars. ***                     */
843 {
844     REBAR_BAND *lpBand;
845     UINT i, xoff;
846     RECT work;
847 
848     for(i=rstart; i<rend; i++){
849         RECT rcBand;
850         lpBand = REBAR_GetBand(infoPtr, i);
851 	if (HIDDENBAND(lpBand)) continue;
852 
853         translate_rect(infoPtr, &rcBand, &lpBand->rcBand);
854 
855         /* set initial gripper rectangle */
856 	SetRect (&lpBand->rcGripper, rcBand.left, rcBand.top, rcBand.right, rcBand.top);
857 
858 	/* calculate gripper rectangle */
859 	if (lpBand->fStatus & HAS_GRIPPER) {
860 	    lpBand->fDraw |= DRAW_GRIPPER;
861 
862 	    if (infoPtr->dwStyle & RBS_VERTICALGRIPPER) {
863 		/*  vertical gripper  */
864 		lpBand->rcGripper.left   += 3;
865 		lpBand->rcGripper.right  = lpBand->rcGripper.left + GRIPPER_WIDTH;
866 		lpBand->rcGripper.top    += REBAR_PRE_GRIPPER;
867 		lpBand->rcGripper.bottom = lpBand->rcGripper.top + GRIPPER_HEIGHT;
868 
869 		/* initialize Caption image rectangle  */
870 		SetRect (&lpBand->rcCapImage, rcBand.left,
871 			 lpBand->rcGripper.bottom + REBAR_ALWAYS_SPACE,
872 			 rcBand.right,
873 			 lpBand->rcGripper.bottom + REBAR_ALWAYS_SPACE);
874 	    }
875 	    else {
876 		/*  horizontal gripper  */
877                 InflateRect(&lpBand->rcGripper, -2, 0);
878 		lpBand->rcGripper.top    += REBAR_PRE_GRIPPER;
879 		lpBand->rcGripper.bottom  = lpBand->rcGripper.top + GRIPPER_WIDTH;
880 
881 		/* initialize Caption image rectangle  */
882 		SetRect (&lpBand->rcCapImage, rcBand.left,
883 			 lpBand->rcGripper.bottom + REBAR_ALWAYS_SPACE,
884 			 rcBand.right,
885 			 lpBand->rcGripper.bottom + REBAR_ALWAYS_SPACE);
886 	    }
887 	}
888 	else {  /* no gripper will be drawn */
889 	    xoff = 0;
890 	    if (lpBand->fStatus & (HAS_IMAGE | HAS_TEXT))
891 		/* if no gripper but either image or text, then leave space */
892 		xoff = REBAR_ALWAYS_SPACE;
893 	    /* initialize Caption image rectangle  */
894 	    SetRect (&lpBand->rcCapImage,
895                       rcBand.left, rcBand.top+xoff,
896                       rcBand.right, rcBand.top+xoff);
897 	}
898 
899 	/* image is visible */
900 	if (lpBand->fStatus & HAS_IMAGE) {
901 	    lpBand->fDraw |= DRAW_IMAGE;
902 
903 	    lpBand->rcCapImage.right  = lpBand->rcCapImage.left + infoPtr->imageSize.cx;
904 	    lpBand->rcCapImage.bottom += infoPtr->imageSize.cy;
905 
906 	    /* set initial caption text rectangle */
907 	    SetRect (&lpBand->rcCapText,
908 		     rcBand.left, lpBand->rcCapImage.bottom+REBAR_POST_IMAGE,
909 		     rcBand.right, rcBand.top+lpBand->cxHeader);
910 	}
911 	else {
912 	    /* set initial caption text rectangle */
913 	    SetRect (&lpBand->rcCapText,
914 		     rcBand.left, lpBand->rcCapImage.bottom,
915 		     rcBand.right, rcBand.top+lpBand->cxHeader);
916 	}
917 
918 	/* text is visible */
919 	if ((lpBand->fStatus & HAS_TEXT) && !(lpBand->fStyle & RBBS_HIDETITLE)) {
920 	    lpBand->fDraw |= DRAW_TEXT;
921 	    lpBand->rcCapText.bottom = max(lpBand->rcCapText.top,
922 					   lpBand->rcCapText.bottom);
923 	}
924 
925 	/* set initial child window rectangle if there is a child */
926 	if (lpBand->hwndChild) {
927             int cxBand = rcBand.right - rcBand.left;
928             xoff = (cxBand - lpBand->cyChild) / 2;
929 	    SetRect (&lpBand->rcChild,
930 		     rcBand.left + xoff,                   rcBand.top + lpBand->cxHeader,
931                      rcBand.left + xoff + lpBand->cyChild, rcBand.bottom - REBAR_POST_CHILD);
932 	}
933 	else {
934 	    SetRect (&lpBand->rcChild,
935 		     rcBand.left, rcBand.top+lpBand->cxHeader,
936 		     rcBand.right, rcBand.bottom);
937 	}
938 
939 	if (lpBand->fDraw & NTF_INVALIDATE) {
940 	    lpBand->fDraw &= ~NTF_INVALIDATE;
941 	    work = rcBand;
942 	    work.bottom += SEP_WIDTH;
943 	    work.right += SEP_WIDTH;
944 	    TRACE("invalidating %s\n", wine_dbgstr_rect(&work));
945 	    InvalidateRect(infoPtr->hwndSelf, &work, TRUE);
946 	    if (lpBand->hwndChild) InvalidateRect(lpBand->hwndChild, NULL, TRUE);
947 	}
948 
949     }
950 }
951 
952 
953 static VOID
954 REBAR_ForceResize (REBAR_INFO *infoPtr)
955      /* Function: This changes the size of the REBAR window to that */
956      /*  calculated by REBAR_Layout.                                */
957 {
958     INT x, y, width, height;
959     INT xedge = 0, yedge = 0;
960     RECT rcSelf;
961 
962     TRACE("new size [%d x %d]\n", infoPtr->calcSize.cx, infoPtr->calcSize.cy);
963 
964     if (infoPtr->dwStyle & CCS_NORESIZE)
965         return;
966 
967     if (infoPtr->dwStyle & WS_BORDER)
968     {
969         xedge = GetSystemMetrics(SM_CXEDGE);
970         yedge = GetSystemMetrics(SM_CYEDGE);
971         /* swap for CCS_VERT? */
972     }
973 
974     /* compute rebar window rect in parent client coordinates */
975     GetWindowRect(infoPtr->hwndSelf, &rcSelf);
976     MapWindowPoints(HWND_DESKTOP, GetParent(infoPtr->hwndSelf), (LPPOINT)&rcSelf, 2);
977     translate_rect(infoPtr, &rcSelf, &rcSelf);
978 
979     height = infoPtr->calcSize.cy + 2*yedge;
980     if (!(infoPtr->dwStyle & CCS_NOPARENTALIGN)) {
981         RECT rcParent;
982 
983         x = -xedge;
984         width = infoPtr->calcSize.cx + 2*xedge;
985         y = 0; /* quiet compiler warning */
986         switch ( infoPtr->dwStyle & CCS_LAYOUT_MASK) {
987             case 0:     /* shouldn't happen - see NCCreate */
988             case CCS_TOP:
989                 y = ((infoPtr->dwStyle & CCS_NODIVIDER) ? 0 : REBAR_DIVIDER) - yedge;
990                 break;
991             case CCS_NOMOVEY:
992                 y = rcSelf.top;
993                 break;
994             case CCS_BOTTOM:
995                 GetClientRect(GetParent(infoPtr->hwndSelf), &rcParent);
996                 translate_rect(infoPtr, &rcParent, &rcParent);
997                 y = rcParent.bottom - infoPtr->calcSize.cy - yedge;
998                 break;
999 	}
1000     }
1001     else {
1002 	x = rcSelf.left;
1003 	/* As on Windows if the CCS_NODIVIDER is not present the control will move
1004 	 * 2 pixel down after every layout */
1005 	y = rcSelf.top + ((infoPtr->dwStyle & CCS_NODIVIDER) ? 0 : REBAR_DIVIDER);
1006 	width = rcSelf.right - rcSelf.left;
1007     }
1008 
1009     TRACE("hwnd %p, style=%08x, setting at (%d,%d) for (%d,%d)\n",
1010 	infoPtr->hwndSelf, infoPtr->dwStyle, x, y, width, height);
1011 
1012     /* Set flag to ignore next WM_SIZE message and resize the window */
1013     infoPtr->fStatus |= SELF_RESIZE;
1014     if ((infoPtr->dwStyle & CCS_VERT) == 0)
1015         SetWindowPos(infoPtr->hwndSelf, 0, x, y, width, height, SWP_NOZORDER);
1016     else
1017         SetWindowPos(infoPtr->hwndSelf, 0, y, x, height, width, SWP_NOZORDER);
1018     infoPtr->fStatus &= ~SELF_RESIZE;
1019 }
1020 
1021 
1022 static VOID
1023 REBAR_MoveChildWindows (const REBAR_INFO *infoPtr, UINT start, UINT endplus)
1024 {
1025     static const WCHAR strComboBox[] = { 'C','o','m','b','o','B','o','x',0 };
1026     REBAR_BAND *lpBand;
1027     WCHAR szClassName[40];
1028     UINT i;
1029     NMREBARCHILDSIZE  rbcz;
1030     HDWP deferpos;
1031 
1032     if (!(deferpos = BeginDeferWindowPos(infoPtr->uNumBands)))
1033         ERR("BeginDeferWindowPos returned NULL\n");
1034 
1035     for (i = start; i < endplus; i++) {
1036 	lpBand = REBAR_GetBand(infoPtr, i);
1037 
1038 	if (HIDDENBAND(lpBand)) continue;
1039 	if (lpBand->hwndChild) {
1040 	    TRACE("hwndChild = %p\n", lpBand->hwndChild);
1041 
1042 	    /* Always generate the RBN_CHILDSIZE even if child
1043 		   did not change */
1044 	    rbcz.uBand = i;
1045 	    rbcz.wID = lpBand->wID;
1046 	    rbcz.rcChild = lpBand->rcChild;
1047             translate_rect(infoPtr, &rbcz.rcBand, &lpBand->rcBand);
1048 	    if (infoPtr->dwStyle & CCS_VERT)
1049 		rbcz.rcBand.top += lpBand->cxHeader;
1050 	    else
1051 		rbcz.rcBand.left += lpBand->cxHeader;
1052 	    REBAR_Notify ((NMHDR *)&rbcz, infoPtr, RBN_CHILDSIZE);
1053 	    if (!EqualRect (&lpBand->rcChild, &rbcz.rcChild)) {
1054 		TRACE("Child rect changed by NOTIFY for band %u\n", i);
1055                 TRACE("    from (%s)  to (%s)\n",
1056                       wine_dbgstr_rect(&lpBand->rcChild),
1057                       wine_dbgstr_rect(&rbcz.rcChild));
1058 		lpBand->rcChild = rbcz.rcChild;  /* *** ??? */
1059             }
1060 
1061 	    GetClassNameW (lpBand->hwndChild, szClassName, ARRAY_SIZE(szClassName));
1062 	    if (!lstrcmpW (szClassName, strComboBox) ||
1063 		!lstrcmpW (szClassName, WC_COMBOBOXEXW)) {
1064 		INT nEditHeight, yPos;
1065 		RECT rc;
1066 
1067 		/* special placement code for combo or comboex box */
1068 
1069 
1070 		/* get size of edit line */
1071 		GetWindowRect (lpBand->hwndChild, &rc);
1072 		nEditHeight = rc.bottom - rc.top;
1073 		yPos = (lpBand->rcChild.bottom + lpBand->rcChild.top - nEditHeight)/2;
1074 
1075 		/* center combo box inside child area */
1076 		TRACE("moving child (Combo(Ex)) %p to (%d,%d) for (%d,%d)\n",
1077 		      lpBand->hwndChild,
1078 		      lpBand->rcChild.left, yPos,
1079 		      lpBand->rcChild.right - lpBand->rcChild.left,
1080 		      nEditHeight);
1081 		deferpos = DeferWindowPos (deferpos, lpBand->hwndChild, HWND_TOP,
1082 					   lpBand->rcChild.left,
1083 					   /*lpBand->rcChild.top*/ yPos,
1084 					   lpBand->rcChild.right - lpBand->rcChild.left,
1085 					   nEditHeight,
1086 					   SWP_NOZORDER);
1087 		if (!deferpos)
1088 		    ERR("DeferWindowPos returned NULL\n");
1089 	    }
1090 	    else {
1091 		TRACE("moving child (Other) %p to (%d,%d) for (%d,%d)\n",
1092 		      lpBand->hwndChild,
1093 		      lpBand->rcChild.left, lpBand->rcChild.top,
1094 		      lpBand->rcChild.right - lpBand->rcChild.left,
1095 		      lpBand->rcChild.bottom - lpBand->rcChild.top);
1096 		deferpos = DeferWindowPos (deferpos, lpBand->hwndChild, HWND_TOP,
1097 					   lpBand->rcChild.left,
1098 					   lpBand->rcChild.top,
1099 					   lpBand->rcChild.right - lpBand->rcChild.left,
1100 					   lpBand->rcChild.bottom - lpBand->rcChild.top,
1101 					   SWP_NOZORDER);
1102 		if (!deferpos)
1103 		    ERR("DeferWindowPos returned NULL\n");
1104 	    }
1105 	}
1106     }
1107     if (!EndDeferWindowPos(deferpos))
1108         ERR("EndDeferWindowPos returned NULL\n");
1109 
1110     if (infoPtr->DoRedraw)
1111 	UpdateWindow (infoPtr->hwndSelf);
1112 }
1113 
1114 /* Returns the next visible band (the first visible band in [i+1; infoPtr->uNumBands) )
1115  * or infoPtr->uNumBands if none */
1116 static int next_visible(const REBAR_INFO *infoPtr, int i)
1117 {
1118     unsigned int n;
1119     for (n = i + 1; n < infoPtr->uNumBands; n++)
1120         if (!HIDDENBAND(REBAR_GetBand(infoPtr, n)))
1121             break;
1122     return n;
1123 }
1124 
1125 /* Returns the previous visible band (the last visible band in [0; i) )
1126  * or -1 if none */
1127 static int prev_visible(const REBAR_INFO *infoPtr, int i)
1128 {
1129     int n;
1130     for (n = i - 1; n >= 0; n--)
1131         if (!HIDDENBAND(REBAR_GetBand(infoPtr, n)))
1132             break;
1133     return n;
1134 }
1135 
1136 /* Returns the first visible band or infoPtr->uNumBands if none */
1137 static int first_visible(const REBAR_INFO *infoPtr)
1138 {
1139     return next_visible(infoPtr, -1); /* this works*/
1140 }
1141 
1142 /* Returns the first visible band for the given row (or iBand if none) */
1143 static int get_row_begin_for_band(const REBAR_INFO *infoPtr, INT iBand)
1144 {
1145     int iLastBand = iBand;
1146     int iRow = REBAR_GetBand(infoPtr, iBand)->iRow;
1147     while ((iBand = prev_visible(infoPtr, iBand)) >= 0) {
1148         if (REBAR_GetBand(infoPtr, iBand)->iRow != iRow)
1149             break;
1150         else
1151             iLastBand = iBand;
1152     }
1153     return iLastBand;
1154 }
1155 
1156 /* Returns the first visible band for the next row (or infoPtr->uNumBands if none) */
1157 static int get_row_end_for_band(const REBAR_INFO *infoPtr, INT iBand)
1158 {
1159     int iRow = REBAR_GetBand(infoPtr, iBand)->iRow;
1160     while ((iBand = next_visible(infoPtr, iBand)) < infoPtr->uNumBands)
1161         if (REBAR_GetBand(infoPtr, iBand)->iRow != iRow)
1162             break;
1163     return iBand;
1164 }
1165 
1166 /* Compute the rcBand.{left,right} from the cxEffective bands widths computed earlier.
1167  * iBeginBand must be visible */
1168 static void REBAR_SetRowRectsX(const REBAR_INFO *infoPtr, INT iBeginBand, INT iEndBand)
1169 {
1170     int xPos = 0, i;
1171     for (i = iBeginBand; i < iEndBand; i = next_visible(infoPtr, i))
1172     {
1173         REBAR_BAND *lpBand = REBAR_GetBand(infoPtr, i);
1174         if (lpBand->rcBand.left != xPos || lpBand->rcBand.right != xPos + lpBand->cxEffective) {
1175             lpBand->fDraw |= NTF_INVALIDATE;
1176             TRACE("Setting rect %d to %d,%d\n", i, xPos, xPos + lpBand->cxEffective);
1177             lpBand->rcBand.left = xPos;
1178             lpBand->rcBand.right = xPos + lpBand->cxEffective;
1179         }
1180         xPos += lpBand->cxEffective + SEP_WIDTH;
1181     }
1182 }
1183 
1184 /* The rationale of this function is probably as follows: if we have some space
1185  * to distribute we want to add it to a band on the right. However we don't want
1186  * to unminimize a minimized band so we search for a band that is big enough.
1187  * For some reason "big enough" is defined as bigger than the minimum size of the
1188  * first band in the row
1189  */
1190 static REBAR_BAND *REBAR_FindBandToGrow(const REBAR_INFO *infoPtr, INT iBeginBand, INT iEndBand)
1191 {
1192     INT cxMinFirstBand = 0, i;
1193 
1194     cxMinFirstBand = REBAR_GetBand(infoPtr, iBeginBand)->cxMinBand;
1195 
1196     for (i = prev_visible(infoPtr, iEndBand); i >= iBeginBand; i = prev_visible(infoPtr, i))
1197         if (REBAR_GetBand(infoPtr, i)->cxEffective > cxMinFirstBand &&
1198           !(REBAR_GetBand(infoPtr, i)->fStyle & RBBS_FIXEDSIZE))
1199             break;
1200 
1201     if (i < iBeginBand)
1202         for (i = prev_visible(infoPtr, iEndBand); i >= iBeginBand; i = prev_visible(infoPtr, i))
1203             if (REBAR_GetBand(infoPtr, i)->cxMinBand == cxMinFirstBand)
1204                 break;
1205 
1206     TRACE("Extra space for row [%d..%d) should be added to band %d\n", iBeginBand, iEndBand, i);
1207     return REBAR_GetBand(infoPtr, i);
1208 }
1209 
1210 /* Try to shrink the visible bands in [iBeginBand; iEndBand) by cxShrink, starting from the right */
1211 static int REBAR_ShrinkBandsRTL(const REBAR_INFO *infoPtr, INT iBeginBand, INT iEndBand, INT cxShrink, BOOL bEnforce)
1212 {
1213     REBAR_BAND *lpBand;
1214     INT width, i;
1215 
1216     TRACE("Shrinking bands [%d..%d) by %d, right-to-left\n", iBeginBand, iEndBand, cxShrink);
1217     for (i = prev_visible(infoPtr, iEndBand); i >= iBeginBand; i = prev_visible(infoPtr, i))
1218     {
1219         lpBand = REBAR_GetBand(infoPtr, i);
1220 
1221         width = max(lpBand->cxEffective - cxShrink, (int)lpBand->cxMinBand);
1222         cxShrink -= lpBand->cxEffective - width;
1223         lpBand->cxEffective = width;
1224         if (bEnforce && lpBand->cx > lpBand->cxEffective)
1225             lpBand->cx = lpBand->cxEffective;
1226         if (cxShrink == 0)
1227             break;
1228     }
1229     return cxShrink;
1230 }
1231 
1232 
1233 /* Try to shrink the visible bands in [iBeginBand; iEndBand) by cxShrink, starting from the left.
1234  * iBeginBand must be visible */
1235 static int REBAR_ShrinkBandsLTR(const REBAR_INFO *infoPtr, INT iBeginBand, INT iEndBand, INT cxShrink, BOOL bEnforce)
1236 {
1237     REBAR_BAND *lpBand;
1238     INT width, i;
1239 
1240     TRACE("Shrinking bands [%d..%d) by %d, left-to-right\n", iBeginBand, iEndBand, cxShrink);
1241     for (i = iBeginBand; i < iEndBand; i = next_visible(infoPtr, i))
1242     {
1243         lpBand = REBAR_GetBand(infoPtr, i);
1244 
1245         width = max(lpBand->cxEffective - cxShrink, (int)lpBand->cxMinBand);
1246         cxShrink -= lpBand->cxEffective - width;
1247         lpBand->cxEffective = width;
1248         if (bEnforce)
1249             lpBand->cx = lpBand->cxEffective;
1250         if (cxShrink == 0)
1251             break;
1252     }
1253     return cxShrink;
1254 }
1255 
1256 /* Tries to move a band to a given offset within a row. */
1257 static int REBAR_MoveBandToRowOffset(REBAR_INFO *infoPtr, INT iBand, INT iFirstBand,
1258     INT iLastBand, INT xOff, BOOL reorder)
1259 {
1260     REBAR_BAND *insertBand = REBAR_GetBand(infoPtr, iBand);
1261     int xPos = 0, i;
1262     const BOOL setBreak = REBAR_GetBand(infoPtr, iFirstBand)->fStyle & RBBS_BREAK;
1263 
1264     /* Find the band's new position */
1265     if(reorder)
1266     {
1267         /* Used during an LR band reorder drag */
1268         for (i = iFirstBand; i < iLastBand; i = next_visible(infoPtr, i))
1269         {
1270             if(xPos > xOff)
1271                 break;
1272             xPos += REBAR_GetBand(infoPtr, i)->cxEffective + SEP_WIDTH;
1273         }
1274     }
1275     else
1276     {
1277         /* Used during a UD band insertion drag */
1278         for (i = iFirstBand; i < iLastBand; i = next_visible(infoPtr, i))
1279         {
1280             const REBAR_BAND *band = REBAR_GetBand(infoPtr, i);
1281             if(xPos + band->cxMinBand / 2 > xOff)
1282                 break;
1283             xPos += band->cxEffective + SEP_WIDTH;
1284         }
1285     }
1286 
1287     /* Move the band to its new position */
1288     DPA_DeletePtr(infoPtr->bands, iBand);
1289     if(i > iBand)
1290         i--;
1291     DPA_InsertPtr(infoPtr->bands, i, insertBand);
1292 
1293     /* Ensure only the last band has the RBBS_BREAK flag set */
1294     insertBand->fStyle &= ~RBBS_BREAK;
1295     if(setBreak)
1296         REBAR_GetBand(infoPtr, iFirstBand)->fStyle |= RBBS_BREAK;
1297 
1298     /* Return the currently grabbed band */
1299     if(infoPtr->iGrabbedBand == iBand)
1300     {
1301         infoPtr->iGrabbedBand = i;
1302         return i;
1303     }
1304     else return -1;
1305 }
1306 
1307 /* Set the heights of the visible bands in [iBeginBand; iEndBand) to the max height. iBeginBand must be visible */
1308 static int REBAR_SetBandsHeight(const REBAR_INFO *infoPtr, INT iBeginBand, INT iEndBand, INT yStart)
1309 {
1310     REBAR_BAND *lpBand;
1311     int yMaxHeight = 0;
1312     int yPos = yStart;
1313     int row, i;
1314 
1315     for (i = iBeginBand; i < iEndBand; i = next_visible(infoPtr, i))
1316     {
1317         lpBand = REBAR_GetBand(infoPtr, i);
1318         lpBand->cyRowSoFar = yMaxHeight;
1319         yMaxHeight = max(yMaxHeight, lpBand->cyMinBand);
1320     }
1321     TRACE("Bands [%d; %d) height: %d\n", iBeginBand, iEndBand, yMaxHeight);
1322 
1323     row = iBeginBand < iEndBand ? REBAR_GetBand(infoPtr, iBeginBand)->iRow : 0;
1324 
1325     for (i = iBeginBand; i < iEndBand; i = next_visible(infoPtr, i))
1326     {
1327         lpBand = REBAR_GetBand(infoPtr, i);
1328         /* we may be called for multiple rows if RBS_VARHEIGHT not set */
1329         if (lpBand->iRow != row) {
1330             yPos += yMaxHeight + SEP_WIDTH;
1331             row = lpBand->iRow;
1332         }
1333 
1334         if (lpBand->rcBand.top != yPos || lpBand->rcBand.bottom != yPos + yMaxHeight) {
1335             lpBand->fDraw |= NTF_INVALIDATE;
1336             lpBand->rcBand.top = yPos;
1337             lpBand->rcBand.bottom = yPos + yMaxHeight;
1338             TRACE("Band %d: %s\n", i, wine_dbgstr_rect(&lpBand->rcBand));
1339         }
1340     }
1341     return yPos + yMaxHeight;
1342 }
1343 
1344 /* Layout the row [iBeginBand; iEndBand). iBeginBand must be visible */
1345 static void REBAR_LayoutRow(const REBAR_INFO *infoPtr, int iBeginBand, int iEndBand, int cx, int *piRow, int *pyPos)
1346 {
1347     REBAR_BAND *lpBand;
1348     int i, extra;
1349     int width = 0;
1350 
1351     TRACE("Adjusting row [%d;%d). Width: %d\n", iBeginBand, iEndBand, cx);
1352     for (i = iBeginBand; i < iEndBand; i++)
1353         REBAR_GetBand(infoPtr, i)->iRow = *piRow;
1354 
1355     /* compute the extra space */
1356     for (i = iBeginBand; i < iEndBand; i = next_visible(infoPtr, i))
1357     {
1358         lpBand = REBAR_GetBand(infoPtr, i);
1359         if (i > iBeginBand)
1360             width += SEP_WIDTH;
1361         lpBand->cxEffective = max(lpBand->cxMinBand, lpBand->cx);
1362         width += lpBand->cxEffective;
1363     }
1364 
1365     extra = cx - width;
1366     TRACE("Extra space: %d\n", extra);
1367     if (extra < 0) {
1368         int ret = REBAR_ShrinkBandsRTL(infoPtr, iBeginBand, iEndBand, -extra, FALSE);
1369         if (ret > 0 && next_visible(infoPtr, iBeginBand) != iEndBand)  /* one band may be longer than expected... */
1370             ERR("Error layouting row %d - couldn't shrink for %d pixels (%d total shrink)\n", *piRow, ret, -extra);
1371     } else
1372     if (extra > 0) {
1373         lpBand = REBAR_FindBandToGrow(infoPtr, iBeginBand, iEndBand);
1374         lpBand->cxEffective += extra;
1375     }
1376 
1377     REBAR_SetRowRectsX(infoPtr, iBeginBand, iEndBand);
1378     if (infoPtr->dwStyle & RBS_VARHEIGHT)
1379     {
1380         if (*piRow > 0)
1381             *pyPos += SEP_WIDTH;
1382         *pyPos = REBAR_SetBandsHeight(infoPtr, iBeginBand, iEndBand, *pyPos);
1383     }
1384     (*piRow)++;
1385 }
1386 
1387 static VOID
1388 REBAR_Layout(REBAR_INFO *infoPtr)
1389 {
1390     REBAR_BAND *lpBand;
1391     RECT rcAdj;
1392     SIZE oldSize;
1393     INT adjcx, i;
1394     INT rowstart;
1395     INT row = 0;
1396     INT xMin, yPos;
1397 
1398     if (infoPtr->dwStyle & (CCS_NORESIZE | CCS_NOPARENTALIGN) || GetParent(infoPtr->hwndSelf) == NULL)
1399         GetClientRect(infoPtr->hwndSelf, &rcAdj);
1400     else
1401         GetClientRect(GetParent(infoPtr->hwndSelf), &rcAdj);
1402     TRACE("adjustment rect is (%s)\n", wine_dbgstr_rect(&rcAdj));
1403 
1404     adjcx = get_rect_cx(infoPtr, &rcAdj);
1405 
1406     if (infoPtr->uNumBands == 0) {
1407         TRACE("No bands - setting size to (0,%d), style: %x\n", adjcx, infoPtr->dwStyle);
1408         infoPtr->calcSize.cx = adjcx;
1409         /* the calcSize.cy won't change for a 0 band rebar */
1410         infoPtr->uNumRows = 0;
1411         REBAR_ForceResize(infoPtr);
1412         return;
1413     }
1414 
1415     yPos = 0;
1416     xMin = 0;
1417     rowstart = first_visible(infoPtr);
1418     /* divide rows */
1419     for (i = rowstart; i < infoPtr->uNumBands; i = next_visible(infoPtr, i))
1420     {
1421         lpBand = REBAR_GetBand(infoPtr, i);
1422 
1423         if (i > rowstart && (lpBand->fStyle & RBBS_BREAK || xMin + lpBand->cxMinBand > adjcx)) {
1424             TRACE("%s break on band %d\n", (lpBand->fStyle & RBBS_BREAK ? "Hard" : "Soft"), i - 1);
1425             REBAR_LayoutRow(infoPtr, rowstart, i, adjcx, &row, &yPos);
1426             rowstart = i;
1427             xMin = 0;
1428         }
1429         else
1430             xMin += SEP_WIDTH;
1431 
1432         xMin += lpBand->cxMinBand;
1433     }
1434     if (rowstart < infoPtr->uNumBands)
1435         REBAR_LayoutRow(infoPtr, rowstart, infoPtr->uNumBands, adjcx, &row, &yPos);
1436 
1437     if (!(infoPtr->dwStyle & RBS_VARHEIGHT))
1438         yPos = REBAR_SetBandsHeight(infoPtr, first_visible(infoPtr), infoPtr->uNumBands, 0);
1439 
1440     infoPtr->uNumRows = row;
1441 
1442     if (infoPtr->dwStyle & CCS_VERT)
1443         REBAR_CalcVertBand(infoPtr, 0, infoPtr->uNumBands);
1444     else
1445         REBAR_CalcHorzBand(infoPtr, 0, infoPtr->uNumBands);
1446     /* now compute size of Rebar itself */
1447     oldSize = infoPtr->calcSize;
1448 
1449     infoPtr->calcSize.cx = adjcx;
1450     infoPtr->calcSize.cy = yPos;
1451     TRACE("calcsize size=(%d, %d), origheight=(%d,%d)\n",
1452             infoPtr->calcSize.cx, infoPtr->calcSize.cy,
1453 	    oldSize.cx, oldSize.cy);
1454 
1455     REBAR_DumpBand (infoPtr);
1456     REBAR_MoveChildWindows (infoPtr, 0, infoPtr->uNumBands);
1457     REBAR_ForceResize (infoPtr);
1458 
1459     /* note: after a RBN_HEIGHTCHANGE native sends once again all the RBN_CHILDSIZE
1460      * and does another ForceResize */
1461     if (oldSize.cy != infoPtr->calcSize.cy)
1462     {
1463         NMHDR heightchange;
1464         REBAR_Notify(&heightchange, infoPtr, RBN_HEIGHTCHANGE);
1465         REBAR_AutoSize(infoPtr, FALSE);
1466     }
1467 }
1468 
1469 /* iBeginBand must be visible */
1470 static int
1471 REBAR_SizeChildrenToHeight(const REBAR_INFO *infoPtr, int iBeginBand, int iEndBand, int extra, BOOL *fChanged)
1472 {
1473     int cyBandsOld;
1474     int cyBandsNew = 0;
1475     int i;
1476 
1477     TRACE("[%d;%d) by %d\n", iBeginBand, iEndBand, extra);
1478 
1479     cyBandsOld = REBAR_GetBand(infoPtr, iBeginBand)->rcBand.bottom -
1480                  REBAR_GetBand(infoPtr, iBeginBand)->rcBand.top;
1481     for (i = iBeginBand; i < iEndBand; i = next_visible(infoPtr, i))
1482     {
1483         REBAR_BAND *lpBand = REBAR_GetBand(infoPtr, i);
1484         int cyMaxChild = cyBandsOld - REBARSPACE(lpBand) + extra;
1485         int cyChild = round_child_height(lpBand, cyMaxChild);
1486 
1487         if (lpBand->hwndChild && cyChild != lpBand->cyChild && (lpBand->fStyle & RBBS_VARIABLEHEIGHT))
1488         {
1489             TRACE("Resizing %d: %d -> %d [%d]\n", i, lpBand->cyChild, cyChild, lpBand->cyMaxChild);
1490             *fChanged = TRUE;
1491             lpBand->cyChild = cyChild;
1492             lpBand->fDraw |= NTF_INVALIDATE;
1493             update_min_band_height(infoPtr, lpBand);
1494         }
1495         cyBandsNew = max(cyBandsNew, lpBand->cyMinBand);
1496     }
1497     return cyBandsNew - cyBandsOld;
1498 }
1499 
1500 /* worker function for RB_SIZETORECT and RBS_AUTOSIZE */
1501 static VOID
1502 REBAR_SizeToHeight(REBAR_INFO *infoPtr, int height)
1503 {
1504     int extra = height - infoPtr->calcSize.cy;  /* may be negative */
1505     BOOL fChanged = FALSE;
1506     UINT uNumRows = infoPtr->uNumRows;
1507     int i;
1508 
1509     if (uNumRows == 0)  /* avoid division by 0 */
1510         return;
1511 
1512     /* That's not exactly what Windows does but should be similar */
1513 
1514     /* Pass one: break-up/glue rows */
1515     if (extra > 0)
1516     {
1517         for (i = prev_visible(infoPtr, infoPtr->uNumBands); i > 0; i = prev_visible(infoPtr, i))
1518         {
1519             REBAR_BAND *lpBand = REBAR_GetBand(infoPtr, i);
1520             int cyBreakExtra;  /* additional cy for the rebar after a RBBS_BREAK on this band */
1521 
1522             height = lpBand->rcBand.bottom - lpBand->rcBand.top;
1523 
1524             if (infoPtr->dwStyle & RBS_VARHEIGHT)
1525                 cyBreakExtra = lpBand->cyRowSoFar; /* 'height' => 'lpBand->cyRowSoFar' + 'height'*/
1526             else
1527                 cyBreakExtra = height;             /* 'height' => 'height' + 'height'*/
1528             cyBreakExtra += SEP_WIDTH;
1529 
1530             if (extra <= cyBreakExtra / 2)
1531                 break;
1532 
1533             if (!(lpBand->fStyle & RBBS_BREAK))
1534             {
1535                 TRACE("Adding break on band %d - extra %d -> %d\n", i, extra, extra - cyBreakExtra);
1536                 lpBand->fStyle |= RBBS_BREAK;
1537                 lpBand->fDraw |= NTF_INVALIDATE;
1538                 fChanged = TRUE;
1539                 extra -= cyBreakExtra;
1540                 uNumRows++;
1541                 /* temporary change for _SizeControlsToHeight. The true values will be computed in _Layout */
1542                 if (infoPtr->dwStyle & RBS_VARHEIGHT)
1543                     lpBand->rcBand.bottom = lpBand->rcBand.top + lpBand->cyMinBand;
1544             }
1545         }
1546     }
1547     /* TODO: else if (extra < 0) { try to remove some RBBS_BREAKs } */
1548 
1549     /* Pass two: increase/decrease control height */
1550     if (infoPtr->dwStyle & RBS_VARHEIGHT)
1551     {
1552         int i = first_visible(infoPtr);
1553         int iRow = 0;
1554         while (i < infoPtr->uNumBands)
1555         {
1556             REBAR_BAND *lpBand = REBAR_GetBand(infoPtr, i);
1557             int extraForRow = extra / (int)(uNumRows - iRow);
1558             int rowEnd;
1559 
1560             /* we can't use get_row_end_for_band as we might have added RBBS_BREAK in the first phase */
1561             for (rowEnd = next_visible(infoPtr, i); rowEnd < infoPtr->uNumBands; rowEnd = next_visible(infoPtr, rowEnd))
1562                 if (REBAR_GetBand(infoPtr, rowEnd)->iRow != lpBand->iRow ||
1563                     REBAR_GetBand(infoPtr, rowEnd)->fStyle & RBBS_BREAK)
1564                     break;
1565 
1566             extra -= REBAR_SizeChildrenToHeight(infoPtr, i, rowEnd, extraForRow, &fChanged);
1567             TRACE("extra = %d\n", extra);
1568             i = rowEnd;
1569             iRow++;
1570         }
1571     }
1572     else
1573         REBAR_SizeChildrenToHeight(infoPtr, first_visible(infoPtr), infoPtr->uNumBands, extra / infoPtr->uNumRows, &fChanged);
1574 
1575     if (fChanged)
1576         REBAR_Layout(infoPtr);
1577 }
1578 
1579 static VOID
1580 REBAR_AutoSize(REBAR_INFO *infoPtr, BOOL needsLayout)
1581 {
1582     RECT rc, rcNew;
1583     NMRBAUTOSIZE autosize;
1584 
1585     if (needsLayout)
1586         REBAR_Layout(infoPtr);
1587     GetClientRect(infoPtr->hwndSelf, &rc);
1588     REBAR_SizeToHeight(infoPtr, get_rect_cy(infoPtr, &rc));
1589     GetClientRect(infoPtr->hwndSelf, &rcNew);
1590 
1591     GetClientRect(infoPtr->hwndSelf, &autosize.rcTarget);
1592     autosize.fChanged = EqualRect(&rc, &rcNew);
1593     autosize.rcTarget = rc;
1594     autosize.rcActual = rcNew;
1595     REBAR_Notify((NMHDR *)&autosize, infoPtr, RBN_AUTOSIZE);
1596 }
1597 
1598 static VOID
1599 REBAR_ValidateBand (const REBAR_INFO *infoPtr, REBAR_BAND *lpBand)
1600      /* Function:  This routine evaluates the band specs supplied */
1601      /*  by the user and updates the following 5 fields in        */
1602      /*  the internal band structure: cxHeader, cyHeader, cxMinBand, cyMinBand, fStatus */
1603 {
1604     UINT header=0;
1605     UINT textheight=0, imageheight = 0;
1606     UINT i, nonfixed;
1607     REBAR_BAND *tBand;
1608 
1609     lpBand->fStatus = 0;
1610     lpBand->cxMinBand = 0;
1611     lpBand->cyMinBand = 0;
1612 
1613     /* Data coming in from users into the cx... and cy... fields   */
1614     /* may be bad, just garbage, because the user never clears     */
1615     /* the fields. RB_{SET|INSERT}BAND{A|W} just passes the data   */
1616     /* along if the fields exist in the input area. Here we must   */
1617     /* determine if the data is valid. I have no idea how MS does  */
1618     /* the validation, but it does because the RB_GETBANDINFO      */
1619     /* returns a 0 when I know the sample program passed in an     */
1620     /* address. Here I will use the algorithm that if the value    */
1621     /* is greater than 65535 then it is bad and replace it with    */
1622     /* a zero. Feel free to improve the algorithm.  -  GA 12/2000  */
1623     if (lpBand->cxMinChild > 65535) lpBand->cxMinChild = 0;
1624     if (lpBand->cyMinChild > 65535) lpBand->cyMinChild = 0;
1625     if (lpBand->cx         > 65535) lpBand->cx         = 0;
1626     if (lpBand->cyChild    > 65535) lpBand->cyChild    = 0;
1627     if (lpBand->cyIntegral > 65535) lpBand->cyIntegral = 0;
1628     if (lpBand->cxIdeal    > 65535) lpBand->cxIdeal    = 0;
1629     if (lpBand->cxHeader   > 65535) lpBand->cxHeader   = 0;
1630 
1631     /* TODO : we could try return to the caller if a value changed so that */
1632     /*        a REBAR_Layout is needed. Till now the caller should call it */
1633     /*        it always (we should also check what native does)            */
1634 
1635     /* Header is where the image, text and gripper exist  */
1636     /* in the band and precede the child window.          */
1637 
1638     /* count number of non-FIXEDSIZE and non-Hidden bands */
1639     nonfixed = 0;
1640     for (i=0; i<infoPtr->uNumBands; i++){
1641 	tBand = REBAR_GetBand(infoPtr, i);
1642 	if (!HIDDENBAND(tBand) && !(tBand->fStyle & RBBS_FIXEDSIZE))
1643 	    nonfixed++;
1644     }
1645 
1646     /* calculate gripper rectangle */
1647     if (  (!(lpBand->fStyle & RBBS_NOGRIPPER)) &&
1648 	  ( (lpBand->fStyle & RBBS_GRIPPERALWAYS) ||
1649 	    ( !(lpBand->fStyle & RBBS_FIXEDSIZE) && (nonfixed > 1)))
1650        ) {
1651 	lpBand->fStatus |= HAS_GRIPPER;
1652         if (infoPtr->dwStyle & CCS_VERT)
1653 	    if (infoPtr->dwStyle & RBS_VERTICALGRIPPER)
1654                 header += (GRIPPER_HEIGHT + REBAR_PRE_GRIPPER);
1655             else
1656 	        header += (GRIPPER_WIDTH + REBAR_PRE_GRIPPER);
1657         else
1658             header += (REBAR_PRE_GRIPPER + GRIPPER_WIDTH);
1659         /* Always have 4 pixels before anything else */
1660         header += REBAR_ALWAYS_SPACE;
1661     }
1662 
1663     /* image is visible */
1664     if (lpBand->iImage != -1 && (infoPtr->himl)) {
1665 	lpBand->fStatus |= HAS_IMAGE;
1666         if (infoPtr->dwStyle & CCS_VERT) {
1667 	   header += (infoPtr->imageSize.cy + REBAR_POST_IMAGE);
1668            imageheight = infoPtr->imageSize.cx + 4;
1669 	}
1670 	else {
1671 	   header += (infoPtr->imageSize.cx + REBAR_POST_IMAGE);
1672            imageheight = infoPtr->imageSize.cy + 4;
1673 	}
1674     }
1675 
1676     /* text is visible */
1677     if ((lpBand->fMask & RBBIM_TEXT) && (lpBand->lpText) &&
1678         !(lpBand->fStyle & RBBS_HIDETITLE)) {
1679 	HDC hdc = GetDC (0);
1680 	HFONT hOldFont = SelectObject (hdc, infoPtr->hFont);
1681 	SIZE size;
1682 
1683 	lpBand->fStatus |= HAS_TEXT;
1684 	GetTextExtentPoint32W (hdc, lpBand->lpText,
1685 			       lstrlenW (lpBand->lpText), &size);
1686 	header += ((infoPtr->dwStyle & CCS_VERT) ? (size.cy + REBAR_POST_TEXT) : (size.cx + REBAR_POST_TEXT));
1687 	textheight = (infoPtr->dwStyle & CCS_VERT) ? 0 : size.cy;
1688 
1689 	SelectObject (hdc, hOldFont);
1690 	ReleaseDC (0, hdc);
1691     }
1692 
1693     /* if no gripper but either image or text, then leave space */
1694     if ((lpBand->fStatus & (HAS_IMAGE | HAS_TEXT)) &&
1695 	!(lpBand->fStatus & HAS_GRIPPER)) {
1696 	header += REBAR_ALWAYS_SPACE;
1697     }
1698 
1699     /* check if user overrode the header value */
1700     if (!(lpBand->fStyle & RBBS_UNDOC_FIXEDHEADER))
1701         lpBand->cxHeader = header;
1702     lpBand->cyHeader = max(textheight, imageheight);
1703 
1704     /* Now compute minimum size of child window */
1705     update_min_band_height(infoPtr, lpBand);       /* update lpBand->cyMinBand from cyHeader and cyChild*/
1706 
1707     lpBand->cxMinBand = lpBand->cxMinChild + lpBand->cxHeader + REBAR_POST_CHILD;
1708     if (lpBand->fStyle & RBBS_USECHEVRON && lpBand->cxMinChild < lpBand->cxIdeal)
1709         lpBand->cxMinBand += CHEVRON_WIDTH;
1710 }
1711 
1712 static UINT
1713 REBAR_CommonSetupBand(HWND hwnd, const REBARBANDINFOW *lprbbi, REBAR_BAND *lpBand)
1714      /* Function:  This routine copies the supplied values from   */
1715      /*  user input (lprbbi) to the internal band structure.      */
1716      /*  It returns the mask of what changed.   */
1717 {
1718     UINT uChanged = 0x0;
1719 
1720     lpBand->fMask |= lprbbi->fMask;
1721 
1722     if( (lprbbi->fMask & RBBIM_STYLE) &&
1723         (lpBand->fStyle != lprbbi->fStyle ) )
1724     {
1725 	lpBand->fStyle = lprbbi->fStyle;
1726         uChanged |= RBBIM_STYLE;
1727     }
1728 
1729     if( (lprbbi->fMask & RBBIM_COLORS) &&
1730        ( ( lpBand->clrFore != lprbbi->clrFore ) ||
1731          ( lpBand->clrBack != lprbbi->clrBack ) ) )
1732     {
1733 	lpBand->clrFore = lprbbi->clrFore;
1734 	lpBand->clrBack = lprbbi->clrBack;
1735         uChanged |= RBBIM_COLORS;
1736     }
1737 
1738     if( (lprbbi->fMask & RBBIM_IMAGE) &&
1739        ( lpBand->iImage != lprbbi->iImage ) )
1740     {
1741 	lpBand->iImage = lprbbi->iImage;
1742         uChanged |= RBBIM_IMAGE;
1743     }
1744 
1745     if( (lprbbi->fMask & RBBIM_CHILD) &&
1746        (lprbbi->hwndChild != lpBand->hwndChild ) )
1747     {
1748 	if (lprbbi->hwndChild) {
1749 	    lpBand->hwndChild = lprbbi->hwndChild;
1750 	    lpBand->hwndPrevParent =
1751 		SetParent (lpBand->hwndChild, hwnd);
1752 	    /* below in trace from WinRAR */
1753 	    ShowWindow(lpBand->hwndChild, SW_SHOWNOACTIVATE | SW_SHOWNORMAL);
1754 	    /* above in trace from WinRAR */
1755 	}
1756 	else {
1757 	    TRACE("child: %p  prev parent: %p\n",
1758 		   lpBand->hwndChild, lpBand->hwndPrevParent);
1759 	    lpBand->hwndChild = 0;
1760 	    lpBand->hwndPrevParent = 0;
1761 	}
1762         uChanged |= RBBIM_CHILD;
1763     }
1764 
1765     if( (lprbbi->fMask & RBBIM_CHILDSIZE) &&
1766         ( (lpBand->cxMinChild != lprbbi->cxMinChild) ||
1767           (lpBand->cyMinChild != lprbbi->cyMinChild ) ||
1768           ( (lprbbi->cbSize >= REBARBANDINFOA_V6_SIZE && (lpBand->fStyle & RBBS_VARIABLEHEIGHT)) &&
1769             ( (lpBand->cyChild    != lprbbi->cyChild ) ||
1770               (lpBand->cyMaxChild != lprbbi->cyMaxChild ) ||
1771               (lpBand->cyIntegral != lprbbi->cyIntegral ) ) ) ||
1772           ( (lprbbi->cbSize < REBARBANDINFOA_V6_SIZE) &&
1773             ( (lpBand->cyChild ||
1774                lpBand->cyMaxChild ||
1775                lpBand->cyIntegral ) ) ) ) )
1776     {
1777 	lpBand->cxMinChild = lprbbi->cxMinChild;
1778 	lpBand->cyMinChild = lprbbi->cyMinChild;
1779         /* These fields where added in WIN32_IE == 0x400 and are set only for RBBS_VARIABLEHEIGHT bands */
1780         if (lprbbi->cbSize >= REBARBANDINFOA_V6_SIZE && (lpBand->fStyle & RBBS_VARIABLEHEIGHT)) {
1781 	    lpBand->cyMaxChild = lprbbi->cyMaxChild;
1782             lpBand->cyIntegral = lprbbi->cyIntegral;
1783 
1784             lpBand->cyChild = round_child_height(lpBand, lprbbi->cyChild);  /* make (cyChild - cyMinChild) a multiple of cyIntergral */
1785         }
1786 	else {
1787 	    lpBand->cyChild    = lpBand->cyMinChild;
1788 	    lpBand->cyMaxChild = 0x7fffffff;
1789 	    lpBand->cyIntegral = 0;
1790 	}
1791         uChanged |= RBBIM_CHILDSIZE;
1792     }
1793 
1794     if( (lprbbi->fMask & RBBIM_SIZE) &&
1795         (lpBand->cx != lprbbi->cx ) )
1796     {
1797 	lpBand->cx = lprbbi->cx;
1798         uChanged |= RBBIM_SIZE;
1799     }
1800 
1801     if( (lprbbi->fMask & RBBIM_BACKGROUND) &&
1802        ( lpBand->hbmBack != lprbbi->hbmBack ) )
1803     {
1804 	lpBand->hbmBack = lprbbi->hbmBack;
1805         uChanged |= RBBIM_BACKGROUND;
1806     }
1807 
1808     if( (lprbbi->fMask & RBBIM_ID) &&
1809         (lpBand->wID != lprbbi->wID ) )
1810     {
1811 	lpBand->wID = lprbbi->wID;
1812         uChanged |= RBBIM_ID;
1813     }
1814 
1815     /* check for additional data */
1816     if (lprbbi->cbSize >= REBARBANDINFOA_V6_SIZE) {
1817 	if( (lprbbi->fMask & RBBIM_IDEALSIZE) &&
1818             ( lpBand->cxIdeal != lprbbi->cxIdeal ) )
1819         {
1820 	    lpBand->cxIdeal = lprbbi->cxIdeal;
1821             uChanged |= RBBIM_IDEALSIZE;
1822         }
1823 
1824 	if( (lprbbi->fMask & RBBIM_LPARAM) &&
1825             (lpBand->lParam != lprbbi->lParam ) )
1826         {
1827 	    lpBand->lParam = lprbbi->lParam;
1828             uChanged |= RBBIM_LPARAM;
1829         }
1830 
1831 	if( (lprbbi->fMask & RBBIM_HEADERSIZE) &&
1832             (lpBand->cxHeader != lprbbi->cxHeader ) )
1833         {
1834 	    lpBand->cxHeader = lprbbi->cxHeader;
1835             lpBand->fStyle |= RBBS_UNDOC_FIXEDHEADER;
1836             uChanged |= RBBIM_HEADERSIZE;
1837         }
1838     }
1839 
1840     return uChanged;
1841 }
1842 
1843 static LRESULT REBAR_EraseBkGnd (const REBAR_INFO *infoPtr, HDC hdc)
1844      /* Function:  This erases the background rectangle by drawing  */
1845      /*  each band with its background color (or the default) and   */
1846      /*  draws each bands right separator if necessary. The row     */
1847      /*  separators are drawn on the first band of the next row.    */
1848 {
1849     REBAR_BAND *lpBand;
1850     UINT i;
1851     INT oldrow;
1852     RECT cr;
1853     COLORREF old = CLR_NONE, new;
1854     HTHEME theme = GetWindowTheme (infoPtr->hwndSelf);
1855 
1856     GetClientRect (infoPtr->hwndSelf, &cr);
1857 
1858 #ifdef __REACTOS__
1859     if (theme)
1860     {
1861         if (IsThemeBackgroundPartiallyTransparent(theme, 0, 0))
1862         {
1863             DrawThemeParentBackground (infoPtr->hwndSelf, hdc, &cr);
1864         }
1865         DrawThemeBackground (theme, hdc, 0, 0, &cr, NULL);
1866     }
1867 #endif
1868 
1869     oldrow = -1;
1870     for(i=0; i<infoPtr->uNumBands; i++) {
1871         RECT rcBand;
1872         lpBand = REBAR_GetBand(infoPtr, i);
1873 	if (HIDDENBAND(lpBand)) continue;
1874         translate_rect(infoPtr, &rcBand, &lpBand->rcBand);
1875 
1876 	/* draw band separator between rows */
1877 	if (lpBand->iRow != oldrow) {
1878 	    oldrow = lpBand->iRow;
1879 	    if (infoPtr->dwStyle & RBS_BANDBORDERS) {
1880 		RECT rcRowSep;
1881 		rcRowSep = rcBand;
1882 		if (infoPtr->dwStyle & CCS_VERT) {
1883 		    rcRowSep.right += SEP_WIDTH_SIZE;
1884 		    rcRowSep.bottom = infoPtr->calcSize.cx;
1885                     if (theme)
1886                         DrawThemeEdge (theme, hdc, RP_BAND, 0, &rcRowSep, EDGE_ETCHED, BF_RIGHT, NULL);
1887                     else
1888 		        DrawEdge (hdc, &rcRowSep, EDGE_ETCHED, BF_RIGHT);
1889 		}
1890 		else {
1891 		    rcRowSep.bottom += SEP_WIDTH_SIZE;
1892 		    rcRowSep.right = infoPtr->calcSize.cx;
1893                     if (theme)
1894                         DrawThemeEdge (theme, hdc, RP_BAND, 0, &rcRowSep, EDGE_ETCHED, BF_BOTTOM, NULL);
1895                     else
1896 		        DrawEdge (hdc, &rcRowSep, EDGE_ETCHED, BF_BOTTOM);
1897 		}
1898                 TRACE ("drawing band separator bottom (%s)\n",
1899                        wine_dbgstr_rect(&rcRowSep));
1900 	    }
1901 	}
1902 
1903 	/* draw band separator between bands in a row */
1904         if (infoPtr->dwStyle & RBS_BANDBORDERS && lpBand->rcBand.left > 0) {
1905 	    RECT rcSep;
1906 	    rcSep = rcBand;
1907 	    if (infoPtr->dwStyle & CCS_VERT) {
1908                 rcSep.bottom = rcSep.top;
1909 		rcSep.top -= SEP_WIDTH_SIZE;
1910                 if (theme)
1911                     DrawThemeEdge (theme, hdc, RP_BAND, 0, &rcSep, EDGE_ETCHED, BF_BOTTOM, NULL);
1912                 else
1913 		    DrawEdge (hdc, &rcSep, EDGE_ETCHED, BF_BOTTOM);
1914 	    }
1915 	    else {
1916                 rcSep.right = rcSep.left;
1917 		rcSep.left -= SEP_WIDTH_SIZE;
1918                 if (theme)
1919                     DrawThemeEdge (theme, hdc, RP_BAND, 0, &rcSep, EDGE_ETCHED, BF_RIGHT, NULL);
1920                 else
1921 		    DrawEdge (hdc, &rcSep, EDGE_ETCHED, BF_RIGHT);
1922 	    }
1923             TRACE("drawing band separator right (%s)\n",
1924                   wine_dbgstr_rect(&rcSep));
1925 	}
1926 
1927 	/* draw the actual background */
1928 	if (lpBand->clrBack != CLR_NONE) {
1929 	    new = (lpBand->clrBack == CLR_DEFAULT) ? infoPtr->clrBtnFace :
1930 		    lpBand->clrBack;
1931 #if GLATESTING
1932 	    /* testing only - make background green to see it */
1933 	    new = RGB(0,128,0);
1934 #endif
1935 	}
1936 	else {
1937 	    /* In the absence of documentation for Rebar vs. CLR_NONE,
1938 	     * we will use the default BtnFace color. Note documentation
1939 	     * exists for Listview and Imagelist.
1940 	     */
1941 	    new = infoPtr->clrBtnFace;
1942 #if GLATESTING
1943 	    /* testing only - make background green to see it */
1944 	    new = RGB(0,128,0);
1945 #endif
1946 	}
1947 
1948         if (theme)
1949         {
1950             /* When themed, the background color is ignored (but not a
1951              * background bitmap */
1952             DrawThemeBackground (theme, hdc, 0, 0, &cr, &rcBand);
1953         }
1954         else
1955         {
1956             old = SetBkColor (hdc, new);
1957             TRACE("%s background color=0x%06x, band %s\n",
1958                   (lpBand->clrBack == CLR_NONE) ? "none" :
1959                     ((lpBand->clrBack == CLR_DEFAULT) ? "dft" : ""),
1960                   GetBkColor(hdc), wine_dbgstr_rect(&rcBand));
1961             ExtTextOutW (hdc, 0, 0, ETO_OPAQUE, &rcBand, NULL, 0, 0);
1962             if (lpBand->clrBack != CLR_NONE)
1963                 SetBkColor (hdc, old);
1964         }
1965     }
1966     return TRUE;
1967 }
1968 
1969 static void
1970 REBAR_InternalHitTest (const REBAR_INFO *infoPtr, const POINT *lpPt, UINT *pFlags, INT *pBand)
1971 {
1972     REBAR_BAND *lpBand;
1973     RECT rect;
1974     UINT  iCount;
1975 
1976     GetClientRect (infoPtr->hwndSelf, &rect);
1977 
1978     *pFlags = RBHT_NOWHERE;
1979     if (PtInRect (&rect, *lpPt))
1980     {
1981 	if (infoPtr->uNumBands == 0) {
1982 	    *pFlags = RBHT_NOWHERE;
1983 	    if (pBand)
1984 		*pBand = -1;
1985 	    TRACE("NOWHERE\n");
1986 	    return;
1987 	}
1988 	else {
1989 	    /* somewhere inside */
1990 	    for (iCount = 0; iCount < infoPtr->uNumBands; iCount++) {
1991                 RECT rcBand;
1992 		lpBand = REBAR_GetBand(infoPtr, iCount);
1993                 translate_rect(infoPtr, &rcBand, &lpBand->rcBand);
1994                 if (HIDDENBAND(lpBand)) continue;
1995 		if (PtInRect (&rcBand, *lpPt)) {
1996 		    if (pBand)
1997 			*pBand = iCount;
1998 		    if (PtInRect (&lpBand->rcGripper, *lpPt)) {
1999 			*pFlags = RBHT_GRABBER;
2000 			TRACE("ON GRABBER %d\n", iCount);
2001 			return;
2002 		    }
2003 		    else if (PtInRect (&lpBand->rcCapImage, *lpPt)) {
2004 			*pFlags = RBHT_CAPTION;
2005 			TRACE("ON CAPTION %d\n", iCount);
2006 			return;
2007 		    }
2008 		    else if (PtInRect (&lpBand->rcCapText, *lpPt)) {
2009 			*pFlags = RBHT_CAPTION;
2010 			TRACE("ON CAPTION %d\n", iCount);
2011 			return;
2012 		    }
2013 		    else if (PtInRect (&lpBand->rcChild, *lpPt)) {
2014 			*pFlags = RBHT_CLIENT;
2015 			TRACE("ON CLIENT %d\n", iCount);
2016 			return;
2017 		    }
2018 		    else if (PtInRect (&lpBand->rcChevron, *lpPt)) {
2019 			*pFlags = RBHT_CHEVRON;
2020 			TRACE("ON CHEVRON %d\n", iCount);
2021 			return;
2022 		    }
2023 		    else {
2024 			*pFlags = RBHT_NOWHERE;
2025 			TRACE("NOWHERE %d\n", iCount);
2026 			return;
2027 		    }
2028 		}
2029 	    }
2030 
2031 	    *pFlags = RBHT_NOWHERE;
2032 	    if (pBand)
2033 		*pBand = -1;
2034 
2035 	    TRACE("NOWHERE\n");
2036 	    return;
2037 	}
2038     }
2039     else {
2040 	*pFlags = RBHT_NOWHERE;
2041 	if (pBand)
2042 	    *pBand = -1;
2043 	TRACE("NOWHERE\n");
2044 	return;
2045     }
2046 }
2047 
2048 static void
2049 REBAR_HandleLRDrag (REBAR_INFO *infoPtr, const POINT *ptsmove)
2050      /* Function:  This will implement the functionality of a     */
2051      /*  Gripper drag within a row. It will not implement "out-   */
2052      /*  of-row" drags. (They are detected and handled in         */
2053      /*  REBAR_MouseMove.)                                        */
2054 {
2055     REBAR_BAND *hitBand;
2056     INT iHitBand, iRowBegin, iRowEnd;
2057     INT movement, xBand, cxLeft = 0;
2058     BOOL shrunkBands = FALSE;
2059 
2060     iHitBand = infoPtr->iGrabbedBand;
2061     iRowBegin = get_row_begin_for_band(infoPtr, iHitBand);
2062     iRowEnd = get_row_end_for_band(infoPtr, iHitBand);
2063     hitBand = REBAR_GetBand(infoPtr, iHitBand);
2064 
2065     xBand = hitBand->rcBand.left;
2066     movement = (infoPtr->dwStyle&CCS_VERT ? ptsmove->y : ptsmove->x)
2067                     - (xBand + REBAR_PRE_GRIPPER - infoPtr->ihitoffset);
2068 
2069     /* Dragging the first band in a row cannot cause shrinking */
2070     if(iHitBand != iRowBegin)
2071     {
2072         if (movement < 0) {
2073             cxLeft = REBAR_ShrinkBandsRTL(infoPtr, iRowBegin, iHitBand, -movement, TRUE);
2074 
2075             if(cxLeft < -movement)
2076             {
2077                 hitBand->cxEffective += -movement - cxLeft;
2078                 hitBand->cx = hitBand->cxEffective;
2079                 shrunkBands = TRUE;
2080             }
2081 
2082         } else if (movement > 0) {
2083 
2084             cxLeft = movement;
2085             if (prev_visible(infoPtr, iHitBand) >= 0)
2086                 cxLeft = REBAR_ShrinkBandsLTR(infoPtr, iHitBand, iRowEnd, movement, TRUE);
2087 
2088             if(cxLeft < movement)
2089             {
2090                 REBAR_BAND *lpPrev = REBAR_GetBand(infoPtr, prev_visible(infoPtr, iHitBand));
2091                 lpPrev->cxEffective += movement - cxLeft;
2092                 lpPrev->cx = hitBand->cxEffective;
2093                 shrunkBands = TRUE;
2094             }
2095 
2096         }
2097     }
2098 
2099     if(!shrunkBands)
2100     {
2101         /* It was not possible to move the band by shrinking bands.
2102          * Try relocating the band instead. */
2103         REBAR_MoveBandToRowOffset(infoPtr, iHitBand, iRowBegin,
2104             iRowEnd, xBand + movement, TRUE);
2105     }
2106 
2107     REBAR_SetRowRectsX(infoPtr, iRowBegin, iRowEnd);
2108     if (infoPtr->dwStyle & CCS_VERT)
2109         REBAR_CalcVertBand(infoPtr, 0, infoPtr->uNumBands);
2110     else
2111         REBAR_CalcHorzBand(infoPtr, 0, infoPtr->uNumBands);
2112     REBAR_MoveChildWindows(infoPtr, iRowBegin, iRowEnd);
2113 }
2114 
2115 static void
2116 REBAR_HandleUDDrag (REBAR_INFO *infoPtr, const POINT *ptsmove)
2117 {
2118     INT yOff = (infoPtr->dwStyle & CCS_VERT) ? ptsmove->x : ptsmove->y;
2119     INT iHitBand, iRowBegin, iNextRowBegin;
2120     REBAR_BAND *hitBand, *rowBeginBand;
2121 
2122     if(infoPtr->uNumBands <= 0)
2123         ERR("There are no bands in this rebar\n");
2124 
2125     /* Up/down dragging can only occur when there is more than one
2126      * band in the rebar */
2127     if(infoPtr->uNumBands <= 1)
2128         return;
2129 
2130     iHitBand = infoPtr->iGrabbedBand;
2131     hitBand = REBAR_GetBand(infoPtr, iHitBand);
2132 
2133     /* If we're taking a band that has the RBBS_BREAK style set, this
2134      * style needs to be reapplied to the band that is going to become
2135      * the new start of the row. */
2136     if((hitBand->fStyle & RBBS_BREAK) &&
2137         (iHitBand < infoPtr->uNumBands - 1))
2138         REBAR_GetBand(infoPtr, iHitBand + 1)->fStyle |= RBBS_BREAK;
2139 
2140     if(yOff < 0)
2141     {
2142         /* Place the band above the current top row */
2143         if(iHitBand==0 && (infoPtr->uNumBands==1 || REBAR_GetBand(infoPtr, 1)->fStyle&RBBS_BREAK))
2144             return;
2145         DPA_DeletePtr(infoPtr->bands, iHitBand);
2146         hitBand->fStyle &= ~RBBS_BREAK;
2147         REBAR_GetBand(infoPtr, 0)->fStyle |= RBBS_BREAK;
2148         infoPtr->iGrabbedBand = DPA_InsertPtr(
2149             infoPtr->bands, 0, hitBand);
2150     }
2151     else if(yOff > REBAR_GetBand(infoPtr, infoPtr->uNumBands - 1)->rcBand.bottom)
2152     {
2153         /* Place the band below the current bottom row */
2154         if(iHitBand == infoPtr->uNumBands-1 && hitBand->fStyle&RBBS_BREAK)
2155             return;
2156         DPA_DeletePtr(infoPtr->bands, iHitBand);
2157         hitBand->fStyle |= RBBS_BREAK;
2158         infoPtr->iGrabbedBand = DPA_InsertPtr(
2159             infoPtr->bands, infoPtr->uNumBands - 1, hitBand);
2160     }
2161     else
2162     {
2163         /* Place the band in the preexisting row the mouse is hovering over */
2164         iRowBegin = first_visible(infoPtr);
2165         while(iRowBegin < infoPtr->uNumBands)
2166         {
2167             iNextRowBegin = get_row_end_for_band(infoPtr, iRowBegin);
2168             rowBeginBand = REBAR_GetBand(infoPtr, iRowBegin);
2169             if(rowBeginBand->rcBand.bottom > yOff)
2170             {
2171                 REBAR_MoveBandToRowOffset(
2172                     infoPtr, iHitBand, iRowBegin, iNextRowBegin,
2173                     ((infoPtr->dwStyle & CCS_VERT) ? ptsmove->y : ptsmove->x)
2174                         - REBAR_PRE_GRIPPER - infoPtr->ihitoffset, FALSE);
2175                 break;
2176             }
2177 
2178             iRowBegin = iNextRowBegin;
2179         }
2180     }
2181 
2182     REBAR_Layout(infoPtr);
2183 }
2184 
2185 
2186 /* << REBAR_BeginDrag >> */
2187 
2188 
2189 static LRESULT
2190 REBAR_DeleteBand (REBAR_INFO *infoPtr, WPARAM wParam)
2191 {
2192     UINT uBand = (UINT)wParam;
2193     REBAR_BAND *lpBand;
2194 
2195     if (uBand >= infoPtr->uNumBands)
2196 	return FALSE;
2197 
2198     TRACE("deleting band %u!\n", uBand);
2199     lpBand = REBAR_GetBand(infoPtr, uBand);
2200     REBAR_Notify_NMREBAR (infoPtr, uBand, RBN_DELETINGBAND);
2201     /* TODO: a return of 1 should probably cancel the deletion */
2202 
2203     if (lpBand->hwndChild)
2204         ShowWindow(lpBand->hwndChild, SW_HIDE);
2205     Free(lpBand->lpText);
2206     Free(lpBand);
2207 
2208     infoPtr->uNumBands--;
2209     DPA_DeletePtr(infoPtr->bands, uBand);
2210 
2211     REBAR_Notify_NMREBAR (infoPtr, -1, RBN_DELETEDBAND);
2212 
2213     /* if only 1 band left the re-validate to possible eliminate gripper */
2214     if (infoPtr->uNumBands == 1)
2215       REBAR_ValidateBand (infoPtr, REBAR_GetBand(infoPtr, 0));
2216 
2217     REBAR_Layout(infoPtr);
2218 
2219     return TRUE;
2220 }
2221 
2222 
2223 /* << REBAR_DragMove >> */
2224 /* << REBAR_EndDrag >> */
2225 
2226 
2227 static LRESULT
2228 REBAR_GetBandBorders (const REBAR_INFO *infoPtr, UINT uBand, RECT *lpRect)
2229 {
2230     REBAR_BAND *lpBand;
2231 
2232     if (!lpRect)
2233 	return 0;
2234     if (uBand >= infoPtr->uNumBands)
2235 	return 0;
2236 
2237     lpBand = REBAR_GetBand(infoPtr, uBand);
2238 
2239     /* FIXME - the following values were determined by experimentation */
2240     /* with the REBAR Control Spy. I have guesses as to what the 4 and */
2241     /* 1 are, but I am not sure. There doesn't seem to be any actual   */
2242     /* difference in size of the control area with and without the     */
2243     /* style.  -  GA                                                   */
2244     if (infoPtr->dwStyle & RBS_BANDBORDERS) {
2245 	if (infoPtr->dwStyle & CCS_VERT) {
2246 	    lpRect->left = 1;
2247 	    lpRect->top = lpBand->cxHeader + 4;
2248 	    lpRect->right = 1;
2249 	    lpRect->bottom = 0;
2250 	}
2251 	else {
2252 	    lpRect->left = lpBand->cxHeader + 4;
2253 	    lpRect->top = 1;
2254 	    lpRect->right = 0;
2255 	    lpRect->bottom = 1;
2256 	}
2257     }
2258     else {
2259 	lpRect->left = lpBand->cxHeader;
2260     }
2261     return 0;
2262 }
2263 
2264 
2265 static inline LRESULT
2266 REBAR_GetBandCount (const REBAR_INFO *infoPtr)
2267 {
2268     TRACE("band count %u!\n", infoPtr->uNumBands);
2269 
2270     return infoPtr->uNumBands;
2271 }
2272 
2273 
2274 static LRESULT
2275 REBAR_GetBandInfoT(const REBAR_INFO *infoPtr, UINT uIndex, LPREBARBANDINFOW lprbbi, BOOL bUnicode)
2276 {
2277     REBAR_BAND *lpBand;
2278 
2279     if (!lprbbi || lprbbi->cbSize < REBARBANDINFOA_V3_SIZE)
2280 	return FALSE;
2281 
2282     if (uIndex >= infoPtr->uNumBands)
2283 	return FALSE;
2284 
2285     TRACE("index %u (bUnicode=%d)\n", uIndex, bUnicode);
2286 
2287     /* copy band information */
2288     lpBand = REBAR_GetBand(infoPtr, uIndex);
2289 
2290     if (lprbbi->fMask & RBBIM_STYLE)
2291 	lprbbi->fStyle = lpBand->fStyle;
2292 
2293     if (lprbbi->fMask & RBBIM_COLORS) {
2294 	lprbbi->clrFore = lpBand->clrFore;
2295 	lprbbi->clrBack = lpBand->clrBack;
2296 	if (lprbbi->clrBack == CLR_DEFAULT)
2297 	    lprbbi->clrBack = infoPtr->clrBtnFace;
2298     }
2299 
2300     if (lprbbi->fMask & RBBIM_TEXT) {
2301         if (bUnicode)
2302             Str_GetPtrW(lpBand->lpText, lprbbi->lpText, lprbbi->cch);
2303         else
2304             Str_GetPtrWtoA(lpBand->lpText, (LPSTR)lprbbi->lpText, lprbbi->cch);
2305     }
2306 
2307     if (lprbbi->fMask & RBBIM_IMAGE)
2308 	lprbbi->iImage = lpBand->iImage;
2309 
2310     if (lprbbi->fMask & RBBIM_CHILD)
2311 	lprbbi->hwndChild = lpBand->hwndChild;
2312 
2313     if (lprbbi->fMask & RBBIM_CHILDSIZE) {
2314 	lprbbi->cxMinChild = lpBand->cxMinChild;
2315 	lprbbi->cyMinChild = lpBand->cyMinChild;
2316         /* to make tests pass we follow Windows' behaviour and allow reading these fields only
2317          * for RBBS_VARIABLEHEIGHTS bands */
2318         if (lprbbi->cbSize >= REBARBANDINFOW_V6_SIZE && (lpBand->fStyle & RBBS_VARIABLEHEIGHT)) {
2319 	    lprbbi->cyChild    = lpBand->cyChild;
2320 	    lprbbi->cyMaxChild = lpBand->cyMaxChild;
2321 	    lprbbi->cyIntegral = lpBand->cyIntegral;
2322 	}
2323     }
2324 
2325     if (lprbbi->fMask & RBBIM_SIZE)
2326 	lprbbi->cx = lpBand->cx;
2327 
2328     if (lprbbi->fMask & RBBIM_BACKGROUND)
2329 	lprbbi->hbmBack = lpBand->hbmBack;
2330 
2331     if (lprbbi->fMask & RBBIM_ID)
2332 	lprbbi->wID = lpBand->wID;
2333 
2334     /* check for additional data */
2335     if (lprbbi->cbSize >= REBARBANDINFOW_V6_SIZE) {
2336 	if (lprbbi->fMask & RBBIM_IDEALSIZE)
2337 	    lprbbi->cxIdeal = lpBand->cxIdeal;
2338 
2339 	if (lprbbi->fMask & RBBIM_LPARAM)
2340 	    lprbbi->lParam = lpBand->lParam;
2341 
2342 	if (lprbbi->fMask & RBBIM_HEADERSIZE)
2343 	    lprbbi->cxHeader = lpBand->cxHeader;
2344     }
2345 
2346     REBAR_DumpBandInfo(lprbbi);
2347 
2348     return TRUE;
2349 }
2350 
2351 
2352 static LRESULT
2353 REBAR_GetBarHeight (const REBAR_INFO *infoPtr)
2354 {
2355     INT nHeight;
2356 
2357     nHeight = infoPtr->calcSize.cy;
2358 
2359     TRACE("height = %d\n", nHeight);
2360 
2361     return nHeight;
2362 }
2363 
2364 
2365 static LRESULT
2366 REBAR_GetBarInfo (const REBAR_INFO *infoPtr, LPREBARINFO lpInfo)
2367 {
2368     if (!lpInfo || lpInfo->cbSize < sizeof (REBARINFO))
2369 	return FALSE;
2370 
2371     TRACE("getting bar info!\n");
2372 
2373     if (infoPtr->himl) {
2374 	lpInfo->himl = infoPtr->himl;
2375 	lpInfo->fMask |= RBIM_IMAGELIST;
2376     }
2377 
2378     return TRUE;
2379 }
2380 
2381 
2382 static inline LRESULT
2383 REBAR_GetBkColor (const REBAR_INFO *infoPtr)
2384 {
2385     COLORREF clr = infoPtr->clrBk;
2386 
2387     if (clr == CLR_DEFAULT)
2388       clr = infoPtr->clrBtnFace;
2389 
2390     TRACE("background color 0x%06x!\n", clr);
2391 
2392     return clr;
2393 }
2394 
2395 
2396 /* << REBAR_GetColorScheme >> */
2397 /* << REBAR_GetDropTarget >> */
2398 
2399 
2400 static LRESULT
2401 REBAR_GetPalette (const REBAR_INFO *infoPtr)
2402 {
2403     FIXME("empty stub!\n");
2404 
2405     return 0;
2406 }
2407 
2408 
2409 static LRESULT
2410 REBAR_GetRect (const REBAR_INFO *infoPtr, INT iBand, RECT *lprc)
2411 {
2412     REBAR_BAND *lpBand;
2413 
2414     if (iBand < 0 || iBand >= infoPtr->uNumBands)
2415 	return FALSE;
2416     if (!lprc)
2417 	return FALSE;
2418 
2419     lpBand = REBAR_GetBand(infoPtr, iBand);
2420     /* For CCS_VERT the coordinates will be swapped - like on Windows */
2421     *lprc = lpBand->rcBand;
2422 
2423     TRACE("band %d, (%s)\n", iBand, wine_dbgstr_rect(lprc));
2424 
2425     return TRUE;
2426 }
2427 
2428 
2429 static inline LRESULT
2430 REBAR_GetRowCount (const REBAR_INFO *infoPtr)
2431 {
2432     TRACE("%u\n", infoPtr->uNumRows);
2433 
2434     return infoPtr->uNumRows;
2435 }
2436 
2437 
2438 static LRESULT
2439 REBAR_GetRowHeight (const REBAR_INFO *infoPtr, INT iRow)
2440 {
2441     int j = 0, ret = 0;
2442     UINT i;
2443     REBAR_BAND *lpBand;
2444 
2445     for (i=0; i<infoPtr->uNumBands; i++) {
2446 	lpBand = REBAR_GetBand(infoPtr, i);
2447 	if (HIDDENBAND(lpBand)) continue;
2448 	if (lpBand->iRow != iRow) continue;
2449         j = lpBand->rcBand.bottom - lpBand->rcBand.top;
2450 	if (j > ret) ret = j;
2451     }
2452 
2453     TRACE("row %d, height %d\n", iRow, ret);
2454 
2455     return ret;
2456 }
2457 
2458 
2459 static inline LRESULT
2460 REBAR_GetTextColor (const REBAR_INFO *infoPtr)
2461 {
2462     TRACE("text color 0x%06x!\n", infoPtr->clrText);
2463 
2464     return infoPtr->clrText;
2465 }
2466 
2467 
2468 static inline LRESULT
2469 REBAR_GetToolTips (const REBAR_INFO *infoPtr)
2470 {
2471     return (LRESULT)infoPtr->hwndToolTip;
2472 }
2473 
2474 
2475 static inline LRESULT
2476 REBAR_GetUnicodeFormat (const REBAR_INFO *infoPtr)
2477 {
2478     TRACE("%s hwnd=%p\n",
2479 	  infoPtr->bUnicode ? "TRUE" : "FALSE", infoPtr->hwndSelf);
2480 
2481     return infoPtr->bUnicode;
2482 }
2483 
2484 
2485 static inline LRESULT
2486 REBAR_GetVersion (const REBAR_INFO *infoPtr)
2487 {
2488     TRACE("version %d\n", infoPtr->iVersion);
2489     return infoPtr->iVersion;
2490 }
2491 
2492 
2493 static LRESULT
2494 REBAR_HitTest (const REBAR_INFO *infoPtr, LPRBHITTESTINFO lprbht)
2495 {
2496     if (!lprbht)
2497 	return -1;
2498 
2499     REBAR_InternalHitTest (infoPtr, &lprbht->pt, &lprbht->flags, &lprbht->iBand);
2500 
2501     return lprbht->iBand;
2502 }
2503 
2504 
2505 static LRESULT
2506 REBAR_IdToIndex (const REBAR_INFO *infoPtr, UINT uId)
2507 {
2508     UINT i;
2509 
2510     if (infoPtr->uNumBands < 1)
2511 	return -1;
2512 
2513     for (i = 0; i < infoPtr->uNumBands; i++) {
2514 	if (REBAR_GetBand(infoPtr, i)->wID == uId) {
2515 	    TRACE("id %u is band %u found!\n", uId, i);
2516 	    return i;
2517 	}
2518     }
2519 
2520     TRACE("id %u is not found\n", uId);
2521     return -1;
2522 }
2523 
2524 
2525 static LRESULT
2526 REBAR_InsertBandT(REBAR_INFO *infoPtr, INT iIndex, const REBARBANDINFOW *lprbbi, BOOL bUnicode)
2527 {
2528     REBAR_BAND *lpBand;
2529 
2530     if (!lprbbi || lprbbi->cbSize < REBARBANDINFOA_V3_SIZE)
2531 	return FALSE;
2532 
2533     /* trace the index as signed to see the -1 */
2534     TRACE("insert band at %d (bUnicode=%d)!\n", iIndex, bUnicode);
2535     REBAR_DumpBandInfo(lprbbi);
2536 
2537     if (!(lpBand = Alloc(sizeof(REBAR_BAND)))) return FALSE;
2538     if ((iIndex == -1) || (iIndex > infoPtr->uNumBands))
2539         iIndex = infoPtr->uNumBands;
2540     if (DPA_InsertPtr(infoPtr->bands, iIndex, lpBand) == -1)
2541     {
2542         Free(lpBand);
2543         return FALSE;
2544     }
2545     infoPtr->uNumBands++;
2546 
2547     TRACE("index %d!\n", iIndex);
2548 
2549     /* initialize band */
2550     memset(lpBand, 0, sizeof(*lpBand));
2551 #ifdef __REACTOS__
2552     lpBand->clrFore = infoPtr->clrText == CLR_NONE ? CLR_DEFAULT : infoPtr->clrText;
2553     lpBand->clrBack = infoPtr->clrBk == CLR_NONE ? CLR_DEFAULT : infoPtr->clrBk;
2554 #else
2555     lpBand->clrFore = infoPtr->clrText == CLR_NONE ? infoPtr->clrBtnText :
2556                                                      infoPtr->clrText;
2557     lpBand->clrBack = infoPtr->clrBk == CLR_NONE ? infoPtr->clrBtnFace :
2558                                                    infoPtr->clrBk;
2559 #endif
2560     lpBand->iImage = -1;
2561 
2562     REBAR_CommonSetupBand(infoPtr->hwndSelf, lprbbi, lpBand);
2563 
2564     /* Make sure the defaults for these are correct */
2565     if (lprbbi->cbSize < REBARBANDINFOA_V6_SIZE || !(lpBand->fStyle & RBBS_VARIABLEHEIGHT)) {
2566         lpBand->cyChild    = lpBand->cyMinChild;
2567         lpBand->cyMaxChild = 0x7fffffff;
2568         lpBand->cyIntegral = 0;
2569     }
2570 
2571     if ((lprbbi->fMask & RBBIM_TEXT) && (lprbbi->lpText)) {
2572         if (bUnicode)
2573             Str_SetPtrW(&lpBand->lpText, lprbbi->lpText);
2574         else
2575             Str_SetPtrAtoW(&lpBand->lpText, (LPSTR)lprbbi->lpText);
2576     }
2577 
2578     REBAR_ValidateBand (infoPtr, lpBand);
2579     /* On insert of second band, revalidate band 1 to possible add gripper */
2580     if (infoPtr->uNumBands == 2)
2581 	REBAR_ValidateBand (infoPtr, REBAR_GetBand(infoPtr, 0));
2582 
2583     REBAR_DumpBand (infoPtr);
2584 
2585     REBAR_Layout(infoPtr);
2586     InvalidateRect(infoPtr->hwndSelf, NULL, TRUE);
2587 
2588     return TRUE;
2589 }
2590 
2591 
2592 static LRESULT
2593 REBAR_MaximizeBand (const REBAR_INFO *infoPtr, INT iBand, LPARAM lParam)
2594 {
2595     REBAR_BAND *lpBand;
2596     int iRowBegin, iRowEnd;
2597     int cxDesired, extra, extraOrig;
2598     int cxIdealBand;
2599 
2600     /* Validate */
2601     if (infoPtr->uNumBands == 0 || iBand < 0 || iBand >= infoPtr->uNumBands) {
2602 	/* error !!! */
2603 	ERR("Illegal MaximizeBand, requested=%d, current band count=%d\n",
2604 	      iBand, infoPtr->uNumBands);
2605       	return FALSE;
2606     }
2607 
2608     lpBand = REBAR_GetBand(infoPtr, iBand);
2609 
2610     if (lpBand->fStyle & RBBS_HIDDEN)
2611     {
2612         /* Windows is buggy and creates a hole */
2613         WARN("Ignoring maximize request on a hidden band (%d)\n", iBand);
2614         return FALSE;
2615     }
2616 
2617     cxIdealBand = lpBand->cxIdeal + lpBand->cxHeader + REBAR_POST_CHILD;
2618     if (lParam && (lpBand->cxEffective < cxIdealBand))
2619         cxDesired = cxIdealBand;
2620     else
2621         cxDesired = infoPtr->calcSize.cx;
2622 
2623     iRowBegin = get_row_begin_for_band(infoPtr, iBand);
2624     iRowEnd   = get_row_end_for_band(infoPtr, iBand);
2625     extraOrig = extra = cxDesired - lpBand->cxEffective;
2626     if (extra > 0)
2627         extra = REBAR_ShrinkBandsRTL(infoPtr, iRowBegin, iBand, extra, TRUE);
2628     if (extra > 0)
2629         extra = REBAR_ShrinkBandsLTR(infoPtr, next_visible(infoPtr, iBand), iRowEnd, extra, TRUE);
2630     lpBand->cxEffective += extraOrig - extra;
2631     lpBand->cx = lpBand->cxEffective;
2632     TRACE("(%d, %ld): Wanted size %d, obtained %d (shrink %d, %d)\n", iBand, lParam, cxDesired, lpBand->cx, extraOrig, extra);
2633     REBAR_SetRowRectsX(infoPtr, iRowBegin, iRowEnd);
2634 
2635     if (infoPtr->dwStyle & CCS_VERT)
2636         REBAR_CalcVertBand(infoPtr, iRowBegin, iRowEnd);
2637     else
2638         REBAR_CalcHorzBand(infoPtr, iRowBegin, iRowEnd);
2639     REBAR_MoveChildWindows(infoPtr, iRowBegin, iRowEnd);
2640     return TRUE;
2641 
2642 }
2643 
2644 
2645 static LRESULT
2646 REBAR_MinimizeBand (const REBAR_INFO *infoPtr, INT iBand)
2647 {
2648     REBAR_BAND *lpBand;
2649     int iPrev, iRowBegin, iRowEnd;
2650 
2651     /* A "minimize" band is equivalent to "dragging" the gripper
2652      * of than band to the right till the band is only the size
2653      * of the cxHeader.
2654      */
2655 
2656     /* Validate */
2657     if (infoPtr->uNumBands == 0 || iBand < 0 || iBand >= infoPtr->uNumBands) {
2658 	/* error !!! */
2659 	ERR("Illegal MinimizeBand, requested=%d, current band count=%d\n",
2660 	      iBand, infoPtr->uNumBands);
2661       	return FALSE;
2662     }
2663 
2664     /* compute amount of movement and validate */
2665     lpBand = REBAR_GetBand(infoPtr, iBand);
2666 
2667     if (lpBand->fStyle & RBBS_HIDDEN)
2668     {
2669         /* Windows is buggy and creates a hole/overlap */
2670         WARN("Ignoring minimize request on a hidden band (%d)\n", iBand);
2671         return FALSE;
2672     }
2673 
2674     iPrev = prev_visible(infoPtr, iBand);
2675     /* if first band in row */
2676     if (iPrev < 0 || REBAR_GetBand(infoPtr, iPrev)->iRow != lpBand->iRow) {
2677         int iNext = next_visible(infoPtr, iBand);
2678         if (iNext < infoPtr->uNumBands && REBAR_GetBand(infoPtr, iNext)->iRow == lpBand->iRow) {
2679             TRACE("(%d): Minimizing the first band in row is by maximizing the second\n", iBand);
2680             REBAR_MaximizeBand(infoPtr, iNext, FALSE);
2681         }
2682         else
2683             TRACE("(%d): Only one band in row - nothing to do\n", iBand);
2684         return TRUE;
2685     }
2686 
2687     REBAR_GetBand(infoPtr, iPrev)->cxEffective += lpBand->cxEffective - lpBand->cxMinBand;
2688     REBAR_GetBand(infoPtr, iPrev)->cx = REBAR_GetBand(infoPtr, iPrev)->cxEffective;
2689     lpBand->cx = lpBand->cxEffective = lpBand->cxMinBand;
2690 
2691     iRowBegin = get_row_begin_for_band(infoPtr, iBand);
2692     iRowEnd = get_row_end_for_band(infoPtr, iBand);
2693     REBAR_SetRowRectsX(infoPtr, iRowBegin, iRowEnd);
2694 
2695     if (infoPtr->dwStyle & CCS_VERT)
2696         REBAR_CalcVertBand(infoPtr, iRowBegin, iRowEnd);
2697     else
2698         REBAR_CalcHorzBand(infoPtr, iRowBegin, iRowEnd);
2699     REBAR_MoveChildWindows(infoPtr, iRowBegin, iRowEnd);
2700     return FALSE;
2701 }
2702 
2703 
2704 static LRESULT
2705 REBAR_MoveBand (REBAR_INFO *infoPtr, INT iFrom, INT iTo)
2706 {
2707     REBAR_BAND *lpBand;
2708 
2709     /* Validate */
2710     if ((infoPtr->uNumBands == 0) ||
2711 	(iFrom < 0) || iFrom >= infoPtr->uNumBands ||
2712 	(iTo < 0)   || iTo >= infoPtr->uNumBands) {
2713 	/* error !!! */
2714 	ERR("Illegal MoveBand, from=%d, to=%d, current band count=%d\n",
2715 	      iFrom, iTo, infoPtr->uNumBands);
2716       	return FALSE;
2717     }
2718 
2719     lpBand = REBAR_GetBand(infoPtr, iFrom);
2720     DPA_DeletePtr(infoPtr->bands, iFrom);
2721     DPA_InsertPtr(infoPtr->bands, iTo, lpBand);
2722 
2723     TRACE("moved band %d to index %d\n", iFrom, iTo);
2724     REBAR_DumpBand (infoPtr);
2725 
2726     /* **************************************************** */
2727     /*                                                      */
2728     /* We do not do a REBAR_Layout here because the native  */
2729     /* control does not do that. The actual layout and      */
2730     /* repaint is done by the *next* real action, ex.:      */
2731     /* RB_INSERTBAND, RB_DELETEBAND, RB_SIZETORECT, etc.    */
2732     /*                                                      */
2733     /* **************************************************** */
2734 
2735     return TRUE;
2736 }
2737 
2738 
2739 /* return TRUE if two strings are different */
2740 static BOOL
2741 REBAR_strdifW( LPCWSTR a, LPCWSTR b )
2742 {
2743     return ( (a && !b) || (b && !a) || (a && b && lstrcmpW(a, b) ) );
2744 }
2745 
2746 static LRESULT
2747 REBAR_SetBandInfoT(REBAR_INFO *infoPtr, INT iBand, const REBARBANDINFOW *lprbbi, BOOL bUnicode)
2748 {
2749     REBAR_BAND *lpBand;
2750     UINT uChanged;
2751 
2752     if (!lprbbi || lprbbi->cbSize < REBARBANDINFOA_V3_SIZE)
2753 	return FALSE;
2754 
2755     if (iBand >= infoPtr->uNumBands)
2756 	return FALSE;
2757 
2758     TRACE("index %d\n", iBand);
2759     REBAR_DumpBandInfo (lprbbi);
2760 
2761     /* set band information */
2762     lpBand = REBAR_GetBand(infoPtr, iBand);
2763 
2764     uChanged = REBAR_CommonSetupBand (infoPtr->hwndSelf, lprbbi, lpBand);
2765     if (lprbbi->fMask & RBBIM_TEXT) {
2766         LPWSTR wstr = NULL;
2767         if (bUnicode)
2768             Str_SetPtrW(&wstr, lprbbi->lpText);
2769         else
2770             Str_SetPtrAtoW(&wstr, (LPSTR)lprbbi->lpText);
2771 
2772         if (REBAR_strdifW(wstr, lpBand->lpText)) {
2773             Free(lpBand->lpText);
2774             lpBand->lpText = wstr;
2775             uChanged |= RBBIM_TEXT;
2776         }
2777         else
2778             Free(wstr);
2779     }
2780 
2781     REBAR_ValidateBand (infoPtr, lpBand);
2782 
2783     REBAR_DumpBand (infoPtr);
2784 
2785     if (uChanged & (RBBIM_CHILDSIZE | RBBIM_SIZE | RBBIM_STYLE | RBBIM_IMAGE)) {
2786 	  REBAR_Layout(infoPtr);
2787 	  InvalidateRect(infoPtr->hwndSelf, NULL, TRUE);
2788     }
2789 
2790     return TRUE;
2791 }
2792 
2793 
2794 static LRESULT
2795 REBAR_SetBarInfo (REBAR_INFO *infoPtr, const REBARINFO *lpInfo)
2796 {
2797     REBAR_BAND *lpBand;
2798     UINT i;
2799 
2800     if (!lpInfo || lpInfo->cbSize < sizeof (REBARINFO))
2801 	return FALSE;
2802 
2803     TRACE("setting bar info!\n");
2804 
2805     if (lpInfo->fMask & RBIM_IMAGELIST) {
2806 	infoPtr->himl = lpInfo->himl;
2807 	if (infoPtr->himl) {
2808             INT cx, cy;
2809 	    ImageList_GetIconSize (infoPtr->himl, &cx, &cy);
2810 	    infoPtr->imageSize.cx = cx;
2811 	    infoPtr->imageSize.cy = cy;
2812 	}
2813 	else {
2814 	    infoPtr->imageSize.cx = 0;
2815 	    infoPtr->imageSize.cy = 0;
2816 	}
2817 	TRACE("new image cx=%d, cy=%d\n", infoPtr->imageSize.cx,
2818 	      infoPtr->imageSize.cy);
2819     }
2820 
2821     /* revalidate all bands to reset flags for images in headers of bands */
2822     for (i=0; i<infoPtr->uNumBands; i++) {
2823         lpBand = REBAR_GetBand(infoPtr, i);
2824 	REBAR_ValidateBand (infoPtr, lpBand);
2825     }
2826 
2827     return TRUE;
2828 }
2829 
2830 
2831 static LRESULT
2832 REBAR_SetBkColor (REBAR_INFO *infoPtr, COLORREF clr)
2833 {
2834     COLORREF clrTemp;
2835 
2836     clrTemp = infoPtr->clrBk;
2837     infoPtr->clrBk = clr;
2838 
2839     TRACE("background color 0x%06x!\n", infoPtr->clrBk);
2840 
2841     return clrTemp;
2842 }
2843 
2844 
2845 /* << REBAR_SetColorScheme >> */
2846 /* << REBAR_SetPalette >> */
2847 
2848 
2849 static LRESULT
2850 REBAR_SetParent (REBAR_INFO *infoPtr, HWND parent)
2851 {
2852     HWND hwndTemp = infoPtr->hwndNotify;
2853 
2854     infoPtr->hwndNotify = parent;
2855 
2856     return (LRESULT)hwndTemp;
2857 }
2858 
2859 
2860 static LRESULT
2861 REBAR_SetTextColor (REBAR_INFO *infoPtr, COLORREF clr)
2862 {
2863     COLORREF clrTemp;
2864 
2865     clrTemp = infoPtr->clrText;
2866     infoPtr->clrText = clr;
2867 
2868     TRACE("text color 0x%06x!\n", infoPtr->clrText);
2869 
2870     return clrTemp;
2871 }
2872 
2873 
2874 /* << REBAR_SetTooltips >> */
2875 
2876 
2877 static inline LRESULT
2878 REBAR_SetUnicodeFormat (REBAR_INFO *infoPtr, BOOL unicode)
2879 {
2880     BOOL bTemp = infoPtr->bUnicode;
2881 
2882     TRACE("to %s hwnd=%p, was %s\n",
2883 	   unicode ? "TRUE" : "FALSE", infoPtr->hwndSelf,
2884 	  (bTemp) ? "TRUE" : "FALSE");
2885 
2886     infoPtr->bUnicode = unicode;
2887 
2888    return bTemp;
2889 }
2890 
2891 
2892 static LRESULT
2893 REBAR_SetVersion (REBAR_INFO *infoPtr, INT iVersion)
2894 {
2895     INT iOldVersion = infoPtr->iVersion;
2896 
2897     if (iVersion > COMCTL32_VERSION)
2898 	return -1;
2899 
2900     infoPtr->iVersion = iVersion;
2901 
2902     TRACE("new version %d\n", iVersion);
2903 
2904     return iOldVersion;
2905 }
2906 
2907 
2908 static LRESULT
2909 REBAR_ShowBand (REBAR_INFO *infoPtr, INT iBand, BOOL show)
2910 {
2911     REBAR_BAND *lpBand;
2912 
2913     if (iBand < 0 || iBand >= infoPtr->uNumBands)
2914 	return FALSE;
2915 
2916     lpBand = REBAR_GetBand(infoPtr, iBand);
2917 
2918     if (show) {
2919 	TRACE("show band %d\n", iBand);
2920 	lpBand->fStyle = lpBand->fStyle & ~RBBS_HIDDEN;
2921 	if (IsWindow (lpBand->hwndChild))
2922 	    ShowWindow (lpBand->hwndChild, SW_SHOW);
2923     }
2924     else {
2925 	TRACE("hide band %d\n", iBand);
2926 	lpBand->fStyle = lpBand->fStyle | RBBS_HIDDEN;
2927 	if (IsWindow (lpBand->hwndChild))
2928 	    ShowWindow (lpBand->hwndChild, SW_HIDE);
2929     }
2930 
2931     REBAR_Layout(infoPtr);
2932     InvalidateRect(infoPtr->hwndSelf, NULL, TRUE);
2933 
2934     return TRUE;
2935 }
2936 
2937 
2938 static LRESULT
2939 #ifdef __REACTOS__
2940 REBAR_SizeToRect (REBAR_INFO *infoPtr, WPARAM flags, RECT *lpRect)
2941 #else
2942 REBAR_SizeToRect (REBAR_INFO *infoPtr, const RECT *lpRect)
2943 #endif
2944 {
2945     if (!lpRect) return FALSE;
2946 
2947     TRACE("[%s]\n", wine_dbgstr_rect(lpRect));
2948     REBAR_SizeToHeight(infoPtr, get_rect_cy(infoPtr, lpRect));
2949 
2950 #ifdef __REACTOS__
2951     /* Note that this undocumented flag is available on comctl32 v6 or later */
2952     if ((flags & RBSTR_CHANGERECT) != 0)
2953     {
2954         RECT rcRebar;
2955         GetClientRect(infoPtr->hwndSelf, &rcRebar);
2956         lpRect->bottom = lpRect->top + (rcRebar.bottom - rcRebar.top);
2957     }
2958 #endif
2959     return TRUE;
2960 }
2961 
2962 
2963 
2964 static LRESULT
2965 REBAR_Create (REBAR_INFO *infoPtr, LPCREATESTRUCTW cs)
2966 {
2967     RECT wnrc1, clrc1;
2968 
2969     if (TRACE_ON(rebar)) {
2970 	GetWindowRect(infoPtr->hwndSelf, &wnrc1);
2971 	GetClientRect(infoPtr->hwndSelf, &clrc1);
2972         TRACE("window=(%s) client=(%s) cs=(%d,%d %dx%d)\n",
2973               wine_dbgstr_rect(&wnrc1), wine_dbgstr_rect(&clrc1),
2974 	      cs->x, cs->y, cs->cx, cs->cy);
2975     }
2976 
2977     TRACE("created!\n");
2978 
2979     if (OpenThemeData (infoPtr->hwndSelf, themeClass))
2980     {
2981         /* native seems to clear WS_BORDER when themed */
2982         infoPtr->dwStyle &= ~WS_BORDER;
2983     }
2984 
2985     return 0;
2986 }
2987 
2988 
2989 static LRESULT
2990 REBAR_Destroy (REBAR_INFO *infoPtr)
2991 {
2992     REBAR_BAND *lpBand;
2993     UINT i;
2994 
2995     /* clean up each band */
2996     for (i = 0; i < infoPtr->uNumBands; i++) {
2997 	lpBand = REBAR_GetBand(infoPtr, i);
2998 
2999 	/* delete text strings */
3000         Free (lpBand->lpText);
3001 	lpBand->lpText = NULL;
3002 	/* destroy child window */
3003 	DestroyWindow (lpBand->hwndChild);
3004 	Free (lpBand);
3005     }
3006 
3007     /* free band array */
3008     DPA_Destroy (infoPtr->bands);
3009     infoPtr->bands = NULL;
3010 
3011     DestroyCursor (infoPtr->hcurArrow);
3012     DestroyCursor (infoPtr->hcurHorz);
3013     DestroyCursor (infoPtr->hcurVert);
3014     DestroyCursor (infoPtr->hcurDrag);
3015     if (infoPtr->hDefaultFont) DeleteObject (infoPtr->hDefaultFont);
3016     SetWindowLongPtrW (infoPtr->hwndSelf, 0, 0);
3017 
3018     CloseThemeData (GetWindowTheme (infoPtr->hwndSelf));
3019 
3020     /* free rebar info data */
3021     Free (infoPtr);
3022     TRACE("destroyed!\n");
3023     return 0;
3024 }
3025 
3026 static LRESULT
3027 REBAR_GetFont (const REBAR_INFO *infoPtr)
3028 {
3029     return (LRESULT)infoPtr->hFont;
3030 }
3031 
3032 static LRESULT
3033 REBAR_PushChevron(const REBAR_INFO *infoPtr, UINT uBand, LPARAM lParam)
3034 {
3035     if (uBand < infoPtr->uNumBands)
3036     {
3037         NMREBARCHEVRON nmrbc;
3038         REBAR_BAND *lpBand = REBAR_GetBand(infoPtr, uBand);
3039 
3040         TRACE("Pressed chevron on band %u\n", uBand);
3041 
3042         /* redraw chevron in pushed state */
3043         lpBand->fDraw |= DRAW_CHEVRONPUSHED;
3044         RedrawWindow(infoPtr->hwndSelf, &lpBand->rcChevron,0,
3045           RDW_ERASE|RDW_INVALIDATE|RDW_UPDATENOW);
3046 
3047         /* notify app so it can display a popup menu or whatever */
3048         nmrbc.uBand = uBand;
3049         nmrbc.wID = lpBand->wID;
3050         nmrbc.lParam = lpBand->lParam;
3051         nmrbc.rc = lpBand->rcChevron;
3052         nmrbc.lParamNM = lParam;
3053         REBAR_Notify((NMHDR*)&nmrbc, infoPtr, RBN_CHEVRONPUSHED);
3054 
3055         /* redraw chevron in previous state */
3056         lpBand->fDraw &= ~DRAW_CHEVRONPUSHED;
3057         InvalidateRect(infoPtr->hwndSelf, &lpBand->rcChevron, TRUE);
3058 
3059         return TRUE;
3060     }
3061     return FALSE;
3062 }
3063 
3064 static LRESULT
3065 REBAR_LButtonDown (REBAR_INFO *infoPtr, LPARAM lParam)
3066 {
3067     UINT htFlags;
3068     INT iHitBand;
3069     POINT ptMouseDown;
3070     ptMouseDown.x = (short)LOWORD(lParam);
3071     ptMouseDown.y = (short)HIWORD(lParam);
3072 
3073     REBAR_InternalHitTest(infoPtr, &ptMouseDown, &htFlags, &iHitBand);
3074 
3075     if (htFlags == RBHT_CHEVRON)
3076     {
3077         REBAR_PushChevron(infoPtr, iHitBand, 0);
3078     }
3079     else if (htFlags == RBHT_GRABBER || htFlags == RBHT_CAPTION)
3080     {
3081         REBAR_BAND *lpBand;
3082 
3083         TRACE("Starting drag\n");
3084 
3085         lpBand = REBAR_GetBand(infoPtr, iHitBand);
3086 
3087         SetCapture (infoPtr->hwndSelf);
3088         infoPtr->iGrabbedBand = iHitBand;
3089 
3090         /* save off the LOWORD and HIWORD of lParam as initial x,y */
3091         infoPtr->dragStart.x = (short)LOWORD(lParam);
3092         infoPtr->dragStart.y = (short)HIWORD(lParam);
3093         infoPtr->dragNow = infoPtr->dragStart;
3094         if (infoPtr->dwStyle & CCS_VERT)
3095             infoPtr->ihitoffset = infoPtr->dragStart.y - (lpBand->rcBand.left + REBAR_PRE_GRIPPER);
3096         else
3097             infoPtr->ihitoffset = infoPtr->dragStart.x - (lpBand->rcBand.left + REBAR_PRE_GRIPPER);
3098     }
3099     return 0;
3100 }
3101 
3102 static LRESULT
3103 REBAR_LButtonUp (REBAR_INFO *infoPtr)
3104 {
3105     if (infoPtr->iGrabbedBand >= 0)
3106     {
3107         NMHDR layout;
3108         RECT rect;
3109 
3110         infoPtr->dragStart.x = 0;
3111         infoPtr->dragStart.y = 0;
3112         infoPtr->dragNow = infoPtr->dragStart;
3113 
3114         ReleaseCapture ();
3115 
3116         if (infoPtr->fStatus & BEGIN_DRAG_ISSUED) {
3117             REBAR_Notify(&layout, infoPtr, RBN_LAYOUTCHANGED);
3118             REBAR_Notify_NMREBAR (infoPtr, infoPtr->iGrabbedBand, RBN_ENDDRAG);
3119             infoPtr->fStatus &= ~BEGIN_DRAG_ISSUED;
3120         }
3121 
3122         infoPtr->iGrabbedBand = -1;
3123 
3124         GetClientRect(infoPtr->hwndSelf, &rect);
3125         InvalidateRect(infoPtr->hwndSelf, NULL, TRUE);
3126     }
3127 
3128     return 0;
3129 }
3130 
3131 static LRESULT
3132 REBAR_MouseLeave (REBAR_INFO *infoPtr)
3133 {
3134     if (infoPtr->ichevronhotBand >= 0)
3135     {
3136         REBAR_BAND *lpChevronBand = REBAR_GetBand(infoPtr, infoPtr->ichevronhotBand);
3137         if (lpChevronBand->fDraw & DRAW_CHEVRONHOT)
3138         {
3139             lpChevronBand->fDraw &= ~DRAW_CHEVRONHOT;
3140             InvalidateRect(infoPtr->hwndSelf, &lpChevronBand->rcChevron, TRUE);
3141         }
3142     }
3143     infoPtr->iOldBand = -1;
3144     infoPtr->ichevronhotBand = -2;
3145 
3146     return TRUE;
3147 }
3148 
3149 static LRESULT
3150 REBAR_MouseMove (REBAR_INFO *infoPtr, LPARAM lParam)
3151 {
3152     REBAR_BAND *lpChevronBand;
3153     POINT ptMove;
3154 
3155     ptMove.x = (short)LOWORD(lParam);
3156     ptMove.y = (short)HIWORD(lParam);
3157 
3158     /* if we are currently dragging a band */
3159     if (infoPtr->iGrabbedBand >= 0)
3160     {
3161         REBAR_BAND *band;
3162         int yPtMove = (infoPtr->dwStyle & CCS_VERT ? ptMove.x : ptMove.y);
3163 
3164         if (GetCapture() != infoPtr->hwndSelf)
3165             ERR("We are dragging but haven't got capture?!?\n");
3166 
3167         band = REBAR_GetBand(infoPtr, infoPtr->iGrabbedBand);
3168 
3169         /* if mouse did not move much, exit */
3170         if ((abs(ptMove.x - infoPtr->dragNow.x) <= mindragx) &&
3171             (abs(ptMove.y - infoPtr->dragNow.y) <= mindragy)) return 0;
3172 
3173         /* on first significant mouse movement, issue notify */
3174         if (!(infoPtr->fStatus & BEGIN_DRAG_ISSUED)) {
3175             if (REBAR_Notify_NMREBAR (infoPtr, -1, RBN_BEGINDRAG)) {
3176                 /* Notify returned TRUE - abort drag */
3177                 infoPtr->dragStart.x = 0;
3178                 infoPtr->dragStart.y = 0;
3179                 infoPtr->dragNow = infoPtr->dragStart;
3180                 infoPtr->iGrabbedBand = -1;
3181                 ReleaseCapture ();
3182                 return 0;
3183             }
3184             infoPtr->fStatus |= BEGIN_DRAG_ISSUED;
3185         }
3186 
3187         /* Test for valid drag case - must not be first band in row */
3188         if ((yPtMove < band->rcBand.top) ||
3189               (yPtMove > band->rcBand.bottom)) {
3190             REBAR_HandleUDDrag (infoPtr, &ptMove);
3191         }
3192         else {
3193             REBAR_HandleLRDrag (infoPtr, &ptMove);
3194         }
3195     }
3196     else
3197     {
3198         INT iHitBand;
3199         UINT htFlags;
3200         TRACKMOUSEEVENT trackinfo;
3201 
3202         REBAR_InternalHitTest(infoPtr, &ptMove, &htFlags, &iHitBand);
3203 
3204         if (infoPtr->iOldBand >= 0 && infoPtr->iOldBand == infoPtr->ichevronhotBand)
3205         {
3206             lpChevronBand = REBAR_GetBand(infoPtr, infoPtr->ichevronhotBand);
3207             if (lpChevronBand->fDraw & DRAW_CHEVRONHOT)
3208             {
3209                 lpChevronBand->fDraw &= ~DRAW_CHEVRONHOT;
3210                 InvalidateRect(infoPtr->hwndSelf, &lpChevronBand->rcChevron, TRUE);
3211             }
3212             infoPtr->ichevronhotBand = -2;
3213         }
3214 
3215         if (htFlags == RBHT_CHEVRON)
3216         {
3217             /* fill in the TRACKMOUSEEVENT struct */
3218             trackinfo.cbSize = sizeof(TRACKMOUSEEVENT);
3219             trackinfo.dwFlags = TME_QUERY;
3220             trackinfo.hwndTrack = infoPtr->hwndSelf;
3221             trackinfo.dwHoverTime = 0;
3222 
3223             /* call _TrackMouseEvent to see if we are currently tracking for this hwnd */
3224             _TrackMouseEvent(&trackinfo);
3225 
3226             /* Make sure tracking is enabled so we receive a WM_MOUSELEAVE message */
3227             if(!(trackinfo.dwFlags & TME_LEAVE))
3228             {
3229                 trackinfo.dwFlags = TME_LEAVE; /* notify upon leaving */
3230 
3231                 /* call TRACKMOUSEEVENT so we receive a WM_MOUSELEAVE message */
3232                 /* and can properly deactivate the hot chevron */
3233                 _TrackMouseEvent(&trackinfo);
3234             }
3235 
3236             lpChevronBand = REBAR_GetBand(infoPtr, iHitBand);
3237             if (!(lpChevronBand->fDraw & DRAW_CHEVRONHOT))
3238             {
3239                 lpChevronBand->fDraw |= DRAW_CHEVRONHOT;
3240                 InvalidateRect(infoPtr->hwndSelf, &lpChevronBand->rcChevron, TRUE);
3241                 infoPtr->ichevronhotBand = iHitBand;
3242             }
3243         }
3244         infoPtr->iOldBand = iHitBand;
3245     }
3246 
3247     return 0;
3248 }
3249 
3250 
3251 static inline LRESULT
3252 REBAR_NCCalcSize (const REBAR_INFO *infoPtr, RECT *rect)
3253 {
3254     HTHEME theme;
3255 
3256     if (infoPtr->dwStyle & WS_BORDER) {
3257         rect->left   = min(rect->left + GetSystemMetrics(SM_CXEDGE), rect->right);
3258         rect->right  = max(rect->right - GetSystemMetrics(SM_CXEDGE), rect->left);
3259         rect->top    = min(rect->top + GetSystemMetrics(SM_CYEDGE), rect->bottom);
3260         rect->bottom = max(rect->bottom - GetSystemMetrics(SM_CYEDGE), rect->top);
3261     }
3262     else if ((theme = GetWindowTheme (infoPtr->hwndSelf)))
3263     {
3264         /* FIXME: should use GetThemeInt */
3265 #ifdef __REACTOS__
3266         rect->top = (rect->top + 1 < rect->bottom) ? rect->top : rect->bottom;
3267 #else
3268         rect->top = min(rect->top + 1, rect->bottom);
3269 #endif
3270     }
3271     TRACE("new client=(%s)\n", wine_dbgstr_rect(rect));
3272     return 0;
3273 }
3274 
3275 
3276 static LRESULT
3277 REBAR_NCCreate (HWND hwnd, const CREATESTRUCTW *cs)
3278 {
3279     REBAR_INFO *infoPtr = REBAR_GetInfoPtr (hwnd);
3280     RECT wnrc1, clrc1;
3281     NONCLIENTMETRICSW ncm;
3282     HFONT tfont;
3283 
3284     if (infoPtr) {
3285 	ERR("Strange info structure pointer *not* NULL\n");
3286 	return FALSE;
3287     }
3288 
3289     if (TRACE_ON(rebar)) {
3290 	GetWindowRect(hwnd, &wnrc1);
3291 	GetClientRect(hwnd, &clrc1);
3292         TRACE("window=(%s) client=(%s) cs=(%d,%d %dx%d)\n",
3293               wine_dbgstr_rect(&wnrc1), wine_dbgstr_rect(&clrc1),
3294 	      cs->x, cs->y, cs->cx, cs->cy);
3295     }
3296 
3297     /* allocate memory for info structure */
3298     infoPtr = Alloc (sizeof(REBAR_INFO));
3299     SetWindowLongPtrW (hwnd, 0, (DWORD_PTR)infoPtr);
3300 
3301     /* initialize info structure - initial values are 0 */
3302     infoPtr->clrBk = CLR_NONE;
3303     infoPtr->clrText = CLR_NONE;
3304     infoPtr->clrBtnText = comctl32_color.clrBtnText;
3305     infoPtr->clrBtnFace = comctl32_color.clrBtnFace;
3306     infoPtr->iOldBand = -1;
3307     infoPtr->ichevronhotBand = -2;
3308     infoPtr->iGrabbedBand = -1;
3309     infoPtr->hwndSelf = hwnd;
3310     infoPtr->DoRedraw = TRUE;
3311     infoPtr->hcurArrow = LoadCursorW (0, (LPWSTR)IDC_ARROW);
3312     infoPtr->hcurHorz  = LoadCursorW (0, (LPWSTR)IDC_SIZEWE);
3313     infoPtr->hcurVert  = LoadCursorW (0, (LPWSTR)IDC_SIZENS);
3314     infoPtr->hcurDrag  = LoadCursorW (0, (LPWSTR)IDC_SIZE);
3315     infoPtr->fStatus = 0;
3316     infoPtr->hFont = GetStockObject (SYSTEM_FONT);
3317     infoPtr->bands = DPA_Create(8);
3318 
3319     /* issue WM_NOTIFYFORMAT to get unicode status of parent */
3320     REBAR_NotifyFormat(infoPtr, NF_REQUERY);
3321 
3322     /* Stow away the original style */
3323     infoPtr->orgStyle = cs->style;
3324     /* add necessary styles to the requested styles */
3325     infoPtr->dwStyle = cs->style | WS_VISIBLE;
3326     if ((infoPtr->dwStyle & CCS_LAYOUT_MASK) == 0)
3327         infoPtr->dwStyle |= CCS_TOP;
3328     SetWindowLongW (hwnd, GWL_STYLE, infoPtr->dwStyle);
3329 
3330     /* get font handle for Caption Font */
3331     ncm.cbSize = sizeof(ncm);
3332     SystemParametersInfoW (SPI_GETNONCLIENTMETRICS, ncm.cbSize, &ncm, 0);
3333     /* if the font is bold, set to normal */
3334     if (ncm.lfCaptionFont.lfWeight > FW_NORMAL) {
3335 	ncm.lfCaptionFont.lfWeight = FW_NORMAL;
3336     }
3337     tfont = CreateFontIndirectW (&ncm.lfCaptionFont);
3338     if (tfont) {
3339         infoPtr->hFont = infoPtr->hDefaultFont = tfont;
3340     }
3341 
3342     return TRUE;
3343 }
3344 
3345 
3346 static LRESULT
3347 REBAR_NCHitTest (const REBAR_INFO *infoPtr, LPARAM lParam)
3348 {
3349     NMMOUSE nmmouse;
3350     POINT clpt;
3351     INT i;
3352     UINT scrap;
3353     LRESULT ret = HTCLIENT;
3354 
3355     /*
3356      * Differences from doc at MSDN (as observed with version 4.71 of
3357      *      comctl32.dll
3358      * 1. doc says nmmouse.pt is in screen coord, trace shows client coord.
3359      * 2. if band is not identified .dwItemSpec is 0xffffffff.
3360      * 3. native always seems to return HTCLIENT if notify return is 0.
3361      */
3362 
3363     clpt.x = (short)LOWORD(lParam);
3364     clpt.y = (short)HIWORD(lParam);
3365     ScreenToClient (infoPtr->hwndSelf, &clpt);
3366     REBAR_InternalHitTest (infoPtr, &clpt, &scrap,
3367 			   (INT *)&nmmouse.dwItemSpec);
3368     nmmouse.dwItemData = 0;
3369     nmmouse.pt = clpt;
3370 #ifdef __REACTOS__
3371     nmmouse.dwHitInfo = scrap;
3372 #else
3373     nmmouse.dwHitInfo = 0;
3374 #endif
3375     if ((i = REBAR_Notify((NMHDR *) &nmmouse, infoPtr, NM_NCHITTEST))) {
3376 	TRACE("notify changed return value from %ld to %d\n",
3377 	      ret, i);
3378 	ret = (LRESULT) i;
3379     }
3380     TRACE("returning %ld, client point %s\n", ret, wine_dbgstr_point(&clpt));
3381     return ret;
3382 }
3383 
3384 
3385 static LRESULT
3386 REBAR_NCPaint (const REBAR_INFO *infoPtr)
3387 {
3388     RECT rcWindow;
3389     HDC hdc;
3390     HTHEME theme;
3391 
3392     if (infoPtr->dwStyle & WS_MINIMIZE)
3393 	return 0; /* Nothing to do */
3394 
3395     if (infoPtr->dwStyle & WS_BORDER) {
3396 
3397 	/* adjust rectangle and draw the necessary edge */
3398 	if (!(hdc = GetDCEx( infoPtr->hwndSelf, 0, DCX_USESTYLE | DCX_WINDOW )))
3399 	    return 0;
3400 	GetWindowRect (infoPtr->hwndSelf, &rcWindow);
3401 	OffsetRect (&rcWindow, -rcWindow.left, -rcWindow.top);
3402         TRACE("rect (%s)\n", wine_dbgstr_rect(&rcWindow));
3403 	DrawEdge (hdc, &rcWindow, EDGE_ETCHED, BF_RECT);
3404 	ReleaseDC( infoPtr->hwndSelf, hdc );
3405     }
3406     else if ((theme = GetWindowTheme (infoPtr->hwndSelf)))
3407     {
3408         /* adjust rectangle and draw the necessary edge */
3409         if (!(hdc = GetDCEx( infoPtr->hwndSelf, 0, DCX_USESTYLE | DCX_WINDOW )))
3410             return 0;
3411         GetWindowRect (infoPtr->hwndSelf, &rcWindow);
3412         OffsetRect (&rcWindow, -rcWindow.left, -rcWindow.top);
3413         TRACE("rect (%s)\n", wine_dbgstr_rect(&rcWindow));
3414         DrawThemeEdge (theme, hdc, 0, 0, &rcWindow, BDR_RAISEDINNER, BF_TOP, NULL);
3415         ReleaseDC( infoPtr->hwndSelf, hdc );
3416     }
3417 
3418     return 0;
3419 }
3420 
3421 
3422 static LRESULT
3423 REBAR_NotifyFormat (REBAR_INFO *infoPtr, LPARAM cmd)
3424 {
3425     INT i;
3426 
3427     if (cmd == NF_REQUERY) {
3428 	i = SendMessageW(REBAR_GetNotifyParent (infoPtr),
3429 			 WM_NOTIFYFORMAT, (WPARAM)infoPtr->hwndSelf, NF_QUERY);
3430         if ((i != NFR_ANSI) && (i != NFR_UNICODE)) {
3431 	    ERR("wrong response to WM_NOTIFYFORMAT (%d), assuming ANSI\n", i);
3432 	    i = NFR_ANSI;
3433 	}
3434         infoPtr->bUnicode = (i == NFR_UNICODE);
3435 	return (LRESULT)i;
3436     }
3437     return (LRESULT)((infoPtr->bUnicode) ? NFR_UNICODE : NFR_ANSI);
3438 }
3439 
3440 
3441 static LRESULT
3442 REBAR_Paint (const REBAR_INFO *infoPtr, HDC hdc)
3443 {
3444     if (hdc) {
3445         TRACE("painting\n");
3446 #ifdef __REACTOS__
3447         REBAR_EraseBkGnd (infoPtr, hdc);
3448 #endif
3449         REBAR_Refresh (infoPtr, hdc);
3450     } else {
3451         PAINTSTRUCT ps;
3452         hdc = BeginPaint (infoPtr->hwndSelf, &ps);
3453         TRACE("painting (%s)\n", wine_dbgstr_rect(&ps.rcPaint));
3454         if (ps.fErase) {
3455             /* Erase area of paint if requested */
3456             REBAR_EraseBkGnd (infoPtr, hdc);
3457         }
3458         REBAR_Refresh (infoPtr, hdc);
3459 	EndPaint (infoPtr->hwndSelf, &ps);
3460     }
3461 
3462     return 0;
3463 }
3464 
3465 
3466 static LRESULT
3467 REBAR_SetCursor (const REBAR_INFO *infoPtr, LPARAM lParam)
3468 {
3469     POINT pt;
3470     UINT  flags;
3471 
3472     TRACE("code=0x%X  id=0x%X\n", LOWORD(lParam), HIWORD(lParam));
3473 
3474     GetCursorPos (&pt);
3475     ScreenToClient (infoPtr->hwndSelf, &pt);
3476 
3477     REBAR_InternalHitTest (infoPtr, &pt, &flags, NULL);
3478 
3479     if (flags == RBHT_GRABBER) {
3480 	if ((infoPtr->dwStyle & CCS_VERT) &&
3481 	    !(infoPtr->dwStyle & RBS_VERTICALGRIPPER))
3482 	    SetCursor (infoPtr->hcurVert);
3483 	else
3484 	    SetCursor (infoPtr->hcurHorz);
3485     }
3486     else if (flags != RBHT_CLIENT)
3487 	SetCursor (infoPtr->hcurArrow);
3488 
3489     return 0;
3490 }
3491 
3492 
3493 static LRESULT
3494 REBAR_SetFont (REBAR_INFO *infoPtr, HFONT font)
3495 {
3496     REBAR_BAND *lpBand;
3497     UINT i;
3498 
3499     infoPtr->hFont = font;
3500 
3501     /* revalidate all bands to change sizes of text in headers of bands */
3502     for (i=0; i<infoPtr->uNumBands; i++) {
3503         lpBand = REBAR_GetBand(infoPtr, i);
3504 	REBAR_ValidateBand (infoPtr, lpBand);
3505     }
3506 
3507     REBAR_Layout(infoPtr);
3508     return 0;
3509 }
3510 
3511 
3512 /*****************************************************
3513  *
3514  *  Handles the WM_SETREDRAW message.
3515  *
3516  * Documentation:
3517  *  According to testing V4.71 of COMCTL32 returns the
3518  *  *previous* status of the redraw flag (either 0 or -1)
3519  *  instead of the MSDN documented value of 0 if handled
3520  *
3521  *****************************************************/
3522 static inline LRESULT
3523 REBAR_SetRedraw (REBAR_INFO *infoPtr, BOOL redraw)
3524 {
3525     BOOL oldredraw = infoPtr->DoRedraw;
3526 
3527     TRACE("set to %s, fStatus=%08x\n",
3528 	  (redraw) ? "TRUE" : "FALSE", infoPtr->fStatus);
3529     infoPtr->DoRedraw = redraw;
3530     if (redraw) {
3531 	if (infoPtr->fStatus & BAND_NEEDS_REDRAW) {
3532 	    REBAR_MoveChildWindows (infoPtr, 0, infoPtr->uNumBands);
3533 	    REBAR_ForceResize (infoPtr);
3534 	    InvalidateRect (infoPtr->hwndSelf, NULL, TRUE);
3535 	}
3536 	infoPtr->fStatus &= ~BAND_NEEDS_REDRAW;
3537     }
3538     return (oldredraw) ? -1 : 0;
3539 }
3540 
3541 
3542 static LRESULT
3543 REBAR_Size (REBAR_INFO *infoPtr, WPARAM wParam, LPARAM lParam)
3544 {
3545     TRACE("wParam=%lx, lParam=%lx\n", wParam, lParam);
3546 
3547     /* avoid _Layout resize recursion (but it shouldn't be infinite and it seems Windows does recurse) */
3548     if (infoPtr->fStatus & SELF_RESIZE) {
3549 	infoPtr->fStatus &= ~SELF_RESIZE;
3550 	TRACE("SELF_RESIZE was set, reset, fStatus=%08x lparam=%08lx\n",
3551 	      infoPtr->fStatus, lParam);
3552 	return 0;
3553     }
3554 
3555     if (infoPtr->dwStyle & RBS_AUTOSIZE)
3556         REBAR_AutoSize(infoPtr, TRUE);
3557     else
3558         REBAR_Layout(infoPtr);
3559 
3560     return 0;
3561 }
3562 
3563 
3564 static LRESULT
3565 REBAR_StyleChanged (REBAR_INFO *infoPtr, INT nType, const STYLESTRUCT *lpStyle)
3566 {
3567     TRACE("current style=%08x, styleOld=%08x, style being set to=%08x\n",
3568 	  infoPtr->dwStyle, lpStyle->styleOld, lpStyle->styleNew);
3569     if (nType == GWL_STYLE)
3570     {
3571         infoPtr->orgStyle = infoPtr->dwStyle = lpStyle->styleNew;
3572         if (GetWindowTheme (infoPtr->hwndSelf))
3573             infoPtr->dwStyle &= ~WS_BORDER;
3574         /* maybe it should be COMMON_STYLES like in toolbar */
3575         if ((lpStyle->styleNew ^ lpStyle->styleOld) & CCS_VERT)
3576             REBAR_Layout(infoPtr);
3577     }
3578     return FALSE;
3579 }
3580 
3581 /* update theme after a WM_THEMECHANGED message */
3582 static LRESULT theme_changed (REBAR_INFO* infoPtr)
3583 {
3584     HTHEME theme = GetWindowTheme (infoPtr->hwndSelf);
3585     CloseThemeData (theme);
3586     theme = OpenThemeData (infoPtr->hwndSelf, themeClass);
3587     /* WS_BORDER disappears when theming is enabled and reappears when
3588      * disabled... */
3589     infoPtr->dwStyle &= ~WS_BORDER;
3590     infoPtr->dwStyle |= theme ? 0 : (infoPtr->orgStyle & WS_BORDER);
3591     return 0;
3592 }
3593 
3594 static LRESULT
3595 REBAR_WindowPosChanged (const REBAR_INFO *infoPtr, WPARAM wParam, LPARAM lParam)
3596 {
3597     LRESULT ret;
3598     RECT rc;
3599 
3600     ret = DefWindowProcW(infoPtr->hwndSelf, WM_WINDOWPOSCHANGED,
3601 			 wParam, lParam);
3602     GetWindowRect(infoPtr->hwndSelf, &rc);
3603     TRACE("hwnd %p new pos (%s)\n", infoPtr->hwndSelf, wine_dbgstr_rect(&rc));
3604     return ret;
3605 }
3606 
3607 
3608 static LRESULT WINAPI
3609 REBAR_WindowProc (HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
3610 {
3611     REBAR_INFO *infoPtr = REBAR_GetInfoPtr (hwnd);
3612 
3613     TRACE("hwnd=%p msg=%x wparam=%lx lparam=%lx\n",
3614 	  hwnd, uMsg, wParam, lParam);
3615     if (!infoPtr && (uMsg != WM_NCCREATE))
3616         return DefWindowProcW (hwnd, uMsg, wParam, lParam);
3617     switch (uMsg)
3618     {
3619 /*	case RB_BEGINDRAG: */
3620 
3621 	case RB_DELETEBAND:
3622 	    return REBAR_DeleteBand (infoPtr, wParam);
3623 
3624 /*	case RB_DRAGMOVE: */
3625 /*	case RB_ENDDRAG: */
3626 
3627 	case RB_GETBANDBORDERS:
3628 	    return REBAR_GetBandBorders (infoPtr, wParam, (LPRECT)lParam);
3629 
3630 	case RB_GETBANDCOUNT:
3631 	    return REBAR_GetBandCount (infoPtr);
3632 
3633 	case RB_GETBANDINFO_OLD:
3634 	case RB_GETBANDINFOA:
3635 	case RB_GETBANDINFOW:
3636 	    return REBAR_GetBandInfoT(infoPtr, wParam, (LPREBARBANDINFOW)lParam,
3637 	                                                uMsg == RB_GETBANDINFOW);
3638 	case RB_GETBARHEIGHT:
3639 	    return REBAR_GetBarHeight (infoPtr);
3640 
3641 	case RB_GETBARINFO:
3642 	    return REBAR_GetBarInfo (infoPtr, (LPREBARINFO)lParam);
3643 
3644 	case RB_GETBKCOLOR:
3645 	    return REBAR_GetBkColor (infoPtr);
3646 
3647 /*	case RB_GETCOLORSCHEME: */
3648 /*	case RB_GETDROPTARGET: */
3649 
3650 	case RB_GETPALETTE:
3651 	    return REBAR_GetPalette (infoPtr);
3652 
3653 	case RB_GETRECT:
3654 	    return REBAR_GetRect (infoPtr, wParam, (LPRECT)lParam);
3655 
3656 	case RB_GETROWCOUNT:
3657 	    return REBAR_GetRowCount (infoPtr);
3658 
3659 	case RB_GETROWHEIGHT:
3660 	    return REBAR_GetRowHeight (infoPtr, wParam);
3661 
3662 	case RB_GETTEXTCOLOR:
3663 	    return REBAR_GetTextColor (infoPtr);
3664 
3665 	case RB_GETTOOLTIPS:
3666 	    return REBAR_GetToolTips (infoPtr);
3667 
3668 	case RB_GETUNICODEFORMAT:
3669 	    return REBAR_GetUnicodeFormat (infoPtr);
3670 
3671 	case CCM_GETVERSION:
3672 	    return REBAR_GetVersion (infoPtr);
3673 
3674 	case RB_HITTEST:
3675 	    return REBAR_HitTest (infoPtr, (LPRBHITTESTINFO)lParam);
3676 
3677 	case RB_IDTOINDEX:
3678 	    return REBAR_IdToIndex (infoPtr, wParam);
3679 
3680 	case RB_INSERTBANDA:
3681 	case RB_INSERTBANDW:
3682 	    return REBAR_InsertBandT(infoPtr, wParam, (LPREBARBANDINFOW)lParam,
3683 	                                               uMsg == RB_INSERTBANDW);
3684 	case RB_MAXIMIZEBAND:
3685 	    return REBAR_MaximizeBand (infoPtr, wParam, lParam);
3686 
3687 	case RB_MINIMIZEBAND:
3688 	    return REBAR_MinimizeBand (infoPtr, wParam);
3689 
3690 	case RB_MOVEBAND:
3691 	    return REBAR_MoveBand (infoPtr, wParam, lParam);
3692 
3693 	case RB_PUSHCHEVRON:
3694 	    return REBAR_PushChevron (infoPtr, wParam, lParam);
3695 
3696 	case RB_SETBANDINFOA:
3697 	case RB_SETBANDINFOW:
3698 	    return REBAR_SetBandInfoT(infoPtr, wParam, (LPREBARBANDINFOW)lParam,
3699 	                                                uMsg == RB_SETBANDINFOW);
3700 	case RB_SETBARINFO:
3701 	    return REBAR_SetBarInfo (infoPtr, (LPREBARINFO)lParam);
3702 
3703 	case RB_SETBKCOLOR:
3704 	    return REBAR_SetBkColor (infoPtr, lParam);
3705 
3706 /*	case RB_SETCOLORSCHEME: */
3707 /*	case RB_SETPALETTE: */
3708 
3709 	case RB_SETPARENT:
3710 	    return REBAR_SetParent (infoPtr, (HWND)wParam);
3711 
3712 	case RB_SETTEXTCOLOR:
3713 	    return REBAR_SetTextColor (infoPtr, lParam);
3714 
3715 /*	case RB_SETTOOLTIPS: */
3716 
3717 	case RB_SETUNICODEFORMAT:
3718 	    return REBAR_SetUnicodeFormat (infoPtr, wParam);
3719 
3720 	case CCM_SETVERSION:
3721 	    return REBAR_SetVersion (infoPtr, (INT)wParam);
3722 
3723 	case RB_SHOWBAND:
3724 	    return REBAR_ShowBand (infoPtr, wParam, lParam);
3725 
3726 	case RB_SIZETORECT:
3727 #ifdef __REACTOS__
3728 	    return REBAR_SizeToRect (infoPtr, wParam, (LPRECT)lParam);
3729 #else
3730 	    return REBAR_SizeToRect (infoPtr, (LPCRECT)lParam);
3731 #endif
3732 
3733 
3734 /*    Messages passed to parent */
3735 	case WM_COMMAND:
3736 	case WM_DRAWITEM:
3737 	case WM_NOTIFY:
3738         case WM_MEASUREITEM:
3739             return SendMessageW(REBAR_GetNotifyParent (infoPtr), uMsg, wParam, lParam);
3740 
3741 
3742 /*      case WM_CHARTOITEM:     supported according to ControlSpy */
3743 
3744 	case WM_CREATE:
3745 	    return REBAR_Create (infoPtr, (LPCREATESTRUCTW)lParam);
3746 
3747 	case WM_DESTROY:
3748 	    return REBAR_Destroy (infoPtr);
3749 
3750         case WM_ERASEBKGND:
3751 	    return REBAR_EraseBkGnd (infoPtr, (HDC)wParam);
3752 
3753 	case WM_GETFONT:
3754 	    return REBAR_GetFont (infoPtr);
3755 
3756 /*      case WM_LBUTTONDBLCLK:  supported according to ControlSpy */
3757 
3758 	case WM_LBUTTONDOWN:
3759 	    return REBAR_LButtonDown (infoPtr, lParam);
3760 
3761 	case WM_LBUTTONUP:
3762 	    return REBAR_LButtonUp (infoPtr);
3763 
3764 	case WM_MOUSEMOVE:
3765 	    return REBAR_MouseMove (infoPtr, lParam);
3766 
3767 	case WM_MOUSELEAVE:
3768 	    return REBAR_MouseLeave (infoPtr);
3769 
3770 	case WM_NCCALCSIZE:
3771 	    return REBAR_NCCalcSize (infoPtr, (RECT*)lParam);
3772 
3773         case WM_NCCREATE:
3774 	    return REBAR_NCCreate (hwnd, (LPCREATESTRUCTW)lParam);
3775 
3776         case WM_NCHITTEST:
3777 	    return REBAR_NCHitTest (infoPtr, lParam);
3778 
3779 	case WM_NCPAINT:
3780 	    return REBAR_NCPaint (infoPtr);
3781 
3782         case WM_NOTIFYFORMAT:
3783 	    return REBAR_NotifyFormat (infoPtr, lParam);
3784 
3785 	case WM_PRINTCLIENT:
3786 	case WM_PAINT:
3787 	    return REBAR_Paint (infoPtr, (HDC)wParam);
3788 
3789 /*      case WM_PALETTECHANGED: supported according to ControlSpy */
3790 /*      case WM_QUERYNEWPALETTE:supported according to ControlSpy */
3791 /*      case WM_RBUTTONDOWN:    supported according to ControlSpy */
3792 /*      case WM_RBUTTONUP:      supported according to ControlSpy */
3793 
3794 	case WM_SETCURSOR:
3795 	    return REBAR_SetCursor (infoPtr, lParam);
3796 
3797 	case WM_SETFONT:
3798 	    return REBAR_SetFont (infoPtr, (HFONT)wParam);
3799 
3800         case WM_SETREDRAW:
3801 	    return REBAR_SetRedraw (infoPtr, wParam);
3802 
3803 	case WM_SIZE:
3804 	    return REBAR_Size (infoPtr, wParam, lParam);
3805 
3806         case WM_STYLECHANGED:
3807 	    return REBAR_StyleChanged (infoPtr, wParam, (LPSTYLESTRUCT)lParam);
3808 
3809         case WM_THEMECHANGED:
3810             return theme_changed (infoPtr);
3811 
3812         case WM_SYSCOLORCHANGE:
3813             COMCTL32_RefreshSysColors();
3814 #ifdef __REACTOS__
3815             /* r51522 - Properly support WM_SYSCOLORCHANGE */
3816             infoPtr->clrBtnText = comctl32_color.clrBtnText;
3817             infoPtr->clrBtnFace = comctl32_color.clrBtnFace;
3818 #endif
3819             return 0;
3820 
3821 /*      case WM_VKEYTOITEM:     supported according to ControlSpy */
3822 /*	case WM_WININICHANGE: */
3823 
3824         case WM_WINDOWPOSCHANGED:
3825 	    return REBAR_WindowPosChanged (infoPtr, wParam, lParam);
3826 
3827 	default:
3828 	    if ((uMsg >= WM_USER) && (uMsg < WM_APP) && !COMCTL32_IsReflectedMessage(uMsg))
3829 		ERR("unknown msg %04x wp=%08lx lp=%08lx\n",
3830 		     uMsg, wParam, lParam);
3831 	    return DefWindowProcW (hwnd, uMsg, wParam, lParam);
3832     }
3833 }
3834 
3835 
3836 VOID
3837 REBAR_Register (void)
3838 {
3839     WNDCLASSW wndClass;
3840 
3841     ZeroMemory (&wndClass, sizeof(WNDCLASSW));
3842     wndClass.style         = CS_GLOBALCLASS | CS_DBLCLKS;
3843     wndClass.lpfnWndProc   = REBAR_WindowProc;
3844     wndClass.cbClsExtra    = 0;
3845     wndClass.cbWndExtra    = sizeof(REBAR_INFO *);
3846     wndClass.hCursor       = 0;
3847     wndClass.hbrBackground = (HBRUSH)(COLOR_BTNFACE + 1);
3848 #if GLATESTING
3849     wndClass.hbrBackground = CreateSolidBrush(RGB(0,128,0));
3850 #endif
3851     wndClass.lpszClassName = REBARCLASSNAMEW;
3852 
3853     RegisterClassW (&wndClass);
3854 
3855     mindragx = GetSystemMetrics (SM_CXDRAG);
3856     mindragy = GetSystemMetrics (SM_CYDRAG);
3857 
3858 }
3859 
3860 
3861 VOID
3862 REBAR_Unregister (void)
3863 {
3864     UnregisterClassW (REBARCLASSNAMEW, NULL);
3865 }
3866