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