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