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