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