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