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