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