rpcrt4: Use safe_multiply when multiplying anything by pStubMsg->ActualCount or pStub...
[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  *   - CCS_NORESIZE
36  *   - CCS_NOMOVEX
37  *   - CCS_NOMOVEY
38  *   Messages:
39  *   - RB_BEGINDRAG
40  *   - RB_DRAGMOVE
41  *   - RB_ENDDRAG
42  *   - RB_GETBANDMARGINS
43  *   - RB_GETCOLORSCHEME
44  *   - RB_GETDROPTARGET
45  *   - RB_GETPALETTE
46  *   - RB_SETCOLORSCHEME
47  *   - RB_SETPALETTE
48  *   - RB_SETTOOLTIPS
49  *   - WM_CHARTOITEM
50  *   - WM_LBUTTONDBLCLK
51  *   - WM_MEASUREITEM
52  *   - WM_PALETTECHANGED
53  *   - WM_QUERYNEWPALETTE
54  *   - WM_RBUTTONDOWN
55  *   - WM_RBUTTONUP
56  *   - WM_SYSCOLORCHANGE
57  *   - WM_VKEYTOITEM
58  *   - WM_WININICHANGE
59  *   Notifications:
60  *   - NM_HCHITTEST
61  *   - NM_RELEASEDCAPTURE
62  *   - RBN_AUTOBREAK
63  *   - RBN_GETOBJECT
64  *   - RBN_MINMAX
65  *   Band styles:
66  *   - RBBS_FIXEDBMP
67  *   Native uses (on each draw!!) SM_CYBORDER (or SM_CXBORDER for CCS_VERT)
68  *   to set the size of the separator width (the value SEP_WIDTH_SIZE
69  *   in here). Should be fixed!!
70  */
71
72 /*
73  * Testing: set to 1 to make background brush *always* green
74  */
75 #define GLATESTING 0
76
77 /*
78  *
79  * 2.  At "FIXME:  problem # 2" WinRAR:
80  *   if "#if 1" then last band draws in separate row
81  *   if "#if 0" then last band draws in previous row *** just like native ***
82  *
83  */
84 #define PROBLEM2 0
85
86 /*
87  * 3. REBAR_MoveChildWindows should have a loop because more than
88  *    one pass is made (together with the RBN_CHILDSIZEs) is made on
89  *    at least RB_INSERTBAND
90  */
91
92 #include <stdarg.h>
93 #include <stdlib.h>
94 #include <string.h>
95
96 #include "windef.h"
97 #include "winbase.h"
98 #include "wingdi.h"
99 #include "wine/unicode.h"
100 #include "winuser.h"
101 #include "winnls.h"
102 #include "commctrl.h"
103 #include "comctl32.h"
104 #include "uxtheme.h"
105 #include "tmschema.h"
106 #include "wine/debug.h"
107
108 WINE_DEFAULT_DEBUG_CHANNEL(rebar);
109
110 typedef struct
111 {
112     UINT    fStyle;
113     UINT    fMask;
114     COLORREF  clrFore;
115     COLORREF  clrBack;
116     INT     iImage;
117     HWND    hwndChild;
118     UINT    cxMinChild;     /* valid if _CHILDSIZE */
119     UINT    cyMinChild;     /* valid if _CHILDSIZE */
120     UINT    cx;             /* valid if _SIZE */
121     HBITMAP hbmBack;
122     UINT    wID;
123     UINT    cyChild;        /* valid if _CHILDSIZE */
124     UINT    cyMaxChild;     /* valid if _CHILDSIZE */
125     UINT    cyIntegral;     /* valid if _CHILDSIZE */
126     UINT    cxIdeal;
127     LPARAM    lParam;
128     UINT    cxHeader;
129
130     UINT    lcx;            /* minimum cx for band */
131     UINT    ccx;            /* current cx for band */
132     UINT    hcx;            /* maximum cx for band */
133     UINT    lcy;            /* minimum cy for band */
134     UINT    ccy;            /* current cy for band */
135     UINT    hcy;            /* maximum cy for band */
136
137     SIZE    offChild;       /* x,y offset if child is not FIXEDSIZE */
138     UINT    uMinHeight;
139     INT     iRow;           /* zero-based index of the row this band assigned to */
140     UINT    fStatus;        /* status flags, reset only by _Validate */
141     UINT    fDraw;          /* drawing flags, reset only by _Layout */
142     UINT    uCDret;         /* last return from NM_CUSTOMDRAW */
143     RECT    rcoldBand;      /* previous calculated band rectangle */
144     RECT    rcBand;         /* calculated band rectangle */
145     RECT    rcGripper;      /* calculated gripper rectangle */
146     RECT    rcCapImage;     /* calculated caption image rectangle */
147     RECT    rcCapText;      /* calculated caption text rectangle */
148     RECT    rcChild;        /* calculated child rectangle */
149     RECT    rcChevron;      /* calculated chevron rectangle */
150
151     LPWSTR    lpText;
152     HWND    hwndPrevParent;
153 } REBAR_BAND;
154
155 /* fStatus flags */
156 #define HAS_GRIPPER    0x00000001
157 #define HAS_IMAGE      0x00000002
158 #define HAS_TEXT       0x00000004
159
160 /* fDraw flags */
161 #define DRAW_GRIPPER    0x00000001
162 #define DRAW_IMAGE      0x00000002
163 #define DRAW_TEXT       0x00000004
164 #define DRAW_RIGHTSEP   0x00000010
165 #define DRAW_BOTTOMSEP  0x00000020
166 #define DRAW_CHEVRONHOT 0x00000040
167 #define DRAW_CHEVRONPUSHED 0x00000080
168 #define DRAW_LAST_IN_ROW   0x00000100
169 #define DRAW_FIRST_IN_ROW  0x00000200
170 #define NTF_INVALIDATE  0x01000000
171
172 typedef struct
173 {
174     COLORREF   clrBk;       /* background color */
175     COLORREF   clrText;     /* text color */
176     COLORREF   clrBtnText;  /* system color for BTNTEXT */
177     COLORREF   clrBtnFace;  /* system color for BTNFACE */
178     HIMAGELIST himl;        /* handle to imagelist */
179     UINT     uNumBands;   /* # of bands in rebar (first=0, last=uNumBands-1 */
180     UINT     uNumRows;    /* # of rows of bands (first=1, last=uNumRows */
181     HWND     hwndSelf;    /* handle of REBAR window itself */
182     HWND     hwndToolTip; /* handle to the tool tip control */
183     HWND     hwndNotify;  /* notification window (parent) */
184     HFONT    hDefaultFont;
185     HFONT    hFont;       /* handle to the rebar's font */
186     SIZE     imageSize;   /* image size (image list) */
187     DWORD    dwStyle;     /* window style */
188     DWORD    orgStyle;    /* original style (dwStyle may change) */
189     SIZE     calcSize;    /* calculated rebar size */
190     SIZE     oldSize;     /* previous calculated rebar size */
191     BOOL     bUnicode;    /* TRUE if this window is W type */
192     BOOL     NtfUnicode;  /* TRUE if parent wants notify in W format */
193     BOOL     DoRedraw;    /* TRUE to acutally draw bands */
194     UINT     fStatus;     /* Status flags (see below)  */
195     HCURSOR  hcurArrow;   /* handle to the arrow cursor */
196     HCURSOR  hcurHorz;    /* handle to the EW cursor */
197     HCURSOR  hcurVert;    /* handle to the NS cursor */
198     HCURSOR  hcurDrag;    /* handle to the drag cursor */
199     INT      iVersion;    /* version number */
200     POINT    dragStart;   /* x,y of button down */
201     POINT    dragNow;     /* x,y of this MouseMove */
202     INT      iOldBand;    /* last band that had the mouse cursor over it */
203     INT      ihitoffset;  /* offset of hotspot from gripper.left */
204     POINT    origin;      /* left/upper corner of client */
205     INT      ichevronhotBand; /* last band that had a hot chevron */
206     INT      iGrabbedBand;/* band number of band whose gripper was grabbed */
207
208     REBAR_BAND *bands;      /* pointer to the array of rebar bands */
209 } REBAR_INFO;
210
211 /* fStatus flags */
212 #define BEGIN_DRAG_ISSUED   0x00000001
213 #define AUTO_RESIZE         0x00000002
214 #define RESIZE_ANYHOW       0x00000004
215 #define NTF_HGHTCHG         0x00000008
216 #define BAND_NEEDS_LAYOUT   0x00000010
217 #define BAND_NEEDS_REDRAW   0x00000020
218 #define CREATE_RUNNING      0x00000040
219
220 /* ----   REBAR layout constants. Mostly determined by        ---- */
221 /* ----   experiment on WIN 98.                               ---- */
222
223 /* Width (or height) of separators between bands (either horz. or  */
224 /* vert.). True only if RBS_BANDBORDERS is set                     */
225 #define SEP_WIDTH_SIZE  2
226 #define SEP_WIDTH       ((infoPtr->dwStyle & RBS_BANDBORDERS) ? SEP_WIDTH_SIZE : 0)
227
228 /* Blank (background color) space between Gripper (if present)     */
229 /* and next item (image, text, or window). Always present          */
230 #define REBAR_ALWAYS_SPACE  4
231
232 /* Blank (background color) space after Image (if present).        */
233 #define REBAR_POST_IMAGE  2
234
235 /* Blank (background color) space after Text (if present).         */
236 #define REBAR_POST_TEXT  4
237
238 /* Height of vertical gripper in a CCS_VERT rebar.                 */
239 #define GRIPPER_HEIGHT  16
240
241 /* Blank (background color) space before Gripper (if present).     */
242 #define REBAR_PRE_GRIPPER   2
243
244 /* Width (of normal vertical gripper) or height (of horz. gripper) */
245 /* if present.                                                     */
246 #define GRIPPER_WIDTH  3
247
248 /* Width of the chevron button if present */
249 #define CHEVRON_WIDTH  10
250
251 /* Height of divider for Rebar if not disabled (CCS_NODIVIDER)     */
252 /* either top or bottom                                            */
253 #define REBAR_DIVIDER  2
254
255 /* minimium vertical height of a normal bar                        */
256 /*   or minimum width of a CCS_VERT bar - from experiment on Win2k */
257 #define REBAR_MINSIZE  23
258
259 /* This is the increment that is used over the band height         */
260 #define REBARSPACE(a)     ((a->fStyle & RBBS_CHILDEDGE) ? 2*REBAR_DIVIDER : 0)
261
262 /* ----   End of REBAR layout constants.                      ---- */
263
264 #define RB_GETBANDINFO_OLD (WM_USER+5) /* obsoleted after IE3, but we have to support it anyway */
265
266 /*  The following 6 defines return the proper rcBand element       */
267 /*  depending on whether CCS_VERT was set.                         */
268 #define rcBlt(b) ((infoPtr->dwStyle & CCS_VERT) ? b->rcBand.top : b->rcBand.left)
269 #define rcBrb(b) ((infoPtr->dwStyle & CCS_VERT) ? b->rcBand.bottom : b->rcBand.right)
270 #define rcBw(b)  ((infoPtr->dwStyle & CCS_VERT) ? (b->rcBand.bottom - b->rcBand.top) : \
271                   (b->rcBand.right - b->rcBand.left))
272 #define ircBlt(b) ((infoPtr->dwStyle & CCS_VERT) ? b->rcBand.left : b->rcBand.top)
273 #define ircBrb(b) ((infoPtr->dwStyle & CCS_VERT) ? b->rcBand.right : b->rcBand.bottom)
274 #define ircBw(b)  ((infoPtr->dwStyle & CCS_VERT) ? (b->rcBand.right - b->rcBand.left) : \
275                   (b->rcBand.bottom - b->rcBand.top))
276
277 /*  The following define determines if a given band is hidden      */
278 #define HIDDENBAND(a)  (((a)->fStyle & RBBS_HIDDEN) ||   \
279                         ((infoPtr->dwStyle & CCS_VERT) &&         \
280                          ((a)->fStyle & RBBS_NOVERT)))
281
282 /*  The following defines adjust the right or left end of a rectangle */
283 #define READJ(b,i) do { if(infoPtr->dwStyle & CCS_VERT) b->rcBand.bottom+=(i); \
284                     else b->rcBand.right += (i); } while(0)
285 #define LEADJ(b,i) do { if(infoPtr->dwStyle & CCS_VERT) b->rcBand.top+=(i); \
286                     else b->rcBand.left += (i); } while(0)
287
288
289 #define REBAR_GetInfoPtr(wndPtr) ((REBAR_INFO *)GetWindowLongPtrW (hwnd, 0))
290
291
292 /* "constant values" retrieved when DLL was initialized    */
293 /* FIXME we do this when the classes are registered.       */
294 static UINT mindragx = 0;
295 static UINT mindragy = 0;
296
297 static const char *band_stylename[] = {
298     "RBBS_BREAK",              /* 0001 */
299     "RBBS_FIXEDSIZE",          /* 0002 */
300     "RBBS_CHILDEDGE",          /* 0004 */
301     "RBBS_HIDDEN",             /* 0008 */
302     "RBBS_NOVERT",             /* 0010 */
303     "RBBS_FIXEDBMP",           /* 0020 */
304     "RBBS_VARIABLEHEIGHT",     /* 0040 */
305     "RBBS_GRIPPERALWAYS",      /* 0080 */
306     "RBBS_NOGRIPPER",          /* 0100 */
307     NULL };
308
309 static const char *band_maskname[] = {
310     "RBBIM_STYLE",         /*    0x00000001 */
311     "RBBIM_COLORS",        /*    0x00000002 */
312     "RBBIM_TEXT",          /*    0x00000004 */
313     "RBBIM_IMAGE",         /*    0x00000008 */
314     "RBBIM_CHILD",         /*    0x00000010 */
315     "RBBIM_CHILDSIZE",     /*    0x00000020 */
316     "RBBIM_SIZE",          /*    0x00000040 */
317     "RBBIM_BACKGROUND",    /*    0x00000080 */
318     "RBBIM_ID",            /*    0x00000100 */
319     "RBBIM_IDEALSIZE",     /*    0x00000200 */
320     "RBBIM_LPARAM",        /*    0x00000400 */
321     "RBBIM_HEADERSIZE",    /*    0x00000800 */
322     NULL };
323
324
325 static CHAR line[200];
326
327 static const WCHAR themeClass[] = { 'R','e','b','a','r',0 };
328
329 static CHAR *
330 REBAR_FmtStyle( UINT style)
331 {
332     INT i = 0;
333
334     *line = 0;
335     while (band_stylename[i]) {
336         if (style & (1<<i)) {
337             if (*line != 0) strcat(line, " | ");
338             strcat(line, band_stylename[i]);
339         }
340         i++;
341     }
342     return line;
343 }
344
345
346 static CHAR *
347 REBAR_FmtMask( UINT mask)
348 {
349     INT i = 0;
350
351     *line = 0;
352     while (band_maskname[i]) {
353         if (mask & (1<<i)) {
354             if (*line != 0) strcat(line, " | ");
355             strcat(line, band_maskname[i]);
356         }
357         i++;
358     }
359     return line;
360 }
361
362
363 static VOID
364 REBAR_DumpBandInfo( LPREBARBANDINFOA pB)
365 {
366     if( !TRACE_ON(rebar) ) return;
367     TRACE("band info: ");
368     if (pB->fMask & RBBIM_ID)
369         TRACE("ID=%u, ", pB->wID);
370     TRACE("size=%u, child=%p", pB->cbSize, pB->hwndChild);
371     if (pB->fMask & RBBIM_COLORS)
372         TRACE(", clrF=0x%06lx, clrB=0x%06lx", pB->clrFore, pB->clrBack);
373     TRACE("\n");
374
375     TRACE("band info: mask=0x%08x (%s)\n", pB->fMask, REBAR_FmtMask(pB->fMask));
376     if (pB->fMask & RBBIM_STYLE)
377         TRACE("band info: style=0x%08x (%s)\n", pB->fStyle, REBAR_FmtStyle(pB->fStyle));
378     if (pB->fMask & (RBBIM_SIZE | RBBIM_IDEALSIZE | RBBIM_HEADERSIZE | RBBIM_LPARAM )) {
379         TRACE("band info:");
380         if (pB->fMask & RBBIM_SIZE)
381             TRACE(" cx=%u", pB->cx);
382         if (pB->fMask & RBBIM_IDEALSIZE)
383             TRACE(" xIdeal=%u", pB->cxIdeal);
384         if (pB->fMask & RBBIM_HEADERSIZE)
385             TRACE(" xHeader=%u", pB->cxHeader);
386         if (pB->fMask & RBBIM_LPARAM)
387             TRACE(" lParam=0x%08lx", pB->lParam);
388         TRACE("\n");
389     }
390     if (pB->fMask & RBBIM_CHILDSIZE)
391         TRACE("band info: xMin=%u, yMin=%u, yChild=%u, yMax=%u, yIntgl=%u\n",
392               pB->cxMinChild,
393               pB->cyMinChild, pB->cyChild, pB->cyMaxChild, pB->cyIntegral);
394 }
395
396 static VOID
397 REBAR_DumpBand (REBAR_INFO *iP)
398 {
399     REBAR_BAND *pB;
400     UINT i;
401
402     if(! TRACE_ON(rebar) ) return;
403
404     TRACE("hwnd=%p: color=%08lx/%08lx, bands=%u, rows=%u, cSize=%ld,%ld\n",
405           iP->hwndSelf, iP->clrText, iP->clrBk, iP->uNumBands, iP->uNumRows,
406           iP->calcSize.cx, iP->calcSize.cy);
407     TRACE("hwnd=%p: flags=%08x, dragStart=%ld,%ld, dragNow=%ld,%ld, iGrabbedBand=%d\n",
408           iP->hwndSelf, iP->fStatus, iP->dragStart.x, iP->dragStart.y,
409           iP->dragNow.x, iP->dragNow.y,
410           iP->iGrabbedBand);
411     TRACE("hwnd=%p: style=%08lx, I'm Unicode=%s, notify in Unicode=%s, redraw=%s\n",
412           iP->hwndSelf, iP->dwStyle, (iP->bUnicode)?"TRUE":"FALSE",
413           (iP->NtfUnicode)?"TRUE":"FALSE", (iP->DoRedraw)?"TRUE":"FALSE");
414     for (i = 0; i < iP->uNumBands; i++) {
415         pB = &iP->bands[i];
416         TRACE("band # %u:", i);
417         if (pB->fMask & RBBIM_ID)
418             TRACE(" ID=%u", pB->wID);
419         if (pB->fMask & RBBIM_CHILD)
420             TRACE(" child=%p", pB->hwndChild);
421         if (pB->fMask & RBBIM_COLORS)
422             TRACE(" clrF=0x%06lx clrB=0x%06lx", pB->clrFore, pB->clrBack);
423         TRACE("\n");
424         TRACE("band # %u: mask=0x%08x (%s)\n", i, pB->fMask, REBAR_FmtMask(pB->fMask));
425         if (pB->fMask & RBBIM_STYLE)
426             TRACE("band # %u: style=0x%08x (%s)\n",
427                   i, pB->fStyle, REBAR_FmtStyle(pB->fStyle));
428         TRACE("band # %u: uMinH=%u xHeader=%u",
429               i, pB->uMinHeight, pB->cxHeader);
430         if (pB->fMask & (RBBIM_SIZE | RBBIM_IDEALSIZE | RBBIM_LPARAM )) {
431             if (pB->fMask & RBBIM_SIZE)
432                 TRACE(" cx=%u", pB->cx);
433             if (pB->fMask & RBBIM_IDEALSIZE)
434                 TRACE(" xIdeal=%u", pB->cxIdeal);
435             if (pB->fMask & RBBIM_LPARAM)
436                 TRACE(" lParam=0x%08lx", pB->lParam);
437         }
438         TRACE("\n");
439         if (RBBIM_CHILDSIZE)
440             TRACE("band # %u: xMin=%u, yMin=%u, yChild=%u, yMax=%u, yIntgl=%u\n",
441                   i, pB->cxMinChild, pB->cyMinChild, pB->cyChild, pB->cyMaxChild, pB->cyIntegral);
442         if (pB->fMask & RBBIM_TEXT)
443             TRACE("band # %u: text=%s\n",
444                   i, (pB->lpText) ? debugstr_w(pB->lpText) : "(null)");
445         TRACE("band # %u: lcx=%u, ccx=%u, hcx=%u, lcy=%u, ccy=%u, hcy=%u, offChild=%ld,%ld\n",
446               i, pB->lcx, pB->ccx, pB->hcx, pB->lcy, pB->ccy, pB->hcy, pB->offChild.cx, pB->offChild.cy);
447         TRACE("band # %u: fStatus=%08x, fDraw=%08x, Band=(%ld,%ld)-(%ld,%ld), Grip=(%ld,%ld)-(%ld,%ld)\n",
448               i, pB->fStatus, pB->fDraw,
449               pB->rcBand.left, pB->rcBand.top, pB->rcBand.right, pB->rcBand.bottom,
450               pB->rcGripper.left, pB->rcGripper.top, pB->rcGripper.right, pB->rcGripper.bottom);
451         TRACE("band # %u: Img=(%ld,%ld)-(%ld,%ld), Txt=(%ld,%ld)-(%ld,%ld), Child=(%ld,%ld)-(%ld,%ld)\n",
452               i,
453               pB->rcCapImage.left, pB->rcCapImage.top, pB->rcCapImage.right, pB->rcCapImage.bottom,
454               pB->rcCapText.left, pB->rcCapText.top, pB->rcCapText.right, pB->rcCapText.bottom,
455               pB->rcChild.left, pB->rcChild.top, pB->rcChild.right, pB->rcChild.bottom);
456     }
457
458 }
459
460 static void
461 REBAR_DrawChevron (HDC hdc, INT left, INT top, INT colorRef)
462 {
463     INT x, y;
464     HPEN hPen, hOldPen;
465
466     if (!(hPen = CreatePen( PS_SOLID, 1, GetSysColor( colorRef )))) return;
467     hOldPen = SelectObject ( hdc, hPen );
468     x = left + 2;
469     y = top;
470     MoveToEx (hdc, x, y, NULL);
471     LineTo (hdc, x+5, y++); x++;
472     MoveToEx (hdc, x, y, NULL);
473     LineTo (hdc, x+3, y++); x++;
474     MoveToEx (hdc, x, y, NULL);
475     LineTo (hdc, x+1, y++);
476     SelectObject( hdc, hOldPen );
477     DeleteObject( hPen );
478 }
479
480 static HWND
481 REBAR_GetNotifyParent (REBAR_INFO *infoPtr)
482 {
483     HWND parent, owner;
484
485     parent = infoPtr->hwndNotify;
486     if (!parent) {
487         parent = GetParent (infoPtr->hwndSelf);
488         owner = GetWindow (infoPtr->hwndSelf, GW_OWNER);
489         if (owner) parent = owner;
490     }
491     return parent;
492 }
493
494
495 static INT
496 REBAR_Notify (NMHDR *nmhdr, REBAR_INFO *infoPtr, UINT code)
497 {
498     HWND parent;
499
500     parent = REBAR_GetNotifyParent (infoPtr);
501     nmhdr->idFrom = GetDlgCtrlID (infoPtr->hwndSelf);
502     nmhdr->hwndFrom = infoPtr->hwndSelf;
503     nmhdr->code = code;
504
505     TRACE("window %p, code=%08x, %s\n", parent, code,
506           (infoPtr->NtfUnicode) ? "via Unicode" : "via ANSI");
507
508     if (infoPtr->NtfUnicode)
509         return SendMessageW (parent, WM_NOTIFY, (WPARAM) nmhdr->idFrom,
510                              (LPARAM)nmhdr);
511     else
512         return SendMessageA (parent, WM_NOTIFY, (WPARAM) nmhdr->idFrom,
513                              (LPARAM)nmhdr);
514 }
515
516 static INT
517 REBAR_Notify_NMREBAR (REBAR_INFO *infoPtr, UINT uBand, UINT code)
518 {
519     NMREBAR notify_rebar;
520     REBAR_BAND *lpBand;
521
522     notify_rebar.dwMask = 0;
523     if (uBand!=-1) {
524         lpBand = &infoPtr->bands[uBand];
525         if (lpBand->fMask & RBBIM_ID) {
526             notify_rebar.dwMask |= RBNM_ID;
527             notify_rebar.wID = lpBand->wID;
528         }
529         if (lpBand->fMask & RBBIM_LPARAM) {
530             notify_rebar.dwMask |= RBNM_LPARAM;
531             notify_rebar.lParam = lpBand->lParam;
532         }
533         if (lpBand->fMask & RBBIM_STYLE) {
534             notify_rebar.dwMask |= RBNM_STYLE;
535             notify_rebar.fStyle = lpBand->fStyle;
536         }
537     }
538     notify_rebar.uBand = uBand;
539     return REBAR_Notify ((NMHDR *)&notify_rebar, infoPtr, code);
540 }
541
542 static VOID
543 REBAR_DrawBand (HDC hdc, REBAR_INFO *infoPtr, REBAR_BAND *lpBand)
544 {
545     HFONT hOldFont = 0;
546     INT oldBkMode = 0;
547     NMCUSTOMDRAW nmcd;
548     HTHEME theme = GetWindowTheme (infoPtr->hwndSelf);
549
550     if (lpBand->fDraw & DRAW_TEXT) {
551         hOldFont = SelectObject (hdc, infoPtr->hFont);
552         oldBkMode = SetBkMode (hdc, TRANSPARENT);
553     }
554
555     /* should test for CDRF_NOTIFYITEMDRAW here */
556     nmcd.dwDrawStage = CDDS_ITEMPREPAINT;
557     nmcd.hdc = hdc;
558     nmcd.rc = lpBand->rcBand;
559     nmcd.rc.right = lpBand->rcCapText.right;
560     nmcd.rc.bottom = lpBand->rcCapText.bottom;
561     nmcd.dwItemSpec = lpBand->wID;
562     nmcd.uItemState = 0;
563     nmcd.lItemlParam = lpBand->lParam;
564     lpBand->uCDret = REBAR_Notify ((NMHDR *)&nmcd, infoPtr, NM_CUSTOMDRAW);
565     if (lpBand->uCDret == CDRF_SKIPDEFAULT) {
566         if (oldBkMode != TRANSPARENT)
567             SetBkMode (hdc, oldBkMode);
568         SelectObject (hdc, hOldFont);
569         return;
570     }
571
572     /* draw gripper */
573     if (lpBand->fDraw & DRAW_GRIPPER)
574     {
575         if (theme)
576         {
577             RECT rcGripper = lpBand->rcGripper;
578             int partId = (infoPtr->dwStyle & CCS_VERT) ? RP_GRIPPERVERT : RP_GRIPPER;
579             GetThemeBackgroundExtent (theme, hdc, partId, 0, &rcGripper, &rcGripper);
580             OffsetRect (&rcGripper, lpBand->rcGripper.left - rcGripper.left,
581                 lpBand->rcGripper.top - rcGripper.top);
582             DrawThemeBackground (theme, hdc, partId, 0, &rcGripper, NULL);
583         }
584         else
585             DrawEdge (hdc, &lpBand->rcGripper, BDR_RAISEDINNER, BF_RECT | BF_MIDDLE);
586     }
587
588     /* draw caption image */
589     if (lpBand->fDraw & DRAW_IMAGE) {
590         POINT pt;
591
592         /* center image */
593         pt.y = (lpBand->rcCapImage.bottom + lpBand->rcCapImage.top - infoPtr->imageSize.cy)/2;
594         pt.x = (lpBand->rcCapImage.right + lpBand->rcCapImage.left - infoPtr->imageSize.cx)/2;
595
596         ImageList_Draw (infoPtr->himl, lpBand->iImage, hdc,
597                         pt.x, pt.y,
598                         ILD_TRANSPARENT);
599     }
600
601     /* draw caption text */
602     if (lpBand->fDraw & DRAW_TEXT) {
603         /* need to handle CDRF_NEWFONT here */
604         INT oldBkMode = SetBkMode (hdc, TRANSPARENT);
605         COLORREF oldcolor = CLR_NONE;
606         COLORREF new;
607         if (lpBand->clrFore != CLR_NONE) {
608             new = (lpBand->clrFore == CLR_DEFAULT) ? infoPtr->clrBtnText :
609                     lpBand->clrFore;
610             oldcolor = SetTextColor (hdc, new);
611         }
612         DrawTextW (hdc, lpBand->lpText, -1, &lpBand->rcCapText,
613                    DT_CENTER | DT_VCENTER | DT_SINGLELINE);
614         if (oldBkMode != TRANSPARENT)
615             SetBkMode (hdc, oldBkMode);
616         if (lpBand->clrFore != CLR_NONE)
617             SetTextColor (hdc, oldcolor);
618         SelectObject (hdc, hOldFont);
619     }
620
621     if (!IsRectEmpty(&lpBand->rcChevron))
622     {
623         if (theme)
624         {
625             int stateId; 
626             if (lpBand->fDraw & DRAW_CHEVRONPUSHED)
627                 stateId = CHEVS_PRESSED;
628             else if (lpBand->fDraw & DRAW_CHEVRONHOT)
629                 stateId = CHEVS_HOT;
630             else
631                 stateId = CHEVS_NORMAL;
632             DrawThemeBackground (theme, hdc, RP_CHEVRON, stateId, &lpBand->rcChevron, NULL);
633         }
634         else
635         {
636             if (lpBand->fDraw & DRAW_CHEVRONPUSHED)
637             {
638                 DrawEdge(hdc, &lpBand->rcChevron, BDR_SUNKENOUTER, BF_RECT | BF_MIDDLE);
639                 REBAR_DrawChevron(hdc, lpBand->rcChevron.left+1, lpBand->rcChevron.top + 11, COLOR_WINDOWFRAME);
640             }
641             else if (lpBand->fDraw & DRAW_CHEVRONHOT)
642             {
643                 DrawEdge(hdc, &lpBand->rcChevron, BDR_RAISEDINNER, BF_RECT | BF_MIDDLE);
644                 REBAR_DrawChevron(hdc, lpBand->rcChevron.left, lpBand->rcChevron.top + 10, COLOR_WINDOWFRAME);
645             }
646             else
647                 REBAR_DrawChevron(hdc, lpBand->rcChevron.left, lpBand->rcChevron.top + 10, COLOR_WINDOWFRAME);
648         }
649     }
650
651     if (lpBand->uCDret == (CDRF_NOTIFYPOSTPAINT | CDRF_NOTIFYITEMDRAW)) {
652         nmcd.dwDrawStage = CDDS_ITEMPOSTPAINT;
653         nmcd.hdc = hdc;
654         nmcd.rc = lpBand->rcBand;
655         nmcd.rc.right = lpBand->rcCapText.right;
656         nmcd.rc.bottom = lpBand->rcCapText.bottom;
657         nmcd.dwItemSpec = lpBand->wID;
658         nmcd.uItemState = 0;
659         nmcd.lItemlParam = lpBand->lParam;
660         lpBand->uCDret = REBAR_Notify ((NMHDR *)&nmcd, infoPtr, NM_CUSTOMDRAW);
661     }
662 }
663
664
665 static VOID
666 REBAR_Refresh (REBAR_INFO *infoPtr, HDC hdc)
667 {
668     REBAR_BAND *lpBand;
669     UINT i;
670
671     if (!infoPtr->DoRedraw) return;
672
673     for (i = 0; i < infoPtr->uNumBands; i++) {
674         lpBand = &infoPtr->bands[i];
675
676         if (HIDDENBAND(lpBand)) continue;
677
678         /* now draw the band */
679         TRACE("[%p] drawing band %i, flags=%08x\n",
680               infoPtr->hwndSelf, i, lpBand->fDraw);
681         REBAR_DrawBand (hdc, infoPtr, lpBand);
682
683     }
684 }
685
686
687 static void
688 REBAR_FixVert (REBAR_INFO *infoPtr, UINT rowstart, UINT rowend,
689                    INT mcy)
690      /* Function:                                                    */
691      /*   Cycle through bands in row and fix height of each band.    */
692      /*   Also determine whether each band has changed.              */
693      /* On entry:                                                    */
694      /*   all bands at desired size.                                 */
695      /*   start and end bands are *not* hidden                       */
696 {
697     REBAR_BAND *lpBand;
698     INT i;
699
700     for (i = (INT)rowstart; i<=(INT)rowend; i++) {
701         lpBand = &infoPtr->bands[i];
702         if (HIDDENBAND(lpBand)) continue;
703
704         /* adjust height of bands in row to "mcy" value */
705         if (infoPtr->dwStyle & CCS_VERT) {
706             if (lpBand->rcBand.right != lpBand->rcBand.left + mcy)
707                 lpBand->rcBand.right = lpBand->rcBand.left + mcy;
708         }
709         else {
710             if (lpBand->rcBand.bottom != lpBand->rcBand.top + mcy)
711                 lpBand->rcBand.bottom = lpBand->rcBand.top + mcy;
712
713         }
714
715         /* mark whether we need to invalidate this band and trace */
716         if ((lpBand->rcoldBand.left !=lpBand->rcBand.left) ||
717             (lpBand->rcoldBand.top !=lpBand->rcBand.top) ||
718             (lpBand->rcoldBand.right !=lpBand->rcBand.right) ||
719             (lpBand->rcoldBand.bottom !=lpBand->rcBand.bottom)) {
720             lpBand->fDraw |= NTF_INVALIDATE;
721             TRACE("band %d row=%d: changed to (%ld,%ld)-(%ld,%ld) from (%ld,%ld)-(%ld,%ld)\n",
722                   i, lpBand->iRow,
723                   lpBand->rcBand.left, lpBand->rcBand.top,
724                   lpBand->rcBand.right, lpBand->rcBand.bottom,
725                   lpBand->rcoldBand.left, lpBand->rcoldBand.top,
726                   lpBand->rcoldBand.right, lpBand->rcoldBand.bottom);
727         }
728         else
729             TRACE("band %d row=%d: unchanged (%ld,%ld)-(%ld,%ld)\n",
730                   i, lpBand->iRow,
731                   lpBand->rcBand.left, lpBand->rcBand.top,
732                   lpBand->rcBand.right, lpBand->rcBand.bottom);
733     }
734 }
735
736
737 static void
738 REBAR_AdjustBands (REBAR_INFO *infoPtr, UINT rowstart, UINT rowend,
739                    INT maxx, INT mcy)
740      /* Function: This routine distributes the extra space in a row. */
741      /*  See algorithm below.                                        */
742      /* On entry:                                                    */
743      /*   all bands @ ->cxHeader size                                */
744      /*   start and end bands are *not* hidden                       */
745 {
746     REBAR_BAND *lpBand;
747     UINT xsep, extra, curwidth, fudge;
748     INT x, i, last_adjusted;
749
750     TRACE("start=%u, end=%u, max x=%d, max y=%d\n",
751           rowstart, rowend, maxx, mcy);
752
753     /* *******************  Phase 1  ************************ */
754     /* Alg:                                                   */
755     /*  For each visible band with valid child                */
756     /*      a. inflate band till either all extra space used  */
757     /*         or band's ->ccx reached.                       */
758     /*  If any band modified, add any space left to last band */
759     /*  adjusted.                                             */
760     /*                                                        */
761     /* ****************************************************** */
762     lpBand = &infoPtr->bands[rowend];
763     extra = maxx - rcBrb(lpBand);
764     x = 0;
765     last_adjusted = -1;
766     for (i=(INT)rowstart; i<=(INT)rowend; i++) {
767         lpBand = &infoPtr->bands[i];
768         if (HIDDENBAND(lpBand)) continue;
769         xsep = (x == 0) ? 0 : SEP_WIDTH;
770         curwidth = rcBw(lpBand);
771
772         /* set new left/top point */
773         if (infoPtr->dwStyle & CCS_VERT)
774             lpBand->rcBand.top = x + xsep;
775         else
776             lpBand->rcBand.left = x + xsep;
777
778         /* compute new width */
779         if ((lpBand->hwndChild && extra) && !(lpBand->fStyle & RBBS_FIXEDSIZE)) {
780             /* set to the "current" band size less the header */
781             fudge = lpBand->ccx;
782             last_adjusted = i;
783             if ((lpBand->fMask & RBBIM_SIZE) && (lpBand->cx > 0) &&
784                 (fudge > curwidth)) {
785                 TRACE("adjusting band %d by %d, fudge=%d, curwidth=%d, extra=%d\n",
786                       i, fudge-curwidth, fudge, curwidth, extra);
787                 if ((fudge - curwidth) > extra)
788                     fudge = curwidth + extra;
789                 extra -= (fudge - curwidth);
790                 curwidth = fudge;
791             }
792             else {
793                 TRACE("adjusting band %d by %d, fudge=%d, curwidth=%d\n",
794                       i, extra, fudge, curwidth);
795                 curwidth += extra;
796                 extra = 0;
797             }
798         }
799
800         /* set new right/bottom point */
801         if (infoPtr->dwStyle & CCS_VERT)
802             lpBand->rcBand.bottom = lpBand->rcBand.top + curwidth;
803         else
804             lpBand->rcBand.right = lpBand->rcBand.left + curwidth;
805         TRACE("Phase 1 band %d, (%ld,%ld)-(%ld,%ld), orig x=%d, xsep=%d\n",
806               i, lpBand->rcBand.left, lpBand->rcBand.top,
807               lpBand->rcBand.right, lpBand->rcBand.bottom, x, xsep);
808         x = rcBrb(lpBand);
809     }
810     if ((x >= maxx) || (last_adjusted != -1)) {
811         if (x > maxx) {
812             ERR("Phase 1 failed, x=%d, maxx=%d, start=%u, end=%u\n",
813                 x, maxx,  rowstart, rowend);
814         }
815         /* done, so spread extra space */
816         if (x < maxx) {
817             fudge = maxx - x;
818             TRACE("Need to spread %d on last adjusted band %d\n",
819                 fudge, last_adjusted);
820             for (i=(INT)last_adjusted; i<=(INT)rowend; i++) {
821                 lpBand = &infoPtr->bands[i];
822                 if (HIDDENBAND(lpBand)) continue;
823
824                 /* set right/bottom point */
825                 if (i != last_adjusted) {
826                     if (infoPtr->dwStyle & CCS_VERT)
827                         lpBand->rcBand.top += fudge;
828                     else
829                         lpBand->rcBand.left += fudge;
830                 }
831
832                 /* set left/bottom point */
833                 if (infoPtr->dwStyle & CCS_VERT)
834                     lpBand->rcBand.bottom += fudge;
835                 else
836                     lpBand->rcBand.right += fudge;
837             }
838         }
839         TRACE("Phase 1 succeeded, used x=%d\n", x);
840         REBAR_FixVert (infoPtr, rowstart, rowend, mcy);
841         return;
842     }
843
844     /* *******************  Phase 2  ************************ */
845     /* Alg:                                                   */
846     /*  Find first visible band, put all                      */
847     /*    extra space there.                                  */
848     /*                                                        */
849     /* ****************************************************** */
850
851     x = 0;
852     for (i=(INT)rowstart; i<=(INT)rowend; i++) {
853         lpBand = &infoPtr->bands[i];
854         if (HIDDENBAND(lpBand)) continue;
855         xsep = (x == 0) ? 0 : SEP_WIDTH;
856         curwidth = rcBw(lpBand);
857
858         /* set new left/top point */
859         if (infoPtr->dwStyle & CCS_VERT)
860             lpBand->rcBand.top = x + xsep;
861         else
862             lpBand->rcBand.left = x + xsep;
863
864         /* compute new width */
865         if (extra) {
866             curwidth += extra;
867             extra = 0;
868         }
869
870         /* set new right/bottom point */
871         if (infoPtr->dwStyle & CCS_VERT)
872             lpBand->rcBand.bottom = lpBand->rcBand.top + curwidth;
873         else
874             lpBand->rcBand.right = lpBand->rcBand.left + curwidth;
875         TRACE("Phase 2 band %d, (%ld,%ld)-(%ld,%ld), orig x=%d, xsep=%d\n",
876               i, lpBand->rcBand.left, lpBand->rcBand.top,
877               lpBand->rcBand.right, lpBand->rcBand.bottom, x, xsep);
878         x = rcBrb(lpBand);
879     }
880     if (x >= maxx) {
881         if (x > maxx) {
882             ERR("Phase 2 failed, x=%d, maxx=%d, start=%u, end=%u\n",
883                 x, maxx,  rowstart, rowend);
884         }
885         /* done, so spread extra space */
886         TRACE("Phase 2 succeeded, used x=%d\n", x);
887         REBAR_FixVert (infoPtr, rowstart, rowend, mcy);
888         return;
889     }
890
891     /* *******************  Phase 3  ************************ */
892     /* at this point everything is back to ->cxHeader values  */
893     /* and should not have gotten here.                       */
894     /* ****************************************************** */
895
896     lpBand = &infoPtr->bands[rowstart];
897     ERR("Serious problem adjusting row %d, start band %d, end band %d\n",
898         lpBand->iRow, rowstart, rowend);
899     REBAR_DumpBand (infoPtr);
900     return;
901 }
902
903
904 static void
905 REBAR_CalcHorzBand (REBAR_INFO *infoPtr, UINT rstart, UINT rend, BOOL notify)
906      /* Function: this routine initializes all the rectangles in */
907      /*  each band in a row to fit in the adjusted rcBand rect.  */
908      /* *** Supports only Horizontal bars. ***                   */
909 {
910     REBAR_BAND *lpBand;
911     UINT i, xoff, yoff;
912     HWND parenthwnd;
913     RECT oldChild, work;
914
915     /* MS seems to use GetDlgCtrlID() for above GetWindowLong call */
916     parenthwnd = GetParent (infoPtr->hwndSelf);
917
918     for(i=rstart; i<rend; i++){
919       lpBand = &infoPtr->bands[i];
920       if (HIDDENBAND(lpBand)) {
921           SetRect (&lpBand->rcChild,
922                    lpBand->rcBand.right, lpBand->rcBand.top,
923                    lpBand->rcBand.right, lpBand->rcBand.bottom);
924           continue;
925       }
926
927       oldChild = lpBand->rcChild;
928
929       /* set initial gripper rectangle */
930       SetRect (&lpBand->rcGripper, lpBand->rcBand.left, lpBand->rcBand.top,
931                lpBand->rcBand.left, lpBand->rcBand.bottom);
932
933       /* calculate gripper rectangle */
934       if ( lpBand->fStatus & HAS_GRIPPER) {
935           lpBand->fDraw |= DRAW_GRIPPER;
936           lpBand->rcGripper.left   += REBAR_PRE_GRIPPER;
937           lpBand->rcGripper.right  = lpBand->rcGripper.left + GRIPPER_WIDTH;
938           lpBand->rcGripper.top    += 2;
939           lpBand->rcGripper.bottom -= 2;
940
941           SetRect (&lpBand->rcCapImage,
942                    lpBand->rcGripper.right+REBAR_ALWAYS_SPACE, lpBand->rcBand.top,
943                    lpBand->rcGripper.right+REBAR_ALWAYS_SPACE, lpBand->rcBand.bottom);
944       }
945       else {  /* no gripper will be drawn */
946           xoff = 0;
947           if (lpBand->fStatus & (HAS_IMAGE | HAS_TEXT))
948               /* if no gripper but either image or text, then leave space */
949               xoff = REBAR_ALWAYS_SPACE;
950           SetRect (&lpBand->rcCapImage,
951                    lpBand->rcBand.left+xoff, lpBand->rcBand.top,
952                    lpBand->rcBand.left+xoff, lpBand->rcBand.bottom);
953       }
954
955       /* image is visible */
956       if (lpBand->fStatus & HAS_IMAGE) {
957           lpBand->fDraw |= DRAW_IMAGE;
958           lpBand->rcCapImage.right  += infoPtr->imageSize.cx;
959           lpBand->rcCapImage.bottom = lpBand->rcCapImage.top + infoPtr->imageSize.cy;
960
961           /* set initial caption text rectangle */
962           SetRect (&lpBand->rcCapText,
963                    lpBand->rcCapImage.right+REBAR_POST_IMAGE, lpBand->rcBand.top+1,
964                    lpBand->rcBand.left+lpBand->cxHeader, lpBand->rcBand.bottom-1);
965           /* update band height
966           if (lpBand->uMinHeight < infoPtr->imageSize.cy + 2) {
967               lpBand->uMinHeight = infoPtr->imageSize.cy + 2;
968               lpBand->rcBand.bottom = lpBand->rcBand.top + lpBand->uMinHeight;
969           }  */
970       }
971       else {
972           /* set initial caption text rectangle */
973           SetRect (&lpBand->rcCapText, lpBand->rcCapImage.right, lpBand->rcBand.top+1,
974                    lpBand->rcBand.left+lpBand->cxHeader, lpBand->rcBand.bottom-1);
975       }
976
977       /* text is visible */
978       if ((lpBand->fStatus & HAS_TEXT) && !(lpBand->fStyle & RBBS_HIDETITLE)) {
979           lpBand->fDraw |= DRAW_TEXT;
980           lpBand->rcCapText.right = max(lpBand->rcCapText.left,
981                                         lpBand->rcCapText.right-REBAR_POST_TEXT);
982       }
983
984       /* set initial child window rectangle if there is a child */
985       if (lpBand->fMask & RBBIM_CHILD) {
986           xoff = lpBand->offChild.cx;
987           yoff = lpBand->offChild.cy;
988           SetRect (&lpBand->rcChild,
989                    lpBand->rcBand.left+lpBand->cxHeader, lpBand->rcBand.top+yoff,
990                    lpBand->rcBand.right-xoff, lpBand->rcBand.bottom-yoff);
991           if ((lpBand->fStyle & RBBS_USECHEVRON) && (lpBand->rcChild.right - lpBand->rcChild.left < lpBand->cxIdeal))
992           {
993               lpBand->rcChild.right -= CHEVRON_WIDTH;
994               SetRect(&lpBand->rcChevron, lpBand->rcChild.right,
995                       lpBand->rcChild.top, lpBand->rcChild.right + CHEVRON_WIDTH,
996                       lpBand->rcChild.bottom);
997           }
998       }
999       else {
1000           SetRect (&lpBand->rcChild,
1001                    lpBand->rcBand.left+lpBand->cxHeader, lpBand->rcBand.top,
1002                    lpBand->rcBand.right, lpBand->rcBand.bottom);
1003       }
1004
1005       /* flag if notify required and invalidate rectangle */
1006       if (notify &&
1007           ((oldChild.right-oldChild.left != lpBand->rcChild.right-lpBand->rcChild.left) ||
1008            (oldChild.bottom-oldChild.top != lpBand->rcChild.bottom-lpBand->rcChild.top))) {
1009           TRACE("Child rectangle changed for band %u\n", i);
1010           TRACE("    from (%ld,%ld)-(%ld,%ld)  to (%ld,%ld)-(%ld,%ld)\n",
1011                 oldChild.left, oldChild.top,
1012                 oldChild.right, oldChild.bottom,
1013                 lpBand->rcChild.left, lpBand->rcChild.top,
1014                 lpBand->rcChild.right, lpBand->rcChild.bottom);
1015       }
1016       if (lpBand->fDraw & NTF_INVALIDATE) {
1017           TRACE("invalidating (%ld,%ld)-(%ld,%ld)\n",
1018                 lpBand->rcBand.left,
1019                 lpBand->rcBand.top,
1020                 lpBand->rcBand.right + ((lpBand->fDraw & DRAW_RIGHTSEP) ? SEP_WIDTH_SIZE : 0),
1021                 lpBand->rcBand.bottom + ((lpBand->fDraw & DRAW_BOTTOMSEP) ? SEP_WIDTH_SIZE : 0));
1022           lpBand->fDraw &= ~NTF_INVALIDATE;
1023           work = lpBand->rcBand;
1024           if (lpBand->fDraw & DRAW_RIGHTSEP) work.right += SEP_WIDTH_SIZE;
1025           if (lpBand->fDraw & DRAW_BOTTOMSEP) work.bottom += SEP_WIDTH_SIZE;
1026           InvalidateRect(infoPtr->hwndSelf, &work, TRUE);
1027       }
1028
1029     }
1030
1031 }
1032
1033
1034 static VOID
1035 REBAR_CalcVertBand (REBAR_INFO *infoPtr, UINT rstart, UINT rend, BOOL notify)
1036      /* Function: this routine initializes all the rectangles in */
1037      /*  each band in a row to fit in the adjusted rcBand rect.  */
1038      /* *** Supports only Vertical bars. ***                     */
1039 {
1040     REBAR_BAND *lpBand;
1041     UINT i, xoff, yoff;
1042     HWND parenthwnd;
1043     RECT oldChild, work;
1044
1045     /* MS seems to use GetDlgCtrlID() for above GetWindowLong call */
1046     parenthwnd = GetParent (infoPtr->hwndSelf);
1047
1048     for(i=rstart; i<rend; i++){
1049         lpBand = &infoPtr->bands[i];
1050         if (HIDDENBAND(lpBand)) continue;
1051         oldChild = lpBand->rcChild;
1052
1053         /* set initial gripper rectangle */
1054         SetRect (&lpBand->rcGripper, lpBand->rcBand.left, lpBand->rcBand.top,
1055                  lpBand->rcBand.right, lpBand->rcBand.top);
1056
1057         /* calculate gripper rectangle */
1058         if (lpBand->fStatus & HAS_GRIPPER) {
1059             lpBand->fDraw |= DRAW_GRIPPER;
1060
1061             if (infoPtr->dwStyle & RBS_VERTICALGRIPPER) {
1062                 /*  vertical gripper  */
1063                 lpBand->rcGripper.left   += 3;
1064                 lpBand->rcGripper.right  = lpBand->rcGripper.left + GRIPPER_WIDTH;
1065                 lpBand->rcGripper.top    += REBAR_PRE_GRIPPER;
1066                 lpBand->rcGripper.bottom = lpBand->rcGripper.top + GRIPPER_HEIGHT;
1067
1068                 /* initialize Caption image rectangle  */
1069                 SetRect (&lpBand->rcCapImage, lpBand->rcBand.left,
1070                          lpBand->rcGripper.bottom + REBAR_ALWAYS_SPACE,
1071                          lpBand->rcBand.right,
1072                          lpBand->rcGripper.bottom + REBAR_ALWAYS_SPACE);
1073             }
1074             else {
1075                 /*  horizontal gripper  */
1076                 lpBand->rcGripper.left   += 2;
1077                 lpBand->rcGripper.right  -= 2;
1078                 lpBand->rcGripper.top    += REBAR_PRE_GRIPPER;
1079                 lpBand->rcGripper.bottom  = lpBand->rcGripper.top + GRIPPER_WIDTH;
1080
1081                 /* initialize Caption image rectangle  */
1082                 SetRect (&lpBand->rcCapImage, lpBand->rcBand.left,
1083                          lpBand->rcGripper.bottom + REBAR_ALWAYS_SPACE,
1084                          lpBand->rcBand.right,
1085                          lpBand->rcGripper.bottom + REBAR_ALWAYS_SPACE);
1086             }
1087         }
1088         else {  /* no gripper will be drawn */
1089             xoff = 0;
1090             if (lpBand->fStatus & (HAS_IMAGE | HAS_TEXT))
1091                 /* if no gripper but either image or text, then leave space */
1092                 xoff = REBAR_ALWAYS_SPACE;
1093             /* initialize Caption image rectangle  */
1094             SetRect (&lpBand->rcCapImage,
1095                      lpBand->rcBand.left, lpBand->rcBand.top+xoff,
1096                      lpBand->rcBand.right, lpBand->rcBand.top+xoff);
1097         }
1098
1099         /* image is visible */
1100         if (lpBand->fStatus & HAS_IMAGE) {
1101             lpBand->fDraw |= DRAW_IMAGE;
1102
1103             lpBand->rcCapImage.right  = lpBand->rcCapImage.left + infoPtr->imageSize.cx;
1104             lpBand->rcCapImage.bottom += infoPtr->imageSize.cy;
1105
1106             /* set initial caption text rectangle */
1107             SetRect (&lpBand->rcCapText,
1108                      lpBand->rcBand.left, lpBand->rcCapImage.bottom+REBAR_POST_IMAGE,
1109                      lpBand->rcBand.right, lpBand->rcBand.top+lpBand->cxHeader);
1110             /* update band height *
1111                if (lpBand->uMinHeight < infoPtr->imageSize.cx + 2) {
1112                lpBand->uMinHeight = infoPtr->imageSize.cx + 2;
1113                lpBand->rcBand.right = lpBand->rcBand.left + lpBand->uMinHeight;
1114                } */
1115         }
1116         else {
1117             /* set initial caption text rectangle */
1118             SetRect (&lpBand->rcCapText,
1119                      lpBand->rcBand.left, lpBand->rcCapImage.bottom,
1120                      lpBand->rcBand.right, lpBand->rcBand.top+lpBand->cxHeader);
1121         }
1122
1123         /* text is visible */
1124         if ((lpBand->fStatus & HAS_TEXT) && !(lpBand->fStyle & RBBS_HIDETITLE)) {
1125             lpBand->fDraw |= DRAW_TEXT;
1126             lpBand->rcCapText.bottom = max(lpBand->rcCapText.top,
1127                                            lpBand->rcCapText.bottom);
1128         }
1129
1130         /* set initial child window rectangle if there is a child */
1131         if (lpBand->fMask & RBBIM_CHILD) {
1132             yoff = lpBand->offChild.cx;
1133             xoff = lpBand->offChild.cy;
1134             SetRect (&lpBand->rcChild,
1135                      lpBand->rcBand.left+xoff, lpBand->rcBand.top+lpBand->cxHeader,
1136                      lpBand->rcBand.right-xoff, lpBand->rcBand.bottom-yoff);
1137         }
1138         else {
1139             SetRect (&lpBand->rcChild,
1140                      lpBand->rcBand.left, lpBand->rcBand.top+lpBand->cxHeader,
1141                      lpBand->rcBand.right, lpBand->rcBand.bottom);
1142         }
1143
1144         /* flag if notify required and invalidate rectangle */
1145         if (notify &&
1146             ((oldChild.right-oldChild.left != lpBand->rcChild.right-lpBand->rcChild.left) ||
1147              (oldChild.bottom-oldChild.top != lpBand->rcChild.bottom-lpBand->rcChild.top))) {
1148             TRACE("Child rectangle changed for band %u\n", i);
1149             TRACE("    from (%ld,%ld)-(%ld,%ld)  to (%ld,%ld)-(%ld,%ld)\n",
1150                   oldChild.left, oldChild.top,
1151                   oldChild.right, oldChild.bottom,
1152                   lpBand->rcChild.left, lpBand->rcChild.top,
1153                   lpBand->rcChild.right, lpBand->rcChild.bottom);
1154         }
1155         if (lpBand->fDraw & NTF_INVALIDATE) {
1156             TRACE("invalidating (%ld,%ld)-(%ld,%ld)\n",
1157                   lpBand->rcBand.left,
1158                   lpBand->rcBand.top,
1159                   lpBand->rcBand.right + ((lpBand->fDraw & DRAW_BOTTOMSEP) ? SEP_WIDTH_SIZE : 0),
1160                   lpBand->rcBand.bottom + ((lpBand->fDraw & DRAW_RIGHTSEP) ? SEP_WIDTH_SIZE : 0));
1161             lpBand->fDraw &= ~NTF_INVALIDATE;
1162             work = lpBand->rcBand;
1163             if (lpBand->fDraw & DRAW_RIGHTSEP) work.bottom += SEP_WIDTH_SIZE;
1164             if (lpBand->fDraw & DRAW_BOTTOMSEP) work.right += SEP_WIDTH_SIZE;
1165             InvalidateRect(infoPtr->hwndSelf, &work, TRUE);
1166         }
1167
1168     }
1169 }
1170
1171
1172 static VOID
1173 REBAR_ForceResize (REBAR_INFO *infoPtr)
1174      /* Function: This changes the size of the REBAR window to that */
1175      /*  calculated by REBAR_Layout.                                */
1176 {
1177     RECT rc;
1178     INT x, y, width, height;
1179     INT xedge = GetSystemMetrics(SM_CXEDGE);
1180     INT yedge = GetSystemMetrics(SM_CYEDGE);
1181
1182     GetClientRect (infoPtr->hwndSelf, &rc);
1183
1184     TRACE( " old [%ld x %ld], new [%ld x %ld], client [%ld x %ld]\n",
1185            infoPtr->oldSize.cx, infoPtr->oldSize.cy,
1186            infoPtr->calcSize.cx, infoPtr->calcSize.cy,
1187            rc.right, rc.bottom);
1188
1189     /* If we need to shrink client, then skip size test */
1190     if ((infoPtr->calcSize.cy >= rc.bottom) &&
1191         (infoPtr->calcSize.cx >= rc.right)) {
1192
1193         /* if size did not change then skip process */
1194         if ((infoPtr->oldSize.cx == infoPtr->calcSize.cx) &&
1195             (infoPtr->oldSize.cy == infoPtr->calcSize.cy) &&
1196             !(infoPtr->fStatus & RESIZE_ANYHOW))
1197             {
1198                 TRACE("skipping reset\n");
1199                 return;
1200             }
1201     }
1202
1203     infoPtr->fStatus &= ~RESIZE_ANYHOW;
1204     /* Set flag to ignore next WM_SIZE message */
1205     infoPtr->fStatus |= AUTO_RESIZE;
1206
1207     width = 0;
1208     height = 0;
1209     x = 0;
1210     y = 0;
1211
1212     if (infoPtr->dwStyle & WS_BORDER) {
1213         width = 2 * xedge;
1214         height = 2 * yedge;
1215     }
1216
1217     if (!(infoPtr->dwStyle & CCS_NOPARENTALIGN)) {
1218         INT mode = infoPtr->dwStyle & (CCS_VERT | CCS_TOP | CCS_BOTTOM);
1219         RECT rcPcl;
1220
1221         GetClientRect(GetParent(infoPtr->hwndSelf), &rcPcl);
1222         switch (mode) {
1223         case CCS_TOP:
1224             /* _TOP sets width to parents width */
1225             width += (rcPcl.right - rcPcl.left);
1226             height += infoPtr->calcSize.cy;
1227             x += ((infoPtr->dwStyle & WS_BORDER) ? -xedge : 0);
1228             y += ((infoPtr->dwStyle & WS_BORDER) ? -yedge : 0);
1229             y += ((infoPtr->dwStyle & CCS_NODIVIDER) ? 0 : REBAR_DIVIDER);
1230             break;
1231         case CCS_BOTTOM:
1232             /* FIXME: wrong wrong wrong */
1233             /* _BOTTOM sets width to parents width */
1234             width += (rcPcl.right - rcPcl.left);
1235             height += infoPtr->calcSize.cy;
1236             x += -xedge;
1237             y = rcPcl.bottom - height + 1;
1238             break;
1239         case CCS_LEFT:
1240             /* _LEFT sets height to parents height */
1241             width += infoPtr->calcSize.cx;
1242             height += (rcPcl.bottom - rcPcl.top);
1243             x += ((infoPtr->dwStyle & WS_BORDER) ? -xedge : 0);
1244             x += ((infoPtr->dwStyle & CCS_NODIVIDER) ? 0 : REBAR_DIVIDER);
1245             y += ((infoPtr->dwStyle & WS_BORDER) ? -yedge : 0);
1246             break;
1247         case CCS_RIGHT:
1248             /* FIXME: wrong wrong wrong */
1249             /* _RIGHT sets height to parents height */
1250             width += infoPtr->calcSize.cx;
1251             height += (rcPcl.bottom - rcPcl.top);
1252             x = rcPcl.right - width + 1;
1253             y = -yedge;
1254             break;
1255         default:
1256             width += infoPtr->calcSize.cx;
1257             height += infoPtr->calcSize.cy;
1258         }
1259     }
1260     else {
1261         width += infoPtr->calcSize.cx;
1262         height += infoPtr->calcSize.cy;
1263         x = infoPtr->origin.x;
1264         y = infoPtr->origin.y;
1265     }
1266
1267     TRACE("hwnd %p, style=%08lx, setting at (%d,%d) for (%d,%d)\n",
1268         infoPtr->hwndSelf, infoPtr->dwStyle,
1269         x, y, width, height);
1270     SetWindowPos (infoPtr->hwndSelf, 0, x, y, width, height,
1271                     SWP_NOZORDER);
1272     infoPtr->fStatus &= ~AUTO_RESIZE;
1273 }
1274
1275
1276 static VOID
1277 REBAR_MoveChildWindows (REBAR_INFO *infoPtr, UINT start, UINT endplus)
1278 {
1279     static const WCHAR strComboBox[] = { 'C','o','m','b','o','B','o','x',0 };
1280     REBAR_BAND *lpBand;
1281     WCHAR szClassName[40];
1282     UINT i;
1283     NMREBARCHILDSIZE  rbcz;
1284     NMHDR heightchange;
1285     HDWP deferpos;
1286
1287     if (!(deferpos = BeginDeferWindowPos(infoPtr->uNumBands)))
1288         ERR("BeginDeferWindowPos returned NULL\n");
1289
1290     for (i = start; i < endplus; i++) {
1291         lpBand = &infoPtr->bands[i];
1292
1293         if (HIDDENBAND(lpBand)) continue;
1294         if (lpBand->hwndChild) {
1295             TRACE("hwndChild = %p\n", lpBand->hwndChild);
1296
1297             /* Always geterate the RBN_CHILDSIZE even it child
1298                    did not change */
1299             rbcz.uBand = i;
1300             rbcz.wID = lpBand->wID;
1301             rbcz.rcChild = lpBand->rcChild;
1302             rbcz.rcBand = lpBand->rcBand;
1303             if (infoPtr->dwStyle & CCS_VERT)
1304                 rbcz.rcBand.top += lpBand->cxHeader;
1305             else
1306                 rbcz.rcBand.left += lpBand->cxHeader;
1307             REBAR_Notify ((NMHDR *)&rbcz, infoPtr, RBN_CHILDSIZE);
1308             if (!EqualRect (&lpBand->rcChild, &rbcz.rcChild)) {
1309                 TRACE("Child rect changed by NOTIFY for band %u\n", i);
1310                 TRACE("    from (%ld,%ld)-(%ld,%ld)  to (%ld,%ld)-(%ld,%ld)\n",
1311                       lpBand->rcChild.left, lpBand->rcChild.top,
1312                       lpBand->rcChild.right, lpBand->rcChild.bottom,
1313                       rbcz.rcChild.left, rbcz.rcChild.top,
1314                       rbcz.rcChild.right, rbcz.rcChild.bottom);
1315                 lpBand->rcChild = rbcz.rcChild;  /* *** ??? */
1316             }
1317
1318             /* native (IE4 in "Favorites" frame **1) does:
1319              *   SetRect (&rc, -1, -1, -1, -1)
1320              *   EqualRect (&rc,band->rc???)
1321              *   if ret==0
1322              *     CopyRect (band->rc????, &rc)
1323              *     set flag outside of loop
1324              */
1325
1326             GetClassNameW (lpBand->hwndChild, szClassName, sizeof(szClassName)/sizeof(szClassName[0]));
1327             if (!lstrcmpW (szClassName, strComboBox) ||
1328                 !lstrcmpW (szClassName, WC_COMBOBOXEXW)) {
1329                 INT nEditHeight, yPos;
1330                 RECT rc;
1331
1332                 /* special placement code for combo or comboex box */
1333
1334
1335                 /* get size of edit line */
1336                 GetWindowRect (lpBand->hwndChild, &rc);
1337                 nEditHeight = rc.bottom - rc.top;
1338                 yPos = (lpBand->rcChild.bottom + lpBand->rcChild.top - nEditHeight)/2;
1339
1340                 /* center combo box inside child area */
1341                 TRACE("moving child (Combo(Ex)) %p to (%ld,%d) for (%ld,%d)\n",
1342                       lpBand->hwndChild,
1343                       lpBand->rcChild.left, yPos,
1344                       lpBand->rcChild.right - lpBand->rcChild.left,
1345                       nEditHeight);
1346                 deferpos = DeferWindowPos (deferpos, lpBand->hwndChild, HWND_TOP,
1347                                            lpBand->rcChild.left,
1348                                            /*lpBand->rcChild.top*/ yPos,
1349                                            lpBand->rcChild.right - lpBand->rcChild.left,
1350                                            nEditHeight,
1351                                            SWP_NOZORDER);
1352                 if (!deferpos)
1353                     ERR("DeferWindowPos returned NULL\n");
1354             }
1355             else {
1356                 TRACE("moving child (Other) %p to (%ld,%ld) for (%ld,%ld)\n",
1357                       lpBand->hwndChild,
1358                       lpBand->rcChild.left, lpBand->rcChild.top,
1359                       lpBand->rcChild.right - lpBand->rcChild.left,
1360                       lpBand->rcChild.bottom - lpBand->rcChild.top);
1361                 deferpos = DeferWindowPos (deferpos, lpBand->hwndChild, HWND_TOP,
1362                                            lpBand->rcChild.left,
1363                                            lpBand->rcChild.top,
1364                                            lpBand->rcChild.right - lpBand->rcChild.left,
1365                                            lpBand->rcChild.bottom - lpBand->rcChild.top,
1366                                            SWP_NOZORDER);
1367                 if (!deferpos)
1368                     ERR("DeferWindowPos returned NULL\n");
1369             }
1370         }
1371     }
1372     if (!EndDeferWindowPos(deferpos))
1373         ERR("EndDeferWindowPos returned NULL\n");
1374
1375     if (infoPtr->DoRedraw)
1376         UpdateWindow (infoPtr->hwndSelf);
1377
1378     if (infoPtr->fStatus & NTF_HGHTCHG) {
1379         infoPtr->fStatus &= ~NTF_HGHTCHG;
1380         /*
1381          * We need to force a resize here, because some applications
1382          * try to get the rebar size during processing of the 
1383          * RBN_HEIGHTCHANGE notification.
1384          */
1385         REBAR_ForceResize (infoPtr);
1386         REBAR_Notify (&heightchange, infoPtr, RBN_HEIGHTCHANGE);
1387     }
1388
1389     /* native (from **1 above) does:
1390      *      UpdateWindow(rebar)
1391      *      REBAR_ForceResize
1392      *      RBN_HEIGHTCHANGE if necessary
1393      *      if ret from any EqualRect was 0
1394      *         Goto "BeginDeferWindowPos"
1395      */
1396
1397 }
1398
1399
1400 static VOID
1401 REBAR_Layout (REBAR_INFO *infoPtr, LPRECT lpRect, BOOL notify, BOOL resetclient)
1402      /* Function: This routine is resposible for laying out all */
1403      /*  the bands in a rebar. It assigns each band to a row and*/
1404      /*  determines when to start a new row.                    */
1405 {
1406     REBAR_BAND *lpBand, *prevBand;
1407     RECT rcClient, rcAdj;
1408     INT initx, inity, x, y, cx, cxsep, mmcy, mcy, clientcx, clientcy;
1409     INT adjcx, adjcy, row, rightx, bottomy, origheight;
1410     UINT i, j, rowstart, origrows, cntonrow;
1411     BOOL dobreak;
1412
1413     if (!(infoPtr->fStatus & BAND_NEEDS_LAYOUT)) {
1414         TRACE("no layout done. No band changed.\n");
1415         REBAR_DumpBand (infoPtr);
1416         return;
1417     }
1418     infoPtr->fStatus &= ~BAND_NEEDS_LAYOUT;
1419     if (!infoPtr->DoRedraw) infoPtr->fStatus |= BAND_NEEDS_REDRAW;
1420
1421     GetClientRect (infoPtr->hwndSelf, &rcClient);
1422     TRACE("Client is (%ld,%ld)-(%ld,%ld)\n",
1423           rcClient.left, rcClient.top, rcClient.right, rcClient.bottom);
1424
1425     if (lpRect) {
1426         rcAdj = *lpRect;
1427         TRACE("adjustment rect is (%ld,%ld)-(%ld,%ld)\n",
1428               rcAdj.left, rcAdj.top, rcAdj.right, rcAdj.bottom);
1429     }
1430     else {
1431         CopyRect (&rcAdj, &rcClient);
1432     }
1433
1434     clientcx = rcClient.right - rcClient.left;
1435     clientcy = rcClient.bottom - rcClient.top;
1436     adjcx = rcAdj.right - rcAdj.left;
1437     adjcy = rcAdj.bottom - rcAdj.top;
1438     if (resetclient) {
1439         TRACE("window client rect will be set to adj rect\n");
1440         clientcx = adjcx;
1441         clientcy = adjcy;
1442     }
1443
1444     if (!infoPtr->DoRedraw && (clientcx == 0) && (clientcy == 0)) {
1445         ERR("no redraw and client is zero, skip layout\n");
1446         infoPtr->fStatus |= BAND_NEEDS_LAYOUT;
1447         return;
1448     }
1449
1450     /* save height of original control */
1451     if (infoPtr->dwStyle & CCS_VERT)
1452         origheight = infoPtr->calcSize.cx;
1453     else
1454         origheight = infoPtr->calcSize.cy;
1455     origrows = infoPtr->uNumRows;
1456
1457     initx = 0;
1458     inity = 0;
1459
1460     /* ******* Start Phase 1 - all bands on row at minimum size ******* */
1461
1462     TRACE("band loop constants, clientcx=%d, clientcy=%d, adjcx=%d, adjcy=%d\n",
1463           clientcx, clientcy, adjcx, adjcy);
1464     x = initx;
1465     y = inity;
1466     row = 0;
1467     cx = 0;
1468     mcy = 0;
1469     rowstart = 0;
1470     prevBand = NULL;
1471     cntonrow = 0;
1472
1473     for (i = 0; i < infoPtr->uNumBands; i++) {
1474         lpBand = &infoPtr->bands[i];
1475         lpBand->fDraw = 0;
1476         lpBand->iRow = row;
1477
1478         SetRectEmpty(&lpBand->rcChevron);
1479
1480         if (HIDDENBAND(lpBand)) continue;
1481
1482         lpBand->rcoldBand = lpBand->rcBand;
1483
1484         /* Set the offset of the child window */
1485         if ((lpBand->fMask & RBBIM_CHILD) &&
1486             !(lpBand->fStyle & RBBS_FIXEDSIZE)) {
1487             lpBand->offChild.cx = ((lpBand->fStyle & RBBS_CHILDEDGE) ? 4 : 0);
1488         }
1489         lpBand->offChild.cy = ((lpBand->fStyle & RBBS_CHILDEDGE) ? 2 : 0);
1490
1491         /* separator from previous band */
1492         cxsep = (cntonrow == 0) ? 0 : SEP_WIDTH;
1493         cx = lpBand->lcx;
1494
1495         /* In native, 0 as one of the coordinates means no limit */
1496         if (infoPtr->dwStyle & CCS_VERT)
1497             dobreak = (adjcy && (y + cx + cxsep > adjcy));
1498         else
1499             dobreak = (adjcx && (x + cx + cxsep > adjcx));
1500
1501         /* This is the check for whether we need to start a new row */
1502         if ( ( (lpBand->fStyle & RBBS_BREAK) && (i != 0) ) ||
1503              ( ((infoPtr->dwStyle & CCS_VERT) ? (y != 0) : (x != 0)) && dobreak)) {
1504
1505             for (j = rowstart; j < i; j++) {
1506                 REBAR_BAND *lpB;
1507                 lpB = &infoPtr->bands[j];
1508                 if (infoPtr->dwStyle & CCS_VERT) {
1509                     lpB->rcBand.right  = lpB->rcBand.left + mcy;
1510                 }
1511                 else {
1512                     lpB->rcBand.bottom = lpB->rcBand.top + mcy;
1513                 }
1514             }
1515
1516             TRACE("P1 Spliting to new row %d on band %u\n", row+1, i);
1517             if (infoPtr->dwStyle & CCS_VERT) {
1518                 y = inity;
1519                 x += (mcy + SEP_WIDTH);
1520             }
1521             else {
1522                 x = initx;
1523                 y += (mcy + SEP_WIDTH);
1524             }
1525
1526             mcy = 0;
1527             cxsep = 0;
1528             row++;
1529             lpBand->iRow = row;
1530             prevBand = NULL;
1531             rowstart = i;
1532             cntonrow = 0;
1533         }
1534
1535         if (mcy < lpBand->lcy + REBARSPACE(lpBand))
1536             mcy = lpBand->lcy + REBARSPACE(lpBand);
1537
1538         /* if boundary rect specified then limit mcy */
1539         if (lpRect) {
1540             if (infoPtr->dwStyle & CCS_VERT) {
1541                 if (adjcx && (x+mcy > adjcx)) {
1542                     mcy = adjcx - x;
1543                     TRACE("P1 row %u limiting mcy=%d, adjcx=%d, x=%d\n",
1544                           i, mcy, adjcx, x);
1545                 }
1546             }
1547             else {
1548                 if (adjcy && (y+mcy > adjcy)) {
1549                     mcy = adjcy - y;
1550                     TRACE("P1 row %u limiting mcy=%d, adjcy=%d, y=%d\n",
1551                           i, mcy, adjcy, y);
1552                 }
1553             }
1554         }
1555
1556         TRACE("P1 band %u, row %d, x=%d, y=%d, cxsep=%d, cx=%d\n",
1557               i, row,
1558               x, y, cxsep, cx);
1559         if (infoPtr->dwStyle & CCS_VERT) {
1560             /* bound the bottom side if we have a bounding rectangle */
1561             rightx = clientcx;
1562             bottomy = (lpRect) ? min(clientcy, y+cxsep+cx) : y+cxsep+cx;
1563             lpBand->rcBand.left   = x;
1564             lpBand->rcBand.right  = x + min(mcy,
1565                                             lpBand->lcy+REBARSPACE(lpBand));
1566             lpBand->rcBand.top    = min(bottomy, y + cxsep);
1567             lpBand->rcBand.bottom = bottomy;
1568             lpBand->uMinHeight = lpBand->lcy;
1569             y = bottomy;
1570         }
1571         else {
1572             /* bound the right side if we have a bounding rectangle */
1573             rightx = (lpRect) ? min(clientcx, x+cxsep+cx) : x+cxsep+cx;
1574             bottomy = clientcy;
1575             lpBand->rcBand.left   = min(rightx, x + cxsep);
1576             lpBand->rcBand.right  = rightx;
1577             lpBand->rcBand.top    = y;
1578             lpBand->rcBand.bottom = y + min(mcy,
1579                                             lpBand->lcy+REBARSPACE(lpBand));
1580             lpBand->uMinHeight = lpBand->lcy;
1581             x = rightx;
1582         }
1583         TRACE("P1 band %u, row %d, (%ld,%ld)-(%ld,%ld)\n",
1584               i, row,
1585               lpBand->rcBand.left, lpBand->rcBand.top,
1586               lpBand->rcBand.right, lpBand->rcBand.bottom);
1587         prevBand = lpBand;
1588         cntonrow++;
1589
1590     } /* for (i = 0; i < infoPtr->uNumBands... */
1591
1592     if (infoPtr->dwStyle & CCS_VERT)
1593         x += mcy;
1594     else
1595         y += mcy;
1596
1597     for (j = rowstart; j < infoPtr->uNumBands; j++) {
1598         lpBand = &infoPtr->bands[j];
1599         if (infoPtr->dwStyle & CCS_VERT) {
1600             lpBand->rcBand.right  = lpBand->rcBand.left + mcy;
1601         }
1602         else {
1603             lpBand->rcBand.bottom = lpBand->rcBand.top + mcy;
1604         }
1605     }
1606
1607     if (infoPtr->uNumBands)
1608         infoPtr->uNumRows = row + 1;
1609
1610     /* ******* End Phase 1 - all bands on row at minimum size ******* */
1611
1612
1613     /* ******* Start Phase 1a - Adjust heights for RBS_VARHEIGHT off ******* */
1614
1615     mmcy = 0;
1616     if (!(infoPtr->dwStyle & RBS_VARHEIGHT)) {
1617         INT xy;
1618
1619         /* get the max height of all bands */
1620         for (i=0; i<infoPtr->uNumBands; i++) {
1621             lpBand = &infoPtr->bands[i];
1622             if (HIDDENBAND(lpBand)) continue;
1623             if (infoPtr->dwStyle & CCS_VERT)
1624                 mmcy = max(mmcy, lpBand->rcBand.right - lpBand->rcBand.left);
1625             else
1626                 mmcy = max(mmcy, lpBand->rcBand.bottom - lpBand->rcBand.top);
1627         }
1628
1629         /* now adjust all rectangles by using the height found above */
1630         xy = 0;
1631         row = 0;
1632         for (i=0; i<infoPtr->uNumBands; i++) {
1633             lpBand = &infoPtr->bands[i];
1634             if (HIDDENBAND(lpBand)) continue;
1635             if (lpBand->iRow != row)
1636                 xy += (mmcy + SEP_WIDTH);
1637             if (infoPtr->dwStyle & CCS_VERT) {
1638                 lpBand->rcBand.left = xy;
1639                 lpBand->rcBand.right = xy + mmcy;
1640             }
1641             else {
1642                 lpBand->rcBand.top = xy;
1643                 lpBand->rcBand.bottom = xy + mmcy;
1644             }
1645         }
1646
1647         /* set the x/y values to the correct maximum */
1648         if (infoPtr->dwStyle & CCS_VERT)
1649             x = xy + mmcy;
1650         else
1651             y = xy + mmcy;
1652     }
1653
1654     /* ******* End Phase 1a - Adjust heights for RBS_VARHEIGHT off ******* */
1655
1656
1657     /* ******* Start Phase 2 - split rows till adjustment height full ******* */
1658
1659     /* assumes that the following variables contain:                 */
1660     /*   y/x       current height/width of all rows                  */
1661     /* adjcy/adjcx adjustment height/width or 0 (as small as possible) */
1662     if (lpRect && ((infoPtr->dwStyle & CCS_VERT) ? adjcx : adjcy)) {
1663         INT i, prev_rh, new_rh, adj_rh, prev_idx, current_idx;
1664         REBAR_BAND *prev, *current, *walk;
1665         UINT j;
1666
1667 /* FIXME:  problem # 2 */
1668         if (((infoPtr->dwStyle & CCS_VERT) ?
1669 #if PROBLEM2
1670              (x < adjcx) : (y < adjcy)
1671 #else
1672              (adjcx - x > 5) : (adjcy - y > 4)
1673 #endif
1674              ) &&
1675             (infoPtr->uNumBands > 1)) {
1676             for (i=(INT)infoPtr->uNumBands-2; i>=0; i--) {
1677                 TRACE("P2 adjcx=%d, adjcy=%d, x=%d, y=%d\n",
1678                       adjcx, adjcy, x, y);
1679
1680                 /* find the current band (starts at i+1) */
1681                 current = &infoPtr->bands[i+1];
1682                 current_idx = i+1;
1683                 while (HIDDENBAND(current)) {
1684                     i--;
1685                     if (i < 0) break; /* out of bands */
1686                     current = &infoPtr->bands[i+1];
1687                     current_idx = i+1;
1688                 }
1689                 if (i < 0) break; /* out of bands */
1690
1691                 /* now find the prev band (starts at i) */
1692                 prev = &infoPtr->bands[i];
1693                 prev_idx = i;
1694                 while (HIDDENBAND(prev)) {
1695                     i--;
1696                     if (i < 0) break; /* out of bands */
1697                     prev = &infoPtr->bands[i];
1698                     prev_idx = i;
1699                 }
1700                 if (i < 0) break; /* out of bands */
1701
1702                 prev_rh = ircBw(prev);
1703                 if (prev->iRow == current->iRow) {
1704                     new_rh = (infoPtr->dwStyle & RBS_VARHEIGHT) ?
1705                         current->lcy + REBARSPACE(current) :
1706                         mmcy;
1707                     adj_rh = new_rh + SEP_WIDTH;
1708                     infoPtr->uNumRows++;
1709                     current->fDraw |= NTF_INVALIDATE;
1710                     current->iRow++;
1711                     if (infoPtr->dwStyle & CCS_VERT) {
1712                         current->rcBand.top = inity;
1713                         current->rcBand.bottom = clientcy;
1714                         current->rcBand.left += (prev_rh + SEP_WIDTH);
1715                         current->rcBand.right = current->rcBand.left + new_rh;
1716                         x += adj_rh;
1717                     }
1718                     else {
1719                         current->rcBand.left = initx;
1720                         current->rcBand.right = clientcx;
1721                         current->rcBand.top += (prev_rh + SEP_WIDTH);
1722                         current->rcBand.bottom = current->rcBand.top + new_rh;
1723                         y += adj_rh;
1724                     }
1725                     TRACE("P2 moving band %d to own row at (%ld,%ld)-(%ld,%ld)\n",
1726                           current_idx,
1727                           current->rcBand.left, current->rcBand.top,
1728                           current->rcBand.right, current->rcBand.bottom);
1729                     TRACE("P2 prev band %d at (%ld,%ld)-(%ld,%ld)\n",
1730                           prev_idx,
1731                           prev->rcBand.left, prev->rcBand.top,
1732                           prev->rcBand.right, prev->rcBand.bottom);
1733                     TRACE("P2 values: prev_rh=%d, new_rh=%d, adj_rh=%d\n",
1734                           prev_rh, new_rh, adj_rh);
1735                     /* for bands below current adjust row # and top/bottom */
1736                     for (j = current_idx+1; j<infoPtr->uNumBands; j++) {
1737                         walk = &infoPtr->bands[j];
1738                         if (HIDDENBAND(walk)) continue;
1739                         walk->fDraw |= NTF_INVALIDATE;
1740                         walk->iRow++;
1741                         if (infoPtr->dwStyle & CCS_VERT) {
1742                             walk->rcBand.left += adj_rh;
1743                             walk->rcBand.right += adj_rh;
1744                         }
1745                         else {
1746                             walk->rcBand.top += adj_rh;
1747                             walk->rcBand.bottom += adj_rh;
1748                         }
1749                     }
1750                     if ((infoPtr->dwStyle & CCS_VERT) ? (x >= adjcx) : (y >= adjcy))
1751                         break; /* all done */
1752                 }
1753             }
1754         }
1755     }
1756
1757     /* ******* End Phase 2 - split rows till adjustment height full ******* */
1758
1759
1760     /* ******* Start Phase 2a - mark first and last band in each ******* */
1761
1762     prevBand = NULL;
1763     for (i = 0; i < infoPtr->uNumBands; i++) {   
1764         lpBand = &infoPtr->bands[i];     
1765         if (HIDDENBAND(lpBand))
1766             continue;
1767         if( !prevBand ) {
1768             lpBand->fDraw |= DRAW_FIRST_IN_ROW;
1769             prevBand = lpBand;
1770         }
1771         else if( prevBand->iRow == lpBand->iRow )
1772             prevBand = lpBand;
1773         else {
1774             prevBand->fDraw |= DRAW_LAST_IN_ROW;
1775             lpBand->fDraw |= DRAW_FIRST_IN_ROW;
1776             prevBand = lpBand;
1777         }
1778     }
1779     if( prevBand )
1780         prevBand->fDraw |= DRAW_LAST_IN_ROW;
1781
1782     /* ******* End Phase 2a - mark first and last band in each ******* */
1783
1784
1785     /* ******* Start Phase 2b - adjust all bands for height full ******* */
1786     /* assumes that the following variables contain:                 */
1787     /*   y/x     current height/width of all rows                    */
1788     /*   clientcy/clientcx     height/width of client area           */
1789
1790     if (((infoPtr->dwStyle & CCS_VERT) ? clientcx > x : clientcy > y) &&
1791         infoPtr->uNumBands) {
1792         INT diff, i;
1793         UINT j;
1794
1795         diff = (infoPtr->dwStyle & CCS_VERT) ? clientcx - x : clientcy - y;
1796
1797         /* iterate backwards thru the rows */
1798         for (i = infoPtr->uNumBands-1; i>=0; i--) {
1799             lpBand = &infoPtr->bands[i];
1800             if(HIDDENBAND(lpBand)) continue;
1801
1802             /* if row has more than 1 band, ignore it */
1803             if( !(lpBand->fDraw&DRAW_FIRST_IN_ROW) )
1804                 continue;
1805             if( !(lpBand->fDraw&DRAW_LAST_IN_ROW) )
1806                 continue;
1807
1808             /* FIXME: this next line is wrong, but fixing it to be inverted causes IE's sidebars to be the wrong size */
1809             if (lpBand->fMask & RBBS_VARIABLEHEIGHT) continue;
1810             if (((INT)lpBand->cyMaxChild < 1) ||
1811                 ((INT)lpBand->cyIntegral < 1)) {
1812                 if (lpBand->cyMaxChild + lpBand->cyIntegral == 0) continue;
1813                 ERR("P2b band %u RBBS_VARIABLEHEIGHT set but cyMax=%d, cyInt=%d\n",
1814                     i, lpBand->cyMaxChild, lpBand->cyIntegral);
1815                 continue;
1816             }
1817             /* j is now the maximum height/width in the client area */
1818             j = ((diff / lpBand->cyIntegral) * lpBand->cyIntegral) +
1819                 ircBw(lpBand);
1820             if (j > lpBand->cyMaxChild + REBARSPACE(lpBand))
1821                 j = lpBand->cyMaxChild + REBARSPACE(lpBand);
1822             diff -= (j - ircBw(lpBand));
1823             if (infoPtr->dwStyle & CCS_VERT)
1824                 lpBand->rcBand.right = lpBand->rcBand.left + j;
1825             else
1826                 lpBand->rcBand.bottom = lpBand->rcBand.top + j;
1827             TRACE("P2b band %d, row %d changed to (%ld,%ld)-(%ld,%ld)\n",
1828                   i, lpBand->iRow,
1829                   lpBand->rcBand.left, lpBand->rcBand.top,
1830                   lpBand->rcBand.right, lpBand->rcBand.bottom);
1831             if (diff <= 0) break;
1832         }
1833         if (diff < 0) {
1834             ERR("P2b allocated more than available, diff=%d\n", diff);
1835             diff = 0;
1836         }
1837         if (infoPtr->dwStyle & CCS_VERT)
1838             x = clientcx - diff;
1839         else
1840             y = clientcy - diff;
1841     }
1842
1843     /* ******* End Phase 2b - adjust all bands for height full ******* */
1844
1845
1846     /* ******* Start Phase 3 - adjust all bands for width full ******* */
1847
1848     if (infoPtr->uNumBands) {
1849         int startband;
1850
1851         /* If RBS_BANDBORDERS set then indicate to draw bottom separator */
1852         /* on all bands in all rows but last row.                        */
1853         /* Also indicate to draw the right separator for each band in    */
1854         /* each row but the rightmost band.                              */
1855         if (infoPtr->dwStyle & RBS_BANDBORDERS) {
1856
1857             for (i=0; i<infoPtr->uNumBands; i++) {
1858                 lpBand = &infoPtr->bands[i];
1859                 if (HIDDENBAND(lpBand))
1860                     continue;
1861
1862                 /* not righthand bands */
1863                 if( !(lpBand->fDraw & DRAW_LAST_IN_ROW) )
1864                     lpBand->fDraw |= DRAW_RIGHTSEP;
1865
1866                 /* not the last row */
1867                 if( lpBand->iRow != infoPtr->uNumRows )
1868                     lpBand->fDraw |= DRAW_BOTTOMSEP;
1869             }
1870         }
1871
1872         /* Distribute the extra space on the horizontal and adjust  */
1873         /* all bands in row to same height.                         */
1874         mcy = 0;
1875         startband = -1;
1876         for (i=0; i<infoPtr->uNumBands; i++) {
1877
1878             lpBand = &infoPtr->bands[i];
1879
1880             if( lpBand->fDraw & DRAW_FIRST_IN_ROW )
1881             {
1882                 startband = i;
1883                 mcy = 0;
1884             }
1885
1886             if ( (mcy < ircBw(lpBand)) && !HIDDENBAND(lpBand) )
1887                 mcy = ircBw(lpBand);
1888
1889             if( lpBand->fDraw & DRAW_LAST_IN_ROW )
1890             {
1891                 TRACE("P3 processing row %d, starting band %d, ending band %d\n",
1892                       lpBand->iRow, startband, i);
1893                 if( startband < 0 )
1894                     ERR("Last band %d with no first, row %d\n", i, lpBand->iRow);
1895
1896                 REBAR_AdjustBands (infoPtr, startband, i,
1897                                (infoPtr->dwStyle & CCS_VERT) ?
1898                                clientcy : clientcx, mcy);
1899             }
1900         }
1901
1902         /* Calculate the other rectangles in each band */
1903         if (infoPtr->dwStyle & CCS_VERT) {
1904             REBAR_CalcVertBand (infoPtr, 0, infoPtr->uNumBands,
1905                                 notify);
1906         }
1907         else {
1908             REBAR_CalcHorzBand (infoPtr, 0, infoPtr->uNumBands,
1909                                 notify);
1910         }
1911     }
1912
1913     /* ******* End Phase 3 - adjust all bands for width full ******* */
1914
1915     /* now compute size of Rebar itself */
1916     infoPtr->oldSize = infoPtr->calcSize;
1917     if (infoPtr->uNumBands == 0) {
1918         /* we have no bands, so make size the size of client */
1919         x = clientcx;
1920         y = clientcy;
1921     }
1922     if (infoPtr->dwStyle & CCS_VERT) {
1923         if( infoPtr->uNumBands != 0 && x < REBAR_MINSIZE )
1924             x = REBAR_MINSIZE;
1925         infoPtr->calcSize.cx = x;
1926         infoPtr->calcSize.cy = clientcy;
1927         TRACE("vert, notify=%d, x=%d, origheight=%d\n",
1928               notify, x, origheight);
1929         if (notify && (x != origheight)) infoPtr->fStatus |= NTF_HGHTCHG;
1930     }
1931     else {
1932         if( infoPtr->uNumBands != 0 && y < REBAR_MINSIZE )
1933             y = REBAR_MINSIZE;
1934         infoPtr->calcSize.cx = clientcx;
1935         infoPtr->calcSize.cy = y;
1936         TRACE("horz, notify=%d, y=%d, origheight=%d\n",
1937               notify, y, origheight);
1938         if (notify && (y != origheight)) infoPtr->fStatus |= NTF_HGHTCHG;
1939     }
1940
1941     REBAR_DumpBand (infoPtr);
1942
1943     REBAR_MoveChildWindows (infoPtr, 0, infoPtr->uNumBands);
1944
1945     REBAR_ForceResize (infoPtr);
1946 }
1947
1948
1949 static VOID
1950 REBAR_ValidateBand (REBAR_INFO *infoPtr, REBAR_BAND *lpBand)
1951      /* Function:  This routine evaluates the band specs supplied */
1952      /*  by the user and updates the following 5 fields in        */
1953      /*  the internal band structure: cxHeader, lcx, lcy, hcx, hcy*/
1954 {
1955     UINT header=0;
1956     UINT textheight=0;
1957     UINT i, nonfixed;
1958     REBAR_BAND *tBand;
1959
1960     lpBand->fStatus = 0;
1961     lpBand->lcx = 0;
1962     lpBand->lcy = 0;
1963     lpBand->ccx = 0;
1964     lpBand->ccy = 0;
1965     lpBand->hcx = 0;
1966     lpBand->hcy = 0;
1967
1968     /* Data comming in from users into the cx... and cy... fields  */
1969     /* may be bad, just garbage, because the user never clears     */
1970     /* the fields. RB_{SET|INSERT}BAND{A|W} just passes the data   */
1971     /* along if the fields exist in the input area. Here we must   */
1972     /* determine if the data is valid. I have no idea how MS does  */
1973     /* the validation, but it does because the RB_GETBANDINFO      */
1974     /* returns a 0 when I know the sample program passed in an     */
1975     /* address. Here I will use the algorithim that if the value   */
1976     /* is greater than 65535 then it is bad and replace it with    */
1977     /* a zero. Feel free to improve the algorithim.  -  GA 12/2000 */
1978     if (lpBand->cxMinChild > 65535) lpBand->cxMinChild = 0;
1979     if (lpBand->cyMinChild > 65535) lpBand->cyMinChild = 0;
1980     if (lpBand->cx         > 65535) lpBand->cx         = 0;
1981     if (lpBand->cyChild    > 65535) lpBand->cyChild    = 0;
1982     if (lpBand->cyMaxChild > 65535) lpBand->cyMaxChild = 0;
1983     if (lpBand->cyIntegral > 65535) lpBand->cyIntegral = 0;
1984     if (lpBand->cxIdeal    > 65535) lpBand->cxIdeal    = 0;
1985     if (lpBand->cxHeader   > 65535) lpBand->cxHeader   = 0;
1986
1987     /* FIXME: probably should only set NEEDS_LAYOUT flag when */
1988     /*        values change. Till then always set it.         */
1989     TRACE("setting NEEDS_LAYOUT\n");
1990     infoPtr->fStatus |= BAND_NEEDS_LAYOUT;
1991
1992     /* Header is where the image, text and gripper exist  */
1993     /* in the band and precede the child window.          */
1994
1995     /* count number of non-FIXEDSIZE and non-Hidden bands */
1996     nonfixed = 0;
1997     for (i=0; i<infoPtr->uNumBands; i++){
1998         tBand = &infoPtr->bands[i];
1999         if (!HIDDENBAND(tBand) && !(tBand->fStyle & RBBS_FIXEDSIZE))
2000             nonfixed++;
2001     }
2002
2003     /* calculate gripper rectangle */
2004     if (  (!(lpBand->fStyle & RBBS_NOGRIPPER)) &&
2005           ( (lpBand->fStyle & RBBS_GRIPPERALWAYS) ||
2006             ( !(lpBand->fStyle & RBBS_FIXEDSIZE) && (nonfixed > 1)))
2007        ) {
2008         lpBand->fStatus |= HAS_GRIPPER;
2009         if (infoPtr->dwStyle & CCS_VERT)
2010             if (infoPtr->dwStyle & RBS_VERTICALGRIPPER)
2011                 header += (GRIPPER_HEIGHT + REBAR_PRE_GRIPPER);
2012             else
2013                 header += (GRIPPER_WIDTH + REBAR_PRE_GRIPPER);
2014         else
2015             header += (REBAR_PRE_GRIPPER + GRIPPER_WIDTH);
2016         /* Always have 4 pixels before anything else */
2017         header += REBAR_ALWAYS_SPACE;
2018     }
2019
2020     /* image is visible */
2021     if ((lpBand->fMask & RBBIM_IMAGE) && (infoPtr->himl)) {
2022         lpBand->fStatus |= HAS_IMAGE;
2023         if (infoPtr->dwStyle & CCS_VERT) {
2024            header += (infoPtr->imageSize.cy + REBAR_POST_IMAGE);
2025            lpBand->lcy = infoPtr->imageSize.cx + 2;
2026         }
2027         else {
2028            header += (infoPtr->imageSize.cx + REBAR_POST_IMAGE);
2029            lpBand->lcy = infoPtr->imageSize.cy + 2;
2030         }
2031     }
2032
2033     /* text is visible */
2034     if ((lpBand->fMask & RBBIM_TEXT) && (lpBand->lpText) &&
2035         !(lpBand->fStyle & RBBS_HIDETITLE)) {
2036         HDC hdc = GetDC (0);
2037         HFONT hOldFont = SelectObject (hdc, infoPtr->hFont);
2038         SIZE size;
2039
2040         lpBand->fStatus |= HAS_TEXT;
2041         GetTextExtentPoint32W (hdc, lpBand->lpText,
2042                                lstrlenW (lpBand->lpText), &size);
2043         header += ((infoPtr->dwStyle & CCS_VERT) ? (size.cy + REBAR_POST_TEXT) : (size.cx + REBAR_POST_TEXT));
2044         textheight = (infoPtr->dwStyle & CCS_VERT) ? 0 : size.cy;
2045
2046         SelectObject (hdc, hOldFont);
2047         ReleaseDC (0, hdc);
2048     }
2049
2050     /* if no gripper but either image or text, then leave space */
2051     if ((lpBand->fStatus & (HAS_IMAGE | HAS_TEXT)) &&
2052         !(lpBand->fStatus & HAS_GRIPPER)) {
2053         header += REBAR_ALWAYS_SPACE;
2054     }
2055
2056     /* check if user overrode the header value */
2057     if (!(lpBand->fMask & RBBIM_HEADERSIZE))
2058         lpBand->cxHeader = header;
2059
2060
2061     /* Now compute minimum size of child window */
2062     lpBand->offChild.cx = 0;
2063     lpBand->offChild.cy = 0;
2064     lpBand->lcy = textheight;
2065     lpBand->ccy = lpBand->lcy;
2066     if (lpBand->fMask & RBBIM_CHILDSIZE) {
2067         lpBand->lcx = lpBand->cxMinChild;
2068
2069         /* Set the .cy values for CHILDSIZE case */
2070         lpBand->lcy = max(lpBand->lcy, lpBand->cyMinChild);
2071         lpBand->ccy = lpBand->lcy;
2072         lpBand->hcy = lpBand->lcy;
2073         if (lpBand->cyMaxChild != 0xffffffff) {
2074             lpBand->hcy = lpBand->cyMaxChild;
2075         }
2076         if (lpBand->cyChild != 0xffffffff)
2077             lpBand->ccy = max (lpBand->cyChild, lpBand->lcy);
2078
2079         TRACE("_CHILDSIZE\n");
2080     }
2081     if (lpBand->fMask & RBBIM_SIZE) {
2082         lpBand->hcx = max (lpBand->cx-lpBand->cxHeader, lpBand->lcx);
2083         TRACE("_SIZE\n");
2084     }
2085     else
2086         lpBand->hcx = lpBand->lcx;
2087     lpBand->ccx = lpBand->hcx;
2088
2089     /* make ->.cx include header size for _Layout */
2090     lpBand->lcx += lpBand->cxHeader;
2091     lpBand->ccx += lpBand->cxHeader;
2092     lpBand->hcx += lpBand->cxHeader;
2093
2094 }
2095
2096 static BOOL
2097 REBAR_CommonSetupBand (HWND hwnd, LPREBARBANDINFOA lprbbi, REBAR_BAND *lpBand)
2098      /* Function:  This routine copies the supplied values from   */
2099      /*  user input (lprbbi) to the internal band structure.      */
2100      /*  It returns true if something changed and false if not.   */
2101 {
2102     BOOL bChanged = FALSE;
2103
2104     lpBand->fMask |= lprbbi->fMask;
2105
2106     if( (lprbbi->fMask & RBBIM_STYLE) &&
2107         (lpBand->fStyle != lprbbi->fStyle ) )
2108     {
2109         lpBand->fStyle = lprbbi->fStyle;
2110         bChanged = TRUE;
2111     }
2112
2113     if( (lprbbi->fMask & RBBIM_COLORS) &&
2114        ( ( lpBand->clrFore != lprbbi->clrFore ) ||
2115          ( lpBand->clrBack != lprbbi->clrBack ) ) )
2116     {
2117         lpBand->clrFore = lprbbi->clrFore;
2118         lpBand->clrBack = lprbbi->clrBack;
2119         bChanged = TRUE;
2120     }
2121
2122     if( (lprbbi->fMask & RBBIM_IMAGE) &&
2123        ( lpBand->iImage != lprbbi->iImage ) )
2124     {
2125         lpBand->iImage = lprbbi->iImage;
2126         bChanged = TRUE;
2127     }
2128
2129     if( (lprbbi->fMask & RBBIM_CHILD) &&
2130        (lprbbi->hwndChild != lpBand->hwndChild ) )
2131     {
2132         if (lprbbi->hwndChild) {
2133             lpBand->hwndChild = lprbbi->hwndChild;
2134             lpBand->hwndPrevParent =
2135                 SetParent (lpBand->hwndChild, hwnd);
2136             /* below in trace from WinRAR */
2137             ShowWindow(lpBand->hwndChild, SW_SHOWNOACTIVATE | SW_SHOWNORMAL);
2138             /* above in trace from WinRAR */
2139         }
2140         else {
2141             TRACE("child: %p  prev parent: %p\n",
2142                    lpBand->hwndChild, lpBand->hwndPrevParent);
2143             lpBand->hwndChild = 0;
2144             lpBand->hwndPrevParent = 0;
2145         }
2146         bChanged = TRUE;
2147     }
2148
2149     if( (lprbbi->fMask & RBBIM_CHILDSIZE) &&
2150         ( (lpBand->cxMinChild != lprbbi->cxMinChild) ||
2151           (lpBand->cyMinChild != lprbbi->cyMinChild ) ||
2152           ( (lprbbi->cbSize >= sizeof (REBARBANDINFOA)) &&
2153             ( (lpBand->cyChild    != lprbbi->cyChild ) ||
2154               (lpBand->cyMaxChild != lprbbi->cyMaxChild ) ||
2155               (lpBand->cyIntegral != lprbbi->cyIntegral ) ) ) ||
2156           ( (lprbbi->cbSize < sizeof (REBARBANDINFOA)) &&
2157             ( (lpBand->cyChild || 
2158                lpBand->cyMaxChild || 
2159                lpBand->cyIntegral ) ) ) ) )
2160     {
2161         lpBand->cxMinChild = lprbbi->cxMinChild;
2162         lpBand->cyMinChild = lprbbi->cyMinChild;
2163         if (lprbbi->cbSize >= sizeof (REBARBANDINFOA)) {
2164             lpBand->cyChild    = lprbbi->cyChild;
2165             lpBand->cyMaxChild = lprbbi->cyMaxChild;
2166             lpBand->cyIntegral = lprbbi->cyIntegral;
2167         }
2168         else { /* special case - these should be zeroed out since   */
2169                /* RBBIM_CHILDSIZE added these in WIN32_IE >= 0x0400 */
2170             lpBand->cyChild    = 0;
2171             lpBand->cyMaxChild = 0;
2172             lpBand->cyIntegral = 0;
2173         }
2174         bChanged = TRUE;
2175     }
2176
2177     if( (lprbbi->fMask & RBBIM_SIZE) &&
2178         (lpBand->cx != lprbbi->cx ) )
2179     {
2180         lpBand->cx = lprbbi->cx;
2181         bChanged = TRUE;
2182     }
2183
2184     if( (lprbbi->fMask & RBBIM_BACKGROUND) &&
2185        ( lpBand->hbmBack != lprbbi->hbmBack ) )
2186     {
2187         lpBand->hbmBack = lprbbi->hbmBack;
2188         bChanged = TRUE;
2189     }
2190
2191     if( (lprbbi->fMask & RBBIM_ID) &&
2192         (lpBand->wID != lprbbi->wID ) )
2193     {
2194         lpBand->wID = lprbbi->wID;
2195         bChanged = TRUE;
2196     }
2197
2198     /* check for additional data */
2199     if (lprbbi->cbSize >= sizeof (REBARBANDINFOA)) {
2200         if( (lprbbi->fMask & RBBIM_IDEALSIZE) &&
2201             ( lpBand->cxIdeal != lprbbi->cxIdeal ) )
2202         {
2203             lpBand->cxIdeal = lprbbi->cxIdeal;
2204             bChanged = TRUE;
2205         }
2206
2207         if( (lprbbi->fMask & RBBIM_LPARAM) &&
2208             (lpBand->lParam != lprbbi->lParam ) )
2209         {
2210             lpBand->lParam = lprbbi->lParam;
2211             bChanged = TRUE;
2212         }
2213
2214         if( (lprbbi->fMask & RBBIM_HEADERSIZE) &&
2215             (lpBand->cxHeader != lprbbi->cxHeader ) )
2216         {
2217             lpBand->cxHeader = lprbbi->cxHeader;
2218             bChanged = TRUE;
2219         }
2220     }
2221
2222     return bChanged;
2223 }
2224
2225 static LRESULT
2226 REBAR_InternalEraseBkGnd (REBAR_INFO *infoPtr, WPARAM wParam, LPARAM lParam, RECT *clip)
2227      /* Function:  This erases the background rectangle by drawing  */
2228      /*  each band with its background color (or the default) and   */
2229      /*  draws each bands right separator if necessary. The row     */
2230      /*  separators are drawn on the first band of the next row.    */
2231 {
2232     REBAR_BAND *lpBand;
2233     UINT i;
2234     INT oldrow;
2235     HDC hdc = (HDC)wParam;
2236     RECT rect, cr;
2237     COLORREF old = CLR_NONE, new;
2238     HTHEME theme = GetWindowTheme (infoPtr->hwndSelf);
2239
2240     GetClientRect (infoPtr->hwndSelf, &cr);
2241
2242     oldrow = -1;
2243     for(i=0; i<infoPtr->uNumBands; i++) {
2244         lpBand = &infoPtr->bands[i];
2245         if (HIDDENBAND(lpBand)) continue;
2246
2247         /* draw band separator between rows */
2248         if (lpBand->iRow != oldrow) {
2249             oldrow = lpBand->iRow;
2250             if (lpBand->fDraw & DRAW_BOTTOMSEP) {
2251                 RECT rcRowSep;
2252                 rcRowSep = lpBand->rcBand;
2253                 if (infoPtr->dwStyle & CCS_VERT) {
2254                     rcRowSep.right += SEP_WIDTH_SIZE;
2255                     rcRowSep.bottom = infoPtr->calcSize.cy;
2256                     if (theme)
2257                         DrawThemeEdge (theme, hdc, RP_BAND, 0, &rcRowSep, EDGE_ETCHED, BF_RIGHT, NULL);
2258                     else
2259                         DrawEdge (hdc, &rcRowSep, EDGE_ETCHED, BF_RIGHT);
2260                 }
2261                 else {
2262                     rcRowSep.bottom += SEP_WIDTH_SIZE;
2263                     rcRowSep.right = infoPtr->calcSize.cx;
2264                     if (theme)
2265                         DrawThemeEdge (theme, hdc, RP_BAND, 0, &rcRowSep, EDGE_ETCHED, BF_BOTTOM, NULL);
2266                     else
2267                         DrawEdge (hdc, &rcRowSep, EDGE_ETCHED, BF_BOTTOM);
2268                 }
2269                 TRACE ("drawing band separator bottom (%ld,%ld)-(%ld,%ld)\n",
2270                        rcRowSep.left, rcRowSep.top,
2271                        rcRowSep.right, rcRowSep.bottom);
2272             }
2273         }
2274
2275         /* draw band separator between bands in a row */
2276         if (lpBand->fDraw & DRAW_RIGHTSEP) {
2277             RECT rcSep;
2278             rcSep = lpBand->rcBand;
2279             if (infoPtr->dwStyle & CCS_VERT) {
2280                 rcSep.bottom += SEP_WIDTH_SIZE;
2281                 if (theme)
2282                     DrawThemeEdge (theme, hdc, RP_BAND, 0, &rcSep, EDGE_ETCHED, BF_BOTTOM, NULL);
2283                 else
2284                     DrawEdge (hdc, &rcSep, EDGE_ETCHED, BF_BOTTOM);
2285             }
2286             else {
2287                 rcSep.right += SEP_WIDTH_SIZE;
2288                 if (theme)
2289                     DrawThemeEdge (theme, hdc, RP_BAND, 0, &rcSep, EDGE_ETCHED, BF_RIGHT, NULL);
2290                 else
2291                     DrawEdge (hdc, &rcSep, EDGE_ETCHED, BF_RIGHT);
2292             }
2293             TRACE("drawing band separator right (%ld,%ld)-(%ld,%ld)\n",
2294                   rcSep.left, rcSep.top, rcSep.right, rcSep.bottom);
2295         }
2296
2297         /* draw the actual background */
2298         if (lpBand->clrBack != CLR_NONE) {
2299             new = (lpBand->clrBack == CLR_DEFAULT) ? infoPtr->clrBtnFace :
2300                     lpBand->clrBack;
2301 #if GLATESTING
2302             /* testing only - make background green to see it */
2303             new = RGB(0,128,0);
2304 #endif
2305         }
2306         else {
2307             /* In the absence of documentation for Rebar vs. CLR_NONE,
2308              * we will use the default BtnFace color. Note documentation
2309              * exists for Listview and Imagelist.
2310              */
2311             new = infoPtr->clrBtnFace;
2312 #if GLATESTING
2313             /* testing only - make background green to see it */
2314             new = RGB(0,128,0);
2315 #endif
2316         }
2317
2318         rect = lpBand->rcBand;
2319
2320         if (theme)
2321         {
2322             /* When themed, the background color is ignored (but not a 
2323              * background bitmap */
2324             DrawThemeBackground (theme, hdc, 0, 0, &cr, &rect);
2325         }
2326         else
2327         {
2328             old = SetBkColor (hdc, new);
2329             TRACE("%s background color=0x%06lx, band (%ld,%ld)-(%ld,%ld), clip (%ld,%ld)-(%ld,%ld)\n",
2330                   (lpBand->clrBack == CLR_NONE) ? "none" :
2331                     ((lpBand->clrBack == CLR_DEFAULT) ? "dft" : ""),
2332                   GetBkColor(hdc),
2333                   lpBand->rcBand.left,lpBand->rcBand.top,
2334                   lpBand->rcBand.right,lpBand->rcBand.bottom,
2335                   clip->left, clip->top,
2336                   clip->right, clip->bottom);
2337             ExtTextOutW (hdc, 0, 0, ETO_OPAQUE, &rect, NULL, 0, 0);
2338             if (lpBand->clrBack != CLR_NONE)
2339                 SetBkColor (hdc, old);
2340         }
2341     }
2342     return TRUE;
2343 }
2344
2345 static void
2346 REBAR_InternalHitTest (REBAR_INFO *infoPtr, const LPPOINT lpPt, UINT *pFlags, INT *pBand)
2347 {
2348     REBAR_BAND *lpBand;
2349     RECT rect;
2350     UINT  iCount;
2351
2352     GetClientRect (infoPtr->hwndSelf, &rect);
2353
2354     *pFlags = RBHT_NOWHERE;
2355     if (PtInRect (&rect, *lpPt))
2356     {
2357         if (infoPtr->uNumBands == 0) {
2358             *pFlags = RBHT_NOWHERE;
2359             if (pBand)
2360                 *pBand = -1;
2361             TRACE("NOWHERE\n");
2362             return;
2363         }
2364         else {
2365             /* somewhere inside */
2366             for (iCount = 0; iCount < infoPtr->uNumBands; iCount++) {
2367                 lpBand = &infoPtr->bands[iCount];
2368                 if (HIDDENBAND(lpBand)) continue;
2369                 if (PtInRect (&lpBand->rcBand, *lpPt)) {
2370                     if (pBand)
2371                         *pBand = iCount;
2372                     if (PtInRect (&lpBand->rcGripper, *lpPt)) {
2373                         *pFlags = RBHT_GRABBER;
2374                         TRACE("ON GRABBER %d\n", iCount);
2375                         return;
2376                     }
2377                     else if (PtInRect (&lpBand->rcCapImage, *lpPt)) {
2378                         *pFlags = RBHT_CAPTION;
2379                         TRACE("ON CAPTION %d\n", iCount);
2380                         return;
2381                     }
2382                     else if (PtInRect (&lpBand->rcCapText, *lpPt)) {
2383                         *pFlags = RBHT_CAPTION;
2384                         TRACE("ON CAPTION %d\n", iCount);
2385                         return;
2386                     }
2387                     else if (PtInRect (&lpBand->rcChild, *lpPt)) {
2388                         *pFlags = RBHT_CLIENT;
2389                         TRACE("ON CLIENT %d\n", iCount);
2390                         return;
2391                     }
2392                     else if (PtInRect (&lpBand->rcChevron, *lpPt)) {
2393                         *pFlags = RBHT_CHEVRON;
2394                         TRACE("ON CHEVRON %d\n", iCount);
2395                         return;
2396                     }
2397                     else {
2398                         *pFlags = RBHT_NOWHERE;
2399                         TRACE("NOWHERE %d\n", iCount);
2400                         return;
2401                     }
2402                 }
2403             }
2404
2405             *pFlags = RBHT_NOWHERE;
2406             if (pBand)
2407                 *pBand = -1;
2408
2409             TRACE("NOWHERE\n");
2410             return;
2411         }
2412     }
2413     else {
2414         *pFlags = RBHT_NOWHERE;
2415         if (pBand)
2416             *pBand = -1;
2417         TRACE("NOWHERE\n");
2418         return;
2419     }
2420 }
2421
2422
2423 static INT
2424 REBAR_Shrink (REBAR_INFO *infoPtr, REBAR_BAND *band, INT movement, INT i)
2425      /* Function:  This attempts to shrink the given band by the  */
2426      /*  the amount in "movement". A shrink to the left is indi-  */
2427      /*  cated by "movement" being negative. "i" is merely the    */
2428      /*  band index for trace messages.                           */
2429 {
2430     INT Leadjust, Readjust, avail, ret;
2431
2432     /* Note: a left drag is indicated by "movement" being negative.  */
2433     /*       Similarly, a right drag is indicated by "movement"      */
2434     /*       being positive. "movement" should never be 0, but if    */
2435     /*       it is then the band does not move.                      */
2436
2437     avail = rcBw(band) - band->lcx;
2438
2439     /* now compute the Left End adjustment factor and Right End */
2440     /* adjustment factor. They may be different if shrinking.   */
2441     if (avail <= 0) {
2442         /* if this band is not shrinkable, then just move it */
2443         Leadjust = Readjust = movement;
2444         ret = movement;
2445     }
2446     else {
2447         if (movement < 0) {
2448             /* Drag to left */
2449             if (avail <= abs(movement)) {
2450                 Readjust = movement;
2451                 Leadjust = movement + avail;
2452                 ret = Leadjust;
2453             }
2454             else {
2455                 Readjust = movement;
2456                 Leadjust = 0;
2457                 ret = 0;
2458             }
2459         }
2460         else {
2461             /* Drag to right */
2462             if (avail <= abs(movement)) {
2463                 Leadjust = movement;
2464                 Readjust = movement - avail;
2465                 ret = Readjust;
2466             }
2467             else {
2468                 Leadjust = movement;
2469                 Readjust = 0;
2470                 ret = 0;
2471             }
2472         }
2473     }
2474
2475     /* Reasonability Check */
2476     if (rcBlt(band) + Leadjust < 0) {
2477         ERR("adjustment will fail, band %d: left=%d, right=%d, move=%d, rtn=%d\n",
2478             i, Leadjust, Readjust, movement, ret);
2479     }
2480
2481     LEADJ(band, Leadjust);
2482     READJ(band, Readjust);
2483
2484     TRACE("band %d:  left=%d, right=%d, move=%d, rtn=%d, rcBand=(%ld,%ld)-(%ld,%ld)\n",
2485           i, Leadjust, Readjust, movement, ret,
2486           band->rcBand.left, band->rcBand.top,
2487           band->rcBand.right, band->rcBand.bottom);
2488     return ret;
2489 }
2490
2491
2492 static void
2493 REBAR_HandleLRDrag (REBAR_INFO *infoPtr, const POINT *ptsmove)
2494      /* Function:  This will implement the functionality of a     */
2495      /*  Gripper drag within a row. It will not implement "out-   */
2496      /*  of-row" drags. (They are detected and handled in         */
2497      /*  REBAR_MouseMove.)                                        */
2498      /*  **** FIXME Switching order of bands in a row not   ****  */
2499      /*  ****       yet implemented.                        ****  */
2500 {
2501     REBAR_BAND *hitBand, *band, *mindBand, *maxdBand;
2502     RECT newrect;
2503     INT imindBand = -1, imaxdBand, ihitBand, i, movement;
2504     INT RHeaderSum = 0, LHeaderSum = 0;
2505     INT compress;
2506
2507     /* on first significant mouse movement, issue notify */
2508
2509     if (!(infoPtr->fStatus & BEGIN_DRAG_ISSUED)) {
2510         if (REBAR_Notify_NMREBAR (infoPtr, -1, RBN_BEGINDRAG)) {
2511             /* Notify returned TRUE - abort drag */
2512             infoPtr->dragStart.x = 0;
2513             infoPtr->dragStart.y = 0;
2514             infoPtr->dragNow = infoPtr->dragStart;
2515             infoPtr->iGrabbedBand = -1;
2516             ReleaseCapture ();
2517             return ;
2518         }
2519         infoPtr->fStatus |= BEGIN_DRAG_ISSUED;
2520     }
2521
2522     ihitBand = infoPtr->iGrabbedBand;
2523     hitBand = &infoPtr->bands[ihitBand];
2524     imaxdBand = ihitBand; /* to suppress warning message */
2525
2526     /* find all the bands in the row of the one whose Gripper was seized */
2527     for (i=0; i<infoPtr->uNumBands; i++) {
2528         band = &infoPtr->bands[i];
2529         if (HIDDENBAND(band)) continue;
2530         if (band->iRow == hitBand->iRow) {
2531             imaxdBand = i;
2532             if (imindBand == -1) imindBand = i;
2533             /* minimum size of each band is size of header plus            */
2534             /* size of minimum child plus offset of child from header plus */
2535             /* one to separate each band.                                  */
2536             if (i < ihitBand)
2537                 LHeaderSum += (band->lcx + SEP_WIDTH);
2538             else
2539                 RHeaderSum += (band->lcx + SEP_WIDTH);
2540
2541         }
2542     }
2543     if (RHeaderSum) RHeaderSum -= SEP_WIDTH; /* no separator after last band */
2544
2545     mindBand = &infoPtr->bands[imindBand];
2546     maxdBand = &infoPtr->bands[imaxdBand];
2547
2548     if (imindBand == imaxdBand) return; /* nothing to drag against */
2549     if (imindBand == ihitBand) return; /* first band in row, can't drag */
2550
2551     /* limit movement to inside adjustable bands - Left */
2552     if ( (ptsmove->x < mindBand->rcBand.left) ||
2553          (ptsmove->x > maxdBand->rcBand.right) ||
2554          (ptsmove->y < mindBand->rcBand.top) ||
2555          (ptsmove->y > maxdBand->rcBand.bottom))
2556         return; /* should swap bands */
2557
2558     if (infoPtr->dwStyle & CCS_VERT)
2559         movement = ptsmove->y - ((hitBand->rcBand.top+REBAR_PRE_GRIPPER) -
2560                              infoPtr->ihitoffset);
2561     else
2562         movement = ptsmove->x - ((hitBand->rcBand.left+REBAR_PRE_GRIPPER) -
2563                              infoPtr->ihitoffset);
2564     infoPtr->dragNow = *ptsmove;
2565
2566     TRACE("before: movement=%d (%ld,%ld), imindBand=%d, ihitBand=%d, imaxdBand=%d, LSum=%d, RSum=%d\n",
2567           movement, ptsmove->x, ptsmove->y, imindBand, ihitBand,
2568           imaxdBand, LHeaderSum, RHeaderSum);
2569     REBAR_DumpBand (infoPtr);
2570
2571     if (movement < 0) {
2572
2573         /* ***  Drag left/up *** */
2574         compress = rcBlt(hitBand) - rcBlt(mindBand) -
2575                    LHeaderSum;
2576         if (compress < abs(movement)) {
2577             TRACE("limiting left drag, was %d changed to %d\n",
2578                   movement, -compress);
2579             movement = -compress;
2580         }
2581
2582         for (i=ihitBand; i>=imindBand; i--) {
2583             band = &infoPtr->bands[i];
2584             if (HIDDENBAND(band)) continue;
2585             if (i == ihitBand) {
2586                 LEADJ(band, movement);
2587             }
2588             else
2589                 movement = REBAR_Shrink (infoPtr, band, movement, i);
2590             band->ccx = rcBw(band);
2591         }
2592     }
2593     else {
2594         BOOL first = TRUE;
2595
2596         /* ***  Drag right/down *** */
2597         compress = rcBrb(maxdBand) - rcBlt(hitBand) -
2598                    RHeaderSum;
2599         if (compress < abs(movement)) {
2600             TRACE("limiting right drag, was %d changed to %d\n",
2601                   movement, compress);
2602             movement = compress;
2603         }
2604         for (i=ihitBand-1; i<=imaxdBand; i++) {
2605             band = &infoPtr->bands[i];
2606             if (HIDDENBAND(band)) continue;
2607             if (first) {
2608                 first = FALSE;
2609                 READJ(band, movement);
2610             }
2611             else
2612                 movement = REBAR_Shrink (infoPtr, band, movement, i);
2613             band->ccx = rcBw(band);
2614         }
2615     }
2616
2617     /* recompute all rectangles */
2618     if (infoPtr->dwStyle & CCS_VERT) {
2619         REBAR_CalcVertBand (infoPtr, imindBand, imaxdBand+1,
2620                             FALSE);
2621     }
2622     else {
2623         REBAR_CalcHorzBand (infoPtr, imindBand, imaxdBand+1,
2624                             FALSE);
2625     }
2626
2627     TRACE("bands after adjustment, see band # %d, %d\n",
2628           imindBand, imaxdBand);
2629     REBAR_DumpBand (infoPtr);
2630
2631     SetRect (&newrect,
2632              mindBand->rcBand.left,
2633              mindBand->rcBand.top,
2634              maxdBand->rcBand.right,
2635              maxdBand->rcBand.bottom);
2636
2637     REBAR_MoveChildWindows (infoPtr, imindBand, imaxdBand+1);
2638
2639     InvalidateRect (infoPtr->hwndSelf, &newrect, TRUE);
2640     UpdateWindow (infoPtr->hwndSelf);
2641
2642 }
2643
2644
2645
2646 /* << REBAR_BeginDrag >> */
2647
2648
2649 static LRESULT
2650 REBAR_DeleteBand (REBAR_INFO *infoPtr, WPARAM wParam, LPARAM lParam)
2651 {
2652     UINT uBand = (UINT)wParam;
2653     HWND childhwnd = 0;
2654     REBAR_BAND *lpBand;
2655
2656     if (uBand >= infoPtr->uNumBands)
2657         return FALSE;
2658
2659     TRACE("deleting band %u!\n", uBand);
2660     lpBand = &infoPtr->bands[uBand];
2661     REBAR_Notify_NMREBAR (infoPtr, uBand, RBN_DELETINGBAND);
2662
2663     if (infoPtr->uNumBands == 1) {
2664         TRACE(" simple delete!\n");
2665         if ((lpBand->fMask & RBBIM_CHILD) && lpBand->hwndChild)
2666             childhwnd = lpBand->hwndChild;
2667         Free (infoPtr->bands);
2668         infoPtr->bands = NULL;
2669         infoPtr->uNumBands = 0;
2670     }
2671     else {
2672         REBAR_BAND *oldBands = infoPtr->bands;
2673         TRACE("complex delete! [uBand=%u]\n", uBand);
2674
2675         if ((lpBand->fMask & RBBIM_CHILD) && lpBand->hwndChild)
2676             childhwnd = lpBand->hwndChild;
2677
2678         infoPtr->uNumBands--;
2679         infoPtr->bands = Alloc (sizeof (REBAR_BAND) * infoPtr->uNumBands);
2680         if (uBand > 0) {
2681             memcpy (&infoPtr->bands[0], &oldBands[0],
2682                     uBand * sizeof(REBAR_BAND));
2683         }
2684
2685         if (uBand < infoPtr->uNumBands) {
2686             memcpy (&infoPtr->bands[uBand], &oldBands[uBand+1],
2687                     (infoPtr->uNumBands - uBand) * sizeof(REBAR_BAND));
2688         }
2689
2690         Free (oldBands);
2691     }
2692
2693     if (childhwnd)
2694         ShowWindow (childhwnd, SW_HIDE);
2695
2696     REBAR_Notify_NMREBAR (infoPtr, -1, RBN_DELETEDBAND);
2697
2698     /* if only 1 band left the re-validate to possible eliminate gripper */
2699     if (infoPtr->uNumBands == 1)
2700       REBAR_ValidateBand (infoPtr, &infoPtr->bands[0]);
2701
2702     TRACE("setting NEEDS_LAYOUT\n");
2703     infoPtr->fStatus |= BAND_NEEDS_LAYOUT;
2704     infoPtr->fStatus |= RESIZE_ANYHOW;
2705     REBAR_Layout (infoPtr, NULL, TRUE, FALSE);
2706
2707     return TRUE;
2708 }
2709
2710
2711 /* << REBAR_DragMove >> */
2712 /* << REBAR_EndDrag >> */
2713
2714
2715 static LRESULT
2716 REBAR_GetBandBorders (REBAR_INFO *infoPtr, WPARAM wParam, LPARAM lParam)
2717 {
2718     LPRECT lpRect = (LPRECT)lParam;
2719     REBAR_BAND *lpBand;
2720
2721     if (!lParam)
2722         return 0;
2723     if ((UINT)wParam >= infoPtr->uNumBands)
2724         return 0;
2725
2726     lpBand = &infoPtr->bands[(UINT)wParam];
2727
2728     /* FIXME - the following values were determined by experimentation */
2729     /* with the REBAR Control Spy. I have guesses as to what the 4 and */
2730     /* 1 are, but I am not sure. There doesn't seem to be any actual   */
2731     /* difference in size of the control area with and without the     */
2732     /* style.  -  GA                                                   */
2733     if (infoPtr->dwStyle & RBS_BANDBORDERS) {
2734         if (infoPtr->dwStyle & CCS_VERT) {
2735             lpRect->left = 1;
2736             lpRect->top = lpBand->cxHeader + 4;
2737             lpRect->right = 1;
2738             lpRect->bottom = 0;
2739         }
2740         else {
2741             lpRect->left = lpBand->cxHeader + 4;
2742             lpRect->top = 1;
2743             lpRect->right = 0;
2744             lpRect->bottom = 1;
2745         }
2746     }
2747     else {
2748         lpRect->left = lpBand->cxHeader;
2749     }
2750     return 0;
2751 }
2752
2753
2754 inline static LRESULT
2755 REBAR_GetBandCount (REBAR_INFO *infoPtr)
2756 {
2757     TRACE("band count %u!\n", infoPtr->uNumBands);
2758
2759     return infoPtr->uNumBands;
2760 }
2761
2762
2763 static LRESULT
2764 REBAR_GetBandInfoA (REBAR_INFO *infoPtr, WPARAM wParam, LPARAM lParam)
2765 {
2766     LPREBARBANDINFOA lprbbi = (LPREBARBANDINFOA)lParam;
2767     REBAR_BAND *lpBand;
2768
2769     if (lprbbi == NULL)
2770         return FALSE;
2771     if (lprbbi->cbSize < REBARBANDINFOA_V3_SIZE)
2772         return FALSE;
2773     if ((UINT)wParam >= infoPtr->uNumBands)
2774         return FALSE;
2775
2776     TRACE("index %u\n", (UINT)wParam);
2777
2778     /* copy band information */
2779     lpBand = &infoPtr->bands[(UINT)wParam];
2780
2781     if (lprbbi->fMask & RBBIM_STYLE)
2782         lprbbi->fStyle = lpBand->fStyle;
2783
2784     if (lprbbi->fMask & RBBIM_COLORS) {
2785         lprbbi->clrFore = lpBand->clrFore;
2786         lprbbi->clrBack = lpBand->clrBack;
2787         if (lprbbi->clrBack == CLR_DEFAULT)
2788             lprbbi->clrBack = infoPtr->clrBtnFace;
2789     }
2790
2791     if ((lprbbi->fMask & RBBIM_TEXT) && (lprbbi->lpText)) {
2792       if (lpBand->lpText && (lpBand->fMask & RBBIM_TEXT))
2793       {
2794           if (!WideCharToMultiByte( CP_ACP, 0, lpBand->lpText, -1,
2795                                     lprbbi->lpText, lprbbi->cch, NULL, NULL ))
2796               lprbbi->lpText[lprbbi->cch-1] = 0;
2797       }
2798       else
2799         *lprbbi->lpText = 0;
2800     }
2801
2802     if (lprbbi->fMask & RBBIM_IMAGE) {
2803       if (lpBand->fMask & RBBIM_IMAGE)
2804         lprbbi->iImage = lpBand->iImage;
2805       else
2806         lprbbi->iImage = -1;
2807     }
2808
2809     if (lprbbi->fMask & RBBIM_CHILD)
2810         lprbbi->hwndChild = lpBand->hwndChild;
2811
2812     if (lprbbi->fMask & RBBIM_CHILDSIZE) {
2813         lprbbi->cxMinChild = lpBand->cxMinChild;
2814         lprbbi->cyMinChild = lpBand->cyMinChild;
2815         if (lprbbi->cbSize >= sizeof (REBARBANDINFOA)) {
2816             lprbbi->cyChild    = lpBand->cyChild;
2817             lprbbi->cyMaxChild = lpBand->cyMaxChild;
2818             lprbbi->cyIntegral = lpBand->cyIntegral;
2819         }
2820     }
2821
2822     if (lprbbi->fMask & RBBIM_SIZE)
2823         lprbbi->cx = lpBand->cx;
2824
2825     if (lprbbi->fMask & RBBIM_BACKGROUND)
2826         lprbbi->hbmBack = lpBand->hbmBack;
2827
2828     if (lprbbi->fMask & RBBIM_ID)
2829         lprbbi->wID = lpBand->wID;
2830
2831     /* check for additional data */
2832     if (lprbbi->cbSize >= sizeof (REBARBANDINFOA)) {
2833         if (lprbbi->fMask & RBBIM_IDEALSIZE)
2834             lprbbi->cxIdeal = lpBand->cxIdeal;
2835
2836         if (lprbbi->fMask & RBBIM_LPARAM)
2837             lprbbi->lParam = lpBand->lParam;
2838
2839         if (lprbbi->fMask & RBBIM_HEADERSIZE)
2840             lprbbi->cxHeader = lpBand->cxHeader;
2841     }
2842
2843     REBAR_DumpBandInfo (lprbbi);
2844
2845     return TRUE;
2846 }
2847
2848
2849 static LRESULT
2850 REBAR_GetBandInfoW (REBAR_INFO *infoPtr, WPARAM wParam, LPARAM lParam)
2851 {
2852     LPREBARBANDINFOW lprbbi = (LPREBARBANDINFOW)lParam;
2853     REBAR_BAND *lpBand;
2854
2855     if (lprbbi == NULL)
2856         return FALSE;
2857     if (lprbbi->cbSize < REBARBANDINFOW_V3_SIZE)
2858         return FALSE;
2859     if ((UINT)wParam >= infoPtr->uNumBands)
2860         return FALSE;
2861
2862     TRACE("index %u\n", (UINT)wParam);
2863
2864     /* copy band information */
2865     lpBand = &infoPtr->bands[(UINT)wParam];
2866
2867     if (lprbbi->fMask & RBBIM_STYLE)
2868         lprbbi->fStyle = lpBand->fStyle;
2869
2870     if (lprbbi->fMask & RBBIM_COLORS) {
2871         lprbbi->clrFore = lpBand->clrFore;
2872         lprbbi->clrBack = lpBand->clrBack;
2873         if (lprbbi->clrBack == CLR_DEFAULT)
2874             lprbbi->clrBack = infoPtr->clrBtnFace;
2875     }
2876
2877     if ((lprbbi->fMask & RBBIM_TEXT) && (lprbbi->lpText)) {
2878       if (lpBand->lpText && (lpBand->fMask & RBBIM_TEXT))
2879         lstrcpynW (lprbbi->lpText, lpBand->lpText, lprbbi->cch);
2880       else
2881         *lprbbi->lpText = 0;
2882     }
2883
2884     if (lprbbi->fMask & RBBIM_IMAGE) {
2885       if (lpBand->fMask & RBBIM_IMAGE)
2886         lprbbi->iImage = lpBand->iImage;
2887       else
2888         lprbbi->iImage = -1;
2889     }
2890
2891     if (lprbbi->fMask & RBBIM_CHILD)
2892         lprbbi->hwndChild = lpBand->hwndChild;
2893
2894     if (lprbbi->fMask & RBBIM_CHILDSIZE) {
2895         lprbbi->cxMinChild = lpBand->cxMinChild;
2896         lprbbi->cyMinChild = lpBand->cyMinChild;
2897         if (lprbbi->cbSize >= sizeof (REBARBANDINFOW)) {
2898             lprbbi->cyChild    = lpBand->cyChild;
2899             lprbbi->cyMaxChild = lpBand->cyMaxChild;
2900             lprbbi->cyIntegral = lpBand->cyIntegral;
2901         }
2902     }
2903
2904     if (lprbbi->fMask & RBBIM_SIZE)
2905         lprbbi->cx = lpBand->cx;
2906
2907     if (lprbbi->fMask & RBBIM_BACKGROUND)
2908         lprbbi->hbmBack = lpBand->hbmBack;
2909
2910     if (lprbbi->fMask & RBBIM_ID)
2911         lprbbi->wID = lpBand->wID;
2912
2913     /* check for additional data */
2914     if (lprbbi->cbSize >= sizeof (REBARBANDINFOW)) {
2915         if (lprbbi->fMask & RBBIM_IDEALSIZE)
2916             lprbbi->cxIdeal = lpBand->cxIdeal;
2917
2918         if (lprbbi->fMask & RBBIM_LPARAM)
2919             lprbbi->lParam = lpBand->lParam;
2920
2921         if (lprbbi->fMask & RBBIM_HEADERSIZE)
2922             lprbbi->cxHeader = lpBand->cxHeader;
2923     }
2924
2925     REBAR_DumpBandInfo ((LPREBARBANDINFOA)lprbbi);
2926
2927     return TRUE;
2928 }
2929
2930
2931 static LRESULT
2932 REBAR_GetBarHeight (REBAR_INFO *infoPtr, WPARAM wParam, LPARAM lParam)
2933 {
2934     INT nHeight;
2935
2936     nHeight = (infoPtr->dwStyle & CCS_VERT) ? infoPtr->calcSize.cx : infoPtr->calcSize.cy;
2937
2938     TRACE("height = %d\n", nHeight);
2939
2940     return nHeight;
2941 }
2942
2943
2944 static LRESULT
2945 REBAR_GetBarInfo (REBAR_INFO *infoPtr, WPARAM wParam, LPARAM lParam)
2946 {
2947     LPREBARINFO lpInfo = (LPREBARINFO)lParam;
2948
2949     if (lpInfo == NULL)
2950         return FALSE;
2951
2952     if (lpInfo->cbSize < sizeof (REBARINFO))
2953         return FALSE;
2954
2955     TRACE("getting bar info!\n");
2956
2957     if (infoPtr->himl) {
2958         lpInfo->himl = infoPtr->himl;
2959         lpInfo->fMask |= RBIM_IMAGELIST;
2960     }
2961
2962     return TRUE;
2963 }
2964
2965
2966 inline static LRESULT
2967 REBAR_GetBkColor (REBAR_INFO *infoPtr)
2968 {
2969     COLORREF clr = infoPtr->clrBk;
2970
2971     if (clr == CLR_DEFAULT)
2972       clr = infoPtr->clrBtnFace;
2973
2974     TRACE("background color 0x%06lx!\n", clr);
2975
2976     return clr;
2977 }
2978
2979
2980 /* << REBAR_GetColorScheme >> */
2981 /* << REBAR_GetDropTarget >> */
2982
2983
2984 static LRESULT
2985 REBAR_GetPalette (REBAR_INFO *infoPtr, WPARAM wParam, LPARAM lParam)
2986 {
2987     FIXME("empty stub!\n");
2988
2989     return 0;
2990 }
2991
2992
2993 static LRESULT
2994 REBAR_GetRect (REBAR_INFO *infoPtr, WPARAM wParam, LPARAM lParam)
2995 {
2996     INT iBand = (INT)wParam;
2997     LPRECT lprc = (LPRECT)lParam;
2998     REBAR_BAND *lpBand;
2999
3000     if ((iBand < 0) && ((UINT)iBand >= infoPtr->uNumBands))
3001         return FALSE;
3002     if (!lprc)
3003         return FALSE;
3004
3005     lpBand = &infoPtr->bands[iBand];
3006     CopyRect (lprc, &lpBand->rcBand);
3007
3008     TRACE("band %d, (%ld,%ld)-(%ld,%ld)\n", iBand,
3009           lprc->left, lprc->top, lprc->right, lprc->bottom);
3010
3011     return TRUE;
3012 }
3013
3014
3015 inline static LRESULT
3016 REBAR_GetRowCount (REBAR_INFO *infoPtr)
3017 {
3018     TRACE("%u\n", infoPtr->uNumRows);
3019
3020     return infoPtr->uNumRows;
3021 }
3022
3023
3024 static LRESULT
3025 REBAR_GetRowHeight (REBAR_INFO *infoPtr, WPARAM wParam, LPARAM lParam)
3026 {
3027     INT iRow = (INT)wParam;
3028     int j = 0, ret = 0;
3029     UINT i;
3030     REBAR_BAND *lpBand;
3031
3032     for (i=0; i<infoPtr->uNumBands; i++) {
3033         lpBand = &infoPtr->bands[i];
3034         if (HIDDENBAND(lpBand)) continue;
3035         if (lpBand->iRow != iRow) continue;
3036         if (infoPtr->dwStyle & CCS_VERT)
3037             j = lpBand->rcBand.right - lpBand->rcBand.left;
3038         else
3039             j = lpBand->rcBand.bottom - lpBand->rcBand.top;
3040         if (j > ret) ret = j;
3041     }
3042
3043     TRACE("row %d, height %d\n", iRow, ret);
3044
3045     return ret;
3046 }
3047
3048
3049 inline static LRESULT
3050 REBAR_GetTextColor (REBAR_INFO *infoPtr)
3051 {
3052     TRACE("text color 0x%06lx!\n", infoPtr->clrText);
3053
3054     return infoPtr->clrText;
3055 }
3056
3057
3058 inline static LRESULT
3059 REBAR_GetToolTips (REBAR_INFO *infoPtr)
3060 {
3061     return (LRESULT)infoPtr->hwndToolTip;
3062 }
3063
3064
3065 inline static LRESULT
3066 REBAR_GetUnicodeFormat (REBAR_INFO *infoPtr)
3067 {
3068     TRACE("%s hwnd=%p\n",
3069           infoPtr->bUnicode ? "TRUE" : "FALSE", infoPtr->hwndSelf);
3070
3071     return infoPtr->bUnicode;
3072 }
3073
3074
3075 inline static LRESULT
3076 REBAR_GetVersion (REBAR_INFO *infoPtr)
3077 {
3078     TRACE("version %d\n", infoPtr->iVersion);
3079     return infoPtr->iVersion;
3080 }
3081
3082
3083 static LRESULT
3084 REBAR_HitTest (REBAR_INFO *infoPtr, WPARAM wParam, LPARAM lParam)
3085 {
3086     LPRBHITTESTINFO lprbht = (LPRBHITTESTINFO)lParam;
3087
3088     if (!lprbht)
3089         return -1;
3090
3091     REBAR_InternalHitTest (infoPtr, &lprbht->pt, &lprbht->flags, &lprbht->iBand);
3092
3093     return lprbht->iBand;
3094 }
3095
3096
3097 static LRESULT
3098 REBAR_IdToIndex (REBAR_INFO *infoPtr, WPARAM wParam, LPARAM lParam)
3099 {
3100     UINT i;
3101
3102     if (infoPtr == NULL)
3103         return -1;
3104
3105     if (infoPtr->uNumBands < 1)
3106         return -1;
3107
3108     for (i = 0; i < infoPtr->uNumBands; i++) {
3109         if (infoPtr->bands[i].wID == (UINT)wParam) {
3110             TRACE("id %u is band %u found!\n", (UINT)wParam, i);
3111             return i;
3112         }
3113     }
3114
3115     TRACE("id %u is not found\n", (UINT)wParam);
3116     return -1;
3117 }
3118
3119
3120 static LRESULT
3121 REBAR_InsertBandA (REBAR_INFO *infoPtr, WPARAM wParam, LPARAM lParam)
3122 {
3123     LPREBARBANDINFOA lprbbi = (LPREBARBANDINFOA)lParam;
3124     UINT uIndex = (UINT)wParam;
3125     REBAR_BAND *lpBand;
3126
3127     if (infoPtr == NULL)
3128         return FALSE;
3129     if (lprbbi == NULL)
3130         return FALSE;
3131     if (lprbbi->cbSize < REBARBANDINFOA_V3_SIZE)
3132         return FALSE;
3133
3134     /* trace the index as signed to see the -1 */
3135     TRACE("insert band at %d!\n", (INT)uIndex);
3136     REBAR_DumpBandInfo (lprbbi);
3137
3138     if (infoPtr->uNumBands == 0) {
3139         infoPtr->bands = (REBAR_BAND *)Alloc (sizeof (REBAR_BAND));
3140         uIndex = 0;
3141     }
3142     else {
3143         REBAR_BAND *oldBands = infoPtr->bands;
3144         infoPtr->bands =
3145             (REBAR_BAND *)Alloc ((infoPtr->uNumBands+1)*sizeof(REBAR_BAND));
3146         if (((INT)uIndex == -1) || (uIndex > infoPtr->uNumBands))
3147             uIndex = infoPtr->uNumBands;
3148
3149         /* pre insert copy */
3150         if (uIndex > 0) {
3151             memcpy (&infoPtr->bands[0], &oldBands[0],
3152                     uIndex * sizeof(REBAR_BAND));
3153         }
3154
3155         /* post copy */
3156         if (uIndex < infoPtr->uNumBands) {
3157             memcpy (&infoPtr->bands[uIndex+1], &oldBands[uIndex],
3158                     (infoPtr->uNumBands - uIndex) * sizeof(REBAR_BAND));
3159         }
3160
3161         Free (oldBands);
3162     }
3163
3164     infoPtr->uNumBands++;
3165
3166     TRACE("index %u!\n", uIndex);
3167
3168     /* initialize band (infoPtr->bands[uIndex])*/
3169     lpBand = &infoPtr->bands[uIndex];
3170     lpBand->fMask = 0;
3171     lpBand->fStatus = 0;
3172     lpBand->clrFore = infoPtr->clrText;
3173     lpBand->clrBack = infoPtr->clrBk;
3174     lpBand->hwndChild = 0;
3175     lpBand->hwndPrevParent = 0;
3176
3177     REBAR_CommonSetupBand (infoPtr->hwndSelf, lprbbi, lpBand);
3178     lpBand->lpText = NULL;
3179     if ((lprbbi->fMask & RBBIM_TEXT) && (lprbbi->lpText)) {
3180         INT len = MultiByteToWideChar( CP_ACP, 0, lprbbi->lpText, -1, NULL, 0 );
3181         if (len > 1) {
3182             lpBand->lpText = (LPWSTR)Alloc (len*sizeof(WCHAR));
3183             MultiByteToWideChar( CP_ACP, 0, lprbbi->lpText, -1, lpBand->lpText, len );
3184         }
3185     }
3186
3187     REBAR_ValidateBand (infoPtr, lpBand);
3188     /* On insert of second band, revalidate band 1 to possible add gripper */
3189     if (infoPtr->uNumBands == 2)
3190         REBAR_ValidateBand (infoPtr, &infoPtr->bands[0]);
3191
3192     REBAR_DumpBand (infoPtr);
3193
3194     REBAR_Layout (infoPtr, NULL, TRUE, FALSE);
3195     InvalidateRect(infoPtr->hwndSelf, 0, 1);
3196
3197     return TRUE;
3198 }
3199
3200
3201 static LRESULT
3202 REBAR_InsertBandW (REBAR_INFO *infoPtr, WPARAM wParam, LPARAM lParam)
3203 {
3204     LPREBARBANDINFOW lprbbi = (LPREBARBANDINFOW)lParam;
3205     UINT uIndex = (UINT)wParam;
3206     REBAR_BAND *lpBand;
3207
3208     if (infoPtr == NULL)
3209         return FALSE;
3210     if (lprbbi == NULL)
3211         return FALSE;
3212     if (lprbbi->cbSize < REBARBANDINFOW_V3_SIZE)
3213         return FALSE;
3214
3215     /* trace the index as signed to see the -1 */
3216     TRACE("insert band at %d!\n", (INT)uIndex);
3217     REBAR_DumpBandInfo ((LPREBARBANDINFOA)lprbbi);
3218
3219     if (infoPtr->uNumBands == 0) {
3220         infoPtr->bands = (REBAR_BAND *)Alloc (sizeof (REBAR_BAND));
3221         uIndex = 0;
3222     }
3223     else {
3224         REBAR_BAND *oldBands = infoPtr->bands;
3225         infoPtr->bands =
3226             (REBAR_BAND *)Alloc ((infoPtr->uNumBands+1)*sizeof(REBAR_BAND));
3227         if (((INT)uIndex == -1) || (uIndex > infoPtr->uNumBands))
3228             uIndex = infoPtr->uNumBands;
3229
3230         /* pre insert copy */
3231         if (uIndex > 0) {
3232             memcpy (&infoPtr->bands[0], &oldBands[0],
3233                     uIndex * sizeof(REBAR_BAND));
3234         }
3235
3236         /* post copy */
3237         if (uIndex <= infoPtr->uNumBands - 1) {
3238             memcpy (&infoPtr->bands[uIndex+1], &oldBands[uIndex],
3239                     (infoPtr->uNumBands - uIndex) * sizeof(REBAR_BAND));
3240         }
3241
3242         Free (oldBands);
3243     }
3244
3245     infoPtr->uNumBands++;
3246
3247     TRACE("index %u!\n", uIndex);
3248
3249     /* initialize band (infoPtr->bands[uIndex])*/
3250     lpBand = &infoPtr->bands[uIndex];
3251     lpBand->fMask = 0;
3252     lpBand->fStatus = 0;
3253     lpBand->clrFore = infoPtr->clrText;
3254     lpBand->clrBack = infoPtr->clrBk;
3255     lpBand->hwndChild = 0;
3256     lpBand->hwndPrevParent = 0;
3257
3258     REBAR_CommonSetupBand (infoPtr->hwndSelf, (LPREBARBANDINFOA)lprbbi, lpBand);
3259     lpBand->lpText = NULL;
3260     if ((lprbbi->fMask & RBBIM_TEXT) && (lprbbi->lpText)) {
3261         INT len = lstrlenW (lprbbi->lpText);
3262         if (len > 0) {
3263             lpBand->lpText = (LPWSTR)Alloc ((len + 1)*sizeof(WCHAR));
3264             strcpyW (lpBand->lpText, lprbbi->lpText);
3265         }
3266     }
3267
3268     REBAR_ValidateBand (infoPtr, lpBand);
3269     /* On insert of second band, revalidate band 1 to possible add gripper */
3270     if (infoPtr->uNumBands == 2)
3271         REBAR_ValidateBand (infoPtr, &infoPtr->bands[uIndex ? 0 : 1]);
3272
3273     REBAR_DumpBand (infoPtr);
3274
3275     REBAR_Layout (infoPtr, NULL, TRUE, FALSE);
3276     InvalidateRect(infoPtr->hwndSelf, 0, 1);
3277
3278     return TRUE;
3279 }
3280
3281
3282 static LRESULT
3283 REBAR_MaximizeBand (REBAR_INFO *infoPtr, WPARAM wParam, LPARAM lParam)
3284 {
3285     REBAR_BAND *lpBand;
3286     UINT uBand = (UINT) wParam;
3287
3288     /* Validate */
3289     if ((infoPtr->uNumBands == 0) ||
3290         ((INT)uBand < 0) || (uBand >= infoPtr->uNumBands)) {
3291         /* error !!! */
3292         ERR("Illegal MaximizeBand, requested=%d, current band count=%d\n",
3293               (INT)uBand, infoPtr->uNumBands);
3294         return FALSE;
3295     }
3296
3297     lpBand = &infoPtr->bands[uBand];
3298
3299     if (lParam && (lpBand->fMask & RBBIM_IDEALSIZE)) {
3300         /* handle setting ideal size */
3301         lpBand->ccx = lpBand->cxIdeal;
3302     }
3303     else {
3304         /* handle setting to max */
3305         FIXME("(uBand = %u fIdeal = %s) case not coded\n",
3306               (UINT)wParam, lParam ? "TRUE" : "FALSE");
3307         return FALSE;
3308     }
3309
3310     infoPtr->fStatus |= BAND_NEEDS_LAYOUT;
3311     REBAR_Layout (infoPtr, 0, TRUE, TRUE);
3312     InvalidateRect (infoPtr->hwndSelf, 0, TRUE);
3313
3314     return TRUE;
3315
3316 }
3317
3318
3319 static LRESULT
3320 REBAR_MinimizeBand (REBAR_INFO *infoPtr, WPARAM wParam, LPARAM lParam)
3321 {
3322     REBAR_BAND *band, *lpBand;
3323     UINT uBand = (UINT) wParam;
3324     RECT newrect;
3325     INT imindBand, imaxdBand, iprevBand, startBand, endBand;
3326     INT movement, i;
3327
3328     /* A "minimize" band is equivalent to "dragging" the gripper
3329      * of than band to the right till the band is only the size
3330      * of the cxHeader.
3331      */
3332
3333     /* Validate */
3334     if ((infoPtr->uNumBands == 0) ||
3335         ((INT)uBand < 0) || (uBand >= infoPtr->uNumBands)) {
3336         /* error !!! */
3337         ERR("Illegal MinimizeBand, requested=%d, current band count=%d\n",
3338               (INT)uBand, infoPtr->uNumBands);
3339         return FALSE;
3340     }
3341
3342     /* compute amount of movement and validate */
3343     lpBand = &infoPtr->bands[uBand];
3344
3345     if (infoPtr->dwStyle & CCS_VERT)
3346         movement = lpBand->rcBand.bottom - lpBand->rcBand.top -
3347             lpBand->cxHeader;
3348     else
3349         movement = lpBand->rcBand.right - lpBand->rcBand.left -
3350             lpBand->cxHeader;
3351     if (movement < 0) {
3352         ERR("something is wrong, band=(%ld,%ld)-(%ld,%ld), cxheader=%d\n",
3353             lpBand->rcBand.left, lpBand->rcBand.top,
3354             lpBand->rcBand.right, lpBand->rcBand.bottom,
3355             lpBand->cxHeader);
3356         return FALSE;
3357     }
3358
3359     imindBand = -1;
3360     imaxdBand = -1;
3361     iprevBand = -1; /* to suppress warning message */
3362
3363     /* find the first band in row of the one whose is being minimized */
3364     for (i=0; i<infoPtr->uNumBands; i++) {
3365         band = &infoPtr->bands[i];
3366         if (HIDDENBAND(band)) continue;
3367         if (band->iRow == lpBand->iRow) {
3368             imaxdBand = i;
3369             if (imindBand == -1) imindBand = i;
3370         }
3371     }
3372
3373     /* if the selected band is first in row then need to expand */
3374     /* next visible band                                        */
3375     if (imindBand == uBand) {
3376         band = NULL;
3377         movement = -movement;
3378         /* find the first visible band to the right of the selected band */
3379         for (i=uBand+1; i<=imaxdBand; i++) {
3380             band = &infoPtr->bands[i];
3381             if (!HIDDENBAND(band)) {
3382                 iprevBand = i;
3383                 LEADJ(band, movement);
3384                 band->ccx = rcBw(band);
3385                 break;
3386             }
3387         }
3388         /* what case is this */
3389         if (iprevBand == -1) {
3390             ERR("no previous visible band\n");
3391             return FALSE;
3392         }
3393         startBand = uBand;
3394         endBand = iprevBand;
3395         SetRect (&newrect,
3396                  lpBand->rcBand.left,
3397                  lpBand->rcBand.top,
3398                  band->rcBand.right,
3399                  band->rcBand.bottom);
3400     }
3401     /* otherwise expand previous visible band                   */
3402     else {
3403         band = NULL;
3404         /* find the first visible band to the left of the selected band */
3405         for (i=uBand-1; i>=imindBand; i--) {
3406             band = &infoPtr->bands[i];
3407             if (!HIDDENBAND(band)) {
3408                 iprevBand = i;
3409                 READJ(band, movement);
3410                 band->ccx = rcBw(band);
3411                 break;
3412             }
3413         }
3414         /* what case is this */
3415         if (iprevBand == -1) {
3416             ERR("no previous visible band\n");
3417             return FALSE;
3418         }
3419         startBand = iprevBand;
3420         endBand = uBand;
3421         SetRect (&newrect,
3422                  band->rcBand.left,
3423                  band->rcBand.top,
3424                  lpBand->rcBand.right,
3425                  lpBand->rcBand.bottom);
3426     }
3427
3428     REBAR_Shrink (infoPtr, lpBand, movement, uBand);
3429
3430     /* recompute all rectangles */
3431     if (infoPtr->dwStyle & CCS_VERT) {
3432         REBAR_CalcVertBand (infoPtr, startBand, endBand+1,
3433                             FALSE);
3434     }
3435     else {
3436         REBAR_CalcHorzBand (infoPtr, startBand, endBand+1,
3437                             FALSE);
3438     }
3439
3440     TRACE("bands after minimize, see band # %d, %d\n",
3441           startBand, endBand);
3442     REBAR_DumpBand (infoPtr);
3443
3444     REBAR_MoveChildWindows (infoPtr, startBand, endBand+1);
3445
3446     InvalidateRect (infoPtr->hwndSelf, &newrect, TRUE);
3447     UpdateWindow (infoPtr->hwndSelf);
3448     return FALSE;
3449 }
3450
3451
3452 static LRESULT
3453 REBAR_MoveBand (REBAR_INFO *infoPtr, WPARAM wParam, LPARAM lParam)
3454 {
3455     REBAR_BAND *oldBands = infoPtr->bands;
3456     REBAR_BAND holder;
3457     UINT uFrom = (UINT)wParam;
3458     UINT uTo = (UINT)lParam;
3459
3460     /* Validate */
3461     if ((infoPtr->uNumBands == 0) ||
3462         ((INT)uFrom < 0) || (uFrom >= infoPtr->uNumBands) ||
3463         ((INT)uTo < 0)   || (uTo >= infoPtr->uNumBands)) {
3464         /* error !!! */
3465         ERR("Illegal MoveBand, from=%d, to=%d, current band count=%d\n",
3466               (INT)uFrom, (INT)uTo, infoPtr->uNumBands);
3467         return FALSE;
3468     }
3469
3470     /* save one to be moved */
3471     memcpy (&holder, &oldBands[uFrom], sizeof(REBAR_BAND));
3472
3473     /* close up rest of bands (pseudo delete) */
3474     if (uFrom < infoPtr->uNumBands - 1) {
3475         memcpy (&oldBands[uFrom], &oldBands[uFrom+1],
3476                 (infoPtr->uNumBands - uFrom - 1) * sizeof(REBAR_BAND));
3477     }
3478
3479     /* allocate new space and copy rest of bands into it */
3480     infoPtr->bands =
3481         (REBAR_BAND *)Alloc ((infoPtr->uNumBands)*sizeof(REBAR_BAND));
3482
3483     /* pre insert copy */
3484     if (uTo > 0) {
3485         memcpy (&infoPtr->bands[0], &oldBands[0],
3486                 uTo * sizeof(REBAR_BAND));
3487     }
3488
3489     /* set moved band */
3490     memcpy (&infoPtr->bands[uTo], &holder, sizeof(REBAR_BAND));
3491
3492     /* post copy */
3493     if (uTo < infoPtr->uNumBands - 1) {
3494         memcpy (&infoPtr->bands[uTo+1], &oldBands[uTo],
3495                 (infoPtr->uNumBands - uTo - 1) * sizeof(REBAR_BAND));
3496     }
3497
3498     Free (oldBands);
3499
3500     TRACE("moved band %d to index %d\n", uFrom, uTo);
3501     REBAR_DumpBand (infoPtr);
3502
3503     infoPtr->fStatus |= BAND_NEEDS_LAYOUT;
3504     /* **************************************************** */
3505     /*                                                      */
3506     /* We do not do a REBAR_Layout here because the native  */
3507     /* control does not do that. The actual layout and      */
3508     /* repaint is done by the *next* real action, ex.:      */
3509     /* RB_INSERTBAND, RB_DELETEBAND, RB_SIZETORECT, etc.    */
3510     /*                                                      */
3511     /* **************************************************** */
3512
3513     return TRUE;
3514 }
3515
3516
3517 /* return TRUE if two strings are different */
3518 static BOOL
3519 REBAR_strdifW( LPCWSTR a, LPCWSTR b )
3520 {
3521     return ( (a && !b) || (b && !a) || (a && b && lstrcmpW(a, b) ) );
3522 }
3523
3524 static LRESULT
3525 REBAR_SetBandInfoA (REBAR_INFO *infoPtr, WPARAM wParam, LPARAM lParam)
3526 {
3527     LPREBARBANDINFOA lprbbi = (LPREBARBANDINFOA)lParam;
3528     REBAR_BAND *lpBand;
3529     BOOL bChanged;
3530
3531     if (lprbbi == NULL)
3532         return FALSE;
3533     if (lprbbi->cbSize < REBARBANDINFOA_V3_SIZE)
3534         return FALSE;
3535     if ((UINT)wParam >= infoPtr->uNumBands)
3536         return FALSE;
3537
3538     TRACE("index %u\n", (UINT)wParam);
3539     REBAR_DumpBandInfo (lprbbi);
3540
3541     /* set band information */
3542     lpBand = &infoPtr->bands[(UINT)wParam];
3543
3544     bChanged = REBAR_CommonSetupBand (infoPtr->hwndSelf, lprbbi, lpBand);
3545     if (lprbbi->fMask & RBBIM_TEXT) {
3546         LPWSTR wstr = NULL;
3547
3548         if (lprbbi->lpText)
3549         {
3550             INT len;
3551             len = MultiByteToWideChar( CP_ACP, 0, lprbbi->lpText, -1, NULL, 0 );
3552             if (len > 1)
3553                 wstr = (LPWSTR)Alloc (len*sizeof(WCHAR));
3554             if (wstr)
3555                 MultiByteToWideChar( CP_ACP, 0, lprbbi->lpText, -1, wstr, len );
3556         }
3557         if (REBAR_strdifW(lpBand->lpText, wstr)) {
3558             if (lpBand->lpText) {
3559                 Free (lpBand->lpText);
3560                 lpBand->lpText = NULL;
3561             }
3562             if (wstr) {
3563                 lpBand->lpText = wstr;
3564                 wstr = NULL;
3565             }
3566             bChanged = TRUE;
3567         }
3568         if (wstr)
3569             Free (wstr);
3570     }
3571
3572     REBAR_ValidateBand (infoPtr, lpBand);
3573
3574     REBAR_DumpBand (infoPtr);
3575
3576     if (bChanged && (lprbbi->fMask & (RBBIM_CHILDSIZE | RBBIM_SIZE))) {
3577           REBAR_Layout (infoPtr, NULL, TRUE, FALSE);
3578           InvalidateRect(infoPtr->hwndSelf, 0, 1);
3579     }
3580
3581     return TRUE;
3582 }
3583
3584 static LRESULT
3585 REBAR_SetBandInfoW (REBAR_INFO *infoPtr, WPARAM wParam, LPARAM lParam)
3586 {
3587     LPREBARBANDINFOW lprbbi = (LPREBARBANDINFOW)lParam;
3588     REBAR_BAND *lpBand;
3589     BOOL bChanged;
3590
3591     if (lprbbi == NULL)
3592         return FALSE;
3593     if (lprbbi->cbSize < REBARBANDINFOW_V3_SIZE)
3594         return FALSE;
3595     if ((UINT)wParam >= infoPtr->uNumBands)
3596         return FALSE;
3597
3598     TRACE("index %u\n", (UINT)wParam);
3599     REBAR_DumpBandInfo ((LPREBARBANDINFOA)lprbbi);
3600
3601     /* set band information */
3602     lpBand = &infoPtr->bands[(UINT)wParam];
3603
3604     bChanged = REBAR_CommonSetupBand (infoPtr->hwndSelf, (LPREBARBANDINFOA)lprbbi, lpBand);
3605     if( (lprbbi->fMask & RBBIM_TEXT) && 
3606         REBAR_strdifW( lpBand->lpText, lprbbi->lpText ) ) {
3607         if (lpBand->lpText) {
3608             Free (lpBand->lpText);
3609             lpBand->lpText = NULL;
3610         }
3611         if (lprbbi->lpText) {
3612             INT len = lstrlenW (lprbbi->lpText);
3613             if (len > 0)
3614             {
3615                 lpBand->lpText = (LPWSTR)Alloc ((len + 1)*sizeof(WCHAR));
3616                 strcpyW (lpBand->lpText, lprbbi->lpText);
3617             }
3618         }
3619         bChanged = TRUE;
3620     }
3621
3622     REBAR_ValidateBand (infoPtr, lpBand);
3623
3624     REBAR_DumpBand (infoPtr);
3625
3626     if ( bChanged && (lprbbi->fMask & (RBBIM_CHILDSIZE | RBBIM_SIZE)) ) {
3627       REBAR_Layout (infoPtr, NULL, TRUE, FALSE);
3628       InvalidateRect(infoPtr->hwndSelf, 0, 1);
3629     }
3630
3631     return TRUE;
3632 }
3633
3634
3635 static LRESULT
3636 REBAR_SetBarInfo (REBAR_INFO *infoPtr, WPARAM wParam, LPARAM lParam)
3637 {
3638     LPREBARINFO lpInfo = (LPREBARINFO)lParam;
3639     REBAR_BAND *lpBand;
3640     UINT i;
3641
3642     if (lpInfo == NULL)
3643         return FALSE;
3644
3645     if (lpInfo->cbSize < sizeof (REBARINFO))
3646         return FALSE;
3647
3648     TRACE("setting bar info!\n");
3649
3650     if (lpInfo->fMask & RBIM_IMAGELIST) {
3651         infoPtr->himl = lpInfo->himl;
3652         if (infoPtr->himl) {
3653             INT cx, cy;
3654             ImageList_GetIconSize (infoPtr->himl, &cx, &cy);
3655             infoPtr->imageSize.cx = cx;
3656             infoPtr->imageSize.cy = cy;
3657         }
3658         else {
3659             infoPtr->imageSize.cx = 0;
3660             infoPtr->imageSize.cy = 0;
3661         }
3662         TRACE("new image cx=%ld, cy=%ld\n", infoPtr->imageSize.cx,
3663               infoPtr->imageSize.cy);
3664     }
3665
3666     /* revalidate all bands to reset flags for images in headers of bands */
3667     for (i=0; i<infoPtr->uNumBands; i++) {
3668         lpBand = &infoPtr->bands[i];
3669         REBAR_ValidateBand (infoPtr, lpBand);
3670     }
3671
3672     return TRUE;
3673 }
3674
3675
3676 static LRESULT
3677 REBAR_SetBkColor (REBAR_INFO *infoPtr, WPARAM wParam, LPARAM lParam)
3678 {
3679     COLORREF clrTemp;
3680
3681     clrTemp = infoPtr->clrBk;
3682     infoPtr->clrBk = (COLORREF)lParam;
3683
3684     TRACE("background color 0x%06lx!\n", infoPtr->clrBk);
3685
3686     return clrTemp;
3687 }
3688
3689
3690 /* << REBAR_SetColorScheme >> */
3691 /* << REBAR_SetPalette >> */
3692
3693
3694 static LRESULT
3695 REBAR_SetParent (REBAR_INFO *infoPtr, WPARAM wParam, LPARAM lParam)
3696 {
3697     HWND hwndTemp = infoPtr->hwndNotify;
3698
3699     infoPtr->hwndNotify = (HWND)wParam;
3700
3701     return (LRESULT)hwndTemp;
3702 }
3703
3704
3705 static LRESULT
3706 REBAR_SetTextColor (REBAR_INFO *infoPtr, WPARAM wParam, LPARAM lParam)
3707 {
3708     COLORREF clrTemp;
3709
3710     clrTemp = infoPtr->clrText;
3711     infoPtr->clrText = (COLORREF)lParam;
3712
3713     TRACE("text color 0x%06lx!\n", infoPtr->clrText);
3714
3715     return clrTemp;
3716 }
3717
3718
3719 /* << REBAR_SetTooltips >> */
3720
3721
3722 inline static LRESULT
3723 REBAR_SetUnicodeFormat (REBAR_INFO *infoPtr, WPARAM wParam)
3724 {
3725     BOOL bTemp = infoPtr->bUnicode;
3726
3727     TRACE("to %s hwnd=%p, was %s\n",
3728           ((BOOL)wParam) ? "TRUE" : "FALSE", infoPtr->hwndSelf,
3729           (bTemp) ? "TRUE" : "FALSE");
3730
3731     infoPtr->bUnicode = (BOOL)wParam;
3732
3733    return bTemp;
3734 }
3735
3736
3737 static LRESULT
3738 REBAR_SetVersion (REBAR_INFO *infoPtr, INT iVersion)
3739 {
3740     INT iOldVersion = infoPtr->iVersion;
3741
3742     if (iVersion > COMCTL32_VERSION)
3743         return -1;
3744
3745     infoPtr->iVersion = iVersion;
3746
3747     TRACE("new version %d\n", iVersion);
3748
3749     return iOldVersion;
3750 }
3751
3752
3753 static LRESULT
3754 REBAR_ShowBand (REBAR_INFO *infoPtr, WPARAM wParam, LPARAM lParam)
3755 {
3756     REBAR_BAND *lpBand;
3757
3758     if (((INT)wParam < 0) || ((INT)wParam > infoPtr->uNumBands))
3759         return FALSE;
3760
3761     lpBand = &infoPtr->bands[(INT)wParam];
3762
3763     if ((BOOL)lParam) {
3764         TRACE("show band %d\n", (INT)wParam);
3765         lpBand->fStyle = lpBand->fStyle & ~RBBS_HIDDEN;
3766         if (IsWindow (lpBand->hwndChild))
3767             ShowWindow (lpBand->hwndChild, SW_SHOW);
3768     }
3769     else {
3770         TRACE("hide band %d\n", (INT)wParam);
3771         lpBand->fStyle = lpBand->fStyle | RBBS_HIDDEN;
3772         if (IsWindow (lpBand->hwndChild))
3773             ShowWindow (lpBand->hwndChild, SW_HIDE);
3774     }
3775
3776     infoPtr->fStatus |= BAND_NEEDS_LAYOUT;
3777     REBAR_Layout (infoPtr, NULL, TRUE, FALSE);
3778     InvalidateRect(infoPtr->hwndSelf, 0, 1);
3779
3780     return TRUE;
3781 }
3782
3783
3784 static LRESULT
3785 REBAR_SizeToRect (REBAR_INFO *infoPtr, WPARAM wParam, LPARAM lParam)
3786 {
3787     LPRECT lpRect = (LPRECT)lParam;
3788     RECT t1;
3789
3790     if (lpRect == NULL)
3791        return FALSE;
3792
3793     TRACE("[%ld %ld %ld %ld]\n",
3794           lpRect->left, lpRect->top, lpRect->right, lpRect->bottom);
3795
3796     /*  what is going on???? */
3797     GetWindowRect(infoPtr->hwndSelf, &t1);
3798     TRACE("window rect [%ld %ld %ld %ld]\n",
3799           t1.left, t1.top, t1.right, t1.bottom);
3800     GetClientRect(infoPtr->hwndSelf, &t1);
3801     TRACE("client rect [%ld %ld %ld %ld]\n",
3802           t1.left, t1.top, t1.right, t1.bottom);
3803
3804     /* force full _Layout processing */
3805     TRACE("setting NEEDS_LAYOUT\n");
3806     infoPtr->fStatus |= BAND_NEEDS_LAYOUT;
3807     REBAR_Layout (infoPtr, lpRect, TRUE, FALSE);
3808     InvalidateRect (infoPtr->hwndSelf, NULL, TRUE);
3809     return TRUE;
3810 }
3811
3812
3813
3814 static LRESULT
3815 REBAR_Create (REBAR_INFO *infoPtr, WPARAM wParam, LPARAM lParam)
3816 {
3817     LPCREATESTRUCTW cs = (LPCREATESTRUCTW) lParam;
3818     RECT wnrc1, clrc1;
3819     HTHEME theme;
3820
3821     if (TRACE_ON(rebar)) {
3822         GetWindowRect(infoPtr->hwndSelf, &wnrc1);
3823         GetClientRect(infoPtr->hwndSelf, &clrc1);
3824         TRACE("window=(%ld,%ld)-(%ld,%ld) client=(%ld,%ld)-(%ld,%ld) cs=(%d,%d %dx%d)\n",
3825               wnrc1.left, wnrc1.top, wnrc1.right, wnrc1.bottom,
3826               clrc1.left, clrc1.top, clrc1.right, clrc1.bottom,
3827               cs->x, cs->y, cs->cx, cs->cy);
3828     }
3829
3830     TRACE("created!\n");
3831     
3832     if ((theme = OpenThemeData (infoPtr->hwndSelf, themeClass)))
3833     {
3834         /* native seems to clear WS_BORDER when themed */
3835         infoPtr->dwStyle &= ~WS_BORDER;
3836     }
3837     
3838     return 0;
3839 }
3840
3841
3842 static LRESULT
3843 REBAR_Destroy (REBAR_INFO *infoPtr, WPARAM wParam, LPARAM lParam)
3844 {
3845     REBAR_BAND *lpBand;
3846     UINT i;
3847
3848
3849     /* free rebar bands */
3850     if ((infoPtr->uNumBands > 0) && infoPtr->bands) {
3851         /* clean up each band */
3852         for (i = 0; i < infoPtr->uNumBands; i++) {
3853             lpBand = &infoPtr->bands[i];
3854
3855             /* delete text strings */
3856             if (lpBand->lpText) {
3857                 Free (lpBand->lpText);
3858                 lpBand->lpText = NULL;
3859             }
3860             /* destroy child window */
3861             DestroyWindow (lpBand->hwndChild);
3862         }
3863
3864         /* free band array */
3865         Free (infoPtr->bands);
3866         infoPtr->bands = NULL;
3867     }
3868
3869     DestroyCursor (infoPtr->hcurArrow);
3870     DestroyCursor (infoPtr->hcurHorz);
3871     DestroyCursor (infoPtr->hcurVert);
3872     DestroyCursor (infoPtr->hcurDrag);
3873     if(infoPtr->hDefaultFont) DeleteObject (infoPtr->hDefaultFont);
3874     SetWindowLongPtrW (infoPtr->hwndSelf, 0, 0);
3875     
3876     CloseThemeData (GetWindowTheme (infoPtr->hwndSelf));
3877
3878     /* free rebar info data */
3879     Free (infoPtr);
3880     TRACE("destroyed!\n");
3881     return 0;
3882 }
3883
3884
3885 static LRESULT
3886 REBAR_EraseBkGnd (REBAR_INFO *infoPtr, WPARAM wParam, LPARAM lParam)
3887 {
3888     RECT cliprect;
3889
3890     if (GetClipBox ( (HDC)wParam, &cliprect))
3891         return REBAR_InternalEraseBkGnd (infoPtr, wParam, lParam, &cliprect);
3892     return 0;
3893 }
3894
3895
3896 static LRESULT
3897 REBAR_GetFont (REBAR_INFO *infoPtr, WPARAM wParam, LPARAM lParam)
3898 {
3899     return (LRESULT)infoPtr->hFont;
3900 }
3901
3902 static LRESULT
3903 REBAR_PushChevron(REBAR_INFO *infoPtr, WPARAM wParam, LPARAM lParam)
3904 {
3905     if (wParam >= 0 && (UINT)wParam < infoPtr->uNumBands)
3906     {
3907         NMREBARCHEVRON nmrbc;
3908         REBAR_BAND *lpBand = &infoPtr->bands[wParam];
3909
3910         TRACE("Pressed chevron on band %d\n", wParam);
3911
3912         /* redraw chevron in pushed state */
3913         lpBand->fDraw |= DRAW_CHEVRONPUSHED;
3914         RedrawWindow(infoPtr->hwndSelf, &lpBand->rcChevron,0,
3915           RDW_ERASE|RDW_INVALIDATE|RDW_UPDATENOW);
3916
3917         /* notify app so it can display a popup menu or whatever */
3918         nmrbc.uBand = wParam;
3919         nmrbc.wID = lpBand->wID;
3920         nmrbc.lParam = lpBand->lParam;
3921         nmrbc.rc = lpBand->rcChevron;
3922         nmrbc.lParamNM = lParam;
3923         REBAR_Notify((NMHDR*)&nmrbc, infoPtr, RBN_CHEVRONPUSHED);
3924
3925         /* redraw chevron in previous state */
3926         lpBand->fDraw &= ~DRAW_CHEVRONPUSHED;
3927         InvalidateRect(infoPtr->hwndSelf, &lpBand->rcChevron, TRUE);
3928
3929         return TRUE;
3930     }
3931     return FALSE;
3932 }
3933
3934 static LRESULT
3935 REBAR_LButtonDown (REBAR_INFO *infoPtr, WPARAM wParam, LPARAM lParam)
3936 {
3937     REBAR_BAND *lpBand;
3938     UINT htFlags;
3939     INT iHitBand;
3940     POINT ptMouseDown;
3941     ptMouseDown.x = (INT)LOWORD(lParam);
3942     ptMouseDown.y = (INT)HIWORD(lParam);
3943
3944     REBAR_InternalHitTest(infoPtr, &ptMouseDown, &htFlags, &iHitBand);
3945     lpBand = &infoPtr->bands[iHitBand];
3946
3947     if (htFlags == RBHT_CHEVRON)
3948     {
3949         REBAR_PushChevron(infoPtr, iHitBand, 0);
3950     }
3951     else if (htFlags == RBHT_GRABBER || htFlags == RBHT_CAPTION)
3952     {
3953         TRACE("Starting drag\n");
3954
3955         SetCapture (infoPtr->hwndSelf);
3956         infoPtr->iGrabbedBand = iHitBand;
3957
3958         /* save off the LOWORD and HIWORD of lParam as initial x,y */
3959         infoPtr->dragStart.x = (short)LOWORD(lParam);
3960         infoPtr->dragStart.y = (short)HIWORD(lParam);
3961         infoPtr->dragNow = infoPtr->dragStart;
3962         if (infoPtr->dwStyle & CCS_VERT)
3963             infoPtr->ihitoffset = infoPtr->dragStart.y - (lpBand->rcBand.top+REBAR_PRE_GRIPPER);
3964         else
3965             infoPtr->ihitoffset = infoPtr->dragStart.x - (lpBand->rcBand.left+REBAR_PRE_GRIPPER);
3966     }
3967     return 0;
3968 }
3969
3970 static LRESULT
3971 REBAR_LButtonUp (REBAR_INFO *infoPtr, WPARAM wParam, LPARAM lParam)
3972 {
3973     if (infoPtr->iGrabbedBand >= 0)
3974     {
3975         NMHDR layout;
3976         RECT rect;
3977
3978         infoPtr->dragStart.x = 0;
3979         infoPtr->dragStart.y = 0;
3980         infoPtr->dragNow = infoPtr->dragStart;
3981
3982         ReleaseCapture ();
3983
3984         if (infoPtr->fStatus & BEGIN_DRAG_ISSUED) {
3985             REBAR_Notify(&layout, infoPtr, RBN_LAYOUTCHANGED);
3986             REBAR_Notify_NMREBAR (infoPtr, infoPtr->iGrabbedBand, RBN_ENDDRAG);
3987             infoPtr->fStatus &= ~BEGIN_DRAG_ISSUED;
3988         }
3989
3990         infoPtr->iGrabbedBand = -1;
3991
3992         GetClientRect(infoPtr->hwndSelf, &rect);
3993         InvalidateRect(infoPtr->hwndSelf, NULL, TRUE);
3994     }
3995
3996     return 0;
3997 }
3998
3999 static LRESULT
4000 REBAR_MouseLeave (REBAR_INFO *infoPtr, WPARAM wParam, LPARAM lParam)
4001 {
4002     if (infoPtr->ichevronhotBand >= 0)
4003     {
4004         REBAR_BAND *lpChevronBand = &infoPtr->bands[infoPtr->ichevronhotBand];
4005         if (lpChevronBand->fDraw & DRAW_CHEVRONHOT)
4006         {
4007             lpChevronBand->fDraw &= ~DRAW_CHEVRONHOT;
4008             InvalidateRect(infoPtr->hwndSelf, &lpChevronBand->rcChevron, TRUE);
4009         }
4010     }
4011     infoPtr->iOldBand = -1;
4012     infoPtr->ichevronhotBand = -2;
4013
4014     return TRUE;
4015 }
4016
4017 static LRESULT
4018 REBAR_MouseMove (REBAR_INFO *infoPtr, WPARAM wParam, LPARAM lParam)
4019 {
4020     REBAR_BAND *lpChevronBand;
4021     POINT ptMove;
4022
4023     ptMove.x = (short)LOWORD(lParam);
4024     ptMove.y = (short)HIWORD(lParam);
4025
4026     /* if we are currently dragging a band */
4027     if (infoPtr->iGrabbedBand >= 0)
4028     {
4029         REBAR_BAND *band1, *band2;
4030     
4031         if (GetCapture() != infoPtr->hwndSelf)
4032             ERR("We are dragging but haven't got capture?!?\n");
4033
4034         band1 = &infoPtr->bands[infoPtr->iGrabbedBand-1];
4035         band2 = &infoPtr->bands[infoPtr->iGrabbedBand];
4036
4037         /* if mouse did not move much, exit */
4038         if ((abs(ptMove.x - infoPtr->dragNow.x) <= mindragx) &&
4039             (abs(ptMove.y - infoPtr->dragNow.y) <= mindragy)) return 0;
4040
4041         /* Test for valid drag case - must not be first band in row */
4042         if (infoPtr->dwStyle & CCS_VERT) {
4043             if ((ptMove.x < band2->rcBand.left) ||
4044               (ptMove.x > band2->rcBand.right) ||
4045               ((infoPtr->iGrabbedBand > 0) && (band1->iRow != band2->iRow))) {
4046                 FIXME("Cannot drag to other rows yet!!\n");
4047             }
4048             else {
4049                 REBAR_HandleLRDrag (infoPtr, &ptMove);
4050             }
4051         }
4052         else {
4053             if ((ptMove.y < band2->rcBand.top) ||
4054               (ptMove.y > band2->rcBand.bottom) ||
4055               ((infoPtr->iGrabbedBand > 0) && (band1->iRow != band2->iRow))) {
4056                 FIXME("Cannot drag to other rows yet!!\n");
4057             }
4058             else {
4059                 REBAR_HandleLRDrag (infoPtr, &ptMove);
4060             }
4061         }
4062     }
4063     else
4064     {
4065         INT iHitBand;
4066         UINT htFlags;
4067         TRACKMOUSEEVENT trackinfo;
4068
4069         REBAR_InternalHitTest(infoPtr, &ptMove, &htFlags, &iHitBand);
4070
4071         if (infoPtr->iOldBand >= 0 && infoPtr->iOldBand == infoPtr->ichevronhotBand)
4072         {
4073             lpChevronBand = &infoPtr->bands[infoPtr->ichevronhotBand];
4074             if (lpChevronBand->fDraw & DRAW_CHEVRONHOT)
4075             {
4076                 lpChevronBand->fDraw &= ~DRAW_CHEVRONHOT;
4077                 InvalidateRect(infoPtr->hwndSelf, &lpChevronBand->rcChevron, TRUE);
4078             }
4079             infoPtr->ichevronhotBand = -2;
4080         }
4081
4082         if (htFlags == RBHT_CHEVRON)
4083         {
4084             /* fill in the TRACKMOUSEEVENT struct */
4085             trackinfo.cbSize = sizeof(TRACKMOUSEEVENT);
4086             trackinfo.dwFlags = TME_QUERY;
4087             trackinfo.hwndTrack = infoPtr->hwndSelf;
4088             trackinfo.dwHoverTime = 0;
4089
4090             /* call _TrackMouseEvent to see if we are currently tracking for this hwnd */
4091             _TrackMouseEvent(&trackinfo);
4092
4093             /* Make sure tracking is enabled so we receive a WM_MOUSELEAVE message */
4094             if(!(trackinfo.dwFlags & TME_LEAVE))
4095             {
4096                 trackinfo.dwFlags = TME_LEAVE; /* notify upon leaving */
4097
4098                 /* call TRACKMOUSEEVENT so we receive a WM_MOUSELEAVE message */
4099                 /* and can properly deactivate the hot chevron */
4100                 _TrackMouseEvent(&trackinfo);
4101             }
4102
4103             lpChevronBand = &infoPtr->bands[iHitBand];
4104             if (!(lpChevronBand->fDraw & DRAW_CHEVRONHOT))
4105             {
4106                 lpChevronBand->fDraw |= DRAW_CHEVRONHOT;
4107                 InvalidateRect(infoPtr->hwndSelf, &lpChevronBand->rcChevron, TRUE);
4108                 infoPtr->ichevronhotBand = iHitBand;
4109             }
4110         }
4111         infoPtr->iOldBand = iHitBand;
4112     }
4113
4114     return 0;
4115 }
4116
4117
4118 inline static LRESULT
4119 REBAR_NCCalcSize (REBAR_INFO *infoPtr, WPARAM wParam, LPARAM lParam)
4120 {
4121     HTHEME theme;
4122     if (infoPtr->dwStyle & WS_BORDER) {
4123         InflateRect((LPRECT)lParam, -GetSystemMetrics(SM_CXEDGE),
4124                     -GetSystemMetrics(SM_CYEDGE));
4125     }
4126     else if ((theme = GetWindowTheme (infoPtr->hwndSelf)))
4127     {
4128         ((LPRECT)lParam)->top++;
4129     }
4130     TRACE("new client=(%ld,%ld)-(%ld,%ld)\n",
4131           ((LPRECT)lParam)->left, ((LPRECT)lParam)->top,
4132           ((LPRECT)lParam)->right, ((LPRECT)lParam)->bottom);
4133     return 0;
4134 }
4135
4136
4137 static LRESULT
4138 REBAR_NCCreate (HWND hwnd, WPARAM wParam, LPARAM lParam)
4139 {
4140     LPCREATESTRUCTW cs = (LPCREATESTRUCTW) lParam;
4141     REBAR_INFO *infoPtr = REBAR_GetInfoPtr (hwnd);
4142     RECT wnrc1, clrc1;
4143     NONCLIENTMETRICSW ncm;
4144     HFONT tfont;
4145     INT i;
4146
4147     if (infoPtr != NULL) {
4148         ERR("Strange info structure pointer *not* NULL\n");
4149         return FALSE;
4150     }
4151
4152     if (TRACE_ON(rebar)) {
4153         GetWindowRect(hwnd, &wnrc1);
4154         GetClientRect(hwnd, &clrc1);
4155         TRACE("window=(%ld,%ld)-(%ld,%ld) client=(%ld,%ld)-(%ld,%ld) cs=(%d,%d %dx%d)\n",
4156               wnrc1.left, wnrc1.top, wnrc1.right, wnrc1.bottom,
4157               clrc1.left, clrc1.top, clrc1.right, clrc1.bottom,
4158               cs->x, cs->y, cs->cx, cs->cy);
4159     }
4160
4161     /* allocate memory for info structure */
4162     infoPtr = (REBAR_INFO *)Alloc (sizeof(REBAR_INFO));
4163     SetWindowLongPtrW (hwnd, 0, (DWORD_PTR)infoPtr);
4164
4165     /* initialize info structure - initial values are 0 */
4166     infoPtr->clrBk = CLR_NONE;
4167     infoPtr->clrText = CLR_NONE;
4168     infoPtr->clrBtnText = GetSysColor (COLOR_BTNTEXT);
4169     infoPtr->clrBtnFace = GetSysColor (COLOR_BTNFACE);
4170     infoPtr->iOldBand = -1;
4171     infoPtr->ichevronhotBand = -2;
4172     infoPtr->iGrabbedBand = -1;
4173     infoPtr->hwndSelf = hwnd;
4174     infoPtr->DoRedraw = TRUE;
4175     infoPtr->hcurArrow = LoadCursorW (0, (LPWSTR)IDC_ARROW);
4176     infoPtr->hcurHorz  = LoadCursorW (0, (LPWSTR)IDC_SIZEWE);
4177     infoPtr->hcurVert  = LoadCursorW (0, (LPWSTR)IDC_SIZENS);
4178     infoPtr->hcurDrag  = LoadCursorW (0, (LPWSTR)IDC_SIZE);
4179     infoPtr->bUnicode = IsWindowUnicode (hwnd);
4180     infoPtr->fStatus = CREATE_RUNNING;
4181     infoPtr->hFont = GetStockObject (SYSTEM_FONT);
4182
4183     /* issue WM_NOTIFYFORMAT to get unicode status of parent */
4184     i = SendMessageW(REBAR_GetNotifyParent (infoPtr),
4185                      WM_NOTIFYFORMAT, (WPARAM)hwnd, NF_QUERY);
4186     if ((i < NFR_ANSI) || (i > NFR_UNICODE)) {
4187         ERR("wrong response to WM_NOTIFYFORMAT (%d), assuming ANSI\n", i);
4188         i = NFR_ANSI;
4189     }
4190     infoPtr->NtfUnicode = (i == NFR_UNICODE) ? 1 : 0;
4191
4192     /* Stow away the original style */
4193     infoPtr->orgStyle = cs->style;
4194     /* add necessary styles to the requested styles */
4195     infoPtr->dwStyle = cs->style | WS_VISIBLE | CCS_TOP;
4196     SetWindowLongW (hwnd, GWL_STYLE, infoPtr->dwStyle);
4197
4198     /* get font handle for Caption Font */
4199     ncm.cbSize = sizeof(ncm);
4200     SystemParametersInfoW (SPI_GETNONCLIENTMETRICS, ncm.cbSize, &ncm, 0);
4201     /* if the font is bold, set to normal */
4202     if (ncm.lfCaptionFont.lfWeight > FW_NORMAL) {
4203         ncm.lfCaptionFont.lfWeight = FW_NORMAL;
4204     }
4205     tfont = CreateFontIndirectW (&ncm.lfCaptionFont);
4206     if (tfont) {
4207         infoPtr->hFont = infoPtr->hDefaultFont = tfont;
4208     }
4209
4210 /* native does:
4211             GetSysColor (numerous);
4212             GetSysColorBrush (numerous) (see WM_SYSCOLORCHANGE);
4213            *GetStockObject (SYSTEM_FONT);
4214            *SetWindowLong (hwnd, 0, info ptr);
4215            *WM_NOTIFYFORMAT;
4216            *SetWindowLong (hwnd, GWL_STYLE, style+0x10000001);
4217                                     WS_VISIBLE = 0x10000000;
4218                                     CCS_TOP    = 0x00000001;
4219            *SystemParametersInfo (SPI_GETNONCLIENTMETRICS...);
4220            *CreateFontIndirect (lfCaptionFont from above);
4221             GetDC ();
4222             SelectObject (hdc, fontabove);
4223             GetTextMetrics (hdc, );    guessing is tmHeight
4224             SelectObject (hdc, oldfont);
4225             ReleaseDC ();
4226             GetWindowRect ();
4227             MapWindowPoints (0, parent, rectabove, 2);
4228             GetWindowRect ();
4229             GetClientRect ();
4230             ClientToScreen (clientrect);
4231             SetWindowPos (hwnd, 0, 0, 0, 0, 0, SWP_NOZORDER);
4232  */
4233     return TRUE;
4234 }
4235
4236
4237 static LRESULT
4238 REBAR_NCHitTest (REBAR_INFO *infoPtr, WPARAM wParam, LPARAM lParam)
4239 {
4240     NMMOUSE nmmouse;
4241     POINT clpt;
4242     INT i;
4243     UINT scrap;
4244     LRESULT ret = HTCLIENT;
4245
4246     /*
4247      * Differences from doc at MSDN (as observed with version 4.71 of
4248      *      comctl32.dll
4249      * 1. doc says nmmouse.pt is in screen coord, trace shows client coord.
4250      * 2. if band is not identified .dwItemSpec is 0xffffffff.
4251      * 3. native always seems to return HTCLIENT if notify return is 0.
4252      */
4253
4254     clpt.x = (short)LOWORD(lParam);
4255     clpt.y = (short)HIWORD(lParam);
4256     ScreenToClient (infoPtr->hwndSelf, &clpt);
4257     REBAR_InternalHitTest (infoPtr, &clpt, &scrap,
4258                            (INT *)&nmmouse.dwItemSpec);
4259     nmmouse.dwItemData = 0;
4260     nmmouse.pt = clpt;
4261     nmmouse.dwHitInfo = 0;
4262     if ((i = REBAR_Notify((NMHDR *) &nmmouse, infoPtr, NM_NCHITTEST))) {
4263         TRACE("notify changed return value from %ld to %d\n",
4264               ret, i);
4265         ret = (LRESULT) i;
4266     }
4267     TRACE("returning %ld, client point (%ld,%ld)\n", ret, clpt.x, clpt.y);
4268     return ret;
4269 }
4270
4271
4272 static LRESULT
4273 REBAR_NCPaint (REBAR_INFO *infoPtr, WPARAM wParam, LPARAM lParam)
4274 {
4275     RECT rcWindow;
4276     HDC hdc;
4277     HTHEME theme;
4278
4279     if (infoPtr->dwStyle & WS_MINIMIZE)
4280         return 0; /* Nothing to do */
4281
4282     if (infoPtr->dwStyle & WS_BORDER) {
4283
4284         /* adjust rectangle and draw the necessary edge */
4285         if (!(hdc = GetDCEx( infoPtr->hwndSelf, 0, DCX_USESTYLE | DCX_WINDOW )))
4286             return 0;
4287         GetWindowRect (infoPtr->hwndSelf, &rcWindow);
4288         OffsetRect (&rcWindow, -rcWindow.left, -rcWindow.top);
4289         TRACE("rect (%ld,%ld)-(%ld,%ld)\n",
4290               rcWindow.left, rcWindow.top,
4291               rcWindow.right, rcWindow.bottom);
4292         DrawEdge (hdc, &rcWindow, EDGE_ETCHED, BF_RECT);
4293         ReleaseDC( infoPtr->hwndSelf, hdc );
4294     }
4295     else if ((theme = GetWindowTheme (infoPtr->hwndSelf)))
4296     {
4297         /* adjust rectangle and draw the necessary edge */
4298         if (!(hdc = GetDCEx( infoPtr->hwndSelf, 0, DCX_USESTYLE | DCX_WINDOW )))
4299             return 0;
4300         GetWindowRect (infoPtr->hwndSelf, &rcWindow);
4301         OffsetRect (&rcWindow, -rcWindow.left, -rcWindow.top);
4302         TRACE("rect (%ld,%ld)-(%ld,%ld)\n",
4303               rcWindow.left, rcWindow.top,
4304               rcWindow.right, rcWindow.bottom);
4305         DrawThemeEdge (theme, hdc, 0, 0, &rcWindow, BDR_RAISEDINNER, BF_TOP, NULL);
4306         ReleaseDC( infoPtr->hwndSelf, hdc );
4307     }
4308
4309     return 0;
4310 }
4311
4312
4313 static LRESULT
4314 REBAR_NotifyFormat (REBAR_INFO *infoPtr, WPARAM wParam, LPARAM lParam)
4315 {
4316     INT i;
4317
4318     if (lParam == NF_REQUERY) {
4319         i = SendMessageW(REBAR_GetNotifyParent (infoPtr),
4320                          WM_NOTIFYFORMAT, (WPARAM)infoPtr->hwndSelf, NF_QUERY);
4321         if ((i < NFR_ANSI) || (i > NFR_UNICODE)) {
4322             ERR("wrong response to WM_NOTIFYFORMAT (%d), assuming ANSI\n", i);
4323             i = NFR_ANSI;
4324         }
4325         infoPtr->NtfUnicode = (i == NFR_UNICODE) ? 1 : 0;
4326         return (LRESULT)i;
4327     }
4328     return (LRESULT)((infoPtr->bUnicode) ? NFR_UNICODE : NFR_ANSI);
4329 }
4330
4331
4332 static LRESULT
4333 REBAR_Paint (REBAR_INFO *infoPtr, WPARAM wParam, LPARAM lParam)
4334 {
4335     HDC hdc;
4336     PAINTSTRUCT ps;
4337     RECT rc;
4338
4339     GetClientRect(infoPtr->hwndSelf, &rc);
4340     hdc = wParam==0 ? BeginPaint (infoPtr->hwndSelf, &ps) : (HDC)wParam;
4341
4342     TRACE("painting (%ld,%ld)-(%ld,%ld) client (%ld,%ld)-(%ld,%ld)\n",
4343           ps.rcPaint.left, ps.rcPaint.top,
4344           ps.rcPaint.right, ps.rcPaint.bottom,
4345           rc.left, rc.top, rc.right, rc.bottom);
4346
4347     if (ps.fErase) {
4348         /* Erase area of paint if requested */
4349         REBAR_InternalEraseBkGnd (infoPtr, wParam, lParam, &ps.rcPaint);
4350     }
4351
4352     REBAR_Refresh (infoPtr, hdc);
4353     if (!wParam)
4354         EndPaint (infoPtr->hwndSelf, &ps);
4355     return 0;
4356 }
4357
4358
4359 static LRESULT
4360 REBAR_SetCursor (REBAR_INFO *infoPtr, WPARAM wParam, LPARAM lParam)
4361 {
4362     POINT pt;
4363     UINT  flags;
4364
4365     TRACE("code=0x%X  id=0x%X\n", LOWORD(lParam), HIWORD(lParam));
4366
4367     GetCursorPos (&pt);
4368     ScreenToClient (infoPtr->hwndSelf, &pt);
4369
4370     REBAR_InternalHitTest (infoPtr, &pt, &flags, NULL);
4371
4372     if (flags == RBHT_GRABBER) {
4373         if ((infoPtr->dwStyle & CCS_VERT) &&
4374             !(infoPtr->dwStyle & RBS_VERTICALGRIPPER))
4375             SetCursor (infoPtr->hcurVert);
4376         else
4377             SetCursor (infoPtr->hcurHorz);
4378     }
4379     else if (flags != RBHT_CLIENT)
4380         SetCursor (infoPtr->hcurArrow);
4381
4382     return 0;
4383 }
4384
4385
4386 static LRESULT
4387 REBAR_SetFont (REBAR_INFO *infoPtr, WPARAM wParam, LPARAM lParam)
4388 {
4389     RECT rcClient;
4390     REBAR_BAND *lpBand;
4391     UINT i;
4392
4393     infoPtr->hFont = (HFONT)wParam;
4394
4395     /* revalidate all bands to change sizes of text in headers of bands */
4396     for (i=0; i<infoPtr->uNumBands; i++) {
4397         lpBand = &infoPtr->bands[i];
4398         REBAR_ValidateBand (infoPtr, lpBand);
4399     }
4400
4401
4402     if (LOWORD(lParam)) {
4403         GetClientRect (infoPtr->hwndSelf, &rcClient);
4404         REBAR_Layout (infoPtr, &rcClient, FALSE, TRUE);
4405     }
4406
4407     return 0;
4408 }
4409
4410
4411 inline static LRESULT
4412 REBAR_SetRedraw (REBAR_INFO *infoPtr, WPARAM wParam, LPARAM lParam)
4413      /*****************************************************
4414       *
4415       * Function;
4416       *  Handles the WM_SETREDRAW message.
4417       *
4418       * Documentation:
4419       *  According to testing V4.71 of COMCTL32 returns the
4420       *  *previous* status of the redraw flag (either 0 or -1)
4421       *  instead of the MSDN documented value of 0 if handled
4422       *
4423       *****************************************************/
4424 {
4425     BOOL oldredraw = infoPtr->DoRedraw;
4426
4427     TRACE("set to %s, fStatus=%08x\n",
4428           (wParam) ? "TRUE" : "FALSE", infoPtr->fStatus);
4429     infoPtr->DoRedraw = (BOOL) wParam;
4430     if (wParam) {
4431         if (infoPtr->fStatus & BAND_NEEDS_REDRAW) {
4432             REBAR_MoveChildWindows (infoPtr, 0, infoPtr->uNumBands);
4433             REBAR_ForceResize (infoPtr);
4434             InvalidateRect (infoPtr->hwndSelf, 0, TRUE);
4435         }
4436         infoPtr->fStatus &= ~BAND_NEEDS_REDRAW;
4437     }
4438     return (oldredraw) ? -1 : 0;
4439 }
4440
4441
4442 static LRESULT
4443 REBAR_Size (REBAR_INFO *infoPtr, WPARAM wParam, LPARAM lParam)
4444 {
4445     RECT rcClient;
4446
4447     /* auto resize deadlock check */
4448     if (infoPtr->fStatus & AUTO_RESIZE) {
4449         infoPtr->fStatus &= ~AUTO_RESIZE;
4450         TRACE("AUTO_RESIZE was set, reset, fStatus=%08x lparam=%08lx\n",
4451               infoPtr->fStatus, lParam);
4452         return 0;
4453     }
4454
4455     if (infoPtr->fStatus & CREATE_RUNNING) {
4456         /* still in CreateWindow */
4457         RECT rcWin;
4458
4459         if ((INT)wParam != SIZE_RESTORED) {
4460             ERR("WM_SIZE in create and flags=%08x, lParam=%08lx\n",
4461                 wParam, lParam);
4462         }
4463
4464         TRACE("still in CreateWindow\n");
4465         infoPtr->fStatus &= ~CREATE_RUNNING;
4466         GetWindowRect ( infoPtr->hwndSelf, &rcWin);
4467         TRACE("win rect (%ld,%ld)-(%ld,%ld)\n",
4468               rcWin.left, rcWin.top, rcWin.right, rcWin.bottom);
4469
4470         if ((lParam == 0) && (rcWin.right-rcWin.left == 0) &&
4471             (rcWin.bottom-rcWin.top == 0)) {
4472             /* native control seems to do this */
4473             GetClientRect (GetParent(infoPtr->hwndSelf), &rcClient);
4474             TRACE("sizing rebar, message and client zero, parent client (%ld,%ld)\n",
4475                   rcClient.right, rcClient.bottom);
4476         }
4477         else {
4478             INT cx, cy;
4479
4480             cx = rcWin.right - rcWin.left;
4481             cy = rcWin.bottom - rcWin.top;
4482             if ((cx == LOWORD(lParam)) && (cy == HIWORD(lParam))) {
4483                 return 0;
4484             }
4485
4486             /* do the actual WM_SIZE request */
4487             GetClientRect (infoPtr->hwndSelf, &rcClient);
4488             TRACE("sizing rebar from (%ld,%ld) to (%d,%d), client (%ld,%ld)\n",
4489                   infoPtr->calcSize.cx, infoPtr->calcSize.cy,
4490                   LOWORD(lParam), HIWORD(lParam),
4491                   rcClient.right, rcClient.bottom);
4492         }
4493     }
4494     else {
4495         if ((INT)wParam != SIZE_RESTORED) {
4496             ERR("WM_SIZE out of create and flags=%08x, lParam=%08lx\n",
4497                 wParam, lParam);
4498         }
4499
4500         /* Handle cases when outside of the CreateWindow process */
4501
4502         GetClientRect (infoPtr->hwndSelf, &rcClient);
4503         if ((lParam == 0) && (rcClient.right + rcClient.bottom != 0) &&
4504             (infoPtr->dwStyle & RBS_AUTOSIZE)) {
4505             /* on a WM_SIZE to zero and current client not zero and AUTOSIZE */
4506             /* native seems to use the current parent width for the size     */
4507             infoPtr->fStatus |= BAND_NEEDS_LAYOUT;
4508             GetClientRect (GetParent(infoPtr->hwndSelf), &rcClient);
4509             if (infoPtr->dwStyle & CCS_VERT)
4510                 rcClient.right = 0;
4511             else
4512                 rcClient.bottom = 0;
4513             TRACE("sizing rebar to parent (%ld,%ld) size is zero but AUTOSIZE set\n",
4514                   rcClient.right, rcClient.bottom);
4515         }
4516         else {
4517             TRACE("sizing rebar from (%ld,%ld) to (%d,%d), client (%ld,%ld)\n",
4518                   infoPtr->calcSize.cx, infoPtr->calcSize.cy,
4519                   LOWORD(lParam), HIWORD(lParam),
4520                   rcClient.right, rcClient.bottom);
4521         }
4522     }
4523
4524     if (infoPtr->dwStyle & RBS_AUTOSIZE) {
4525         NMRBAUTOSIZE autosize;
4526
4527         GetClientRect(infoPtr->hwndSelf, &autosize.rcTarget);
4528         autosize.fChanged = 0;  /* ??? */
4529         autosize.rcActual = autosize.rcTarget;  /* ??? */
4530         REBAR_Notify((NMHDR *) &autosize, infoPtr, RBN_AUTOSIZE);
4531         TRACE("RBN_AUTOSIZE client=(%ld,%ld), lp=%08lx\n",
4532               autosize.rcTarget.right, autosize.rcTarget.bottom, lParam);
4533     }
4534
4535     if ((infoPtr->calcSize.cx != rcClient.right) ||
4536         (infoPtr->calcSize.cy != rcClient.bottom))
4537         infoPtr->fStatus |= BAND_NEEDS_LAYOUT;
4538
4539     REBAR_Layout (infoPtr, &rcClient, TRUE, TRUE);
4540
4541     return 0;
4542 }
4543
4544
4545 static LRESULT
4546 REBAR_StyleChanged (REBAR_INFO *infoPtr, WPARAM wParam, LPARAM lParam)
4547 {
4548     STYLESTRUCT *ss = (STYLESTRUCT *)lParam;
4549
4550     TRACE("current style=%08lx, styleOld=%08lx, style being set to=%08lx\n",
4551           infoPtr->dwStyle, ss->styleOld, ss->styleNew);
4552     infoPtr->orgStyle = infoPtr->dwStyle = ss->styleNew;
4553     if (GetWindowTheme (infoPtr->hwndSelf))
4554         infoPtr->dwStyle &= ~WS_BORDER;
4555
4556     return FALSE;
4557 }
4558
4559 /* update theme after a WM_THEMECHANGED message */
4560 static LRESULT theme_changed (REBAR_INFO* infoPtr)
4561 {
4562     HTHEME theme = GetWindowTheme (infoPtr->hwndSelf);
4563     CloseThemeData (theme);
4564     theme = OpenThemeData (infoPtr->hwndSelf, themeClass);
4565     /* WS_BORDER disappears when theming is enabled and reappears when
4566      * disabled... */
4567     infoPtr->dwStyle &= ~WS_BORDER;
4568     infoPtr->dwStyle |= theme ? 0 : (infoPtr->orgStyle & WS_BORDER);
4569     return 0;
4570 }
4571
4572 static LRESULT
4573 REBAR_WindowPosChanged (REBAR_INFO *infoPtr, WPARAM wParam, LPARAM lParam)
4574 {
4575     WINDOWPOS *lpwp = (WINDOWPOS *)lParam;
4576     LRESULT ret;
4577     RECT rc;
4578
4579     /* Save the new origin of this window - used by _ForceResize */
4580     infoPtr->origin.x = lpwp->x;
4581     infoPtr->origin.y = lpwp->y;
4582     ret = DefWindowProcW(infoPtr->hwndSelf, WM_WINDOWPOSCHANGED,
4583                          wParam, lParam);
4584     GetWindowRect(infoPtr->hwndSelf, &rc);
4585     TRACE("hwnd %p new pos (%ld,%ld)-(%ld,%ld)\n",
4586           infoPtr->hwndSelf, rc.left, rc.top, rc.right, rc.bottom);
4587     return ret;
4588 }
4589
4590
4591 static LRESULT WINAPI
4592 REBAR_WindowProc (HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
4593 {
4594     REBAR_INFO *infoPtr = REBAR_GetInfoPtr (hwnd);
4595
4596     TRACE("hwnd=%p msg=%x wparam=%x lparam=%lx\n",
4597           hwnd, uMsg, wParam, lParam);
4598     if (!infoPtr && (uMsg != WM_NCCREATE))
4599         return DefWindowProcW (hwnd, uMsg, wParam, lParam);
4600     switch (uMsg)
4601     {
4602 /*      case RB_BEGINDRAG: */
4603
4604         case RB_DELETEBAND:
4605             return REBAR_DeleteBand (infoPtr, wParam, lParam);
4606
4607 /*      case RB_DRAGMOVE: */
4608 /*      case RB_ENDDRAG: */
4609
4610         case RB_GETBANDBORDERS:
4611             return REBAR_GetBandBorders (infoPtr, wParam, lParam);
4612
4613         case RB_GETBANDCOUNT:
4614             return REBAR_GetBandCount (infoPtr);
4615
4616         case RB_GETBANDINFO_OLD:
4617         case RB_GETBANDINFOA:
4618             return REBAR_GetBandInfoA (infoPtr, wParam, lParam);
4619
4620         case RB_GETBANDINFOW:
4621             return REBAR_GetBandInfoW (infoPtr, wParam, lParam);
4622
4623         case RB_GETBARHEIGHT:
4624             return REBAR_GetBarHeight (infoPtr, wParam, lParam);
4625
4626         case RB_GETBARINFO:
4627             return REBAR_GetBarInfo (infoPtr, wParam, lParam);
4628
4629         case RB_GETBKCOLOR:
4630             return REBAR_GetBkColor (infoPtr);
4631
4632 /*      case RB_GETCOLORSCHEME: */
4633 /*      case RB_GETDROPTARGET: */
4634
4635         case RB_GETPALETTE:
4636             return REBAR_GetPalette (infoPtr, wParam, lParam);
4637
4638         case RB_GETRECT:
4639             return REBAR_GetRect (infoPtr, wParam, lParam);
4640
4641         case RB_GETROWCOUNT:
4642             return REBAR_GetRowCount (infoPtr);
4643
4644         case RB_GETROWHEIGHT:
4645             return REBAR_GetRowHeight (infoPtr, wParam, lParam);
4646
4647         case RB_GETTEXTCOLOR:
4648             return REBAR_GetTextColor (infoPtr);
4649
4650         case RB_GETTOOLTIPS:
4651             return REBAR_GetToolTips (infoPtr);
4652
4653         case RB_GETUNICODEFORMAT:
4654             return REBAR_GetUnicodeFormat (infoPtr);
4655
4656         case CCM_GETVERSION:
4657             return REBAR_GetVersion (infoPtr);
4658
4659         case RB_HITTEST:
4660             return REBAR_HitTest (infoPtr, wParam, lParam);
4661
4662         case RB_IDTOINDEX:
4663             return REBAR_IdToIndex (infoPtr, wParam, lParam);
4664
4665         case RB_INSERTBANDA:
4666             return REBAR_InsertBandA (infoPtr, wParam, lParam);
4667
4668         case RB_INSERTBANDW:
4669             return REBAR_InsertBandW (infoPtr, wParam, lParam);
4670
4671         case RB_MAXIMIZEBAND:
4672             return REBAR_MaximizeBand (infoPtr, wParam, lParam);
4673
4674         case RB_MINIMIZEBAND:
4675             return REBAR_MinimizeBand (infoPtr, wParam, lParam);
4676
4677         case RB_MOVEBAND:
4678             return REBAR_MoveBand (infoPtr, wParam, lParam);
4679
4680         case RB_PUSHCHEVRON:
4681             return REBAR_PushChevron (infoPtr, wParam, lParam);
4682
4683         case RB_SETBANDINFOA:
4684             return REBAR_SetBandInfoA (infoPtr, wParam, lParam);
4685
4686         case RB_SETBANDINFOW:
4687             return REBAR_SetBandInfoW (infoPtr, wParam, lParam);
4688
4689         case RB_SETBARINFO:
4690             return REBAR_SetBarInfo (infoPtr, wParam, lParam);
4691
4692         case RB_SETBKCOLOR:
4693             return REBAR_SetBkColor (infoPtr, wParam, lParam);
4694
4695 /*      case RB_SETCOLORSCHEME: */
4696 /*      case RB_SETPALETTE: */
4697 /*          return REBAR_GetPalette (infoPtr, wParam, lParam); */
4698
4699         case RB_SETPARENT:
4700             return REBAR_SetParent (infoPtr, wParam, lParam);
4701
4702         case RB_SETTEXTCOLOR:
4703             return REBAR_SetTextColor (infoPtr, wParam, lParam);
4704
4705 /*      case RB_SETTOOLTIPS: */
4706
4707         case RB_SETUNICODEFORMAT:
4708             return REBAR_SetUnicodeFormat (infoPtr, wParam);
4709
4710         case CCM_SETVERSION:
4711             return REBAR_SetVersion (infoPtr, (INT)wParam);
4712
4713         case RB_SHOWBAND:
4714             return REBAR_ShowBand (infoPtr, wParam, lParam);
4715
4716         case RB_SIZETORECT:
4717             return REBAR_SizeToRect (infoPtr, wParam, lParam);
4718
4719
4720 /*    Messages passed to parent */
4721         case WM_COMMAND:
4722         case WM_DRAWITEM:
4723         case WM_NOTIFY:
4724             if (infoPtr->NtfUnicode)
4725                 return SendMessageW (REBAR_GetNotifyParent (infoPtr),
4726                                      uMsg, wParam, lParam);
4727             else
4728                 return SendMessageA (REBAR_GetNotifyParent (infoPtr),
4729                                      uMsg, wParam, lParam);
4730
4731
4732 /*      case WM_CHARTOITEM:     supported according to ControlSpy */
4733
4734         case WM_CREATE:
4735             return REBAR_Create (infoPtr, wParam, lParam);
4736
4737         case WM_DESTROY:
4738             return REBAR_Destroy (infoPtr, wParam, lParam);
4739
4740         case WM_ERASEBKGND:
4741             return REBAR_EraseBkGnd (infoPtr, wParam, lParam);
4742
4743         case WM_GETFONT:
4744             return REBAR_GetFont (infoPtr, wParam, lParam);
4745
4746 /*      case WM_LBUTTONDBLCLK:  supported according to ControlSpy */
4747
4748         case WM_LBUTTONDOWN:
4749             return REBAR_LButtonDown (infoPtr, wParam, lParam);
4750
4751         case WM_LBUTTONUP:
4752             return REBAR_LButtonUp (infoPtr, wParam, lParam);
4753
4754 /*      case WM_MEASUREITEM:    supported according to ControlSpy */
4755
4756         case WM_MOUSEMOVE:
4757             return REBAR_MouseMove (infoPtr, wParam, lParam);
4758
4759         case WM_MOUSELEAVE:
4760             return REBAR_MouseLeave (infoPtr, wParam, lParam);
4761
4762         case WM_NCCALCSIZE:
4763             return REBAR_NCCalcSize (infoPtr, wParam, lParam);
4764
4765         case WM_NCCREATE:
4766             return REBAR_NCCreate (hwnd, wParam, lParam);
4767
4768         case WM_NCHITTEST:
4769             return REBAR_NCHitTest (infoPtr, wParam, lParam);
4770
4771         case WM_NCPAINT:
4772             return REBAR_NCPaint (infoPtr, wParam, lParam);
4773
4774         case WM_NOTIFYFORMAT:
4775             return REBAR_NotifyFormat (infoPtr, wParam, lParam);
4776
4777         case WM_PRINTCLIENT:
4778         case WM_PAINT:
4779             return REBAR_Paint (infoPtr, wParam, lParam);
4780
4781 /*      case WM_PALETTECHANGED: supported according to ControlSpy */
4782 /*      case WM_QUERYNEWPALETTE:supported according to ControlSpy */
4783 /*      case WM_RBUTTONDOWN:    supported according to ControlSpy */
4784 /*      case WM_RBUTTONUP:      supported according to ControlSpy */
4785
4786         case WM_SETCURSOR:
4787             return REBAR_SetCursor (infoPtr, wParam, lParam);
4788
4789         case WM_SETFONT:
4790             return REBAR_SetFont (infoPtr, wParam, lParam);
4791
4792         case WM_SETREDRAW:
4793             return REBAR_SetRedraw (infoPtr, wParam, lParam);
4794
4795         case WM_SIZE:
4796             return REBAR_Size (infoPtr, wParam, lParam);
4797
4798         case WM_STYLECHANGED:
4799             return REBAR_StyleChanged (infoPtr, wParam, lParam);
4800
4801         case WM_THEMECHANGED:
4802             return theme_changed (infoPtr);
4803
4804 /*      case WM_SYSCOLORCHANGE: supported according to ControlSpy */
4805 /*      "Applications that have brushes using the existing system colors
4806          should delete those brushes and recreate them using the new
4807          system colors."  per MSDN                                */
4808
4809 /*      case WM_VKEYTOITEM:     supported according to ControlSpy */
4810 /*      case WM_WININICHANGE: */
4811
4812         case WM_WINDOWPOSCHANGED:
4813             return REBAR_WindowPosChanged (infoPtr, wParam, lParam);
4814
4815         default:
4816             if ((uMsg >= WM_USER) && (uMsg < WM_APP))
4817                 ERR("unknown msg %04x wp=%08x lp=%08lx\n",
4818                      uMsg, wParam, lParam);
4819             return DefWindowProcW (hwnd, uMsg, wParam, lParam);
4820     }
4821 }
4822
4823
4824 VOID
4825 REBAR_Register (void)
4826 {
4827     WNDCLASSW wndClass;
4828
4829     ZeroMemory (&wndClass, sizeof(WNDCLASSW));
4830     wndClass.style         = CS_GLOBALCLASS | CS_DBLCLKS;
4831     wndClass.lpfnWndProc   = REBAR_WindowProc;
4832     wndClass.cbClsExtra    = 0;
4833     wndClass.cbWndExtra    = sizeof(REBAR_INFO *);
4834     wndClass.hCursor       = 0;
4835     wndClass.hbrBackground = (HBRUSH)(COLOR_BTNFACE + 1);
4836 #if GLATESTING
4837     wndClass.hbrBackground = CreateSolidBrush(RGB(0,128,0));
4838 #endif
4839     wndClass.lpszClassName = REBARCLASSNAMEW;
4840
4841     RegisterClassW (&wndClass);
4842
4843     mindragx = GetSystemMetrics (SM_CXDRAG);
4844     mindragy = GetSystemMetrics (SM_CYDRAG);
4845
4846 }
4847
4848
4849 VOID
4850 REBAR_Unregister (void)
4851 {
4852     UnregisterClassW (REBARCLASSNAMEW, NULL);
4853 }