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