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