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