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