rebar.c 113 KB
Newer Older
1
/*
2
 * Rebar control
Alexandre Julliard's avatar
Alexandre Julliard committed
3
 *
4
 * Copyright 1998, 1999 Eric Kohl
5
 * Copyright 2007, 2008 Mikolaj Zalewski
Alexandre Julliard's avatar
Alexandre Julliard committed
6
 *
7 8 9 10 11 12 13 14 15 16 17 18
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library; if not, write to the Free Software
19
 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
20
 *
21
 * NOTES
Alexandre Julliard's avatar
Alexandre Julliard committed
22
 *
23
 * This code was audited for completeness against the documented features
24
 * of Comctl32.dll version 6.0 on Oct. 19, 2004, by Robert Shearman.
25 26 27 28
 * 
 * Unless otherwise noted, we believe this code to be complete, as per
 * the specification mentioned above.
 * If you discover missing features or bugs please note them below.
29
 *
30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76
 * TODO
 *   Styles:
 *   - RBS_DBLCLKTOGGLE
 *   - RBS_FIXEDORDER
 *   - RBS_REGISTERDROP
 *   - RBS_TOOLTIPS
 *   Messages:
 *   - RB_BEGINDRAG
 *   - RB_DRAGMOVE
 *   - RB_ENDDRAG
 *   - RB_GETBANDMARGINS
 *   - RB_GETCOLORSCHEME
 *   - RB_GETDROPTARGET
 *   - RB_GETPALETTE
 *   - RB_SETCOLORSCHEME
 *   - RB_SETPALETTE
 *   - RB_SETTOOLTIPS
 *   - WM_CHARTOITEM
 *   - WM_LBUTTONDBLCLK
 *   - WM_MEASUREITEM
 *   - WM_PALETTECHANGED
 *   - WM_QUERYNEWPALETTE
 *   - WM_RBUTTONDOWN
 *   - WM_RBUTTONUP
 *   - WM_SYSCOLORCHANGE
 *   - WM_VKEYTOITEM
 *   - WM_WININICHANGE
 *   Notifications:
 *   - NM_HCHITTEST
 *   - NM_RELEASEDCAPTURE
 *   - RBN_AUTOBREAK
 *   - RBN_GETOBJECT
 *   - RBN_MINMAX
 *   Band styles:
 *   - RBBS_FIXEDBMP
 *   Native uses (on each draw!!) SM_CYBORDER (or SM_CXBORDER for CCS_VERT)
 *   to set the size of the separator width (the value SEP_WIDTH_SIZE
 *   in here). Should be fixed!!
 */

/*
 * Testing: set to 1 to make background brush *always* green
 */
#define GLATESTING 0

/*
 * 3. REBAR_MoveChildWindows should have a loop because more than
77
 *    one pass (together with the RBN_CHILDSIZEs) is made on
78
 *    at least RB_INSERTBAND
Alexandre Julliard's avatar
Alexandre Julliard committed
79 80
 */

81
#include <stdarg.h>
82
#include <stdlib.h>
83 84
#include <string.h>

85
#include "windef.h"
86
#include "winbase.h"
87
#include "wingdi.h"
88
#include "wine/unicode.h"
89 90
#include "winuser.h"
#include "winnls.h"
Alexandre Julliard's avatar
Alexandre Julliard committed
91
#include "commctrl.h"
92
#include "comctl32.h"
93 94
#include "uxtheme.h"
#include "tmschema.h"
95
#include "wine/debug.h"
Alexandre Julliard's avatar
Alexandre Julliard committed
96

97
WINE_DEFAULT_DEBUG_CHANNEL(rebar);
98 99 100 101

typedef struct
{
    UINT    fStyle;
102
    UINT    fMask;
103 104 105 106
    COLORREF  clrFore;
    COLORREF  clrBack;
    INT     iImage;
    HWND    hwndChild;
107 108 109
    UINT    cxMinChild;     /* valid if _CHILDSIZE */
    UINT    cyMinChild;     /* valid if _CHILDSIZE */
    UINT    cx;             /* valid if _SIZE */
110 111
    HBITMAP hbmBack;
    UINT    wID;
112 113 114
    UINT    cyChild;        /* valid if _CHILDSIZE */
    UINT    cyMaxChild;     /* valid if _CHILDSIZE */
    UINT    cyIntegral;     /* valid if _CHILDSIZE */
115 116 117 118
    UINT    cxIdeal;
    LPARAM    lParam;
    UINT    cxHeader;

119 120
    INT     cxEffective;    /* current cx for band */
    UINT    cyHeader;       /* the height of the header */
121 122
    UINT    cxMinBand;      /* minimum cx for band */
    UINT    cyMinBand;      /* minimum cy for band */
123

124
    UINT    cyRowSoFar;     /* for RBS_VARHEIGHT - the height of the row if it would break on this band (set by _Layout) */
125
    INT     iRow;           /* zero-based index of the row this band assigned to */
126 127
    UINT    fStatus;        /* status flags, reset only by _Validate */
    UINT    fDraw;          /* drawing flags, reset only by _Layout */
128
    UINT    uCDret;         /* last return from NM_CUSTOMDRAW */
129
    RECT    rcBand;         /* calculated band rectangle - coordinates swapped for CCS_VERT */
130 131 132 133
    RECT    rcGripper;      /* calculated gripper rectangle */
    RECT    rcCapImage;     /* calculated caption image rectangle */
    RECT    rcCapText;      /* calculated caption text rectangle */
    RECT    rcChild;        /* calculated child rectangle */
Robert Shearman's avatar
Robert Shearman committed
134
    RECT    rcChevron;      /* calculated chevron rectangle */
135 136 137 138 139

    LPWSTR    lpText;
    HWND    hwndPrevParent;
} REBAR_BAND;

140 141 142 143 144
/* fStatus flags */
#define HAS_GRIPPER    0x00000001
#define HAS_IMAGE      0x00000002
#define HAS_TEXT       0x00000004

145
/* fDraw flags */
146 147 148
#define DRAW_GRIPPER    0x00000001
#define DRAW_IMAGE      0x00000002
#define DRAW_TEXT       0x00000004
Robert Shearman's avatar
Robert Shearman committed
149 150
#define DRAW_CHEVRONHOT 0x00000040
#define DRAW_CHEVRONPUSHED 0x00000080
151
#define NTF_INVALIDATE  0x01000000
152

153 154 155 156
typedef struct
{
    COLORREF   clrBk;       /* background color */
    COLORREF   clrText;     /* text color */
157
    COLORREF   clrBtnText;  /* system color for BTNTEXT */
158
    COLORREF   clrBtnFace;  /* system color for BTNFACE */
159
    HIMAGELIST himl;        /* handle to imagelist */
160
    UINT     uNumBands;   /* # of bands in rebar (first=0, last=uNumBands-1 */
161 162
    UINT     uNumRows;    /* # of rows of bands (first=1, last=uNumRows */
    HWND     hwndSelf;    /* handle of REBAR window itself */
163 164
    HWND     hwndToolTip; /* handle to the tool tip control */
    HWND     hwndNotify;  /* notification window (parent) */
165
    HFONT    hDefaultFont;
166 167
    HFONT    hFont;       /* handle to the rebar's font */
    SIZE     imageSize;   /* image size (image list) */
168
    DWORD    dwStyle;     /* window style */
169
    DWORD    orgStyle;    /* original style (dwStyle may change) */
170
    SIZE     calcSize;    /* calculated rebar size - coordinates swapped for CCS_VERT */
171
    BOOL     bUnicode;    /* TRUE if parent wants notify in W format */
172
    BOOL     DoRedraw;    /* TRUE to actually draw bands */
173
    UINT     fStatus;     /* Status flags (see below)  */
174 175 176 177 178
    HCURSOR  hcurArrow;   /* handle to the arrow cursor */
    HCURSOR  hcurHorz;    /* handle to the EW cursor */
    HCURSOR  hcurVert;    /* handle to the NS cursor */
    HCURSOR  hcurDrag;    /* handle to the drag cursor */
    INT      iVersion;    /* version number */
179 180
    POINT    dragStart;   /* x,y of button down */
    POINT    dragNow;     /* x,y of this MouseMove */
Robert Shearman's avatar
Robert Shearman committed
181
    INT      iOldBand;    /* last band that had the mouse cursor over it */
182
    INT      ihitoffset;  /* offset of hotspot from gripper.left */
Robert Shearman's avatar
Robert Shearman committed
183 184
    INT      ichevronhotBand; /* last band that had a hot chevron */
    INT      iGrabbedBand;/* band number of band whose gripper was grabbed */
185 186 187

    REBAR_BAND *bands;      /* pointer to the array of rebar bands */
} REBAR_INFO;
188

189
/* fStatus flags */
190
#define BEGIN_DRAG_ISSUED   0x00000001
191
#define SELF_RESIZE         0x00000002
192
#define BAND_NEEDS_REDRAW   0x00000020
193

194 195 196
/* used by Windows to mark that the header size has been set by the user and shouldn't be changed */
#define RBBS_UNDOC_FIXEDHEADER 0x40000000

197 198 199 200 201 202
/* ----   REBAR layout constants. Mostly determined by        ---- */
/* ----   experiment on WIN 98.                               ---- */

/* Width (or height) of separators between bands (either horz. or  */
/* vert.). True only if RBS_BANDBORDERS is set                     */
#define SEP_WIDTH_SIZE  2
203
#define SEP_WIDTH       ((infoPtr->dwStyle & RBS_BANDBORDERS) ? SEP_WIDTH_SIZE : 0)
Alexandre Julliard's avatar
Alexandre Julliard committed
204

205 206 207
/* Blank (background color) space between Gripper (if present)     */
/* and next item (image, text, or window). Always present          */
#define REBAR_ALWAYS_SPACE  4
Eric Kohl's avatar
Eric Kohl committed
208

209 210 211 212 213 214 215
/* Blank (background color) space after Image (if present).        */
#define REBAR_POST_IMAGE  2

/* Blank (background color) space after Text (if present).         */
#define REBAR_POST_TEXT  4

/* Height of vertical gripper in a CCS_VERT rebar.                 */
216
#define GRIPPER_HEIGHT  16
217 218 219 220 221 222 223

/* Blank (background color) space before Gripper (if present).     */
#define REBAR_PRE_GRIPPER   2

/* Width (of normal vertical gripper) or height (of horz. gripper) */
/* if present.                                                     */
#define GRIPPER_WIDTH  3
Eric Kohl's avatar
Eric Kohl committed
224

Robert Shearman's avatar
Robert Shearman committed
225 226 227
/* Width of the chevron button if present */
#define CHEVRON_WIDTH  10

228 229 230
/* the gap between the child and the next band */
#define REBAR_POST_CHILD 4

231 232 233 234
/* Height of divider for Rebar if not disabled (CCS_NODIVIDER)     */
/* either top or bottom                                            */
#define REBAR_DIVIDER  2

235 236 237
/* height of a rebar without a child */
#define REBAR_NO_CHILD_HEIGHT 4

238
/* minimum vertical height of a normal bar                        */
239 240 241
/*   or minimum width of a CCS_VERT bar - from experiment on Win2k */
#define REBAR_MINSIZE  23

242 243
/* This is the increment that is used over the band height         */
#define REBARSPACE(a)     ((a->fStyle & RBBS_CHILDEDGE) ? 2*REBAR_DIVIDER : 0)
244

245 246
/* ----   End of REBAR layout constants.                      ---- */

247
#define RB_GETBANDINFO_OLD (WM_USER+5) /* obsoleted after IE3, but we have to support it anyway */
248 249 250

/*  The following define determines if a given band is hidden      */
#define HIDDENBAND(a)  (((a)->fStyle & RBBS_HIDDEN) ||   \
251
                        ((infoPtr->dwStyle & CCS_VERT) &&         \
252 253
                         ((a)->fStyle & RBBS_NOVERT)))

254
#define REBAR_GetInfoPtr(wndPtr) ((REBAR_INFO *)GetWindowLongPtrW (hwnd, 0))
Alexandre Julliard's avatar
Alexandre Julliard committed
255

256
static LRESULT REBAR_NotifyFormat(REBAR_INFO *infoPtr, LPARAM lParam);
257
static void REBAR_AutoSize(REBAR_INFO *infoPtr, BOOL needsLayout);
258 259 260 261 262 263

/* "constant values" retrieved when DLL was initialized    */
/* FIXME we do this when the classes are registered.       */
static UINT mindragx = 0;
static UINT mindragy = 0;

264
static const char * const band_stylename[] = {
265 266 267 268 269 270 271 272 273 274 275
    "RBBS_BREAK",              /* 0001 */
    "RBBS_FIXEDSIZE",          /* 0002 */
    "RBBS_CHILDEDGE",          /* 0004 */
    "RBBS_HIDDEN",             /* 0008 */
    "RBBS_NOVERT",             /* 0010 */
    "RBBS_FIXEDBMP",           /* 0020 */
    "RBBS_VARIABLEHEIGHT",     /* 0040 */
    "RBBS_GRIPPERALWAYS",      /* 0080 */
    "RBBS_NOGRIPPER",          /* 0100 */
    NULL };

276
static const char * const band_maskname[] = {
277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293
    "RBBIM_STYLE",         /*    0x00000001 */
    "RBBIM_COLORS",        /*    0x00000002 */
    "RBBIM_TEXT",          /*    0x00000004 */
    "RBBIM_IMAGE",         /*    0x00000008 */
    "RBBIM_CHILD",         /*    0x00000010 */
    "RBBIM_CHILDSIZE",     /*    0x00000020 */
    "RBBIM_SIZE",          /*    0x00000040 */
    "RBBIM_BACKGROUND",    /*    0x00000080 */
    "RBBIM_ID",            /*    0x00000100 */
    "RBBIM_IDEALSIZE",     /*    0x00000200 */
    "RBBIM_LPARAM",        /*    0x00000400 */
    "RBBIM_HEADERSIZE",    /*    0x00000800 */
    NULL };


static CHAR line[200];

294
static const WCHAR themeClass[] = { 'R','e','b','a','r',0 };
295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328

static CHAR *
REBAR_FmtStyle( UINT style)
{
    INT i = 0;

    *line = 0;
    while (band_stylename[i]) {
	if (style & (1<<i)) {
	    if (*line != 0) strcat(line, " | ");
	    strcat(line, band_stylename[i]);
	}
	i++;
    }
    return line;
}


static CHAR *
REBAR_FmtMask( UINT mask)
{
    INT i = 0;

    *line = 0;
    while (band_maskname[i]) {
	if (mask & (1<<i)) {
	    if (*line != 0) strcat(line, " | ");
	    strcat(line, band_maskname[i]);
	}
	i++;
    }
    return line;
}

329

330
static VOID
331
REBAR_DumpBandInfo(const REBARBANDINFOW *pB)
332
{
333
    if( !TRACE_ON(rebar) ) return;
334
    TRACE("band info: ");
335
    if (pB->fMask & RBBIM_ID)
336 337 338
        TRACE("ID=%u, ", pB->wID);
    TRACE("size=%u, child=%p", pB->cbSize, pB->hwndChild);
    if (pB->fMask & RBBIM_COLORS)
339
        TRACE(", clrF=0x%06x, clrB=0x%06x", pB->clrFore, pB->clrBack);
340 341
    TRACE("\n");

342 343 344 345 346 347
    TRACE("band info: mask=0x%08x (%s)\n", pB->fMask, REBAR_FmtMask(pB->fMask));
    if (pB->fMask & RBBIM_STYLE)
	TRACE("band info: style=0x%08x (%s)\n", pB->fStyle, REBAR_FmtStyle(pB->fStyle));
    if (pB->fMask & (RBBIM_SIZE | RBBIM_IDEALSIZE | RBBIM_HEADERSIZE | RBBIM_LPARAM )) {
	TRACE("band info:");
	if (pB->fMask & RBBIM_SIZE)
348
	    TRACE(" cx=%u", pB->cx);
349
	if (pB->fMask & RBBIM_IDEALSIZE)
350
	    TRACE(" xIdeal=%u", pB->cxIdeal);
351
	if (pB->fMask & RBBIM_HEADERSIZE)
352
	    TRACE(" xHeader=%u", pB->cxHeader);
353
	if (pB->fMask & RBBIM_LPARAM)
354 355
	    TRACE(" lParam=0x%08lx", pB->lParam);
	TRACE("\n");
356 357 358
    }
    if (pB->fMask & RBBIM_CHILDSIZE)
	TRACE("band info: xMin=%u, yMin=%u, yChild=%u, yMax=%u, yIntgl=%u\n",
359
	      pB->cxMinChild,
360
	      pB->cyMinChild, pB->cyChild, pB->cyMaxChild, pB->cyIntegral);
361 362 363
}

static VOID
364
REBAR_DumpBand (const REBAR_INFO *iP)
365 366 367 368
{
    REBAR_BAND *pB;
    UINT i;

369
    if(! TRACE_ON(rebar) ) return;
370

371
    TRACE("hwnd=%p: color=%08x/%08x, bands=%u, rows=%u, cSize=%d,%d\n",
372 373
	  iP->hwndSelf, iP->clrText, iP->clrBk, iP->uNumBands, iP->uNumRows,
	  iP->calcSize.cx, iP->calcSize.cy);
374
    TRACE("hwnd=%p: flags=%08x, dragStart=%d,%d, dragNow=%d,%d, iGrabbedBand=%d\n",
375 376
	  iP->hwndSelf, iP->fStatus, iP->dragStart.x, iP->dragStart.y,
	  iP->dragNow.x, iP->dragNow.y,
Robert Shearman's avatar
Robert Shearman committed
377
	  iP->iGrabbedBand);
378 379 380
    TRACE("hwnd=%p: style=%08x, notify in Unicode=%s, redraw=%s\n",
          iP->hwndSelf, iP->dwStyle, (iP->bUnicode)?"TRUE":"FALSE",
          (iP->DoRedraw)?"TRUE":"FALSE");
381
    for (i = 0; i < iP->uNumBands; i++) {
382
	pB = &iP->bands[i];
383
	TRACE("band # %u:", i);
384
	if (pB->fMask & RBBIM_ID)
385 386 387 388
	    TRACE(" ID=%u", pB->wID);
	if (pB->fMask & RBBIM_CHILD)
	    TRACE(" child=%p", pB->hwndChild);
	if (pB->fMask & RBBIM_COLORS)
389
            TRACE(" clrF=0x%06x clrB=0x%06x", pB->clrFore, pB->clrBack);
390
	TRACE("\n");
391 392
	TRACE("band # %u: mask=0x%08x (%s)\n", i, pB->fMask, REBAR_FmtMask(pB->fMask));
	if (pB->fMask & RBBIM_STYLE)
393
	    TRACE("band # %u: style=0x%08x (%s)\n",
394
		  i, pB->fStyle, REBAR_FmtStyle(pB->fStyle));
395 396
	TRACE("band # %u: xHeader=%u",
	      i, pB->cxHeader);
397 398
	if (pB->fMask & (RBBIM_SIZE | RBBIM_IDEALSIZE | RBBIM_LPARAM )) {
	    if (pB->fMask & RBBIM_SIZE)
399
		TRACE(" cx=%u", pB->cx);
400
	    if (pB->fMask & RBBIM_IDEALSIZE)
401
		TRACE(" xIdeal=%u", pB->cxIdeal);
402
	    if (pB->fMask & RBBIM_LPARAM)
403
		TRACE(" lParam=0x%08lx", pB->lParam);
404
	}
405
	TRACE("\n");
406 407 408
	if (RBBIM_CHILDSIZE)
	    TRACE("band # %u: xMin=%u, yMin=%u, yChild=%u, yMax=%u, yIntgl=%u\n",
		  i, pB->cxMinChild, pB->cyMinChild, pB->cyChild, pB->cyMaxChild, pB->cyIntegral);
409 410 411
	if (pB->fMask & RBBIM_TEXT)
	    TRACE("band # %u: text=%s\n",
		  i, (pB->lpText) ? debugstr_w(pB->lpText) : "(null)");
412 413
        TRACE("band # %u: cxMinBand=%u, cxEffective=%u, cyMinBand=%u\n",
              i, pB->cxMinBand, pB->cxEffective, pB->cyMinBand);
414 415 416 417 418 419
        TRACE("band # %u: fStatus=%08x, fDraw=%08x, Band=(%s), Grip=(%s)\n",
              i, pB->fStatus, pB->fDraw, wine_dbgstr_rect(&pB->rcBand),
              wine_dbgstr_rect(&pB->rcGripper));
        TRACE("band # %u: Img=(%s), Txt=(%s), Child=(%s)\n",
              i, wine_dbgstr_rect(&pB->rcCapImage),
              wine_dbgstr_rect(&pB->rcCapText), wine_dbgstr_rect(&pB->rcChild));
420
    }
421

422
}
Alexandre Julliard's avatar
Alexandre Julliard committed
423

424
/* dest can be equal to src */
425
static void translate_rect(const REBAR_INFO *infoPtr, RECT *dest, const RECT *src)
426 427
{
    if (infoPtr->dwStyle & CCS_VERT) {
428 429
        int tmp;
        tmp = src->left;
430
        dest->left = src->top;
431 432 433
        dest->top = tmp;
        
        tmp = src->right;
434
        dest->right = src->bottom;
435
        dest->bottom = tmp;
436 437 438 439 440
    } else {
        *dest = *src;
    }
}

441
static int get_rect_cx(const REBAR_INFO *infoPtr, const RECT *lpRect)
442 443 444 445 446 447
{
    if (infoPtr->dwStyle & CCS_VERT)
        return lpRect->bottom - lpRect->top;
    return lpRect->right - lpRect->left;
}

448
static int get_rect_cy(const REBAR_INFO *infoPtr, const RECT *lpRect)
449 450 451 452 453 454
{
    if (infoPtr->dwStyle & CCS_VERT)
        return lpRect->right - lpRect->left;
    return lpRect->bottom - lpRect->top;
}

455
static int round_child_height(REBAR_BAND *lpBand, int cyHeight)
456 457 458
{
    int cy = 0;
    if (lpBand->cyIntegral == 0)
459
        return cyHeight;
460 461 462
    cy = max(cyHeight - (int)lpBand->cyMinChild, 0);
    cy = lpBand->cyMinChild + (cy/lpBand->cyIntegral) * lpBand->cyIntegral;
    cy = min(cy, lpBand->cyMaxChild);
463 464 465 466 467
    return cy;
}

static void update_min_band_height(const REBAR_INFO *infoPtr, REBAR_BAND *lpBand)
{
468
    lpBand->cyMinBand = max(lpBand->cyHeader,
469
        (lpBand->hwndChild ? lpBand->cyChild + REBARSPACE(lpBand) : REBAR_NO_CHILD_HEIGHT));
470 471
}

Robert Shearman's avatar
Robert Shearman committed
472 473 474 475 476 477 478 479 480 481 482 483 484 485 486
static void
REBAR_DrawChevron (HDC hdc, INT left, INT top, INT colorRef)
{
    INT x, y;
    HPEN hPen, hOldPen;

    if (!(hPen = CreatePen( PS_SOLID, 1, GetSysColor( colorRef )))) return;
    hOldPen = SelectObject ( hdc, hPen );
    x = left + 2;
    y = top;
    MoveToEx (hdc, x, y, NULL);
    LineTo (hdc, x+5, y++); x++;
    MoveToEx (hdc, x, y, NULL);
    LineTo (hdc, x+3, y++); x++;
    MoveToEx (hdc, x, y, NULL);
487
    LineTo (hdc, x+1, y);
Robert Shearman's avatar
Robert Shearman committed
488 489 490
    SelectObject( hdc, hOldPen );
    DeleteObject( hPen );
}
491 492

static HWND
493
REBAR_GetNotifyParent (const REBAR_INFO *infoPtr)
494 495 496
{
    HWND parent, owner;

497 498
    parent = infoPtr->hwndNotify;
    if (!parent) {
499 500
        parent = GetParent (infoPtr->hwndSelf);
	owner = GetWindow (infoPtr->hwndSelf, GW_OWNER);
501 502
	if (owner) parent = owner;
    }
503 504 505 506 507
    return parent;
}


static INT
508
REBAR_Notify (NMHDR *nmhdr, const REBAR_INFO *infoPtr, UINT code)
509 510 511 512 513 514
{
    HWND parent;

    parent = REBAR_GetNotifyParent (infoPtr);
    nmhdr->idFrom = GetDlgCtrlID (infoPtr->hwndSelf);
    nmhdr->hwndFrom = infoPtr->hwndSelf;
515 516
    nmhdr->code = code;

517
    TRACE("window %p, code=%08x, via %s\n", parent, code, (infoPtr->bUnicode)?"Unicode":"ANSI");
518

519
    return SendMessageW(parent, WM_NOTIFY, nmhdr->idFrom, (LPARAM)nmhdr);
520 521 522
}

static INT
523
REBAR_Notify_NMREBAR (const REBAR_INFO *infoPtr, UINT uBand, UINT code)
524 525 526 527 528 529 530 531 532 533 534 535 536 537 538 539 540 541 542 543 544
{
    NMREBAR notify_rebar;
    REBAR_BAND *lpBand;

    notify_rebar.dwMask = 0;
    if (uBand!=-1) {
	lpBand = &infoPtr->bands[uBand];
	if (lpBand->fMask & RBBIM_ID) {
	    notify_rebar.dwMask |= RBNM_ID;
	    notify_rebar.wID = lpBand->wID;
	}
	if (lpBand->fMask & RBBIM_LPARAM) {
	    notify_rebar.dwMask |= RBNM_LPARAM;
	    notify_rebar.lParam = lpBand->lParam;
	}
	if (lpBand->fMask & RBBIM_STYLE) {
	    notify_rebar.dwMask |= RBNM_STYLE;
	    notify_rebar.fStyle = lpBand->fStyle;
	}
    }
    notify_rebar.uBand = uBand;
545
    return REBAR_Notify ((NMHDR *)&notify_rebar, infoPtr, code);
546 547
}

Eric Kohl's avatar
Eric Kohl committed
548
static VOID
549
REBAR_DrawBand (HDC hdc, const REBAR_INFO *infoPtr, REBAR_BAND *lpBand)
Eric Kohl's avatar
Eric Kohl committed
550
{
551 552 553
    HFONT hOldFont = 0;
    INT oldBkMode = 0;
    NMCUSTOMDRAW nmcd;
554
    HTHEME theme = GetWindowTheme (infoPtr->hwndSelf);
555 556 557
    RECT rcBand;

    translate_rect(infoPtr, &rcBand, &lpBand->rcBand);
Eric Kohl's avatar
Eric Kohl committed
558

559 560 561 562 563 564 565 566
    if (lpBand->fDraw & DRAW_TEXT) {
	hOldFont = SelectObject (hdc, infoPtr->hFont);
	oldBkMode = SetBkMode (hdc, TRANSPARENT);
    }

    /* should test for CDRF_NOTIFYITEMDRAW here */
    nmcd.dwDrawStage = CDDS_ITEMPREPAINT;
    nmcd.hdc = hdc;
567
    nmcd.rc = rcBand;
568 569 570 571 572 573 574 575 576 577 578 579
    nmcd.rc.right = lpBand->rcCapText.right;
    nmcd.rc.bottom = lpBand->rcCapText.bottom;
    nmcd.dwItemSpec = lpBand->wID;
    nmcd.uItemState = 0;
    nmcd.lItemlParam = lpBand->lParam;
    lpBand->uCDret = REBAR_Notify ((NMHDR *)&nmcd, infoPtr, NM_CUSTOMDRAW);
    if (lpBand->uCDret == CDRF_SKIPDEFAULT) {
	if (oldBkMode != TRANSPARENT)
	    SetBkMode (hdc, oldBkMode);
	SelectObject (hdc, hOldFont);
	return;
    }
Eric Kohl's avatar
Eric Kohl committed
580 581 582

    /* draw gripper */
    if (lpBand->fDraw & DRAW_GRIPPER)
583 584 585 586 587 588 589 590 591 592 593 594 595
    {
        if (theme)
        {
            RECT rcGripper = lpBand->rcGripper;
            int partId = (infoPtr->dwStyle & CCS_VERT) ? RP_GRIPPERVERT : RP_GRIPPER;
            GetThemeBackgroundExtent (theme, hdc, partId, 0, &rcGripper, &rcGripper);
            OffsetRect (&rcGripper, lpBand->rcGripper.left - rcGripper.left,
                lpBand->rcGripper.top - rcGripper.top);
            DrawThemeBackground (theme, hdc, partId, 0, &rcGripper, NULL);
        }
        else
            DrawEdge (hdc, &lpBand->rcGripper, BDR_RAISEDINNER, BF_RECT | BF_MIDDLE);
    }
Eric Kohl's avatar
Eric Kohl committed
596 597

    /* draw caption image */
Eric Kohl's avatar
Eric Kohl committed
598
    if (lpBand->fDraw & DRAW_IMAGE) {
599
	POINT pt;
Eric Kohl's avatar
Eric Kohl committed
600

601
	/* center image */
Eric Kohl's avatar
Eric Kohl committed
602 603 604
	pt.y = (lpBand->rcCapImage.bottom + lpBand->rcCapImage.top - infoPtr->imageSize.cy)/2;
	pt.x = (lpBand->rcCapImage.right + lpBand->rcCapImage.left - infoPtr->imageSize.cx)/2;

Eric Kohl's avatar
Eric Kohl committed
605
	ImageList_Draw (infoPtr->himl, lpBand->iImage, hdc,
Eric Kohl's avatar
Eric Kohl committed
606
			pt.x, pt.y,
Eric Kohl's avatar
Eric Kohl committed
607
			ILD_TRANSPARENT);
Eric Kohl's avatar
Eric Kohl committed
608
    }
Eric Kohl's avatar
Eric Kohl committed
609 610 611

    /* draw caption text */
    if (lpBand->fDraw & DRAW_TEXT) {
612
	/* need to handle CDRF_NEWFONT here */
613
	INT oldBkMode = SetBkMode (hdc, TRANSPARENT);
614
	COLORREF oldcolor = CLR_NONE;
Guy Albertelli's avatar
Guy Albertelli committed
615 616 617 618 619 620
	COLORREF new;
	if (lpBand->clrFore != CLR_NONE) {
	    new = (lpBand->clrFore == CLR_DEFAULT) ? infoPtr->clrBtnText :
		    lpBand->clrFore;
	    oldcolor = SetTextColor (hdc, new);
	}
621
	DrawTextW (hdc, lpBand->lpText, -1, &lpBand->rcCapText,
622
		   DT_CENTER | DT_VCENTER | DT_SINGLELINE);
Eric Kohl's avatar
Eric Kohl committed
623
	if (oldBkMode != TRANSPARENT)
624
	    SetBkMode (hdc, oldBkMode);
625
	if (lpBand->clrFore != CLR_NONE)
Guy Albertelli's avatar
Guy Albertelli committed
626
	    SetTextColor (hdc, oldcolor);
627
	SelectObject (hdc, hOldFont);
Eric Kohl's avatar
Eric Kohl committed
628
    }
629

Robert Shearman's avatar
Robert Shearman committed
630 631
    if (!IsRectEmpty(&lpBand->rcChevron))
    {
632
        if (theme)
Robert Shearman's avatar
Robert Shearman committed
633
        {
634 635 636 637 638 639 640 641
            int stateId; 
            if (lpBand->fDraw & DRAW_CHEVRONPUSHED)
                stateId = CHEVS_PRESSED;
            else if (lpBand->fDraw & DRAW_CHEVRONHOT)
                stateId = CHEVS_HOT;
            else
                stateId = CHEVS_NORMAL;
            DrawThemeBackground (theme, hdc, RP_CHEVRON, stateId, &lpBand->rcChevron, NULL);
Robert Shearman's avatar
Robert Shearman committed
642
        }
643
        else
Robert Shearman's avatar
Robert Shearman committed
644
        {
645 646 647 648 649 650 651 652 653 654 655 656
            if (lpBand->fDraw & DRAW_CHEVRONPUSHED)
            {
                DrawEdge(hdc, &lpBand->rcChevron, BDR_SUNKENOUTER, BF_RECT | BF_MIDDLE);
                REBAR_DrawChevron(hdc, lpBand->rcChevron.left+1, lpBand->rcChevron.top + 11, COLOR_WINDOWFRAME);
            }
            else if (lpBand->fDraw & DRAW_CHEVRONHOT)
            {
                DrawEdge(hdc, &lpBand->rcChevron, BDR_RAISEDINNER, BF_RECT | BF_MIDDLE);
                REBAR_DrawChevron(hdc, lpBand->rcChevron.left, lpBand->rcChevron.top + 10, COLOR_WINDOWFRAME);
            }
            else
                REBAR_DrawChevron(hdc, lpBand->rcChevron.left, lpBand->rcChevron.top + 10, COLOR_WINDOWFRAME);
Robert Shearman's avatar
Robert Shearman committed
657 658 659
        }
    }

660 661 662
    if (lpBand->uCDret == (CDRF_NOTIFYPOSTPAINT | CDRF_NOTIFYITEMDRAW)) {
	nmcd.dwDrawStage = CDDS_ITEMPOSTPAINT;
	nmcd.hdc = hdc;
663
	nmcd.rc = rcBand;
664 665 666 667 668 669 670
	nmcd.rc.right = lpBand->rcCapText.right;
	nmcd.rc.bottom = lpBand->rcCapText.bottom;
	nmcd.dwItemSpec = lpBand->wID;
	nmcd.uItemState = 0;
	nmcd.lItemlParam = lpBand->lParam;
	lpBand->uCDret = REBAR_Notify ((NMHDR *)&nmcd, infoPtr, NM_CUSTOMDRAW);
    }
Eric Kohl's avatar
Eric Kohl committed
671
}
Alexandre Julliard's avatar
Alexandre Julliard committed
672 673 674


static VOID
675
REBAR_Refresh (const REBAR_INFO *infoPtr, HDC hdc)
Alexandre Julliard's avatar
Alexandre Julliard committed
676
{
Eric Kohl's avatar
Eric Kohl committed
677
    REBAR_BAND *lpBand;
678
    UINT i;
Eric Kohl's avatar
Eric Kohl committed
679

680 681
    if (!infoPtr->DoRedraw) return;

Eric Kohl's avatar
Eric Kohl committed
682 683 684
    for (i = 0; i < infoPtr->uNumBands; i++) {
	lpBand = &infoPtr->bands[i];

685
	if (HIDDENBAND(lpBand)) continue;
Eric Kohl's avatar
Eric Kohl committed
686

687
	/* now draw the band */
688
	TRACE("[%p] drawing band %i, flags=%08x\n",
689
	      infoPtr->hwndSelf, i, lpBand->fDraw);
690
	REBAR_DrawBand (hdc, infoPtr, lpBand);
Eric Kohl's avatar
Eric Kohl committed
691 692 693 694

    }
}

695

696
static void
697
REBAR_CalcHorzBand (const REBAR_INFO *infoPtr, UINT rstart, UINT rend)
698 699 700 701 702 703
     /* Function: this routine initializes all the rectangles in */
     /*  each band in a row to fit in the adjusted rcBand rect.  */
     /* *** Supports only Horizontal bars. ***                   */
{
    REBAR_BAND *lpBand;
    UINT i, xoff, yoff;
704
    RECT work;
705

706
    for(i=rstart; i<rend; i++){
707
      lpBand = &infoPtr->bands[i];
708 709 710 711 712 713 714
      if (HIDDENBAND(lpBand)) {
          SetRect (&lpBand->rcChild,
		   lpBand->rcBand.right, lpBand->rcBand.top,
		   lpBand->rcBand.right, lpBand->rcBand.bottom);
	  continue;
      }

715 716
      /* set initial gripper rectangle */
      SetRect (&lpBand->rcGripper, lpBand->rcBand.left, lpBand->rcBand.top,
717
	       lpBand->rcBand.left, lpBand->rcBand.bottom);
718 719

      /* calculate gripper rectangle */
720 721 722 723 724 725 726 727 728 729
      if ( lpBand->fStatus & HAS_GRIPPER) {
	  lpBand->fDraw |= DRAW_GRIPPER;
	  lpBand->rcGripper.left   += REBAR_PRE_GRIPPER;
	  lpBand->rcGripper.right  = lpBand->rcGripper.left + GRIPPER_WIDTH;
	  lpBand->rcGripper.top    += 2;
	  lpBand->rcGripper.bottom -= 2;

	  SetRect (&lpBand->rcCapImage,
		   lpBand->rcGripper.right+REBAR_ALWAYS_SPACE, lpBand->rcBand.top,
		   lpBand->rcGripper.right+REBAR_ALWAYS_SPACE, lpBand->rcBand.bottom);
730
      }
731 732 733 734 735
      else {  /* no gripper will be drawn */
	  xoff = 0;
	  if (lpBand->fStatus & (HAS_IMAGE | HAS_TEXT))
	      /* if no gripper but either image or text, then leave space */
	      xoff = REBAR_ALWAYS_SPACE;
736
	  SetRect (&lpBand->rcCapImage,
737 738
		   lpBand->rcBand.left+xoff, lpBand->rcBand.top,
		   lpBand->rcBand.left+xoff, lpBand->rcBand.bottom);
739 740 741
      }

      /* image is visible */
742 743 744 745 746 747 748 749 750 751 752 753 754 755
      if (lpBand->fStatus & HAS_IMAGE) {
	  lpBand->fDraw |= DRAW_IMAGE;
	  lpBand->rcCapImage.right  += infoPtr->imageSize.cx;
	  lpBand->rcCapImage.bottom = lpBand->rcCapImage.top + infoPtr->imageSize.cy;

	  /* set initial caption text rectangle */
	  SetRect (&lpBand->rcCapText,
		   lpBand->rcCapImage.right+REBAR_POST_IMAGE, lpBand->rcBand.top+1,
		   lpBand->rcBand.left+lpBand->cxHeader, lpBand->rcBand.bottom-1);
      }
      else {
	  /* set initial caption text rectangle */
	  SetRect (&lpBand->rcCapText, lpBand->rcCapImage.right, lpBand->rcBand.top+1,
		   lpBand->rcBand.left+lpBand->cxHeader, lpBand->rcBand.bottom-1);
756
      }
Eric Kohl's avatar
Eric Kohl committed
757

758
      /* text is visible */
759
      if ((lpBand->fStatus & HAS_TEXT) && !(lpBand->fStyle & RBBS_HIDETITLE)) {
760
	  lpBand->fDraw |= DRAW_TEXT;
761
	  lpBand->rcCapText.right = max(lpBand->rcCapText.left,
762
					lpBand->rcCapText.right-REBAR_POST_TEXT);
763
      }
Eric Kohl's avatar
Eric Kohl committed
764

765
      /* set initial child window rectangle if there is a child */
766 767 768
      if (lpBand->hwndChild != NULL) {
          int cyBand = lpBand->rcBand.bottom - lpBand->rcBand.top;
          yoff = (cyBand - lpBand->cyChild) / 2;
769
	  SetRect (&lpBand->rcChild,
770 771
                   lpBand->rcBand.left + lpBand->cxHeader, lpBand->rcBand.top + yoff,
                   lpBand->rcBand.right - REBAR_POST_CHILD, lpBand->rcBand.top + yoff + lpBand->cyChild);
Robert Shearman's avatar
Robert Shearman committed
772 773 774 775 776 777 778
	  if ((lpBand->fStyle & RBBS_USECHEVRON) && (lpBand->rcChild.right - lpBand->rcChild.left < lpBand->cxIdeal))
	  {
	      lpBand->rcChild.right -= CHEVRON_WIDTH;
	      SetRect(&lpBand->rcChevron, lpBand->rcChild.right,
	              lpBand->rcChild.top, lpBand->rcChild.right + CHEVRON_WIDTH,
	              lpBand->rcChild.bottom);
	  }
779 780
      }
      else {
781 782 783
          SetRect (&lpBand->rcChild,
		   lpBand->rcBand.left+lpBand->cxHeader, lpBand->rcBand.top,
		   lpBand->rcBand.right, lpBand->rcBand.bottom);
784 785
      }

786 787
      /* flag if notify required and invalidate rectangle */
      if (lpBand->fDraw & NTF_INVALIDATE) {
788
          TRACE("invalidating (%d,%d)-(%d,%d)\n",
789
		lpBand->rcBand.left,
790
		lpBand->rcBand.top,
791 792
		lpBand->rcBand.right + SEP_WIDTH,
		lpBand->rcBand.bottom + SEP_WIDTH);
793 794
	  lpBand->fDraw &= ~NTF_INVALIDATE;
	  work = lpBand->rcBand;
795 796
	  work.right += SEP_WIDTH;
	  work.bottom += SEP_WIDTH;
797
	  InvalidateRect(infoPtr->hwndSelf, &work, TRUE);
798
	  InvalidateRect(lpBand->hwndChild, NULL, TRUE);
799
      }
Eric Kohl's avatar
Eric Kohl committed
800 801 802 803 804

    }

}

805 806

static VOID
807
REBAR_CalcVertBand (const REBAR_INFO *infoPtr, UINT rstart, UINT rend)
808 809 810
     /* Function: this routine initializes all the rectangles in */
     /*  each band in a row to fit in the adjusted rcBand rect.  */
     /* *** Supports only Vertical bars. ***                     */
811
{
812
    REBAR_BAND *lpBand;
813 814
    UINT i, xoff;
    RECT work;
815

816
    for(i=rstart; i<rend; i++){
817 818
        RECT rcBand;
        lpBand = &infoPtr->bands[i];
819
	if (HIDDENBAND(lpBand)) continue;
820

821 822 823 824
        translate_rect(infoPtr, &rcBand, &lpBand->rcBand);

        /* set initial gripper rectangle */
	SetRect (&lpBand->rcGripper, rcBand.left, rcBand.top, rcBand.right, rcBand.top);
825

826 827 828 829
	/* calculate gripper rectangle */
	if (lpBand->fStatus & HAS_GRIPPER) {
	    lpBand->fDraw |= DRAW_GRIPPER;

830
	    if (infoPtr->dwStyle & RBS_VERTICALGRIPPER) {
831 832 833 834 835 836 837
		/*  vertical gripper  */
		lpBand->rcGripper.left   += 3;
		lpBand->rcGripper.right  = lpBand->rcGripper.left + GRIPPER_WIDTH;
		lpBand->rcGripper.top    += REBAR_PRE_GRIPPER;
		lpBand->rcGripper.bottom = lpBand->rcGripper.top + GRIPPER_HEIGHT;

		/* initialize Caption image rectangle  */
838
		SetRect (&lpBand->rcCapImage, rcBand.left,
839
			 lpBand->rcGripper.bottom + REBAR_ALWAYS_SPACE,
840
			 rcBand.right,
841 842 843 844
			 lpBand->rcGripper.bottom + REBAR_ALWAYS_SPACE);
	    }
	    else {
		/*  horizontal gripper  */
845 846
		lpBand->rcGripper.left   += 2;
		lpBand->rcGripper.right  -= 2;
847 848 849 850
		lpBand->rcGripper.top    += REBAR_PRE_GRIPPER;
		lpBand->rcGripper.bottom  = lpBand->rcGripper.top + GRIPPER_WIDTH;

		/* initialize Caption image rectangle  */
851
		SetRect (&lpBand->rcCapImage, rcBand.left,
852
			 lpBand->rcGripper.bottom + REBAR_ALWAYS_SPACE,
853
			 rcBand.right,
854 855
			 lpBand->rcGripper.bottom + REBAR_ALWAYS_SPACE);
	    }
856
	}
857 858 859 860 861
	else {  /* no gripper will be drawn */
	    xoff = 0;
	    if (lpBand->fStatus & (HAS_IMAGE | HAS_TEXT))
		/* if no gripper but either image or text, then leave space */
		xoff = REBAR_ALWAYS_SPACE;
862
	    /* initialize Caption image rectangle  */
863
	    SetRect (&lpBand->rcCapImage,
864 865
                      rcBand.left, rcBand.top+xoff,
                      rcBand.right, rcBand.top+xoff);
866 867
	}

868 869 870 871 872 873 874 875
	/* image is visible */
	if (lpBand->fStatus & HAS_IMAGE) {
	    lpBand->fDraw |= DRAW_IMAGE;

	    lpBand->rcCapImage.right  = lpBand->rcCapImage.left + infoPtr->imageSize.cx;
	    lpBand->rcCapImage.bottom += infoPtr->imageSize.cy;

	    /* set initial caption text rectangle */
876
	    SetRect (&lpBand->rcCapText,
877 878
		     rcBand.left, lpBand->rcCapImage.bottom+REBAR_POST_IMAGE,
		     rcBand.right, rcBand.top+lpBand->cxHeader);
879 880 881
	}
	else {
	    /* set initial caption text rectangle */
882
	    SetRect (&lpBand->rcCapText,
883 884
		     rcBand.left, lpBand->rcCapImage.bottom,
		     rcBand.right, rcBand.top+lpBand->cxHeader);
885 886
	}

887
	/* text is visible */
888
	if ((lpBand->fStatus & HAS_TEXT) && !(lpBand->fStyle & RBBS_HIDETITLE)) {
889 890
	    lpBand->fDraw |= DRAW_TEXT;
	    lpBand->rcCapText.bottom = max(lpBand->rcCapText.top,
891
					   lpBand->rcCapText.bottom);
892
	}
893

894
	/* set initial child window rectangle if there is a child */
895 896 897
	if (lpBand->hwndChild != NULL) {
            int cxBand = rcBand.right - rcBand.left;
            xoff = (cxBand - lpBand->cyChild) / 2;
898
	    SetRect (&lpBand->rcChild,
899 900
		     rcBand.left + xoff,                   rcBand.top + lpBand->cxHeader,
                     rcBand.left + xoff + lpBand->cyChild, rcBand.bottom - REBAR_POST_CHILD);
901 902 903
	}
	else {
	    SetRect (&lpBand->rcChild,
904 905
		     rcBand.left, rcBand.top+lpBand->cxHeader,
		     rcBand.right, rcBand.bottom);
906
	}
907

908
	if (lpBand->fDraw & NTF_INVALIDATE) {
909
            TRACE("invalidating (%d,%d)-(%d,%d)\n",
910 911 912 913
                  rcBand.left,
                  rcBand.top,
                  rcBand.right + SEP_WIDTH,
                  rcBand.bottom + SEP_WIDTH);
914
	    lpBand->fDraw &= ~NTF_INVALIDATE;
915 916 917
	    work = rcBand;
	    work.bottom += SEP_WIDTH;
	    work.right += SEP_WIDTH;
918
	    InvalidateRect(infoPtr->hwndSelf, &work, TRUE);
919
	    InvalidateRect(lpBand->hwndChild, NULL, TRUE);
Eric Kohl's avatar
Eric Kohl committed
920
	}
921

922 923 924 925
    }
}


Eric Kohl's avatar
Eric Kohl committed
926
static VOID
927 928 929 930
REBAR_ForceResize (REBAR_INFO *infoPtr)
     /* Function: This changes the size of the REBAR window to that */
     /*  calculated by REBAR_Layout.                                */
{
931
    INT x, y, width, height;
932 933
    INT xedge = 0, yedge = 0;
    RECT rcSelf;
934

935
    TRACE("new size [%d x %d]\n", infoPtr->calcSize.cx, infoPtr->calcSize.cy);
936

937 938 939
    if (infoPtr->dwStyle & CCS_NORESIZE)
        return;

940 941 942 943 944
    if (infoPtr->dwStyle & WS_BORDER)
    {
        xedge = GetSystemMetrics(SM_CXEDGE);
        yedge = GetSystemMetrics(SM_CYEDGE);
        /* swap for CCS_VERT? */
945 946
    }

947 948 949 950
    /* compute rebar window rect in parent client coordinates */
    GetWindowRect(infoPtr->hwndSelf, &rcSelf);
    MapWindowPoints(HWND_DESKTOP, GetParent(infoPtr->hwndSelf), (LPPOINT)&rcSelf, 2);
    translate_rect(infoPtr, &rcSelf, &rcSelf);
951

952
    height = infoPtr->calcSize.cy + 2*yedge;
953
    if (!(infoPtr->dwStyle & CCS_NOPARENTALIGN)) {
954 955 956
        RECT rcParent;

        x = -xedge;
957
        width = infoPtr->calcSize.cx + 2*xedge;
958 959 960 961 962 963 964 965 966 967 968 969
        y = 0; /* quiet compiler warning */
        switch ( infoPtr->dwStyle & CCS_LAYOUT_MASK) {
            case 0:     /* shouldn't happen - see NCCreate */
            case CCS_TOP:
                y = ((infoPtr->dwStyle & CCS_NODIVIDER) ? 0 : REBAR_DIVIDER) - yedge;
                break;
            case CCS_NOMOVEY:
                y = rcSelf.top;
                break;
            case CCS_BOTTOM:
                GetClientRect(GetParent(infoPtr->hwndSelf), &rcParent);
                translate_rect(infoPtr, &rcParent, &rcParent);
970
                y = rcParent.bottom - infoPtr->calcSize.cy - yedge;
971
                break;
972 973 974
	}
    }
    else {
975 976 977 978 979
	x = rcSelf.left;
	/* As on Windows if the CCS_NODIVIDER is not present the control will move
	 * 2 pixel down after every layout */
	y = rcSelf.top + ((infoPtr->dwStyle & CCS_NODIVIDER) ? 0 : REBAR_DIVIDER);
	width = rcSelf.right - rcSelf.left;
980 981
    }

982
    TRACE("hwnd %p, style=%08x, setting at (%d,%d) for (%d,%d)\n",
983 984 985
	infoPtr->hwndSelf, infoPtr->dwStyle, x, y, width, height);

    /* Set flag to ignore next WM_SIZE message and resize the window */
986
    infoPtr->fStatus |= SELF_RESIZE;
987 988 989 990
    if ((infoPtr->dwStyle & CCS_VERT) == 0)
        SetWindowPos(infoPtr->hwndSelf, 0, x, y, width, height, SWP_NOZORDER);
    else
        SetWindowPos(infoPtr->hwndSelf, 0, y, x, height, width, SWP_NOZORDER);
991
    infoPtr->fStatus &= ~SELF_RESIZE;
992 993 994 995
}


static VOID
996
REBAR_MoveChildWindows (const REBAR_INFO *infoPtr, UINT start, UINT endplus)
997
{
998
    static const WCHAR strComboBox[] = { 'C','o','m','b','o','B','o','x',0 };
999
    REBAR_BAND *lpBand;
1000
    WCHAR szClassName[40];
1001 1002 1003 1004 1005 1006 1007 1008 1009 1010 1011 1012
    UINT i;
    NMREBARCHILDSIZE  rbcz;
    HDWP deferpos;

    if (!(deferpos = BeginDeferWindowPos(infoPtr->uNumBands)))
        ERR("BeginDeferWindowPos returned NULL\n");

    for (i = start; i < endplus; i++) {
	lpBand = &infoPtr->bands[i];

	if (HIDDENBAND(lpBand)) continue;
	if (lpBand->hwndChild) {
1013
	    TRACE("hwndChild = %p\n", lpBand->hwndChild);
1014

1015
	    /* Always generate the RBN_CHILDSIZE even if child
1016 1017 1018 1019
		   did not change */
	    rbcz.uBand = i;
	    rbcz.wID = lpBand->wID;
	    rbcz.rcChild = lpBand->rcChild;
1020
            translate_rect(infoPtr, &rbcz.rcBand, &lpBand->rcBand);
1021
	    if (infoPtr->dwStyle & CCS_VERT)
1022 1023 1024
		rbcz.rcBand.top += lpBand->cxHeader;
	    else
		rbcz.rcBand.left += lpBand->cxHeader;
1025 1026 1027
	    REBAR_Notify ((NMHDR *)&rbcz, infoPtr, RBN_CHILDSIZE);
	    if (!EqualRect (&lpBand->rcChild, &rbcz.rcChild)) {
		TRACE("Child rect changed by NOTIFY for band %u\n", i);
1028 1029 1030
                TRACE("    from (%s)  to (%s)\n",
                      wine_dbgstr_rect(&lpBand->rcChild),
                      wine_dbgstr_rect(&rbcz.rcChild));
1031
		lpBand->rcChild = rbcz.rcChild;  /* *** ??? */
1032
            }
1033

1034 1035 1036 1037 1038 1039 1040 1041
	    /* native (IE4 in "Favorites" frame **1) does:
	     *   SetRect (&rc, -1, -1, -1, -1)
	     *   EqualRect (&rc,band->rc???)
	     *   if ret==0
	     *     CopyRect (band->rc????, &rc)
	     *     set flag outside of loop
	     */

1042 1043 1044
	    GetClassNameW (lpBand->hwndChild, szClassName, sizeof(szClassName)/sizeof(szClassName[0]));
	    if (!lstrcmpW (szClassName, strComboBox) ||
		!lstrcmpW (szClassName, WC_COMBOBOXEXW)) {
1045 1046 1047 1048 1049 1050 1051 1052 1053 1054 1055 1056
		INT nEditHeight, yPos;
		RECT rc;

		/* special placement code for combo or comboex box */


		/* get size of edit line */
		GetWindowRect (lpBand->hwndChild, &rc);
		nEditHeight = rc.bottom - rc.top;
		yPos = (lpBand->rcChild.bottom + lpBand->rcChild.top - nEditHeight)/2;

		/* center combo box inside child area */
1057
		TRACE("moving child (Combo(Ex)) %p to (%d,%d) for (%d,%d)\n",
1058 1059 1060 1061 1062 1063 1064 1065 1066 1067 1068 1069 1070 1071
		      lpBand->hwndChild,
		      lpBand->rcChild.left, yPos,
		      lpBand->rcChild.right - lpBand->rcChild.left,
		      nEditHeight);
		deferpos = DeferWindowPos (deferpos, lpBand->hwndChild, HWND_TOP,
					   lpBand->rcChild.left,
					   /*lpBand->rcChild.top*/ yPos,
					   lpBand->rcChild.right - lpBand->rcChild.left,
					   nEditHeight,
					   SWP_NOZORDER);
		if (!deferpos)
		    ERR("DeferWindowPos returned NULL\n");
	    }
	    else {
1072
		TRACE("moving child (Other) %p to (%d,%d) for (%d,%d)\n",
1073 1074 1075 1076 1077 1078 1079 1080 1081 1082 1083 1084 1085 1086 1087 1088 1089
		      lpBand->hwndChild,
		      lpBand->rcChild.left, lpBand->rcChild.top,
		      lpBand->rcChild.right - lpBand->rcChild.left,
		      lpBand->rcChild.bottom - lpBand->rcChild.top);
		deferpos = DeferWindowPos (deferpos, lpBand->hwndChild, HWND_TOP,
					   lpBand->rcChild.left,
					   lpBand->rcChild.top,
					   lpBand->rcChild.right - lpBand->rcChild.left,
					   lpBand->rcChild.bottom - lpBand->rcChild.top,
					   SWP_NOZORDER);
		if (!deferpos)
		    ERR("DeferWindowPos returned NULL\n");
	    }
	}
    }
    if (!EndDeferWindowPos(deferpos))
        ERR("EndDeferWindowPos returned NULL\n");
1090

1091 1092
    if (infoPtr->DoRedraw)
	UpdateWindow (infoPtr->hwndSelf);
1093 1094 1095 1096 1097 1098 1099 1100 1101

    /* native (from **1 above) does:
     *      UpdateWindow(rebar)
     *      REBAR_ForceResize
     *      RBN_HEIGHTCHANGE if necessary
     *      if ret from any EqualRect was 0
     *         Goto "BeginDeferWindowPos"
     */

1102 1103
}

1104 1105 1106
/* Returns the next visible band (the first visible band in [i+1; infoPtr->uNumBands) )
 * or infoPtr->uNumBands if none */
static int next_visible(const REBAR_INFO *infoPtr, int i)
1107 1108 1109 1110 1111 1112 1113
{
    int n;
    for (n = i + 1; n < infoPtr->uNumBands; n++)
        if (!HIDDENBAND(&infoPtr->bands[n]))
            break;
    return n;
}
1114

1115 1116 1117
/* Returns the previous visible band (the last visible band in [0; i) )
 * or -1 if none */
static int prev_visible(const REBAR_INFO *infoPtr, int i)
1118 1119 1120 1121 1122 1123 1124
{
    int n;
    for (n = i - 1; n >= 0; n--)
        if (!HIDDENBAND(&infoPtr->bands[n]))
            break;
    return n;
}
1125

1126 1127 1128 1129 1130 1131 1132
/* Returns the first visible band or infoPtr->uNumBands if none */
static int first_visible(const REBAR_INFO *infoPtr)
{
    return next_visible(infoPtr, -1); /* this works*/
}

/* Returns the first visible band for the given row (or iBand if none) */
1133
static int get_row_begin_for_band(const REBAR_INFO *infoPtr, INT iBand)
1134 1135 1136
{
    int iLastBand = iBand;
    int iRow = infoPtr->bands[iBand].iRow;
1137
    while ((iBand = prev_visible(infoPtr, iBand)) >= 0) {
1138 1139
        if (infoPtr->bands[iBand].iRow != iRow)
            break;
1140
        else
1141 1142 1143 1144
            iLastBand = iBand;
    }
    return iLastBand;
}
1145

1146
/* Returns the first visible band for the next row (or infoPtr->uNumBands if none) */
1147
static int get_row_end_for_band(const REBAR_INFO *infoPtr, INT iBand)
1148 1149
{
    int iRow = infoPtr->bands[iBand].iRow;
1150
    while ((iBand = next_visible(infoPtr, iBand)) < infoPtr->uNumBands)
1151 1152 1153 1154
        if (infoPtr->bands[iBand].iRow != iRow)
            break;
    return iBand;
}
1155

Austin English's avatar
Austin English committed
1156
/* Compute the rcBand.{left,right} from the cxEffective bands widths computed earlier.
1157
 * iBeginBand must be visible */
1158
static void REBAR_SetRowRectsX(const REBAR_INFO *infoPtr, INT iBeginBand, INT iEndBand)
1159 1160
{
    int xPos = 0, i;
1161
    for (i = iBeginBand; i < iEndBand; i = next_visible(infoPtr, i))
1162 1163
    {
        REBAR_BAND *lpBand = &infoPtr->bands[i];
1164

1165 1166 1167 1168 1169 1170 1171 1172
        lpBand = &infoPtr->bands[i];
        if (lpBand->rcBand.left != xPos || lpBand->rcBand.right != xPos + lpBand->cxEffective) {
            lpBand->fDraw |= NTF_INVALIDATE;
            TRACE("Setting rect %d to %d,%d\n", i, xPos, xPos + lpBand->cxEffective);
            lpBand->rcBand.left = xPos;
            lpBand->rcBand.right = xPos + lpBand->cxEffective;
        }
        xPos += lpBand->cxEffective + SEP_WIDTH;
1173
    }
1174
}
1175

1176 1177 1178 1179 1180 1181
/* The rationale of this function is probably as follows: if we have some space
 * to distribute we want to add it to a band on the right. However we don't want
 * to unminimize a minimized band so we search for a band that is big enough.
 * For some reason "big enough" is defined as bigger than the minimum size of the
 * first band in the row
 */
1182
static REBAR_BAND *REBAR_FindBandToGrow(const REBAR_INFO *infoPtr, INT iBeginBand, INT iEndBand)
1183
{
1184
    INT cxMinFirstBand = 0, i;
1185

1186
    cxMinFirstBand = infoPtr->bands[iBeginBand].cxMinBand;
1187

1188
    for (i = prev_visible(infoPtr, iEndBand); i >= iBeginBand; i = prev_visible(infoPtr, i))
1189
        if (infoPtr->bands[i].cxEffective > cxMinFirstBand && !(infoPtr->bands[i].fStyle&RBBS_FIXEDSIZE))
1190
            break;
1191

1192
    if (i < iBeginBand)
1193
        for (i = prev_visible(infoPtr, iEndBand); i >= iBeginBand; i = prev_visible(infoPtr, i))
1194
            if (infoPtr->bands[i].cxMinBand == cxMinFirstBand)
1195
                break;
1196

1197 1198 1199
    TRACE("Extra space for row [%d..%d) should be added to band %d\n", iBeginBand, iEndBand, i);
    return &infoPtr->bands[i];
}
1200

1201
/* Try to shrink the visible bands in [iBeginBand; iEndBand) by cxShrink, starting from the right */
1202
static int REBAR_ShrinkBandsRTL(const REBAR_INFO *infoPtr, INT iBeginBand, INT iEndBand, INT cxShrink, BOOL bEnforce)
1203 1204 1205
{
    REBAR_BAND *lpBand;
    INT width, i;
1206

1207
    TRACE("Shrinking bands [%d..%d) by %d, right-to-left\n", iBeginBand, iEndBand, cxShrink);
1208
    for (i = prev_visible(infoPtr, iEndBand); i >= iBeginBand; i = prev_visible(infoPtr, i))
1209 1210
    {
        lpBand = &infoPtr->bands[i];
1211

1212
        width = max(lpBand->cxEffective - cxShrink, (int)lpBand->cxMinBand);
1213 1214 1215 1216 1217 1218
        cxShrink -= lpBand->cxEffective - width;
        lpBand->cxEffective = width;
        if (bEnforce && lpBand->cx > lpBand->cxEffective)
            lpBand->cx = lpBand->cxEffective;
        if (cxShrink == 0)
            break;
1219
    }
1220 1221
    return cxShrink;
}
1222 1223


1224 1225
/* Try to shrink the visible bands in [iBeginBand; iEndBand) by cxShrink, starting from the left.
 * iBeginBand must be visible */
1226
static int REBAR_ShrinkBandsLTR(const REBAR_INFO *infoPtr, INT iBeginBand, INT iEndBand, INT cxShrink, BOOL bEnforce)
1227 1228 1229
{
    REBAR_BAND *lpBand;
    INT width, i;
1230

1231
    TRACE("Shrinking bands [%d..%d) by %d, left-to-right\n", iBeginBand, iEndBand, cxShrink);
1232
    for (i = iBeginBand; i < iEndBand; i = next_visible(infoPtr, i))
1233 1234
    {
        lpBand = &infoPtr->bands[i];
1235

1236
        width = max(lpBand->cxEffective - cxShrink, (int)lpBand->cxMinBand);
1237 1238 1239 1240 1241 1242
        cxShrink -= lpBand->cxEffective - width;
        lpBand->cxEffective = width;
        if (bEnforce)
            lpBand->cx = lpBand->cxEffective;
        if (cxShrink == 0)
            break;
Eric Kohl's avatar
Eric Kohl committed
1243
    }
1244 1245
    return cxShrink;
}
1246

1247
/* Set the heights of the visible bands in [iBeginBand; iEndBand) to the max height. iBeginBand must be visible */
1248
static int REBAR_SetBandsHeight(const REBAR_INFO *infoPtr, INT iBeginBand, INT iEndBand, INT yStart)
1249 1250 1251 1252 1253 1254
{
    REBAR_BAND *lpBand;
    int yMaxHeight = 0;
    int yPos = yStart;
    int row = infoPtr->bands[iBeginBand].iRow;
    int i;
1255
    for (i = iBeginBand; i < iEndBand; i = next_visible(infoPtr, i))
1256 1257
    {
        lpBand = &infoPtr->bands[i];
1258
        lpBand->cyRowSoFar = yMaxHeight;
1259
        yMaxHeight = max(yMaxHeight, lpBand->cyMinBand);
1260 1261
    }
    TRACE("Bands [%d; %d) height: %d\n", iBeginBand, iEndBand, yMaxHeight);
1262

1263
    for (i = iBeginBand; i < iEndBand; i = next_visible(infoPtr, i))
1264 1265 1266 1267 1268 1269
    {
        lpBand = &infoPtr->bands[i];
        /* we may be called for multiple rows if RBS_VARHEIGHT not set */
        if (lpBand->iRow != row) {
            yPos += yMaxHeight + SEP_WIDTH;
            row = lpBand->iRow;
1270
        }
1271 1272 1273 1274 1275 1276

        if (lpBand->rcBand.top != yPos || lpBand->rcBand.bottom != yPos + yMaxHeight) {
            lpBand->fDraw |= NTF_INVALIDATE;
            lpBand->rcBand.top = yPos;
            lpBand->rcBand.bottom = yPos + yMaxHeight;
            TRACE("Band %d: %s\n", i, wine_dbgstr_rect(&lpBand->rcBand));
1277 1278
        }
    }
1279 1280
    return yPos + yMaxHeight;
}
1281

1282
/* Layout the row [iBeginBand; iEndBand). iBeginBand must be visible */
1283
static void REBAR_LayoutRow(const REBAR_INFO *infoPtr, int iBeginBand, int iEndBand, int cx, int *piRow, int *pyPos)
1284 1285 1286 1287
{
    REBAR_BAND *lpBand;
    int i, extra;
    int width = 0;
1288

1289 1290 1291
    TRACE("Adjusting row [%d;%d). Width: %d\n", iBeginBand, iEndBand, cx);
    for (i = iBeginBand; i < iEndBand; i++)
        infoPtr->bands[i].iRow = *piRow;
1292

1293
    /* compute the extra space */
1294
    for (i = iBeginBand; i < iEndBand; i = next_visible(infoPtr, i))
1295 1296 1297 1298
    {
        lpBand = &infoPtr->bands[i];
        if (i > iBeginBand)
            width += SEP_WIDTH;
1299
        lpBand->cxEffective = max(lpBand->cxMinBand, lpBand->cx);
1300 1301 1302 1303 1304 1305 1306
        width += lpBand->cxEffective;
    }

    extra = cx - width;
    TRACE("Extra space: %d\n", extra);
    if (extra < 0) {
        int ret = REBAR_ShrinkBandsRTL(infoPtr, iBeginBand, iEndBand, -extra, FALSE);
1307
        if (ret > 0 && next_visible(infoPtr, iBeginBand) != iEndBand)  /* one band may be longer than expected... */
1308 1309 1310 1311 1312 1313 1314 1315 1316 1317 1318 1319 1320
            ERR("Error layouting row %d - couldn't shrink for %d pixels (%d total shrink)\n", *piRow, ret, -extra);
    } else
    if (extra > 0) {
        lpBand = REBAR_FindBandToGrow(infoPtr, iBeginBand, iEndBand);
        lpBand->cxEffective += extra;
    }

    REBAR_SetRowRectsX(infoPtr, iBeginBand, iEndBand);
    if (infoPtr->dwStyle & RBS_VARHEIGHT)
    {
        if (*piRow > 0)
            *pyPos += SEP_WIDTH;
        *pyPos = REBAR_SetBandsHeight(infoPtr, iBeginBand, iEndBand, *pyPos);
1321
    }
1322 1323
    (*piRow)++;
}
1324

1325
static VOID
1326
REBAR_Layout(REBAR_INFO *infoPtr)
1327 1328 1329
{
    REBAR_BAND *lpBand;
    RECT rcAdj;
1330
    SIZE oldSize;
1331
    INT adjcx, i;
1332
    INT rowstart;
1333 1334
    INT row = 0;
    INT xMin, yPos;
1335 1336

    if (infoPtr->dwStyle & (CCS_NORESIZE | CCS_NOPARENTALIGN) || GetParent(infoPtr->hwndSelf) == NULL)
1337 1338 1339
        GetClientRect(infoPtr->hwndSelf, &rcAdj);
    else
        GetClientRect(GetParent(infoPtr->hwndSelf), &rcAdj);
1340
    TRACE("adjustment rect is (%s)\n", wine_dbgstr_rect(&rcAdj));
1341

1342
    adjcx = get_rect_cx(infoPtr, &rcAdj);
1343

1344 1345 1346
    if (infoPtr->uNumBands == 0) {
        TRACE("No bands - setting size to (0,%d), vert: %lx\n", adjcx, infoPtr->dwStyle & CCS_VERT);
        infoPtr->calcSize.cx = adjcx;
1347
        /* the calcSize.cy won't change for a 0 band rebar */
1348 1349 1350 1351 1352
        infoPtr->uNumRows = 0;
        REBAR_ForceResize(infoPtr);
        return;
    }

1353
    yPos = 0;
1354
    xMin = 0;
1355
    rowstart = first_visible(infoPtr);
1356
    /* divide rows */
1357
    for (i = rowstart; i < infoPtr->uNumBands; i = next_visible(infoPtr, i))
1358 1359
    {
        lpBand = &infoPtr->bands[i];
1360

1361
        if (i > rowstart && (lpBand->fStyle & RBBS_BREAK || xMin + lpBand->cxMinBand > adjcx)) {
1362 1363 1364 1365 1366 1367 1368
            TRACE("%s break on band %d\n", (lpBand->fStyle & RBBS_BREAK ? "Hard" : "Soft"), i - 1);
            REBAR_LayoutRow(infoPtr, rowstart, i, adjcx, &row, &yPos);
            rowstart = i;
            xMin = 0;
        }
        else
            xMin += SEP_WIDTH;
1369

1370
        xMin += lpBand->cxMinBand;
1371
    }
1372 1373 1374
    REBAR_LayoutRow(infoPtr, rowstart, infoPtr->uNumBands, adjcx, &row, &yPos);

    if (!(infoPtr->dwStyle & RBS_VARHEIGHT))
1375
        yPos = REBAR_SetBandsHeight(infoPtr, first_visible(infoPtr), infoPtr->uNumBands, 0);
1376

1377
    infoPtr->uNumRows = row;
1378

1379 1380 1381 1382
    if (infoPtr->dwStyle & CCS_VERT)
        REBAR_CalcVertBand(infoPtr, 0, infoPtr->uNumBands);
    else
        REBAR_CalcHorzBand(infoPtr, 0, infoPtr->uNumBands);
1383
    /* now compute size of Rebar itself */
1384
    oldSize = infoPtr->calcSize;
Eric Kohl's avatar
Eric Kohl committed
1385

1386 1387
    infoPtr->calcSize.cx = adjcx;
    infoPtr->calcSize.cy = yPos;
1388
    TRACE("calcsize size=(%d, %d), origheight=(%d,%d)\n",
1389
            infoPtr->calcSize.cx, infoPtr->calcSize.cy,
1390
	    oldSize.cx, oldSize.cy);
Eric Kohl's avatar
Eric Kohl committed
1391

1392 1393
    REBAR_DumpBand (infoPtr);
    REBAR_MoveChildWindows (infoPtr, 0, infoPtr->uNumBands);
1394
    REBAR_ForceResize (infoPtr);
1395 1396 1397

    /* note: after a RBN_HEIGHTCHANGE native sends once again all the RBN_CHILDSIZE
     * and does another ForceResize */
1398
    if (oldSize.cy != infoPtr->calcSize.cy)
1399 1400 1401
    {
        NMHDR heightchange;
        REBAR_Notify(&heightchange, infoPtr, RBN_HEIGHTCHANGE);
1402
        REBAR_AutoSize(infoPtr, FALSE);
1403
    }
Eric Kohl's avatar
Eric Kohl committed
1404 1405
}

1406
/* iBeginBand must be visible */
1407 1408 1409 1410 1411 1412 1413 1414 1415 1416
static int
REBAR_SizeChildrenToHeight(const REBAR_INFO *infoPtr, int iBeginBand, int iEndBand, int extra, BOOL *fChanged)
{
    int cyBandsOld;
    int cyBandsNew = 0;
    int i;

    TRACE("[%d;%d) by %d\n", iBeginBand, iEndBand, extra);

    cyBandsOld = infoPtr->bands[iBeginBand].rcBand.bottom - infoPtr->bands[iBeginBand].rcBand.top;
1417
    for (i = iBeginBand; i < iEndBand; i = next_visible(infoPtr, i))
1418 1419 1420 1421 1422 1423 1424 1425 1426 1427 1428 1429 1430
    {
        REBAR_BAND *lpBand = &infoPtr->bands[i];
        int cyMaxChild = cyBandsOld - REBARSPACE(lpBand) + extra;
        int cyChild = round_child_height(lpBand, cyMaxChild);

        if (lpBand->hwndChild && cyChild != lpBand->cyChild && (lpBand->fStyle & RBBS_VARIABLEHEIGHT))
        {
            TRACE("Resizing %d: %d -> %d [%d]\n", i, lpBand->cyChild, cyChild, lpBand->cyMaxChild);
            *fChanged = TRUE;
            lpBand->cyChild = cyChild;
            lpBand->fDraw |= NTF_INVALIDATE;
            update_min_band_height(infoPtr, lpBand);
        }
1431
        cyBandsNew = max(cyBandsNew, lpBand->cyMinBand);
1432 1433 1434 1435 1436 1437 1438 1439 1440 1441 1442 1443 1444
    }
    return cyBandsNew - cyBandsOld;
}

/* worker function for RB_SIZETORECT and RBS_AUTOSIZE */
static VOID
REBAR_SizeToHeight(REBAR_INFO *infoPtr, int height)
{
    int extra = height - infoPtr->calcSize.cy;  /* may be negative */
    BOOL fChanged = FALSE;
    UINT uNumRows = infoPtr->uNumRows;
    int i;

1445 1446 1447
    if (uNumRows == 0)  /* avoid division by 0 */
        return;

1448 1449 1450 1451 1452
    /* That's not exactly what Windows does but should be similar */

    /* Pass one: break-up/glue rows */
    if (extra > 0)
    {
1453
        for (i = prev_visible(infoPtr, infoPtr->uNumBands); i > 0; i = prev_visible(infoPtr, i))
1454 1455 1456 1457 1458 1459 1460 1461 1462 1463 1464 1465 1466 1467 1468 1469 1470 1471 1472 1473 1474 1475 1476 1477
        {
            REBAR_BAND *lpBand = &infoPtr->bands[i];
            int height = lpBand->rcBand.bottom - lpBand->rcBand.top;
            int cyBreakExtra;  /* additional cy for the rebar after a RBBS_BREAK on this band */

            if (infoPtr->dwStyle & RBS_VARHEIGHT)
                cyBreakExtra = lpBand->cyRowSoFar; /* 'height' => 'lpBand->cyRowSoFar' + 'height'*/
            else
                cyBreakExtra = height;             /* 'height' => 'height' + 'height'*/
            cyBreakExtra += SEP_WIDTH;

            if (extra <= cyBreakExtra / 2)
                break;

            if (!(lpBand->fStyle & RBBS_BREAK))
            {
                TRACE("Adding break on band %d - extra %d -> %d\n", i, extra, extra - cyBreakExtra);
                lpBand->fStyle |= RBBS_BREAK;
                lpBand->fDraw |= NTF_INVALIDATE;
                fChanged = TRUE;
                extra -= cyBreakExtra;
                uNumRows++;
                /* temporary change for _SizeControlsToHeight. The true values will be computed in _Layout */
                if (infoPtr->dwStyle & RBS_VARHEIGHT)
1478
                    lpBand->rcBand.bottom = lpBand->rcBand.top + lpBand->cyMinBand;
1479 1480 1481 1482 1483 1484 1485 1486
            }
        }
    }
    /* TODO: else if (extra < 0) { try to remove some RBBS_BREAKs } */

    /* Pass two: increase/decrease control height */
    if (infoPtr->dwStyle & RBS_VARHEIGHT)
    {
1487
        int i = first_visible(infoPtr);
1488 1489 1490 1491 1492 1493 1494 1495
        int iRow = 0;
        while (i < infoPtr->uNumBands)
        {
            REBAR_BAND *lpBand = &infoPtr->bands[i];
            int extraForRow = extra / (int)(uNumRows - iRow);
            int rowEnd;

            /* we can't use get_row_end_for_band as we might have added RBBS_BREAK in the first phase */
1496
            for (rowEnd = next_visible(infoPtr, i); rowEnd < infoPtr->uNumBands; rowEnd = next_visible(infoPtr, rowEnd))
1497 1498 1499 1500 1501 1502 1503 1504 1505 1506
                if (infoPtr->bands[rowEnd].iRow != lpBand->iRow || (infoPtr->bands[rowEnd].fStyle & RBBS_BREAK))
                    break;

            extra -= REBAR_SizeChildrenToHeight(infoPtr, i, rowEnd, extraForRow, &fChanged);
            TRACE("extra = %d\n", extra);
            i = rowEnd;
            iRow++;
        }
    }
    else
1507
        extra -= REBAR_SizeChildrenToHeight(infoPtr, first_visible(infoPtr), infoPtr->uNumBands, extra / infoPtr->uNumRows, &fChanged);
1508 1509

    if (fChanged)
1510
        REBAR_Layout(infoPtr);
1511 1512
}

1513 1514 1515 1516 1517 1518 1519
static VOID
REBAR_AutoSize(REBAR_INFO *infoPtr, BOOL needsLayout)
{
    RECT rc, rcNew;
    NMRBAUTOSIZE autosize;

    if (needsLayout)
1520
        REBAR_Layout(infoPtr);
1521
    GetClientRect(infoPtr->hwndSelf, &rc);
1522 1523 1524 1525 1526 1527 1528 1529 1530
    REBAR_SizeToHeight(infoPtr, get_rect_cy(infoPtr, &rc));
    GetClientRect(infoPtr->hwndSelf, &rcNew);

    GetClientRect(infoPtr->hwndSelf, &autosize.rcTarget);
    autosize.fChanged = (memcmp(&rc, &rcNew, sizeof(RECT)) == 0);
    autosize.rcTarget = rc;
    autosize.rcActual = rcNew;
    REBAR_Notify((NMHDR *)&autosize, infoPtr, RBN_AUTOSIZE);
}
Eric Kohl's avatar
Eric Kohl committed
1531 1532

static VOID
1533
REBAR_ValidateBand (const REBAR_INFO *infoPtr, REBAR_BAND *lpBand)
1534 1535
     /* Function:  This routine evaluates the band specs supplied */
     /*  by the user and updates the following 5 fields in        */
1536
     /*  the internal band structure: cxHeader, cyHeader, cxMinBand, cyMinBand, fStatus */
1537 1538
{
    UINT header=0;
1539
    UINT textheight=0, imageheight = 0;
1540
    UINT i, nonfixed;
1541
    REBAR_BAND *tBand;
1542

1543
    lpBand->fStatus = 0;
1544 1545
    lpBand->cxMinBand = 0;
    lpBand->cyMinBand = 0;
1546

1547
    /* Data coming in from users into the cx... and cy... fields   */
1548 1549 1550 1551 1552 1553
    /* may be bad, just garbage, because the user never clears     */
    /* the fields. RB_{SET|INSERT}BAND{A|W} just passes the data   */
    /* along if the fields exist in the input area. Here we must   */
    /* determine if the data is valid. I have no idea how MS does  */
    /* the validation, but it does because the RB_GETBANDINFO      */
    /* returns a 0 when I know the sample program passed in an     */
1554
    /* address. Here I will use the algorithm that if the value    */
1555
    /* is greater than 65535 then it is bad and replace it with    */
1556
    /* a zero. Feel free to improve the algorithm.  -  GA 12/2000  */
1557 1558 1559 1560 1561 1562 1563 1564
    if (lpBand->cxMinChild > 65535) lpBand->cxMinChild = 0;
    if (lpBand->cyMinChild > 65535) lpBand->cyMinChild = 0;
    if (lpBand->cx         > 65535) lpBand->cx         = 0;
    if (lpBand->cyChild    > 65535) lpBand->cyChild    = 0;
    if (lpBand->cyIntegral > 65535) lpBand->cyIntegral = 0;
    if (lpBand->cxIdeal    > 65535) lpBand->cxIdeal    = 0;
    if (lpBand->cxHeader   > 65535) lpBand->cxHeader   = 0;

1565 1566 1567
    /* TODO : we could try return to the caller if a value changed so that */
    /*        a REBAR_Layout is needed. Till now the caller should call it */
    /*        it always (we should also check what native does)            */
1568

1569
    /* Header is where the image, text and gripper exist  */
1570
    /* in the band and precede the child window.          */
1571

1572 1573 1574 1575 1576 1577 1578 1579
    /* count number of non-FIXEDSIZE and non-Hidden bands */
    nonfixed = 0;
    for (i=0; i<infoPtr->uNumBands; i++){
	tBand = &infoPtr->bands[i];
	if (!HIDDENBAND(tBand) && !(tBand->fStyle & RBBS_FIXEDSIZE))
	    nonfixed++;
    }

1580
    /* calculate gripper rectangle */
1581
    if (  (!(lpBand->fStyle & RBBS_NOGRIPPER)) &&
1582
	  ( (lpBand->fStyle & RBBS_GRIPPERALWAYS) ||
1583
	    ( !(lpBand->fStyle & RBBS_FIXEDSIZE) && (nonfixed > 1)))
1584 1585
       ) {
	lpBand->fStatus |= HAS_GRIPPER;
1586 1587
        if (infoPtr->dwStyle & CCS_VERT)
	    if (infoPtr->dwStyle & RBS_VERTICALGRIPPER)
1588 1589 1590 1591 1592 1593 1594
                header += (GRIPPER_HEIGHT + REBAR_PRE_GRIPPER);
            else
	        header += (GRIPPER_WIDTH + REBAR_PRE_GRIPPER);
        else
            header += (REBAR_PRE_GRIPPER + GRIPPER_WIDTH);
        /* Always have 4 pixels before anything else */
        header += REBAR_ALWAYS_SPACE;
1595 1596 1597
    }

    /* image is visible */
1598
    if (lpBand->iImage != -1 && (infoPtr->himl)) {
1599
	lpBand->fStatus |= HAS_IMAGE;
1600
        if (infoPtr->dwStyle & CCS_VERT) {
1601
	   header += (infoPtr->imageSize.cy + REBAR_POST_IMAGE);
1602
           imageheight = infoPtr->imageSize.cx + 4;
1603 1604
	}
	else {
1605
	   header += (infoPtr->imageSize.cx + REBAR_POST_IMAGE);
1606
           imageheight = infoPtr->imageSize.cy + 4;
1607 1608 1609 1610
	}
    }

    /* text is visible */
1611 1612
    if ((lpBand->fMask & RBBIM_TEXT) && (lpBand->lpText) &&
        !(lpBand->fStyle & RBBS_HIDETITLE)) {
1613 1614 1615 1616
	HDC hdc = GetDC (0);
	HFONT hOldFont = SelectObject (hdc, infoPtr->hFont);
	SIZE size;

1617
	lpBand->fStatus |= HAS_TEXT;
1618 1619
	GetTextExtentPoint32W (hdc, lpBand->lpText,
			       lstrlenW (lpBand->lpText), &size);
1620 1621
	header += ((infoPtr->dwStyle & CCS_VERT) ? (size.cy + REBAR_POST_TEXT) : (size.cx + REBAR_POST_TEXT));
	textheight = (infoPtr->dwStyle & CCS_VERT) ? 0 : size.cy;
1622 1623 1624 1625 1626

	SelectObject (hdc, hOldFont);
	ReleaseDC (0, hdc);
    }

1627 1628 1629 1630 1631 1632
    /* if no gripper but either image or text, then leave space */
    if ((lpBand->fStatus & (HAS_IMAGE | HAS_TEXT)) &&
	!(lpBand->fStatus & HAS_GRIPPER)) {
	header += REBAR_ALWAYS_SPACE;
    }

1633
    /* check if user overrode the header value */
1634
    if (!(lpBand->fStyle & RBBS_UNDOC_FIXEDHEADER))
1635
        lpBand->cxHeader = header;
1636
    lpBand->cyHeader = max(textheight, imageheight);
1637 1638

    /* Now compute minimum size of child window */
1639
    update_min_band_height(infoPtr, lpBand);       /* update lpBand->cyMinBand from cyHeader and cyChild*/
1640

1641
    lpBand->cxMinBand = lpBand->cxMinChild + lpBand->cxHeader + REBAR_POST_CHILD;
1642
    if (lpBand->fStyle & RBBS_USECHEVRON && lpBand->cxMinChild < lpBand->cxIdeal)
1643
        lpBand->cxMinBand += CHEVRON_WIDTH;
1644 1645
}

1646
static UINT
1647
REBAR_CommonSetupBand(HWND hwnd, const REBARBANDINFOW *lprbbi, REBAR_BAND *lpBand)
1648 1649
     /* Function:  This routine copies the supplied values from   */
     /*  user input (lprbbi) to the internal band structure.      */
1650
     /*  It returns the mask of what changed.   */
1651
{
1652
    UINT uChanged = 0x0;
1653

1654 1655
    lpBand->fMask |= lprbbi->fMask;

1656 1657 1658
    if( (lprbbi->fMask & RBBIM_STYLE) &&
        (lpBand->fStyle != lprbbi->fStyle ) )
    {
1659
	lpBand->fStyle = lprbbi->fStyle;
1660
        uChanged |= RBBIM_STYLE;
1661
    }
1662

1663 1664 1665 1666
    if( (lprbbi->fMask & RBBIM_COLORS) &&
       ( ( lpBand->clrFore != lprbbi->clrFore ) ||
         ( lpBand->clrBack != lprbbi->clrBack ) ) )
    {
1667 1668
	lpBand->clrFore = lprbbi->clrFore;
	lpBand->clrBack = lprbbi->clrBack;
1669
        uChanged |= RBBIM_COLORS;
1670 1671
    }

1672 1673 1674
    if( (lprbbi->fMask & RBBIM_IMAGE) &&
       ( lpBand->iImage != lprbbi->iImage ) )
    {
1675
	lpBand->iImage = lprbbi->iImage;
1676
        uChanged |= RBBIM_IMAGE;
1677
    }
1678

1679 1680 1681
    if( (lprbbi->fMask & RBBIM_CHILD) &&
       (lprbbi->hwndChild != lpBand->hwndChild ) )
    {
1682 1683 1684 1685
	if (lprbbi->hwndChild) {
	    lpBand->hwndChild = lprbbi->hwndChild;
	    lpBand->hwndPrevParent =
		SetParent (lpBand->hwndChild, hwnd);
1686
	    /* below in trace from WinRAR */
1687
	    ShowWindow(lpBand->hwndChild, SW_SHOWNOACTIVATE | SW_SHOWNORMAL);
1688
	    /* above in trace from WinRAR */
1689 1690
	}
	else {
1691
	    TRACE("child: %p  prev parent: %p\n",
1692 1693 1694 1695
		   lpBand->hwndChild, lpBand->hwndPrevParent);
	    lpBand->hwndChild = 0;
	    lpBand->hwndPrevParent = 0;
	}
1696
        uChanged |= RBBIM_CHILD;
1697 1698
    }

1699 1700 1701
    if( (lprbbi->fMask & RBBIM_CHILDSIZE) &&
        ( (lpBand->cxMinChild != lprbbi->cxMinChild) ||
          (lpBand->cyMinChild != lprbbi->cyMinChild ) ||
1702
          ( (lprbbi->cbSize >= sizeof (REBARBANDINFOA) && (lpBand->fStyle & RBBS_VARIABLEHEIGHT)) &&
1703 1704 1705 1706 1707 1708 1709 1710
            ( (lpBand->cyChild    != lprbbi->cyChild ) ||
              (lpBand->cyMaxChild != lprbbi->cyMaxChild ) ||
              (lpBand->cyIntegral != lprbbi->cyIntegral ) ) ) ||
          ( (lprbbi->cbSize < sizeof (REBARBANDINFOA)) &&
            ( (lpBand->cyChild || 
               lpBand->cyMaxChild || 
               lpBand->cyIntegral ) ) ) ) )
    {
1711 1712
	lpBand->cxMinChild = lprbbi->cxMinChild;
	lpBand->cyMinChild = lprbbi->cyMinChild;
1713
        /* These fields where added in WIN32_IE == 0x400 and are set only for RBBS_VARIABLEHEIGHT bands */
1714
        if (lprbbi->cbSize >= sizeof (REBARBANDINFOA) && (lpBand->fStyle & RBBS_VARIABLEHEIGHT)) {
1715
	    lpBand->cyMaxChild = lprbbi->cyMaxChild;
1716 1717
            lpBand->cyIntegral = lprbbi->cyIntegral;

1718
            lpBand->cyChild = round_child_height(lpBand, lprbbi->cyChild);  /* make (cyChild - cyMinChild) a multiple of cyIntergral */
1719 1720 1721 1722
        }
	else {
	    lpBand->cyChild    = lpBand->cyMinChild;
	    lpBand->cyMaxChild = 0x7fffffff;
1723 1724
	    lpBand->cyIntegral = 0;
	}
1725
        uChanged |= RBBIM_CHILDSIZE;
1726 1727
    }

1728 1729 1730
    if( (lprbbi->fMask & RBBIM_SIZE) &&
        (lpBand->cx != lprbbi->cx ) )
    {
1731
	lpBand->cx = lprbbi->cx;
1732
        uChanged |= RBBIM_SIZE;
1733
    }
1734

1735 1736 1737
    if( (lprbbi->fMask & RBBIM_BACKGROUND) &&
       ( lpBand->hbmBack != lprbbi->hbmBack ) )
    {
1738
	lpBand->hbmBack = lprbbi->hbmBack;
1739
        uChanged |= RBBIM_BACKGROUND;
1740
    }
1741

1742 1743 1744
    if( (lprbbi->fMask & RBBIM_ID) &&
        (lpBand->wID != lprbbi->wID ) )
    {
1745
	lpBand->wID = lprbbi->wID;
1746
        uChanged |= RBBIM_ID;
1747
    }
1748 1749 1750

    /* check for additional data */
    if (lprbbi->cbSize >= sizeof (REBARBANDINFOA)) {
1751 1752 1753
	if( (lprbbi->fMask & RBBIM_IDEALSIZE) &&
            ( lpBand->cxIdeal != lprbbi->cxIdeal ) )
        {
1754
	    lpBand->cxIdeal = lprbbi->cxIdeal;
1755
            uChanged |= RBBIM_IDEALSIZE;
1756
        }
1757

1758 1759 1760
	if( (lprbbi->fMask & RBBIM_LPARAM) &&
            (lpBand->lParam != lprbbi->lParam ) )
        {
1761
	    lpBand->lParam = lprbbi->lParam;
1762
            uChanged |= RBBIM_LPARAM;
1763
        }
1764

1765 1766 1767
	if( (lprbbi->fMask & RBBIM_HEADERSIZE) &&
            (lpBand->cxHeader != lprbbi->cxHeader ) )
        {
1768
	    lpBand->cxHeader = lprbbi->cxHeader;
1769
            lpBand->fStyle |= RBBS_UNDOC_FIXEDHEADER;
1770
            uChanged |= RBBIM_HEADERSIZE;
1771
        }
1772
    }
1773

1774
    return uChanged;
1775 1776
}

1777
static LRESULT
1778
REBAR_InternalEraseBkGnd (const REBAR_INFO *infoPtr, WPARAM wParam, const RECT *clip)
1779 1780 1781 1782
     /* Function:  This erases the background rectangle by drawing  */
     /*  each band with its background color (or the default) and   */
     /*  draws each bands right separator if necessary. The row     */
     /*  separators are drawn on the first band of the next row.    */
1783 1784
{
    REBAR_BAND *lpBand;
1785 1786
    UINT i;
    INT oldrow;
1787
    HDC hdc = (HDC)wParam;
1788
    RECT cr;
Guy Albertelli's avatar
Guy Albertelli committed
1789
    COLORREF old = CLR_NONE, new;
1790 1791 1792
    HTHEME theme = GetWindowTheme (infoPtr->hwndSelf);

    GetClientRect (infoPtr->hwndSelf, &cr);
1793

1794
    oldrow = -1;
1795
    for(i=0; i<infoPtr->uNumBands; i++) {
1796
        RECT rcBand;
1797
        lpBand = &infoPtr->bands[i];
1798
	if (HIDDENBAND(lpBand)) continue;
1799
        translate_rect(infoPtr, &rcBand, &lpBand->rcBand);
1800 1801 1802 1803

	/* draw band separator between rows */
	if (lpBand->iRow != oldrow) {
	    oldrow = lpBand->iRow;
1804
	    if (infoPtr->dwStyle & RBS_BANDBORDERS) {
1805
		RECT rcRowSep;
1806
		rcRowSep = rcBand;
1807
		if (infoPtr->dwStyle & CCS_VERT) {
1808
		    rcRowSep.right += SEP_WIDTH_SIZE;
1809
		    rcRowSep.bottom = infoPtr->calcSize.cx;
1810 1811 1812 1813
                    if (theme)
                        DrawThemeEdge (theme, hdc, RP_BAND, 0, &rcRowSep, EDGE_ETCHED, BF_RIGHT, NULL);
                    else
		        DrawEdge (hdc, &rcRowSep, EDGE_ETCHED, BF_RIGHT);
1814 1815 1816 1817
		}
		else {
		    rcRowSep.bottom += SEP_WIDTH_SIZE;
		    rcRowSep.right = infoPtr->calcSize.cx;
1818 1819 1820 1821
                    if (theme)
                        DrawThemeEdge (theme, hdc, RP_BAND, 0, &rcRowSep, EDGE_ETCHED, BF_BOTTOM, NULL);
                    else
		        DrawEdge (hdc, &rcRowSep, EDGE_ETCHED, BF_BOTTOM);
1822
		}
1823 1824
                TRACE ("drawing band separator bottom (%s)\n",
                       wine_dbgstr_rect(&rcRowSep));
1825 1826 1827 1828
	    }
	}

	/* draw band separator between bands in a row */
1829
        if (infoPtr->dwStyle & RBS_BANDBORDERS && lpBand->rcBand.left > 0) {
1830
	    RECT rcSep;
1831
	    rcSep = rcBand;
1832
	    if (infoPtr->dwStyle & CCS_VERT) {
1833 1834
                rcSep.bottom = rcSep.top;
		rcSep.top -= SEP_WIDTH_SIZE;
1835 1836 1837 1838
                if (theme)
                    DrawThemeEdge (theme, hdc, RP_BAND, 0, &rcSep, EDGE_ETCHED, BF_BOTTOM, NULL);
                else
		    DrawEdge (hdc, &rcSep, EDGE_ETCHED, BF_BOTTOM);
1839 1840
	    }
	    else {
1841 1842
                rcSep.right = rcSep.left;
		rcSep.left -= SEP_WIDTH_SIZE;
1843 1844 1845 1846
                if (theme)
                    DrawThemeEdge (theme, hdc, RP_BAND, 0, &rcSep, EDGE_ETCHED, BF_RIGHT, NULL);
                else
		    DrawEdge (hdc, &rcSep, EDGE_ETCHED, BF_RIGHT);
1847
	    }
1848 1849
            TRACE("drawing band separator right (%s)\n",
                  wine_dbgstr_rect(&rcSep));
1850
	}
1851 1852

	/* draw the actual background */
Guy Albertelli's avatar
Guy Albertelli committed
1853 1854 1855
	if (lpBand->clrBack != CLR_NONE) {
	    new = (lpBand->clrBack == CLR_DEFAULT) ? infoPtr->clrBtnFace :
		    lpBand->clrBack;
1856
#if GLATESTING
Guy Albertelli's avatar
Guy Albertelli committed
1857 1858
	    /* testing only - make background green to see it */
	    new = RGB(0,128,0);
1859
#endif
Guy Albertelli's avatar
Guy Albertelli committed
1860
	}
1861 1862 1863 1864 1865 1866 1867 1868 1869 1870 1871
	else {
	    /* In the absence of documentation for Rebar vs. CLR_NONE,
	     * we will use the default BtnFace color. Note documentation
	     * exists for Listview and Imagelist.
	     */
	    new = infoPtr->clrBtnFace;
#if GLATESTING
	    /* testing only - make background green to see it */
	    new = RGB(0,128,0);
#endif
	}
Guy Albertelli's avatar
Guy Albertelli committed
1872

1873 1874
        if (theme)
        {
1875
            /* When themed, the background color is ignored (but not a
1876
             * background bitmap */
1877
            DrawThemeBackground (theme, hdc, 0, 0, &cr, &rcBand);
1878 1879 1880 1881
        }
        else
        {
            old = SetBkColor (hdc, new);
1882
            TRACE("%s background color=0x%06x, band (%d,%d)-(%d,%d), clip (%d,%d)-(%d,%d)\n",
1883 1884 1885
                  (lpBand->clrBack == CLR_NONE) ? "none" :
                    ((lpBand->clrBack == CLR_DEFAULT) ? "dft" : ""),
                  GetBkColor(hdc),
1886 1887
                  rcBand.left,rcBand.top,
                  rcBand.right,rcBand.bottom,
1888 1889
                  clip->left, clip->top,
                  clip->right, clip->bottom);
1890
            ExtTextOutW (hdc, 0, 0, ETO_OPAQUE, &rcBand, NULL, 0, 0);
1891 1892 1893
            if (lpBand->clrBack != CLR_NONE)
                SetBkColor (hdc, old);
        }
1894 1895 1896 1897
    }
    return TRUE;
}

Eric Kohl's avatar
Eric Kohl committed
1898
static void
1899
REBAR_InternalHitTest (const REBAR_INFO *infoPtr, const POINT *lpPt, UINT *pFlags, INT *pBand)
Eric Kohl's avatar
Eric Kohl committed
1900 1901
{
    REBAR_BAND *lpBand;
1902
    RECT rect;
1903
    UINT  iCount;
Alexandre Julliard's avatar
Alexandre Julliard committed
1904

1905
    GetClientRect (infoPtr->hwndSelf, &rect);
Alexandre Julliard's avatar
Alexandre Julliard committed
1906

Eric Kohl's avatar
Eric Kohl committed
1907
    *pFlags = RBHT_NOWHERE;
1908
    if (PtInRect (&rect, *lpPt))
Eric Kohl's avatar
Eric Kohl committed
1909 1910 1911 1912 1913
    {
	if (infoPtr->uNumBands == 0) {
	    *pFlags = RBHT_NOWHERE;
	    if (pBand)
		*pBand = -1;
1914
	    TRACE("NOWHERE\n");
Eric Kohl's avatar
Eric Kohl committed
1915 1916 1917 1918 1919
	    return;
	}
	else {
	    /* somewhere inside */
	    for (iCount = 0; iCount < infoPtr->uNumBands; iCount++) {
1920
                RECT rcBand;
Eric Kohl's avatar
Eric Kohl committed
1921
		lpBand = &infoPtr->bands[iCount];
1922 1923 1924
                translate_rect(infoPtr, &rcBand, &lpBand->rcBand);
                if (HIDDENBAND(lpBand)) continue;
		if (PtInRect (&rcBand, *lpPt)) {
Eric Kohl's avatar
Eric Kohl committed
1925 1926
		    if (pBand)
			*pBand = iCount;
1927
		    if (PtInRect (&lpBand->rcGripper, *lpPt)) {
Eric Kohl's avatar
Eric Kohl committed
1928
			*pFlags = RBHT_GRABBER;
1929
			TRACE("ON GRABBER %d\n", iCount);
Eric Kohl's avatar
Eric Kohl committed
1930 1931
			return;
		    }
1932
		    else if (PtInRect (&lpBand->rcCapImage, *lpPt)) {
Eric Kohl's avatar
Eric Kohl committed
1933
			*pFlags = RBHT_CAPTION;
1934
			TRACE("ON CAPTION %d\n", iCount);
Eric Kohl's avatar
Eric Kohl committed
1935 1936
			return;
		    }
1937
		    else if (PtInRect (&lpBand->rcCapText, *lpPt)) {
Eric Kohl's avatar
Eric Kohl committed
1938
			*pFlags = RBHT_CAPTION;
1939
			TRACE("ON CAPTION %d\n", iCount);
Eric Kohl's avatar
Eric Kohl committed
1940 1941
			return;
		    }
1942
		    else if (PtInRect (&lpBand->rcChild, *lpPt)) {
Eric Kohl's avatar
Eric Kohl committed
1943
			*pFlags = RBHT_CLIENT;
1944
			TRACE("ON CLIENT %d\n", iCount);
Eric Kohl's avatar
Eric Kohl committed
1945 1946
			return;
		    }
Robert Shearman's avatar
Robert Shearman committed
1947 1948 1949 1950 1951
		    else if (PtInRect (&lpBand->rcChevron, *lpPt)) {
			*pFlags = RBHT_CHEVRON;
			TRACE("ON CHEVRON %d\n", iCount);
			return;
		    }
Eric Kohl's avatar
Eric Kohl committed
1952 1953
		    else {
			*pFlags = RBHT_NOWHERE;
1954
			TRACE("NOWHERE %d\n", iCount);
Eric Kohl's avatar
Eric Kohl committed
1955 1956 1957 1958
			return;
		    }
		}
	    }
Alexandre Julliard's avatar
Alexandre Julliard committed
1959

Eric Kohl's avatar
Eric Kohl committed
1960 1961 1962 1963
	    *pFlags = RBHT_NOWHERE;
	    if (pBand)
		*pBand = -1;

1964
	    TRACE("NOWHERE\n");
Eric Kohl's avatar
Eric Kohl committed
1965 1966 1967 1968 1969 1970 1971
	    return;
	}
    }
    else {
	*pFlags = RBHT_NOWHERE;
	if (pBand)
	    *pBand = -1;
1972
	TRACE("NOWHERE\n");
Eric Kohl's avatar
Eric Kohl committed
1973 1974 1975
	return;
    }
}
Alexandre Julliard's avatar
Alexandre Julliard committed
1976

1977
static void
1978
REBAR_HandleLRDrag (REBAR_INFO *infoPtr, const POINT *ptsmove)
1979 1980 1981 1982 1983 1984 1985
     /* Function:  This will implement the functionality of a     */
     /*  Gripper drag within a row. It will not implement "out-   */
     /*  of-row" drags. (They are detected and handled in         */
     /*  REBAR_MouseMove.)                                        */
     /*  **** FIXME Switching order of bands in a row not   ****  */
     /*  ****       yet implemented.                        ****  */
{
1986 1987 1988
    REBAR_BAND *hitBand;
    INT iHitBand, iRowBegin, iRowEnd;
    INT movement, xBand;
1989 1990 1991

    /* on first significant mouse movement, issue notify */
    if (!(infoPtr->fStatus & BEGIN_DRAG_ISSUED)) {
1992
	if (REBAR_Notify_NMREBAR (infoPtr, -1, RBN_BEGINDRAG)) {
1993 1994 1995 1996
	    /* Notify returned TRUE - abort drag */
	    infoPtr->dragStart.x = 0;
	    infoPtr->dragStart.y = 0;
	    infoPtr->dragNow = infoPtr->dragStart;
Robert Shearman's avatar
Robert Shearman committed
1997
	    infoPtr->iGrabbedBand = -1;
1998 1999 2000
	    ReleaseCapture ();
	    return ;
	}
2001 2002 2003
	infoPtr->fStatus |= BEGIN_DRAG_ISSUED;
    }

2004 2005 2006 2007
    iHitBand = infoPtr->iGrabbedBand;
    iRowBegin = get_row_begin_for_band(infoPtr, iHitBand);
    iRowEnd = get_row_end_for_band(infoPtr, iHitBand);
    hitBand = &infoPtr->bands[iHitBand];
2008

2009 2010 2011
    xBand = hitBand->rcBand.left;
    movement = (infoPtr->dwStyle&CCS_VERT ? ptsmove->y : ptsmove->x)
                    - (xBand + REBAR_PRE_GRIPPER - infoPtr->ihitoffset);
2012

2013 2014 2015 2016 2017 2018
    if (movement < 0) {
        int cxLeft = REBAR_ShrinkBandsRTL(infoPtr, iRowBegin, iHitBand, -movement, TRUE);
        hitBand->cxEffective += -movement - cxLeft;
        hitBand->cx = hitBand->cxEffective;
    } else if (movement > 0) {
        int cxLeft = REBAR_ShrinkBandsLTR(infoPtr, iHitBand, iRowEnd, movement, TRUE);
2019
        REBAR_BAND *lpPrev = &infoPtr->bands[prev_visible(infoPtr, iHitBand)];
2020 2021
        lpPrev->cxEffective += movement - cxLeft;
        lpPrev->cx = lpPrev->cxEffective;
2022 2023
    }

2024
    REBAR_SetRowRectsX(infoPtr, iRowBegin, iRowEnd);
2025
    if (infoPtr->dwStyle & CCS_VERT)
2026
        REBAR_CalcVertBand(infoPtr, 0, infoPtr->uNumBands);
2027
    else
2028 2029
        REBAR_CalcHorzBand(infoPtr, 0, infoPtr->uNumBands);
    REBAR_MoveChildWindows(infoPtr, iRowBegin, iRowEnd);
2030 2031
}

Alexandre Julliard's avatar
Alexandre Julliard committed
2032 2033


2034
/* << REBAR_BeginDrag >> */
Alexandre Julliard's avatar
Alexandre Julliard committed
2035 2036 2037


static LRESULT
2038
REBAR_DeleteBand (REBAR_INFO *infoPtr, WPARAM wParam)
Alexandre Julliard's avatar
Alexandre Julliard committed
2039
{
2040
    UINT uBand = (UINT)wParam;
2041
    REBAR_BAND *lpBand;
Alexandre Julliard's avatar
Alexandre Julliard committed
2042 2043 2044 2045

    if (uBand >= infoPtr->uNumBands)
	return FALSE;

2046
    TRACE("deleting band %u!\n", uBand);
2047
    lpBand = &infoPtr->bands[uBand];
2048
    REBAR_Notify_NMREBAR (infoPtr, uBand, RBN_DELETINGBAND);
2049
    /* TODO: a return of 1 should probably cancel the deletion */
Alexandre Julliard's avatar
Alexandre Julliard committed
2050

2051 2052 2053
    if (lpBand->hwndChild)
        ShowWindow(lpBand->hwndChild, SW_HIDE);
    Free(lpBand->lpText);
Eric Kohl's avatar
Eric Kohl committed
2054

2055 2056 2057 2058
    infoPtr->uNumBands--;
    memmove(&infoPtr->bands[uBand], &infoPtr->bands[uBand+1],
        (infoPtr->uNumBands - uBand) * sizeof(REBAR_BAND));
    infoPtr->bands = ReAlloc(infoPtr->bands, infoPtr->uNumBands * sizeof(REBAR_BAND));
2059

2060
    REBAR_Notify_NMREBAR (infoPtr, -1, RBN_DELETEDBAND);
2061 2062 2063

    /* if only 1 band left the re-validate to possible eliminate gripper */
    if (infoPtr->uNumBands == 1)
2064
      REBAR_ValidateBand (infoPtr, &infoPtr->bands[0]);
2065

2066
    REBAR_Layout(infoPtr);
Eric Kohl's avatar
Eric Kohl committed
2067

Alexandre Julliard's avatar
Alexandre Julliard committed
2068 2069
    return TRUE;
}
Alexandre Julliard's avatar
Alexandre Julliard committed
2070 2071


2072 2073
/* << REBAR_DragMove >> */
/* << REBAR_EndDrag >> */
Eric Kohl's avatar
Eric Kohl committed
2074 2075 2076


static LRESULT
2077
REBAR_GetBandBorders (const REBAR_INFO *infoPtr, WPARAM wParam, LPARAM lParam)
Eric Kohl's avatar
Eric Kohl committed
2078
{
2079
    LPRECT lpRect = (LPRECT)lParam;
2080 2081 2082 2083
    REBAR_BAND *lpBand;

    if (!lParam)
	return 0;
2084
    if ((UINT)wParam >= infoPtr->uNumBands)
2085 2086
	return 0;

2087
    lpBand = &infoPtr->bands[(UINT)wParam];
2088 2089 2090 2091 2092 2093

    /* FIXME - the following values were determined by experimentation */
    /* with the REBAR Control Spy. I have guesses as to what the 4 and */
    /* 1 are, but I am not sure. There doesn't seem to be any actual   */
    /* difference in size of the control area with and without the     */
    /* style.  -  GA                                                   */
2094 2095
    if (infoPtr->dwStyle & RBS_BANDBORDERS) {
	if (infoPtr->dwStyle & CCS_VERT) {
2096 2097 2098 2099 2100 2101 2102 2103 2104 2105 2106
	    lpRect->left = 1;
	    lpRect->top = lpBand->cxHeader + 4;
	    lpRect->right = 1;
	    lpRect->bottom = 0;
	}
	else {
	    lpRect->left = lpBand->cxHeader + 4;
	    lpRect->top = 1;
	    lpRect->right = 0;
	    lpRect->bottom = 1;
	}
2107 2108
    }
    else {
2109
	lpRect->left = lpBand->cxHeader;
2110
    }
Eric Kohl's avatar
Eric Kohl committed
2111 2112
    return 0;
}
Alexandre Julliard's avatar
Alexandre Julliard committed
2113 2114


2115
static inline LRESULT
2116
REBAR_GetBandCount (const REBAR_INFO *infoPtr)
Alexandre Julliard's avatar
Alexandre Julliard committed
2117
{
2118
    TRACE("band count %u!\n", infoPtr->uNumBands);
Alexandre Julliard's avatar
Alexandre Julliard committed
2119 2120 2121 2122 2123 2124

    return infoPtr->uNumBands;
}


static LRESULT
2125
REBAR_GetBandInfoT(const REBAR_INFO *infoPtr, WPARAM wParam, LPARAM lParam, BOOL bUnicode)
Alexandre Julliard's avatar
Alexandre Julliard committed
2126
{
2127
    LPREBARBANDINFOW lprbbi = (LPREBARBANDINFOW)lParam;
Alexandre Julliard's avatar
Alexandre Julliard committed
2128 2129 2130 2131
    REBAR_BAND *lpBand;

    if (lprbbi == NULL)
	return FALSE;
2132
    if (lprbbi->cbSize < REBARBANDINFOA_V3_SIZE)
Alexandre Julliard's avatar
Alexandre Julliard committed
2133
	return FALSE;
2134
    if ((UINT)wParam >= infoPtr->uNumBands)
Alexandre Julliard's avatar
Alexandre Julliard committed
2135 2136
	return FALSE;

2137
    TRACE("index %u (bUnicode=%d)\n", (UINT)wParam, bUnicode);
Alexandre Julliard's avatar
Alexandre Julliard committed
2138 2139

    /* copy band information */
2140
    lpBand = &infoPtr->bands[(UINT)wParam];
Alexandre Julliard's avatar
Alexandre Julliard committed
2141 2142 2143 2144 2145 2146 2147

    if (lprbbi->fMask & RBBIM_STYLE)
	lprbbi->fStyle = lpBand->fStyle;

    if (lprbbi->fMask & RBBIM_COLORS) {
	lprbbi->clrFore = lpBand->clrFore;
	lprbbi->clrBack = lpBand->clrBack;
Guy Albertelli's avatar
Guy Albertelli committed
2148
	if (lprbbi->clrBack == CLR_DEFAULT)
2149
	    lprbbi->clrBack = infoPtr->clrBtnFace;
Alexandre Julliard's avatar
Alexandre Julliard committed
2150 2151
    }

2152 2153 2154 2155 2156
    if (lprbbi->fMask & RBBIM_TEXT) {
        if (bUnicode)
            Str_GetPtrW(lpBand->lpText, lprbbi->lpText, lprbbi->cch);
        else
            Str_GetPtrWtoA(lpBand->lpText, (LPSTR)lprbbi->lpText, lprbbi->cch);
Alexandre Julliard's avatar
Alexandre Julliard committed
2157 2158
    }

2159
    if (lprbbi->fMask & RBBIM_IMAGE)
Alexandre Julliard's avatar
Alexandre Julliard committed
2160 2161 2162 2163 2164 2165 2166 2167
	lprbbi->iImage = lpBand->iImage;

    if (lprbbi->fMask & RBBIM_CHILD)
	lprbbi->hwndChild = lpBand->hwndChild;

    if (lprbbi->fMask & RBBIM_CHILDSIZE) {
	lprbbi->cxMinChild = lpBand->cxMinChild;
	lprbbi->cyMinChild = lpBand->cyMinChild;
2168 2169 2170
        /* to make tests pass we follow Windows behaviour and allow to read these fields only
         * for RBBS_VARIABLEHEIGHTS bands */
        if (lprbbi->cbSize >= sizeof (REBARBANDINFOA) && (lpBand->fStyle & RBBS_VARIABLEHEIGHT)) {
2171 2172 2173 2174
	    lprbbi->cyChild    = lpBand->cyChild;
	    lprbbi->cyMaxChild = lpBand->cyMaxChild;
	    lprbbi->cyIntegral = lpBand->cyIntegral;
	}
Alexandre Julliard's avatar
Alexandre Julliard committed
2175 2176 2177 2178 2179 2180 2181 2182 2183 2184 2185
    }

    if (lprbbi->fMask & RBBIM_SIZE)
	lprbbi->cx = lpBand->cx;

    if (lprbbi->fMask & RBBIM_BACKGROUND)
	lprbbi->hbmBack = lpBand->hbmBack;

    if (lprbbi->fMask & RBBIM_ID)
	lprbbi->wID = lpBand->wID;

Alexandre Julliard's avatar
Alexandre Julliard committed
2186
    /* check for additional data */
2187
    if (lprbbi->cbSize >= sizeof (REBARBANDINFOA)) {
Alexandre Julliard's avatar
Alexandre Julliard committed
2188 2189
	if (lprbbi->fMask & RBBIM_IDEALSIZE)
	    lprbbi->cxIdeal = lpBand->cxIdeal;
Alexandre Julliard's avatar
Alexandre Julliard committed
2190

Alexandre Julliard's avatar
Alexandre Julliard committed
2191 2192
	if (lprbbi->fMask & RBBIM_LPARAM)
	    lprbbi->lParam = lpBand->lParam;
Alexandre Julliard's avatar
Alexandre Julliard committed
2193

Alexandre Julliard's avatar
Alexandre Julliard committed
2194 2195 2196
	if (lprbbi->fMask & RBBIM_HEADERSIZE)
	    lprbbi->cxHeader = lpBand->cxHeader;
    }
Alexandre Julliard's avatar
Alexandre Julliard committed
2197

2198
    REBAR_DumpBandInfo(lprbbi);
2199

Eric Kohl's avatar
Eric Kohl committed
2200 2201
    return TRUE;
}
Alexandre Julliard's avatar
Alexandre Julliard committed
2202

Alexandre Julliard's avatar
Alexandre Julliard committed
2203 2204

static LRESULT
2205
REBAR_GetBarHeight (const REBAR_INFO *infoPtr)
Alexandre Julliard's avatar
Alexandre Julliard committed
2206
{
2207
    INT nHeight;
Alexandre Julliard's avatar
Alexandre Julliard committed
2208

2209
    nHeight = infoPtr->calcSize.cy;
2210

2211
    TRACE("height = %d\n", nHeight);
Alexandre Julliard's avatar
Alexandre Julliard committed
2212

2213
    return nHeight;
Alexandre Julliard's avatar
Alexandre Julliard committed
2214
}
Alexandre Julliard's avatar
Alexandre Julliard committed
2215 2216 2217


static LRESULT
2218
REBAR_GetBarInfo (const REBAR_INFO *infoPtr, LPARAM lParam)
Alexandre Julliard's avatar
Alexandre Julliard committed
2219 2220 2221 2222 2223 2224 2225 2226 2227
{
    LPREBARINFO lpInfo = (LPREBARINFO)lParam;

    if (lpInfo == NULL)
	return FALSE;

    if (lpInfo->cbSize < sizeof (REBARINFO))
	return FALSE;

2228
    TRACE("getting bar info!\n");
Alexandre Julliard's avatar
Alexandre Julliard committed
2229 2230 2231 2232 2233 2234 2235 2236 2237 2238

    if (infoPtr->himl) {
	lpInfo->himl = infoPtr->himl;
	lpInfo->fMask |= RBIM_IMAGELIST;
    }

    return TRUE;
}


2239
static inline LRESULT
2240
REBAR_GetBkColor (const REBAR_INFO *infoPtr)
Alexandre Julliard's avatar
Alexandre Julliard committed
2241
{
2242
    COLORREF clr = infoPtr->clrBk;
Alexandre Julliard's avatar
Alexandre Julliard committed
2243

Guy Albertelli's avatar
Guy Albertelli committed
2244
    if (clr == CLR_DEFAULT)
2245
      clr = infoPtr->clrBtnFace;
2246

2247
    TRACE("background color 0x%06x!\n", clr);
Alexandre Julliard's avatar
Alexandre Julliard committed
2248

2249
    return clr;
Alexandre Julliard's avatar
Alexandre Julliard committed
2250 2251 2252
}


2253 2254
/* << REBAR_GetColorScheme >> */
/* << REBAR_GetDropTarget >> */
Alexandre Julliard's avatar
Alexandre Julliard committed
2255

Eric Kohl's avatar
Eric Kohl committed
2256 2257

static LRESULT
2258
REBAR_GetPalette (const REBAR_INFO *infoPtr, WPARAM wParam, LPARAM lParam)
Eric Kohl's avatar
Eric Kohl committed
2259
{
2260
    FIXME("empty stub!\n");
Eric Kohl's avatar
Eric Kohl committed
2261 2262 2263 2264 2265 2266

    return 0;
}


static LRESULT
2267
REBAR_GetRect (const REBAR_INFO *infoPtr, WPARAM wParam, LPARAM lParam)
Eric Kohl's avatar
Eric Kohl committed
2268
{
2269 2270
    INT iBand = (INT)wParam;
    LPRECT lprc = (LPRECT)lParam;
Eric Kohl's avatar
Eric Kohl committed
2271 2272
    REBAR_BAND *lpBand;

2273
    if ((iBand < 0) || ((UINT)iBand >= infoPtr->uNumBands))
Eric Kohl's avatar
Eric Kohl committed
2274 2275 2276 2277 2278
	return FALSE;
    if (!lprc)
	return FALSE;

    lpBand = &infoPtr->bands[iBand];
2279
    /* For CCS_VERT the coordinates will be swapped - like on Windows */
2280
    CopyRect (lprc, &lpBand->rcBand);
2281

2282
    TRACE("band %d, (%s)\n", iBand, wine_dbgstr_rect(lprc));
Eric Kohl's avatar
Eric Kohl committed
2283 2284 2285 2286 2287

    return TRUE;
}


2288
static inline LRESULT
2289
REBAR_GetRowCount (const REBAR_INFO *infoPtr)
Eric Kohl's avatar
Eric Kohl committed
2290
{
2291
    TRACE("%u\n", infoPtr->uNumRows);
Eric Kohl's avatar
Eric Kohl committed
2292

2293
    return infoPtr->uNumRows;
Eric Kohl's avatar
Eric Kohl committed
2294 2295 2296 2297
}


static LRESULT
2298
REBAR_GetRowHeight (const REBAR_INFO *infoPtr, WPARAM wParam)
Eric Kohl's avatar
Eric Kohl committed
2299
{
2300
    INT iRow = (INT)wParam;
2301 2302
    int j = 0, ret = 0;
    UINT i;
2303
    REBAR_BAND *lpBand;
Eric Kohl's avatar
Eric Kohl committed
2304

2305
    for (i=0; i<infoPtr->uNumBands; i++) {
2306 2307 2308
	lpBand = &infoPtr->bands[i];
	if (HIDDENBAND(lpBand)) continue;
	if (lpBand->iRow != iRow) continue;
2309
        j = lpBand->rcBand.bottom - lpBand->rcBand.top;
2310
	if (j > ret) ret = j;
2311 2312 2313
    }

    TRACE("row %d, height %d\n", iRow, ret);
Eric Kohl's avatar
Eric Kohl committed
2314

2315
    return ret;
Eric Kohl's avatar
Eric Kohl committed
2316
}
Alexandre Julliard's avatar
Alexandre Julliard committed
2317 2318


2319
static inline LRESULT
2320
REBAR_GetTextColor (const REBAR_INFO *infoPtr)
Alexandre Julliard's avatar
Alexandre Julliard committed
2321
{
2322
    TRACE("text color 0x%06x!\n", infoPtr->clrText);
Alexandre Julliard's avatar
Alexandre Julliard committed
2323 2324 2325 2326 2327

    return infoPtr->clrText;
}


2328
static inline LRESULT
2329
REBAR_GetToolTips (const REBAR_INFO *infoPtr)
Eric Kohl's avatar
Eric Kohl committed
2330
{
2331
    return (LRESULT)infoPtr->hwndToolTip;
Eric Kohl's avatar
Eric Kohl committed
2332 2333 2334
}


2335
static inline LRESULT
2336
REBAR_GetUnicodeFormat (const REBAR_INFO *infoPtr)
Eric Kohl's avatar
Eric Kohl committed
2337
{
2338
    TRACE("%s hwnd=%p\n",
2339 2340
	  infoPtr->bUnicode ? "TRUE" : "FALSE", infoPtr->hwndSelf);

Eric Kohl's avatar
Eric Kohl committed
2341 2342
    return infoPtr->bUnicode;
}
Eric Kohl's avatar
Eric Kohl committed
2343 2344


2345
static inline LRESULT
2346
REBAR_GetVersion (const REBAR_INFO *infoPtr)
Eric Kohl's avatar
Eric Kohl committed
2347
{
2348
    TRACE("version %d\n", infoPtr->iVersion);
Eric Kohl's avatar
Eric Kohl committed
2349 2350 2351 2352
    return infoPtr->iVersion;
}


Eric Kohl's avatar
Eric Kohl committed
2353
static LRESULT
2354
REBAR_HitTest (const REBAR_INFO *infoPtr, LPARAM lParam)
Eric Kohl's avatar
Eric Kohl committed
2355
{
2356
    LPRBHITTESTINFO lprbht = (LPRBHITTESTINFO)lParam;
Eric Kohl's avatar
Eric Kohl committed
2357 2358 2359 2360

    if (!lprbht)
	return -1;

2361
    REBAR_InternalHitTest (infoPtr, &lprbht->pt, &lprbht->flags, &lprbht->iBand);
Eric Kohl's avatar
Eric Kohl committed
2362 2363 2364

    return lprbht->iBand;
}
Alexandre Julliard's avatar
Alexandre Julliard committed
2365 2366 2367


static LRESULT
2368
REBAR_IdToIndex (const REBAR_INFO *infoPtr, WPARAM wParam)
Alexandre Julliard's avatar
Alexandre Julliard committed
2369
{
2370
    UINT i;
Alexandre Julliard's avatar
Alexandre Julliard committed
2371 2372 2373 2374 2375 2376 2377 2378

    if (infoPtr == NULL)
	return -1;

    if (infoPtr->uNumBands < 1)
	return -1;

    for (i = 0; i < infoPtr->uNumBands; i++) {
2379
	if (infoPtr->bands[i].wID == (UINT)wParam) {
2380
	    TRACE("id %u is band %u found!\n", (UINT)wParam, i);
Alexandre Julliard's avatar
Alexandre Julliard committed
2381
	    return i;
Alexandre Julliard's avatar
Alexandre Julliard committed
2382
	}
Alexandre Julliard's avatar
Alexandre Julliard committed
2383 2384
    }

2385
    TRACE("id %u is not found\n", (UINT)wParam);
Alexandre Julliard's avatar
Alexandre Julliard committed
2386 2387 2388 2389 2390
    return -1;
}


static LRESULT
2391
REBAR_InsertBandT(REBAR_INFO *infoPtr, WPARAM wParam, LPARAM lParam, BOOL bUnicode)
Alexandre Julliard's avatar
Alexandre Julliard committed
2392
{
2393
    LPREBARBANDINFOW lprbbi = (LPREBARBANDINFOW)lParam;
2394
    UINT uIndex = (UINT)wParam;
Alexandre Julliard's avatar
Alexandre Julliard committed
2395 2396 2397 2398 2399 2400
    REBAR_BAND *lpBand;

    if (infoPtr == NULL)
	return FALSE;
    if (lprbbi == NULL)
	return FALSE;
2401
    if (lprbbi->cbSize < REBARBANDINFOA_V3_SIZE)
Alexandre Julliard's avatar
Alexandre Julliard committed
2402 2403
	return FALSE;

2404
    /* trace the index as signed to see the -1 */
2405
    TRACE("insert band at %d (bUnicode=%d)!\n", (INT)uIndex, bUnicode);
2406
    REBAR_DumpBandInfo(lprbbi);
2407 2408 2409 2410 2411 2412

    infoPtr->bands = ReAlloc(infoPtr->bands, (infoPtr->uNumBands+1) * sizeof(REBAR_BAND));
    if (((INT)uIndex == -1) || (uIndex > infoPtr->uNumBands))
        uIndex = infoPtr->uNumBands;
    memmove(&infoPtr->bands[uIndex+1], &infoPtr->bands[uIndex],
        sizeof(REBAR_BAND) * (infoPtr->uNumBands - uIndex));
Alexandre Julliard's avatar
Alexandre Julliard committed
2413 2414
    infoPtr->uNumBands++;

2415
    TRACE("index %u!\n", uIndex);
Alexandre Julliard's avatar
Alexandre Julliard committed
2416 2417 2418

    /* initialize band (infoPtr->bands[uIndex])*/
    lpBand = &infoPtr->bands[uIndex];
2419
    ZeroMemory(lpBand, sizeof(*lpBand));
2420 2421
    lpBand->clrFore = infoPtr->clrText;
    lpBand->clrBack = infoPtr->clrBk;
2422
    lpBand->iImage = -1;
2423

2424
    REBAR_CommonSetupBand(infoPtr->hwndSelf, lprbbi, lpBand);
2425 2426 2427 2428 2429 2430 2431 2432

    /* Make sure the defaults for these are correct */
    if (lprbbi->cbSize < sizeof (REBARBANDINFOA) || !(lpBand->fStyle & RBBS_VARIABLEHEIGHT)) {
        lpBand->cyChild    = lpBand->cyMinChild;
        lpBand->cyMaxChild = 0x7fffffff;
        lpBand->cyIntegral = 0;
    }

Alexandre Julliard's avatar
Alexandre Julliard committed
2433
    if ((lprbbi->fMask & RBBIM_TEXT) && (lprbbi->lpText)) {
2434 2435 2436 2437
        if (bUnicode)
            Str_SetPtrW(&lpBand->lpText, lprbbi->lpText);
        else
            Str_SetPtrAtoW(&lpBand->lpText, (LPSTR)lprbbi->lpText);
Alexandre Julliard's avatar
Alexandre Julliard committed
2438 2439
    }

2440
    REBAR_ValidateBand (infoPtr, lpBand);
2441 2442
    /* On insert of second band, revalidate band 1 to possible add gripper */
    if (infoPtr->uNumBands == 2)
2443
	REBAR_ValidateBand (infoPtr, &infoPtr->bands[0]);
Alexandre Julliard's avatar
Alexandre Julliard committed
2444

2445
    REBAR_DumpBand (infoPtr);
Eric Kohl's avatar
Eric Kohl committed
2446

2447
    REBAR_Layout(infoPtr);
2448
    InvalidateRect(infoPtr->hwndSelf, 0, TRUE);
Eric Kohl's avatar
Eric Kohl committed
2449 2450 2451 2452 2453

    return TRUE;
}


2454
static LRESULT
2455
REBAR_MaximizeBand (const REBAR_INFO *infoPtr, WPARAM wParam, LPARAM lParam)
2456
{
2457 2458
    REBAR_BAND *lpBand;
    UINT uBand = (UINT) wParam;
2459 2460 2461
    int iRowBegin, iRowEnd;
    int cxDesired, extra, extraOrig;
    int cxIdealBand;
2462

2463 2464 2465 2466 2467 2468 2469 2470 2471 2472 2473
    /* Validate */
    if ((infoPtr->uNumBands == 0) ||
	((INT)uBand < 0) || (uBand >= infoPtr->uNumBands)) {
	/* error !!! */
	ERR("Illegal MaximizeBand, requested=%d, current band count=%d\n",
	      (INT)uBand, infoPtr->uNumBands);
      	return FALSE;
    }

    lpBand = &infoPtr->bands[uBand];

2474 2475 2476 2477 2478 2479 2480
    if (lpBand->fStyle & RBBS_HIDDEN)
    {
        /* Windows is buggy and creates a hole */
        WARN("Ignoring maximize request on a hidden band (%d)\n", uBand);
        return FALSE;
    }

2481 2482 2483 2484
    cxIdealBand = lpBand->cxIdeal + lpBand->cxHeader + REBAR_POST_CHILD;
    if (lParam && (lpBand->cxEffective < cxIdealBand))
        cxDesired = cxIdealBand;
    else
2485
        cxDesired = infoPtr->calcSize.cx;
2486 2487 2488 2489 2490 2491 2492

    iRowBegin = get_row_begin_for_band(infoPtr, uBand);
    iRowEnd   = get_row_end_for_band(infoPtr, uBand);
    extraOrig = extra = cxDesired - lpBand->cxEffective;
    if (extra > 0)
        extra = REBAR_ShrinkBandsRTL(infoPtr, iRowBegin, uBand, extra, TRUE);
    if (extra > 0)
2493
        extra = REBAR_ShrinkBandsLTR(infoPtr, next_visible(infoPtr, uBand), iRowEnd, extra, TRUE);
2494 2495
    lpBand->cxEffective += extraOrig - extra;
    lpBand->cx = lpBand->cxEffective;
2496
    TRACE("(%ld, %ld): Wanted size %d, obtained %d (shrink %d, %d)\n", wParam, lParam, cxDesired, lpBand->cx, extraOrig, extra);
2497
    REBAR_SetRowRectsX(infoPtr, iRowBegin, iRowEnd);
2498

2499 2500 2501 2502 2503
    if (infoPtr->dwStyle & CCS_VERT)
        REBAR_CalcVertBand(infoPtr, iRowBegin, iRowEnd);
    else
        REBAR_CalcHorzBand(infoPtr, iRowBegin, iRowEnd);
    REBAR_MoveChildWindows(infoPtr, iRowBegin, iRowEnd);
2504
    return TRUE;
2505

2506 2507 2508 2509
}


static LRESULT
2510
REBAR_MinimizeBand (const REBAR_INFO *infoPtr, WPARAM wParam)
2511
{
2512
    REBAR_BAND *lpBand;
2513
    UINT uBand = (UINT) wParam;
2514
    int iPrev, iRowBegin, iRowEnd;
2515

2516 2517 2518 2519 2520 2521 2522 2523 2524 2525 2526 2527 2528 2529 2530 2531
    /* A "minimize" band is equivalent to "dragging" the gripper
     * of than band to the right till the band is only the size
     * of the cxHeader.
     */

    /* Validate */
    if ((infoPtr->uNumBands == 0) ||
	((INT)uBand < 0) || (uBand >= infoPtr->uNumBands)) {
	/* error !!! */
	ERR("Illegal MinimizeBand, requested=%d, current band count=%d\n",
	      (INT)uBand, infoPtr->uNumBands);
      	return FALSE;
    }

    /* compute amount of movement and validate */
    lpBand = &infoPtr->bands[uBand];
2532 2533 2534 2535 2536 2537 2538 2539 2540

    if (lpBand->fStyle & RBBS_HIDDEN)
    {
        /* Windows is buggy and creates a hole/overlap */
        WARN("Ignoring minimize request on a hidden band (%d)\n", uBand);
        return FALSE;
    }

    iPrev = prev_visible(infoPtr, uBand);
2541 2542
    /* if first band in row */
    if (iPrev < 0 || infoPtr->bands[iPrev].iRow != lpBand->iRow) {
2543
        int iNext = next_visible(infoPtr, uBand);
2544
        if (iNext < infoPtr->uNumBands && infoPtr->bands[iNext].iRow == lpBand->iRow) {
2545
            TRACE("(%ld): Minimizing the first band in row is by maximizing the second\n", wParam);
2546 2547 2548
            REBAR_MaximizeBand(infoPtr, iNext, FALSE);
        }
        else
2549
            TRACE("(%ld): Only one band in row - nothing to do\n", wParam);
2550
        return TRUE;
2551 2552
    }

2553
    infoPtr->bands[iPrev].cxEffective += lpBand->cxEffective - lpBand->cxMinBand;
2554
    infoPtr->bands[iPrev].cx = infoPtr->bands[iPrev].cxEffective;
2555
    lpBand->cx = lpBand->cxEffective = lpBand->cxMinBand;
2556

2557 2558 2559
    iRowBegin = get_row_begin_for_band(infoPtr, uBand);
    iRowEnd = get_row_end_for_band(infoPtr, uBand);
    REBAR_SetRowRectsX(infoPtr, iRowBegin, iRowEnd);
2560

2561 2562 2563 2564 2565
    if (infoPtr->dwStyle & CCS_VERT)
        REBAR_CalcVertBand(infoPtr, iRowBegin, iRowEnd);
    else
        REBAR_CalcHorzBand(infoPtr, iRowBegin, iRowEnd);
    REBAR_MoveChildWindows(infoPtr, iRowBegin, iRowEnd);
2566
    return FALSE;
2567 2568 2569 2570
}


static LRESULT
2571
REBAR_MoveBand (REBAR_INFO *infoPtr, WPARAM wParam, LPARAM lParam)
2572
{
2573 2574 2575 2576
    REBAR_BAND *oldBands = infoPtr->bands;
    REBAR_BAND holder;
    UINT uFrom = (UINT)wParam;
    UINT uTo = (UINT)lParam;
2577

2578 2579 2580 2581 2582 2583 2584 2585 2586 2587 2588
    /* Validate */
    if ((infoPtr->uNumBands == 0) ||
	((INT)uFrom < 0) || (uFrom >= infoPtr->uNumBands) ||
	((INT)uTo < 0)   || (uTo >= infoPtr->uNumBands)) {
	/* error !!! */
	ERR("Illegal MoveBand, from=%d, to=%d, current band count=%d\n",
	      (INT)uFrom, (INT)uTo, infoPtr->uNumBands);
      	return FALSE;
    }

    /* save one to be moved */
2589
    holder = oldBands[uFrom];
2590

2591
    /* close up rest of bands (pseudo delete) */
2592 2593 2594 2595 2596 2597
    if (uFrom < infoPtr->uNumBands - 1) {
	memcpy (&oldBands[uFrom], &oldBands[uFrom+1],
		(infoPtr->uNumBands - uFrom - 1) * sizeof(REBAR_BAND));
    }

    /* allocate new space and copy rest of bands into it */
2598
    infoPtr->bands = Alloc ((infoPtr->uNumBands)*sizeof(REBAR_BAND));
2599 2600 2601 2602 2603 2604 2605 2606

    /* pre insert copy */
    if (uTo > 0) {
	memcpy (&infoPtr->bands[0], &oldBands[0],
		uTo * sizeof(REBAR_BAND));
    }

    /* set moved band */
2607
    infoPtr->bands[uTo] = holder;
2608 2609 2610 2611 2612 2613 2614

    /* post copy */
    if (uTo < infoPtr->uNumBands - 1) {
	memcpy (&infoPtr->bands[uTo+1], &oldBands[uTo],
		(infoPtr->uNumBands - uTo - 1) * sizeof(REBAR_BAND));
    }

2615
    Free (oldBands);
2616 2617 2618 2619 2620 2621 2622 2623 2624 2625 2626 2627 2628 2629

    TRACE("moved band %d to index %d\n", uFrom, uTo);
    REBAR_DumpBand (infoPtr);

    /* **************************************************** */
    /*                                                      */
    /* We do not do a REBAR_Layout here because the native  */
    /* control does not do that. The actual layout and      */
    /* repaint is done by the *next* real action, ex.:      */
    /* RB_INSERTBAND, RB_DELETEBAND, RB_SIZETORECT, etc.    */
    /*                                                      */
    /* **************************************************** */

    return TRUE;
2630
}
Alexandre Julliard's avatar
Alexandre Julliard committed
2631 2632


2633 2634 2635 2636 2637 2638 2639
/* return TRUE if two strings are different */
static BOOL
REBAR_strdifW( LPCWSTR a, LPCWSTR b )
{
    return ( (a && !b) || (b && !a) || (a && b && lstrcmpW(a, b) ) );
}

Alexandre Julliard's avatar
Alexandre Julliard committed
2640
static LRESULT
2641
REBAR_SetBandInfoT(REBAR_INFO *infoPtr, WPARAM wParam, LPARAM lParam, BOOL bUnicode)
Alexandre Julliard's avatar
Alexandre Julliard committed
2642
{
2643
    LPREBARBANDINFOW lprbbi = (LPREBARBANDINFOW)lParam;
Alexandre Julliard's avatar
Alexandre Julliard committed
2644
    REBAR_BAND *lpBand;
2645
    UINT uChanged;
Alexandre Julliard's avatar
Alexandre Julliard committed
2646 2647 2648

    if (lprbbi == NULL)
	return FALSE;
2649
    if (lprbbi->cbSize < REBARBANDINFOA_V3_SIZE)
Alexandre Julliard's avatar
Alexandre Julliard committed
2650
	return FALSE;
2651
    if ((UINT)wParam >= infoPtr->uNumBands)
Alexandre Julliard's avatar
Alexandre Julliard committed
2652 2653
	return FALSE;

2654
    TRACE("index %u\n", (UINT)wParam);
2655
    REBAR_DumpBandInfo (lprbbi);
Alexandre Julliard's avatar
Alexandre Julliard committed
2656 2657

    /* set band information */
2658
    lpBand = &infoPtr->bands[(UINT)wParam];
Alexandre Julliard's avatar
Alexandre Julliard committed
2659

2660
    uChanged = REBAR_CommonSetupBand (infoPtr->hwndSelf, lprbbi, lpBand);
Eric Kohl's avatar
Eric Kohl committed
2661
    if (lprbbi->fMask & RBBIM_TEXT) {
2662
        LPWSTR wstr = NULL;
2663 2664 2665 2666
        if (bUnicode)
            Str_SetPtrW(&wstr, lprbbi->lpText);
        else
            Str_SetPtrAtoW(&wstr, (LPSTR)lprbbi->lpText);
2667

Lei Zhang's avatar
Lei Zhang committed
2668
        if (REBAR_strdifW(wstr, lpBand->lpText)) {
2669 2670
            Free(lpBand->lpText);
            lpBand->lpText = wstr;
2671
            uChanged |= RBBIM_TEXT;
2672
        }
2673 2674
        else
            Free(wstr);
Alexandre Julliard's avatar
Alexandre Julliard committed
2675 2676
    }

2677
    REBAR_ValidateBand (infoPtr, lpBand);
Alexandre Julliard's avatar
Alexandre Julliard committed
2678

2679
    REBAR_DumpBand (infoPtr);
Alexandre Julliard's avatar
Alexandre Julliard committed
2680

2681
    if (uChanged & (RBBIM_CHILDSIZE | RBBIM_SIZE | RBBIM_STYLE | RBBIM_IMAGE)) {
2682
	  REBAR_Layout(infoPtr);
2683 2684
	  InvalidateRect(infoPtr->hwndSelf, 0, 1);
    }
Alexandre Julliard's avatar
Alexandre Julliard committed
2685 2686 2687 2688 2689 2690

    return TRUE;
}


static LRESULT
2691
REBAR_SetBarInfo (REBAR_INFO *infoPtr, LPARAM lParam)
Alexandre Julliard's avatar
Alexandre Julliard committed
2692 2693
{
    LPREBARINFO lpInfo = (LPREBARINFO)lParam;
2694 2695
    REBAR_BAND *lpBand;
    UINT i;
Alexandre Julliard's avatar
Alexandre Julliard committed
2696 2697 2698 2699 2700 2701 2702

    if (lpInfo == NULL)
	return FALSE;

    if (lpInfo->cbSize < sizeof (REBARINFO))
	return FALSE;

2703
    TRACE("setting bar info!\n");
Alexandre Julliard's avatar
Alexandre Julliard committed
2704

Eric Kohl's avatar
Eric Kohl committed
2705
    if (lpInfo->fMask & RBIM_IMAGELIST) {
Alexandre Julliard's avatar
Alexandre Julliard committed
2706
	infoPtr->himl = lpInfo->himl;
Eric Kohl's avatar
Eric Kohl committed
2707
	if (infoPtr->himl) {
2708 2709 2710 2711
            INT cx, cy;
	    ImageList_GetIconSize (infoPtr->himl, &cx, &cy);
	    infoPtr->imageSize.cx = cx;
	    infoPtr->imageSize.cy = cy;
Eric Kohl's avatar
Eric Kohl committed
2712 2713 2714 2715 2716
	}
	else {
	    infoPtr->imageSize.cx = 0;
	    infoPtr->imageSize.cy = 0;
	}
2717
	TRACE("new image cx=%d, cy=%d\n", infoPtr->imageSize.cx,
2718
	      infoPtr->imageSize.cy);
Eric Kohl's avatar
Eric Kohl committed
2719
    }
Alexandre Julliard's avatar
Alexandre Julliard committed
2720

2721 2722 2723
    /* revalidate all bands to reset flags for images in headers of bands */
    for (i=0; i<infoPtr->uNumBands; i++) {
        lpBand = &infoPtr->bands[i];
2724
	REBAR_ValidateBand (infoPtr, lpBand);
2725 2726
    }

Alexandre Julliard's avatar
Alexandre Julliard committed
2727 2728 2729 2730 2731
    return TRUE;
}


static LRESULT
2732
REBAR_SetBkColor (REBAR_INFO *infoPtr, LPARAM lParam)
Alexandre Julliard's avatar
Alexandre Julliard committed
2733 2734 2735 2736 2737 2738
{
    COLORREF clrTemp;

    clrTemp = infoPtr->clrBk;
    infoPtr->clrBk = (COLORREF)lParam;

2739
    TRACE("background color 0x%06x!\n", infoPtr->clrBk);
Alexandre Julliard's avatar
Alexandre Julliard committed
2740 2741 2742 2743 2744

    return clrTemp;
}


2745 2746
/* << REBAR_SetColorScheme >> */
/* << REBAR_SetPalette >> */
Eric Kohl's avatar
Eric Kohl committed
2747 2748 2749


static LRESULT
2750
REBAR_SetParent (REBAR_INFO *infoPtr, WPARAM wParam)
Eric Kohl's avatar
Eric Kohl committed
2751
{
2752
    HWND hwndTemp = infoPtr->hwndNotify;
Eric Kohl's avatar
Eric Kohl committed
2753

2754
    infoPtr->hwndNotify = (HWND)wParam;
Eric Kohl's avatar
Eric Kohl committed
2755 2756 2757

    return (LRESULT)hwndTemp;
}
Alexandre Julliard's avatar
Alexandre Julliard committed
2758 2759 2760


static LRESULT
2761
REBAR_SetTextColor (REBAR_INFO *infoPtr, LPARAM lParam)
Alexandre Julliard's avatar
Alexandre Julliard committed
2762 2763 2764 2765 2766 2767
{
    COLORREF clrTemp;

    clrTemp = infoPtr->clrText;
    infoPtr->clrText = (COLORREF)lParam;

2768
    TRACE("text color 0x%06x!\n", infoPtr->clrText);
Alexandre Julliard's avatar
Alexandre Julliard committed
2769 2770 2771 2772 2773

    return clrTemp;
}


2774
/* << REBAR_SetTooltips >> */
Eric Kohl's avatar
Eric Kohl committed
2775 2776


2777
static inline LRESULT
2778
REBAR_SetUnicodeFormat (REBAR_INFO *infoPtr, WPARAM wParam)
Eric Kohl's avatar
Eric Kohl committed
2779
{
2780
    BOOL bTemp = infoPtr->bUnicode;
2781

2782
    TRACE("to %s hwnd=%p, was %s\n",
2783 2784 2785
	  ((BOOL)wParam) ? "TRUE" : "FALSE", infoPtr->hwndSelf,
	  (bTemp) ? "TRUE" : "FALSE");

2786
    infoPtr->bUnicode = (BOOL)wParam;
2787

2788
   return bTemp;
Eric Kohl's avatar
Eric Kohl committed
2789
}
Alexandre Julliard's avatar
Alexandre Julliard committed
2790 2791


Eric Kohl's avatar
Eric Kohl committed
2792
static LRESULT
2793
REBAR_SetVersion (REBAR_INFO *infoPtr, INT iVersion)
Eric Kohl's avatar
Eric Kohl committed
2794 2795 2796 2797 2798 2799 2800 2801
{
    INT iOldVersion = infoPtr->iVersion;

    if (iVersion > COMCTL32_VERSION)
	return -1;

    infoPtr->iVersion = iVersion;

2802 2803
    TRACE("new version %d\n", iVersion);

Eric Kohl's avatar
Eric Kohl committed
2804 2805 2806 2807
    return iOldVersion;
}


Alexandre Julliard's avatar
Alexandre Julliard committed
2808
static LRESULT
2809
REBAR_ShowBand (REBAR_INFO *infoPtr, WPARAM wParam, LPARAM lParam)
Alexandre Julliard's avatar
Alexandre Julliard committed
2810
{
Eric Kohl's avatar
Eric Kohl committed
2811
    REBAR_BAND *lpBand;
Alexandre Julliard's avatar
Alexandre Julliard committed
2812

2813
    if (((INT)wParam < 0) || ((INT)wParam > infoPtr->uNumBands))
Alexandre Julliard's avatar
Alexandre Julliard committed
2814 2815
	return FALSE;

2816
    lpBand = &infoPtr->bands[(INT)wParam];
Eric Kohl's avatar
Eric Kohl committed
2817

2818
    if ((BOOL)lParam) {
2819
	TRACE("show band %d\n", (INT)wParam);
Eric Kohl's avatar
Eric Kohl committed
2820
	lpBand->fStyle = lpBand->fStyle & ~RBBS_HIDDEN;
2821 2822
	if (IsWindow (lpBand->hwndChild))
	    ShowWindow (lpBand->hwndChild, SW_SHOW);
Eric Kohl's avatar
Eric Kohl committed
2823 2824
    }
    else {
2825
	TRACE("hide band %d\n", (INT)wParam);
Eric Kohl's avatar
Eric Kohl committed
2826
	lpBand->fStyle = lpBand->fStyle | RBBS_HIDDEN;
2827
	if (IsWindow (lpBand->hwndChild))
2828
	    ShowWindow (lpBand->hwndChild, SW_HIDE);
Eric Kohl's avatar
Eric Kohl committed
2829 2830
    }

2831
    REBAR_Layout(infoPtr);
2832
    InvalidateRect(infoPtr->hwndSelf, 0, 1);
Alexandre Julliard's avatar
Alexandre Julliard committed
2833 2834 2835 2836 2837 2838

    return TRUE;
}


static LRESULT
2839
REBAR_SizeToRect (REBAR_INFO *infoPtr, LPARAM lParam)
Alexandre Julliard's avatar
Alexandre Julliard committed
2840
{
2841
    LPRECT lpRect = (LPRECT)lParam;
Alexandre Julliard's avatar
Alexandre Julliard committed
2842 2843

    if (lpRect == NULL)
2844
       return FALSE;
Alexandre Julliard's avatar
Alexandre Julliard committed
2845

2846
    TRACE("[%s]\n", wine_dbgstr_rect(lpRect));
2847
    REBAR_SizeToHeight(infoPtr, get_rect_cy(infoPtr, lpRect));
Alexandre Julliard's avatar
Alexandre Julliard committed
2848 2849
    return TRUE;
}
Alexandre Julliard's avatar
Alexandre Julliard committed
2850 2851 2852 2853



static LRESULT
2854
REBAR_Create (REBAR_INFO *infoPtr, LPARAM lParam)
Alexandre Julliard's avatar
Alexandre Julliard committed
2855
{
2856
    LPCREATESTRUCTW cs = (LPCREATESTRUCTW) lParam;
2857 2858 2859
    RECT wnrc1, clrc1;

    if (TRACE_ON(rebar)) {
2860 2861
	GetWindowRect(infoPtr->hwndSelf, &wnrc1);
	GetClientRect(infoPtr->hwndSelf, &clrc1);
2862 2863
        TRACE("window=(%s) client=(%s) cs=(%d,%d %dx%d)\n",
              wine_dbgstr_rect(&wnrc1), wine_dbgstr_rect(&clrc1),
2864 2865
	      cs->x, cs->y, cs->cx, cs->cy);
    }
Alexandre Julliard's avatar
Alexandre Julliard committed
2866

2867
    TRACE("created!\n");
2868 2869

    if (OpenThemeData (infoPtr->hwndSelf, themeClass))
2870 2871 2872 2873 2874
    {
        /* native seems to clear WS_BORDER when themed */
        infoPtr->dwStyle &= ~WS_BORDER;
    }
    
Alexandre Julliard's avatar
Alexandre Julliard committed
2875 2876 2877 2878 2879
    return 0;
}


static LRESULT
2880
REBAR_Destroy (REBAR_INFO *infoPtr)
Alexandre Julliard's avatar
Alexandre Julliard committed
2881 2882
{
    REBAR_BAND *lpBand;
2883
    UINT i;
Alexandre Julliard's avatar
Alexandre Julliard committed
2884 2885 2886 2887 2888 2889 2890 2891 2892


    /* free rebar bands */
    if ((infoPtr->uNumBands > 0) && infoPtr->bands) {
	/* clean up each band */
	for (i = 0; i < infoPtr->uNumBands; i++) {
	    lpBand = &infoPtr->bands[i];

	    /* delete text strings */
2893 2894
            Free (lpBand->lpText);
            lpBand->lpText = NULL;
2895
	    /* destroy child window */
2896
	    DestroyWindow (lpBand->hwndChild);
Alexandre Julliard's avatar
Alexandre Julliard committed
2897 2898 2899
	}

	/* free band array */
2900
	Free (infoPtr->bands);
Alexandre Julliard's avatar
Alexandre Julliard committed
2901 2902 2903
	infoPtr->bands = NULL;
    }

2904 2905 2906 2907
    DestroyCursor (infoPtr->hcurArrow);
    DestroyCursor (infoPtr->hcurHorz);
    DestroyCursor (infoPtr->hcurVert);
    DestroyCursor (infoPtr->hcurDrag);
2908
    if(infoPtr->hDefaultFont) DeleteObject (infoPtr->hDefaultFont);
2909
    SetWindowLongPtrW (infoPtr->hwndSelf, 0, 0);
2910 2911
    
    CloseThemeData (GetWindowTheme (infoPtr->hwndSelf));
Eric Kohl's avatar
Eric Kohl committed
2912

Alexandre Julliard's avatar
Alexandre Julliard committed
2913
    /* free rebar info data */
2914
    Free (infoPtr);
2915
    TRACE("destroyed!\n");
Alexandre Julliard's avatar
Alexandre Julliard committed
2916 2917 2918 2919
    return 0;
}


2920
static LRESULT
2921
REBAR_EraseBkGnd (const REBAR_INFO *infoPtr, WPARAM wParam)
2922 2923 2924 2925
{
    RECT cliprect;

    if (GetClipBox ( (HDC)wParam, &cliprect))
2926
        return REBAR_InternalEraseBkGnd (infoPtr, wParam, &cliprect);
2927 2928 2929 2930
    return 0;
}


Eric Kohl's avatar
Eric Kohl committed
2931
static LRESULT
2932
REBAR_GetFont (const REBAR_INFO *infoPtr)
Eric Kohl's avatar
Eric Kohl committed
2933 2934 2935 2936
{
    return (LRESULT)infoPtr->hFont;
}

Robert Shearman's avatar
Robert Shearman committed
2937
static LRESULT
2938
REBAR_PushChevron(const REBAR_INFO *infoPtr, WPARAM wParam, LPARAM lParam)
Robert Shearman's avatar
Robert Shearman committed
2939
{
2940
    if ((UINT)wParam < infoPtr->uNumBands)
Robert Shearman's avatar
Robert Shearman committed
2941 2942 2943 2944
    {
        NMREBARCHEVRON nmrbc;
        REBAR_BAND *lpBand = &infoPtr->bands[wParam];

2945
        TRACE("Pressed chevron on band %ld\n", wParam);
Robert Shearman's avatar
Robert Shearman committed
2946 2947 2948 2949 2950 2951 2952 2953 2954 2955 2956 2957 2958 2959 2960 2961 2962 2963 2964 2965 2966 2967

        /* redraw chevron in pushed state */
        lpBand->fDraw |= DRAW_CHEVRONPUSHED;
        RedrawWindow(infoPtr->hwndSelf, &lpBand->rcChevron,0,
          RDW_ERASE|RDW_INVALIDATE|RDW_UPDATENOW);

        /* notify app so it can display a popup menu or whatever */
        nmrbc.uBand = wParam;
        nmrbc.wID = lpBand->wID;
        nmrbc.lParam = lpBand->lParam;
        nmrbc.rc = lpBand->rcChevron;
        nmrbc.lParamNM = lParam;
        REBAR_Notify((NMHDR*)&nmrbc, infoPtr, RBN_CHEVRONPUSHED);

        /* redraw chevron in previous state */
        lpBand->fDraw &= ~DRAW_CHEVRONPUSHED;
        InvalidateRect(infoPtr->hwndSelf, &lpBand->rcChevron, TRUE);

        return TRUE;
    }
    return FALSE;
}
Eric Kohl's avatar
Eric Kohl committed
2968

2969
static LRESULT
2970
REBAR_LButtonDown (REBAR_INFO *infoPtr, LPARAM lParam)
2971 2972
{
    REBAR_BAND *lpBand;
Robert Shearman's avatar
Robert Shearman committed
2973
    UINT htFlags;
Mike McCormack's avatar
Mike McCormack committed
2974
    INT iHitBand;
Robert Shearman's avatar
Robert Shearman committed
2975
    POINT ptMouseDown;
2976 2977
    ptMouseDown.x = (short)LOWORD(lParam);
    ptMouseDown.y = (short)HIWORD(lParam);
2978

Robert Shearman's avatar
Robert Shearman committed
2979 2980
    REBAR_InternalHitTest(infoPtr, &ptMouseDown, &htFlags, &iHitBand);
    lpBand = &infoPtr->bands[iHitBand];
2981

Robert Shearman's avatar
Robert Shearman committed
2982 2983 2984 2985 2986 2987 2988
    if (htFlags == RBHT_CHEVRON)
    {
        REBAR_PushChevron(infoPtr, iHitBand, 0);
    }
    else if (htFlags == RBHT_GRABBER || htFlags == RBHT_CAPTION)
    {
        TRACE("Starting drag\n");
2989

Robert Shearman's avatar
Robert Shearman committed
2990 2991
        SetCapture (infoPtr->hwndSelf);
        infoPtr->iGrabbedBand = iHitBand;
2992

Robert Shearman's avatar
Robert Shearman committed
2993
        /* save off the LOWORD and HIWORD of lParam as initial x,y */
2994 2995
        infoPtr->dragStart.x = (short)LOWORD(lParam);
        infoPtr->dragStart.y = (short)HIWORD(lParam);
Robert Shearman's avatar
Robert Shearman committed
2996 2997
        infoPtr->dragNow = infoPtr->dragStart;
        if (infoPtr->dwStyle & CCS_VERT)
2998
            infoPtr->ihitoffset = infoPtr->dragStart.y - (lpBand->rcBand.left + REBAR_PRE_GRIPPER);
Robert Shearman's avatar
Robert Shearman committed
2999
        else
3000
            infoPtr->ihitoffset = infoPtr->dragStart.x - (lpBand->rcBand.left + REBAR_PRE_GRIPPER);
Robert Shearman's avatar
Robert Shearman committed
3001
    }
3002 3003 3004 3005
    return 0;
}

static LRESULT
3006
REBAR_LButtonUp (REBAR_INFO *infoPtr)
3007
{
Robert Shearman's avatar
Robert Shearman committed
3008 3009 3010 3011 3012 3013 3014 3015
    if (infoPtr->iGrabbedBand >= 0)
    {
        NMHDR layout;
        RECT rect;

        infoPtr->dragStart.x = 0;
        infoPtr->dragStart.y = 0;
        infoPtr->dragNow = infoPtr->dragStart;
3016

Robert Shearman's avatar
Robert Shearman committed
3017
        ReleaseCapture ();
3018

Robert Shearman's avatar
Robert Shearman committed
3019 3020 3021 3022 3023
        if (infoPtr->fStatus & BEGIN_DRAG_ISSUED) {
            REBAR_Notify(&layout, infoPtr, RBN_LAYOUTCHANGED);
            REBAR_Notify_NMREBAR (infoPtr, infoPtr->iGrabbedBand, RBN_ENDDRAG);
            infoPtr->fStatus &= ~BEGIN_DRAG_ISSUED;
        }
3024

Robert Shearman's avatar
Robert Shearman committed
3025
        infoPtr->iGrabbedBand = -1;
3026

Robert Shearman's avatar
Robert Shearman committed
3027 3028
        GetClientRect(infoPtr->hwndSelf, &rect);
        InvalidateRect(infoPtr->hwndSelf, NULL, TRUE);
3029 3030 3031 3032 3033
    }

    return 0;
}

Robert Shearman's avatar
Robert Shearman committed
3034
static LRESULT
3035
REBAR_MouseLeave (REBAR_INFO *infoPtr)
Robert Shearman's avatar
Robert Shearman committed
3036 3037 3038 3039 3040 3041 3042 3043 3044 3045 3046 3047 3048 3049 3050
{
    if (infoPtr->ichevronhotBand >= 0)
    {
        REBAR_BAND *lpChevronBand = &infoPtr->bands[infoPtr->ichevronhotBand];
        if (lpChevronBand->fDraw & DRAW_CHEVRONHOT)
        {
            lpChevronBand->fDraw &= ~DRAW_CHEVRONHOT;
            InvalidateRect(infoPtr->hwndSelf, &lpChevronBand->rcChevron, TRUE);
        }
    }
    infoPtr->iOldBand = -1;
    infoPtr->ichevronhotBand = -2;

    return TRUE;
}
3051

Eric Kohl's avatar
Eric Kohl committed
3052
static LRESULT
3053
REBAR_MouseMove (REBAR_INFO *infoPtr, LPARAM lParam)
Eric Kohl's avatar
Eric Kohl committed
3054
{
Robert Shearman's avatar
Robert Shearman committed
3055
    REBAR_BAND *lpChevronBand;
3056
    POINT ptMove;
Eric Kohl's avatar
Eric Kohl committed
3057

3058 3059
    ptMove.x = (short)LOWORD(lParam);
    ptMove.y = (short)HIWORD(lParam);
3060

Robert Shearman's avatar
Robert Shearman committed
3061 3062 3063 3064
    /* if we are currently dragging a band */
    if (infoPtr->iGrabbedBand >= 0)
    {
        REBAR_BAND *band1, *band2;
3065 3066
        int yPtMove = (infoPtr->dwStyle & CCS_VERT ? ptMove.x : ptMove.y);

Robert Shearman's avatar
Robert Shearman committed
3067 3068
        if (GetCapture() != infoPtr->hwndSelf)
            ERR("We are dragging but haven't got capture?!?\n");
3069

Robert Shearman's avatar
Robert Shearman committed
3070 3071
        band1 = &infoPtr->bands[infoPtr->iGrabbedBand-1];
        band2 = &infoPtr->bands[infoPtr->iGrabbedBand];
3072

Robert Shearman's avatar
Robert Shearman committed
3073
        /* if mouse did not move much, exit */
3074 3075
        if ((abs(ptMove.x - infoPtr->dragNow.x) <= mindragx) &&
            (abs(ptMove.y - infoPtr->dragNow.y) <= mindragy)) return 0;
Robert Shearman's avatar
Robert Shearman committed
3076 3077

        /* Test for valid drag case - must not be first band in row */
3078 3079
        if ((yPtMove < band2->rcBand.top) ||
	      (yPtMove > band2->rcBand.bottom) ||
Robert Shearman's avatar
Robert Shearman committed
3080
              ((infoPtr->iGrabbedBand > 0) && (band1->iRow != band2->iRow))) {
3081
            FIXME("Cannot drag to other rows yet!!\n");
Robert Shearman's avatar
Robert Shearman committed
3082 3083
        }
        else {
3084
            REBAR_HandleLRDrag (infoPtr, &ptMove);
Robert Shearman's avatar
Robert Shearman committed
3085
        }
3086
    }
Robert Shearman's avatar
Robert Shearman committed
3087 3088 3089 3090 3091 3092 3093 3094 3095 3096 3097 3098 3099 3100 3101 3102 3103 3104 3105 3106 3107 3108 3109 3110 3111 3112 3113 3114 3115 3116 3117 3118 3119 3120 3121 3122 3123 3124 3125 3126 3127 3128 3129 3130 3131 3132 3133 3134 3135
    else
    {
        INT iHitBand;
        UINT htFlags;
        TRACKMOUSEEVENT trackinfo;

        REBAR_InternalHitTest(infoPtr, &ptMove, &htFlags, &iHitBand);

        if (infoPtr->iOldBand >= 0 && infoPtr->iOldBand == infoPtr->ichevronhotBand)
        {
            lpChevronBand = &infoPtr->bands[infoPtr->ichevronhotBand];
            if (lpChevronBand->fDraw & DRAW_CHEVRONHOT)
            {
                lpChevronBand->fDraw &= ~DRAW_CHEVRONHOT;
                InvalidateRect(infoPtr->hwndSelf, &lpChevronBand->rcChevron, TRUE);
            }
            infoPtr->ichevronhotBand = -2;
        }

        if (htFlags == RBHT_CHEVRON)
        {
            /* fill in the TRACKMOUSEEVENT struct */
            trackinfo.cbSize = sizeof(TRACKMOUSEEVENT);
            trackinfo.dwFlags = TME_QUERY;
            trackinfo.hwndTrack = infoPtr->hwndSelf;
            trackinfo.dwHoverTime = 0;

            /* call _TrackMouseEvent to see if we are currently tracking for this hwnd */
            _TrackMouseEvent(&trackinfo);

            /* Make sure tracking is enabled so we receive a WM_MOUSELEAVE message */
            if(!(trackinfo.dwFlags & TME_LEAVE))
            {
                trackinfo.dwFlags = TME_LEAVE; /* notify upon leaving */

                /* call TRACKMOUSEEVENT so we receive a WM_MOUSELEAVE message */
                /* and can properly deactivate the hot chevron */
                _TrackMouseEvent(&trackinfo);
            }

            lpChevronBand = &infoPtr->bands[iHitBand];
            if (!(lpChevronBand->fDraw & DRAW_CHEVRONHOT))
            {
                lpChevronBand->fDraw |= DRAW_CHEVRONHOT;
                InvalidateRect(infoPtr->hwndSelf, &lpChevronBand->rcChevron, TRUE);
                infoPtr->ichevronhotBand = iHitBand;
            }
        }
        infoPtr->iOldBand = iHitBand;
3136
    }
Robert Shearman's avatar
Robert Shearman committed
3137

Eric Kohl's avatar
Eric Kohl committed
3138 3139 3140 3141
    return 0;
}


3142
static inline LRESULT
3143
REBAR_NCCalcSize (const REBAR_INFO *infoPtr, LPARAM lParam)
Eric Kohl's avatar
Eric Kohl committed
3144
{
3145
    HTHEME theme;
3146 3147
    RECT *rect = (RECT *)lParam;

3148
    if (infoPtr->dwStyle & WS_BORDER) {
3149 3150
        rect->left   = min(rect->left + GetSystemMetrics(SM_CXEDGE), rect->right);
        rect->right  = max(rect->right - GetSystemMetrics(SM_CXEDGE), rect->left);
3151 3152
        rect->top    = min(rect->top + GetSystemMetrics(SM_CYEDGE), rect->bottom);
        rect->bottom = max(rect->bottom - GetSystemMetrics(SM_CYEDGE), rect->top);
Eric Kohl's avatar
Eric Kohl committed
3153
    }
3154 3155
    else if ((theme = GetWindowTheme (infoPtr->hwndSelf)))
    {
3156
        /* FIXME: should use GetThemeInt */
3157
        rect->top = min(rect->top + 1, rect->bottom);
3158
    }
3159
    TRACE("new client=(%s)\n", wine_dbgstr_rect(rect));
3160
    return 0;
Eric Kohl's avatar
Eric Kohl committed
3161 3162 3163
}


3164
static LRESULT
3165
REBAR_NCCreate (HWND hwnd, LPARAM lParam)
3166
{
3167
    LPCREATESTRUCTW cs = (LPCREATESTRUCTW) lParam;
3168 3169
    REBAR_INFO *infoPtr = REBAR_GetInfoPtr (hwnd);
    RECT wnrc1, clrc1;
3170
    NONCLIENTMETRICSW ncm;
3171
    HFONT tfont;
3172 3173 3174 3175 3176 3177 3178 3179 3180

    if (infoPtr != NULL) {
	ERR("Strange info structure pointer *not* NULL\n");
	return FALSE;
    }

    if (TRACE_ON(rebar)) {
	GetWindowRect(hwnd, &wnrc1);
	GetClientRect(hwnd, &clrc1);
3181 3182
        TRACE("window=(%s) client=(%s) cs=(%d,%d %dx%d)\n",
              wine_dbgstr_rect(&wnrc1), wine_dbgstr_rect(&clrc1),
3183 3184 3185 3186
	      cs->x, cs->y, cs->cx, cs->cy);
    }

    /* allocate memory for info structure */
3187
    infoPtr = Alloc (sizeof(REBAR_INFO));
3188
    SetWindowLongPtrW (hwnd, 0, (DWORD_PTR)infoPtr);
3189 3190 3191

    /* initialize info structure - initial values are 0 */
    infoPtr->clrBk = CLR_NONE;
3192 3193
    infoPtr->clrText = CLR_NONE;
    infoPtr->clrBtnText = GetSysColor (COLOR_BTNTEXT);
3194
    infoPtr->clrBtnFace = GetSysColor (COLOR_BTNFACE);
Robert Shearman's avatar
Robert Shearman committed
3195 3196 3197
    infoPtr->iOldBand = -1;
    infoPtr->ichevronhotBand = -2;
    infoPtr->iGrabbedBand = -1;
3198 3199
    infoPtr->hwndSelf = hwnd;
    infoPtr->DoRedraw = TRUE;
3200 3201 3202 3203
    infoPtr->hcurArrow = LoadCursorW (0, (LPWSTR)IDC_ARROW);
    infoPtr->hcurHorz  = LoadCursorW (0, (LPWSTR)IDC_SIZEWE);
    infoPtr->hcurVert  = LoadCursorW (0, (LPWSTR)IDC_SIZENS);
    infoPtr->hcurDrag  = LoadCursorW (0, (LPWSTR)IDC_SIZE);
3204
    infoPtr->fStatus = 0;
3205
    infoPtr->hFont = GetStockObject (SYSTEM_FONT);
3206 3207

    /* issue WM_NOTIFYFORMAT to get unicode status of parent */
3208
    REBAR_NotifyFormat(infoPtr, NF_REQUERY);
3209

3210 3211
    /* Stow away the original style */
    infoPtr->orgStyle = cs->style;
3212
    /* add necessary styles to the requested styles */
3213 3214 3215
    infoPtr->dwStyle = cs->style | WS_VISIBLE;
    if ((infoPtr->dwStyle & CCS_LAYOUT_MASK) == 0)
        infoPtr->dwStyle |= CCS_TOP;
3216
    SetWindowLongW (hwnd, GWL_STYLE, infoPtr->dwStyle);
3217

3218
    /* get font handle for Caption Font */
3219
    ncm.cbSize = sizeof(ncm);
3220
    SystemParametersInfoW (SPI_GETNONCLIENTMETRICS, ncm.cbSize, &ncm, 0);
3221 3222 3223 3224
    /* if the font is bold, set to normal */
    if (ncm.lfCaptionFont.lfWeight > FW_NORMAL) {
	ncm.lfCaptionFont.lfWeight = FW_NORMAL;
    }
3225
    tfont = CreateFontIndirectW (&ncm.lfCaptionFont);
3226
    if (tfont) {
3227
        infoPtr->hFont = infoPtr->hDefaultFont = tfont;
3228 3229
    }

3230 3231 3232
/* native does:
	    GetSysColor (numerous);
	    GetSysColorBrush (numerous) (see WM_SYSCOLORCHANGE);
3233
	   *GetStockObject (SYSTEM_FONT);
3234 3235 3236 3237 3238
	   *SetWindowLong (hwnd, 0, info ptr);
	   *WM_NOTIFYFORMAT;
	   *SetWindowLong (hwnd, GWL_STYLE, style+0x10000001);
                                    WS_VISIBLE = 0x10000000;
                                    CCS_TOP    = 0x00000001;
3239 3240
	   *SystemParametersInfo (SPI_GETNONCLIENTMETRICS...);
	   *CreateFontIndirect (lfCaptionFont from above);
3241 3242 3243 3244 3245 3246 3247 3248 3249 3250 3251 3252 3253 3254 3255 3256 3257
	    GetDC ();
	    SelectObject (hdc, fontabove);
	    GetTextMetrics (hdc, );    guessing is tmHeight
	    SelectObject (hdc, oldfont);
	    ReleaseDC ();
	    GetWindowRect ();
	    MapWindowPoints (0, parent, rectabove, 2);
	    GetWindowRect ();
	    GetClientRect ();
	    ClientToScreen (clientrect);
	    SetWindowPos (hwnd, 0, 0, 0, 0, 0, SWP_NOZORDER);
 */
    return TRUE;
}


static LRESULT
3258
REBAR_NCHitTest (const REBAR_INFO *infoPtr, LPARAM lParam)
3259 3260
{
    NMMOUSE nmmouse;
3261
    POINT clpt;
3262 3263 3264 3265 3266 3267 3268 3269 3270 3271 3272 3273
    INT i;
    UINT scrap;
    LRESULT ret = HTCLIENT;

    /*
     * Differences from doc at MSDN (as observed with version 4.71 of
     *      comctl32.dll
     * 1. doc says nmmouse.pt is in screen coord, trace shows client coord.
     * 2. if band is not identified .dwItemSpec is 0xffffffff.
     * 3. native always seems to return HTCLIENT if notify return is 0.
     */

3274 3275
    clpt.x = (short)LOWORD(lParam);
    clpt.y = (short)HIWORD(lParam);
3276
    ScreenToClient (infoPtr->hwndSelf, &clpt);
3277
    REBAR_InternalHitTest (infoPtr, &clpt, &scrap,
3278 3279 3280 3281 3282 3283
			   (INT *)&nmmouse.dwItemSpec);
    nmmouse.dwItemData = 0;
    nmmouse.pt = clpt;
    nmmouse.dwHitInfo = 0;
    if ((i = REBAR_Notify((NMHDR *) &nmmouse, infoPtr, NM_NCHITTEST))) {
	TRACE("notify changed return value from %ld to %d\n",
3284
	      ret, i);
3285 3286
	ret = (LRESULT) i;
    }
3287
    TRACE("returning %ld, client point (%d,%d)\n", ret, clpt.x, clpt.y);
3288 3289 3290 3291
    return ret;
}


Eric Kohl's avatar
Eric Kohl committed
3292
static LRESULT
3293
REBAR_NCPaint (const REBAR_INFO *infoPtr)
Eric Kohl's avatar
Eric Kohl committed
3294
{
3295
    RECT rcWindow;
3296
    HDC hdc;
3297
    HTHEME theme;
Eric Kohl's avatar
Eric Kohl committed
3298

3299
    if (infoPtr->dwStyle & WS_MINIMIZE)
3300
	return 0; /* Nothing to do */
Eric Kohl's avatar
Eric Kohl committed
3301

3302
    if (infoPtr->dwStyle & WS_BORDER) {
3303 3304 3305 3306

	/* adjust rectangle and draw the necessary edge */
	if (!(hdc = GetDCEx( infoPtr->hwndSelf, 0, DCX_USESTYLE | DCX_WINDOW )))
	    return 0;
3307
	GetWindowRect (infoPtr->hwndSelf, &rcWindow);
3308
	OffsetRect (&rcWindow, -rcWindow.left, -rcWindow.top);
3309
        TRACE("rect (%s)\n", wine_dbgstr_rect(&rcWindow));
3310 3311
	DrawEdge (hdc, &rcWindow, EDGE_ETCHED, BF_RECT);
	ReleaseDC( infoPtr->hwndSelf, hdc );
3312
    }
3313 3314 3315 3316 3317 3318 3319
    else if ((theme = GetWindowTheme (infoPtr->hwndSelf)))
    {
        /* adjust rectangle and draw the necessary edge */
        if (!(hdc = GetDCEx( infoPtr->hwndSelf, 0, DCX_USESTYLE | DCX_WINDOW )))
            return 0;
        GetWindowRect (infoPtr->hwndSelf, &rcWindow);
        OffsetRect (&rcWindow, -rcWindow.left, -rcWindow.top);
3320
        TRACE("rect (%s)\n", wine_dbgstr_rect(&rcWindow));
3321 3322 3323
        DrawThemeEdge (theme, hdc, 0, 0, &rcWindow, BDR_RAISEDINNER, BF_TOP, NULL);
        ReleaseDC( infoPtr->hwndSelf, hdc );
    }
Eric Kohl's avatar
Eric Kohl committed
3324 3325 3326 3327

    return 0;
}

Alexandre Julliard's avatar
Alexandre Julliard committed
3328

3329
static LRESULT
3330
REBAR_NotifyFormat (REBAR_INFO *infoPtr, LPARAM lParam)
3331 3332 3333 3334
{
    INT i;

    if (lParam == NF_REQUERY) {
3335
	i = SendMessageW(REBAR_GetNotifyParent (infoPtr),
3336
			 WM_NOTIFYFORMAT, (WPARAM)infoPtr->hwndSelf, NF_QUERY);
3337
        if ((i != NFR_ANSI) && (i != NFR_UNICODE)) {
3338
	    ERR("wrong response to WM_NOTIFYFORMAT (%d), assuming ANSI\n", i);
3339 3340
	    i = NFR_ANSI;
	}
3341
        infoPtr->bUnicode = (i == NFR_UNICODE) ? 1 : 0;
3342 3343 3344 3345 3346 3347
	return (LRESULT)i;
    }
    return (LRESULT)((infoPtr->bUnicode) ? NFR_UNICODE : NFR_ANSI);
}


Alexandre Julliard's avatar
Alexandre Julliard committed
3348
static LRESULT
3349
REBAR_Paint (const REBAR_INFO *infoPtr, WPARAM wParam)
Alexandre Julliard's avatar
Alexandre Julliard committed
3350
{
3351
    HDC hdc = (HDC)wParam;
3352

3353 3354 3355 3356 3357 3358 3359 3360 3361
    if (hdc) {
        TRACE("painting\n");
        REBAR_Refresh (infoPtr, hdc);
    } else {
        PAINTSTRUCT ps;
        hdc = BeginPaint (infoPtr->hwndSelf, &ps);
        TRACE("painting (%s)\n", wine_dbgstr_rect(&ps.rcPaint));
        if (ps.fErase) {
            /* Erase area of paint if requested */
3362
            REBAR_InternalEraseBkGnd (infoPtr, wParam, &ps.rcPaint);
3363 3364 3365
        }
        REBAR_Refresh (infoPtr, hdc);
	EndPaint (infoPtr->hwndSelf, &ps);
3366 3367
    }

Alexandre Julliard's avatar
Alexandre Julliard committed
3368 3369 3370 3371
    return 0;
}


Eric Kohl's avatar
Eric Kohl committed
3372
static LRESULT
3373
REBAR_SetCursor (const REBAR_INFO *infoPtr, LPARAM lParam)
Eric Kohl's avatar
Eric Kohl committed
3374
{
3375 3376
    POINT pt;
    UINT  flags;
Eric Kohl's avatar
Eric Kohl committed
3377

3378
    TRACE("code=0x%X  id=0x%X\n", LOWORD(lParam), HIWORD(lParam));
Eric Kohl's avatar
Eric Kohl committed
3379

3380
    GetCursorPos (&pt);
3381
    ScreenToClient (infoPtr->hwndSelf, &pt);
Eric Kohl's avatar
Eric Kohl committed
3382

3383
    REBAR_InternalHitTest (infoPtr, &pt, &flags, NULL);
Eric Kohl's avatar
Eric Kohl committed
3384 3385

    if (flags == RBHT_GRABBER) {
3386 3387
	if ((infoPtr->dwStyle & CCS_VERT) &&
	    !(infoPtr->dwStyle & RBS_VERTICALGRIPPER))
3388
	    SetCursor (infoPtr->hcurVert);
Eric Kohl's avatar
Eric Kohl committed
3389
	else
3390
	    SetCursor (infoPtr->hcurHorz);
Eric Kohl's avatar
Eric Kohl committed
3391 3392
    }
    else if (flags != RBHT_CLIENT)
3393
	SetCursor (infoPtr->hcurArrow);
Eric Kohl's avatar
Eric Kohl committed
3394 3395 3396 3397 3398 3399

    return 0;
}


static LRESULT
3400
REBAR_SetFont (REBAR_INFO *infoPtr, WPARAM wParam)
Eric Kohl's avatar
Eric Kohl committed
3401
{
3402 3403
    REBAR_BAND *lpBand;
    UINT i;
Eric Kohl's avatar
Eric Kohl committed
3404

3405
    infoPtr->hFont = (HFONT)wParam;
Eric Kohl's avatar
Eric Kohl committed
3406

3407 3408 3409
    /* revalidate all bands to change sizes of text in headers of bands */
    for (i=0; i<infoPtr->uNumBands; i++) {
        lpBand = &infoPtr->bands[i];
3410
	REBAR_ValidateBand (infoPtr, lpBand);
3411 3412
    }

3413
    REBAR_Layout(infoPtr);
Eric Kohl's avatar
Eric Kohl committed
3414 3415 3416
    return 0;
}

3417

3418
static inline LRESULT
3419
REBAR_SetRedraw (REBAR_INFO *infoPtr, WPARAM wParam)
3420 3421 3422 3423 3424 3425
     /*****************************************************
      *
      * Function;
      *  Handles the WM_SETREDRAW message.
      *
      * Documentation:
3426
      *  According to testing V4.71 of COMCTL32 returns the
3427 3428 3429 3430 3431 3432 3433
      *  *previous* status of the redraw flag (either 0 or -1)
      *  instead of the MSDN documented value of 0 if handled
      *
      *****************************************************/
{
    BOOL oldredraw = infoPtr->DoRedraw;

3434
    TRACE("set to %s, fStatus=%08x\n",
3435
	  (wParam) ? "TRUE" : "FALSE", infoPtr->fStatus);
3436
    infoPtr->DoRedraw = (BOOL) wParam;
3437 3438 3439 3440 3441 3442 3443 3444 3445
    if (wParam) {
	if (infoPtr->fStatus & BAND_NEEDS_REDRAW) {
	    REBAR_MoveChildWindows (infoPtr, 0, infoPtr->uNumBands);
	    REBAR_ForceResize (infoPtr);
	    InvalidateRect (infoPtr->hwndSelf, 0, TRUE);
	}
	infoPtr->fStatus &= ~BAND_NEEDS_REDRAW;
    }
    return (oldredraw) ? -1 : 0;
3446 3447
}

3448

Eric Kohl's avatar
Eric Kohl committed
3449
static LRESULT
3450
REBAR_Size (REBAR_INFO *infoPtr, WPARAM wParam, LPARAM lParam)
Eric Kohl's avatar
Eric Kohl committed
3451
{
3452
    TRACE("wParam=%lx, lParam=%lx\n", wParam, lParam);
Eric Kohl's avatar
Eric Kohl committed
3453

3454
    /* avoid _Layout resize recursion (but it shouldn't be infinite and it seems Windows does recurse) */
3455 3456 3457
    if (infoPtr->fStatus & SELF_RESIZE) {
	infoPtr->fStatus &= ~SELF_RESIZE;
	TRACE("SELF_RESIZE was set, reset, fStatus=%08x lparam=%08lx\n",
3458
	      infoPtr->fStatus, lParam);
Eric Kohl's avatar
Eric Kohl committed
3459 3460
	return 0;
    }
3461
    
3462 3463 3464
    if (infoPtr->dwStyle & RBS_AUTOSIZE)
        REBAR_AutoSize(infoPtr, TRUE);
    else
3465
        REBAR_Layout(infoPtr);
Eric Kohl's avatar
Eric Kohl committed
3466 3467 3468 3469

    return 0;
}

Alexandre Julliard's avatar
Alexandre Julliard committed
3470

3471
static LRESULT
3472
REBAR_StyleChanged (REBAR_INFO *infoPtr, LPARAM lParam)
3473 3474 3475
{
    STYLESTRUCT *ss = (STYLESTRUCT *)lParam;

3476
    TRACE("current style=%08x, styleOld=%08x, style being set to=%08x\n",
3477
	  infoPtr->dwStyle, ss->styleOld, ss->styleNew);
3478 3479 3480
    infoPtr->orgStyle = infoPtr->dwStyle = ss->styleNew;
    if (GetWindowTheme (infoPtr->hwndSelf))
        infoPtr->dwStyle &= ~WS_BORDER;
3481 3482
    /* maybe it should be COMMON_STYLES like in toolbar */
    if ((ss->styleNew ^ ss->styleOld) & CCS_VERT)
3483
        REBAR_Layout(infoPtr);
3484

3485 3486 3487
    return FALSE;
}

3488 3489 3490 3491 3492 3493 3494 3495 3496 3497 3498 3499
/* update theme after a WM_THEMECHANGED message */
static LRESULT theme_changed (REBAR_INFO* infoPtr)
{
    HTHEME theme = GetWindowTheme (infoPtr->hwndSelf);
    CloseThemeData (theme);
    theme = OpenThemeData (infoPtr->hwndSelf, themeClass);
    /* WS_BORDER disappears when theming is enabled and reappears when
     * disabled... */
    infoPtr->dwStyle &= ~WS_BORDER;
    infoPtr->dwStyle |= theme ? 0 : (infoPtr->orgStyle & WS_BORDER);
    return 0;
}
3500

3501
static LRESULT
3502
REBAR_WindowPosChanged (const REBAR_INFO *infoPtr, WPARAM wParam, LPARAM lParam)
3503 3504 3505 3506
{
    LRESULT ret;
    RECT rc;

3507
    ret = DefWindowProcW(infoPtr->hwndSelf, WM_WINDOWPOSCHANGED,
3508 3509
			 wParam, lParam);
    GetWindowRect(infoPtr->hwndSelf, &rc);
3510
    TRACE("hwnd %p new pos (%s)\n", infoPtr->hwndSelf, wine_dbgstr_rect(&rc));
3511 3512 3513 3514
    return ret;
}


3515
static LRESULT WINAPI
3516
REBAR_WindowProc (HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
Alexandre Julliard's avatar
Alexandre Julliard committed
3517
{
3518 3519
    REBAR_INFO *infoPtr = REBAR_GetInfoPtr (hwnd);

3520
    TRACE("hwnd=%p msg=%x wparam=%lx lparam=%lx\n",
3521
	  hwnd, uMsg, wParam, lParam);
3522
    if (!infoPtr && (uMsg != WM_NCCREATE))
3523
        return DefWindowProcW (hwnd, uMsg, wParam, lParam);
Alexandre Julliard's avatar
Alexandre Julliard committed
3524 3525
    switch (uMsg)
    {
3526
/*	case RB_BEGINDRAG: */
Alexandre Julliard's avatar
Alexandre Julliard committed
3527 3528

	case RB_DELETEBAND:
3529
	    return REBAR_DeleteBand (infoPtr, wParam);
Alexandre Julliard's avatar
Alexandre Julliard committed
3530

3531 3532
/*	case RB_DRAGMOVE: */
/*	case RB_ENDDRAG: */
3533 3534

	case RB_GETBANDBORDERS:
3535
	    return REBAR_GetBandBorders (infoPtr, wParam, lParam);
Alexandre Julliard's avatar
Alexandre Julliard committed
3536 3537

	case RB_GETBANDCOUNT:
3538
	    return REBAR_GetBandCount (infoPtr);
Alexandre Julliard's avatar
Alexandre Julliard committed
3539

3540
	case RB_GETBANDINFO_OLD:
3541
	case RB_GETBANDINFOA:
3542
	    return REBAR_GetBandInfoT(infoPtr, wParam, lParam, FALSE);
Alexandre Julliard's avatar
Alexandre Julliard committed
3543

3544
	case RB_GETBANDINFOW:
3545
	    return REBAR_GetBandInfoT(infoPtr, wParam, lParam, TRUE);
Alexandre Julliard's avatar
Alexandre Julliard committed
3546 3547

	case RB_GETBARHEIGHT:
3548
	    return REBAR_GetBarHeight (infoPtr);
Alexandre Julliard's avatar
Alexandre Julliard committed
3549 3550

	case RB_GETBARINFO:
3551
	    return REBAR_GetBarInfo (infoPtr, lParam);
Alexandre Julliard's avatar
Alexandre Julliard committed
3552 3553

	case RB_GETBKCOLOR:
3554
	    return REBAR_GetBkColor (infoPtr);
Alexandre Julliard's avatar
Alexandre Julliard committed
3555

3556 3557
/*	case RB_GETCOLORSCHEME: */
/*	case RB_GETDROPTARGET: */
Eric Kohl's avatar
Eric Kohl committed
3558 3559

	case RB_GETPALETTE:
3560
	    return REBAR_GetPalette (infoPtr, wParam, lParam);
Eric Kohl's avatar
Eric Kohl committed
3561 3562

	case RB_GETRECT:
3563
	    return REBAR_GetRect (infoPtr, wParam, lParam);
Eric Kohl's avatar
Eric Kohl committed
3564 3565

	case RB_GETROWCOUNT:
3566
	    return REBAR_GetRowCount (infoPtr);
Eric Kohl's avatar
Eric Kohl committed
3567 3568

	case RB_GETROWHEIGHT:
3569
	    return REBAR_GetRowHeight (infoPtr, wParam);
Alexandre Julliard's avatar
Alexandre Julliard committed
3570 3571

	case RB_GETTEXTCOLOR:
3572
	    return REBAR_GetTextColor (infoPtr);
Alexandre Julliard's avatar
Alexandre Julliard committed
3573

Eric Kohl's avatar
Eric Kohl committed
3574
	case RB_GETTOOLTIPS:
3575
	    return REBAR_GetToolTips (infoPtr);
Eric Kohl's avatar
Eric Kohl committed
3576

Eric Kohl's avatar
Eric Kohl committed
3577
	case RB_GETUNICODEFORMAT:
3578
	    return REBAR_GetUnicodeFormat (infoPtr);
Eric Kohl's avatar
Eric Kohl committed
3579

Eric Kohl's avatar
Eric Kohl committed
3580
	case CCM_GETVERSION:
3581
	    return REBAR_GetVersion (infoPtr);
Eric Kohl's avatar
Eric Kohl committed
3582

Eric Kohl's avatar
Eric Kohl committed
3583
	case RB_HITTEST:
3584
	    return REBAR_HitTest (infoPtr, lParam);
Alexandre Julliard's avatar
Alexandre Julliard committed
3585 3586

	case RB_IDTOINDEX:
3587
	    return REBAR_IdToIndex (infoPtr, wParam);
Alexandre Julliard's avatar
Alexandre Julliard committed
3588

3589
	case RB_INSERTBANDA:
3590
	    return REBAR_InsertBandT(infoPtr, wParam, lParam, FALSE);
Alexandre Julliard's avatar
Alexandre Julliard committed
3591

3592
	case RB_INSERTBANDW:
3593
	    return REBAR_InsertBandT(infoPtr, wParam, lParam, TRUE);
Eric Kohl's avatar
Eric Kohl committed
3594

3595
	case RB_MAXIMIZEBAND:
3596
	    return REBAR_MaximizeBand (infoPtr, wParam, lParam);
3597 3598

	case RB_MINIMIZEBAND:
3599
	    return REBAR_MinimizeBand (infoPtr, wParam);
3600 3601

	case RB_MOVEBAND:
3602
	    return REBAR_MoveBand (infoPtr, wParam, lParam);
Alexandre Julliard's avatar
Alexandre Julliard committed
3603

Robert Shearman's avatar
Robert Shearman committed
3604 3605 3606
	case RB_PUSHCHEVRON:
	    return REBAR_PushChevron (infoPtr, wParam, lParam);

3607
	case RB_SETBANDINFOA:
3608
	    return REBAR_SetBandInfoT(infoPtr, wParam, lParam, FALSE);
Alexandre Julliard's avatar
Alexandre Julliard committed
3609

3610
	case RB_SETBANDINFOW:
3611
	    return REBAR_SetBandInfoT(infoPtr, wParam, lParam, TRUE);
Alexandre Julliard's avatar
Alexandre Julliard committed
3612 3613

	case RB_SETBARINFO:
3614
	    return REBAR_SetBarInfo (infoPtr, lParam);
Alexandre Julliard's avatar
Alexandre Julliard committed
3615 3616

	case RB_SETBKCOLOR:
3617
	    return REBAR_SetBkColor (infoPtr, lParam);
Alexandre Julliard's avatar
Alexandre Julliard committed
3618

3619 3620
/*	case RB_SETCOLORSCHEME: */
/*	case RB_SETPALETTE: */
3621
/*	    return REBAR_GetPalette (infoPtr, wParam, lParam); */
Eric Kohl's avatar
Eric Kohl committed
3622 3623

	case RB_SETPARENT:
3624
	    return REBAR_SetParent (infoPtr, wParam);
Alexandre Julliard's avatar
Alexandre Julliard committed
3625 3626

	case RB_SETTEXTCOLOR:
3627
	    return REBAR_SetTextColor (infoPtr, lParam);
Alexandre Julliard's avatar
Alexandre Julliard committed
3628

3629
/*	case RB_SETTOOLTIPS: */
Eric Kohl's avatar
Eric Kohl committed
3630 3631

	case RB_SETUNICODEFORMAT:
3632
	    return REBAR_SetUnicodeFormat (infoPtr, wParam);
Alexandre Julliard's avatar
Alexandre Julliard committed
3633

Eric Kohl's avatar
Eric Kohl committed
3634
	case CCM_SETVERSION:
3635
	    return REBAR_SetVersion (infoPtr, (INT)wParam);
Eric Kohl's avatar
Eric Kohl committed
3636

Alexandre Julliard's avatar
Alexandre Julliard committed
3637
	case RB_SHOWBAND:
3638
	    return REBAR_ShowBand (infoPtr, wParam, lParam);
Alexandre Julliard's avatar
Alexandre Julliard committed
3639 3640

	case RB_SIZETORECT:
3641
	    return REBAR_SizeToRect (infoPtr, lParam);
Alexandre Julliard's avatar
Alexandre Julliard committed
3642 3643


3644
/*    Messages passed to parent */
3645
	case WM_COMMAND:
3646 3647
	case WM_DRAWITEM:
	case WM_NOTIFY:
3648
            return SendMessageW(REBAR_GetNotifyParent (infoPtr), uMsg, wParam, lParam);
3649

3650 3651 3652

/*      case WM_CHARTOITEM:     supported according to ControlSpy */

Alexandre Julliard's avatar
Alexandre Julliard committed
3653
	case WM_CREATE:
3654
	    return REBAR_Create (infoPtr, lParam);
Alexandre Julliard's avatar
Alexandre Julliard committed
3655

Alexandre Julliard's avatar
Alexandre Julliard committed
3656
	case WM_DESTROY:
3657
	    return REBAR_Destroy (infoPtr);
Alexandre Julliard's avatar
Alexandre Julliard committed
3658

3659
        case WM_ERASEBKGND:
3660
	    return REBAR_EraseBkGnd (infoPtr, wParam);
3661

Eric Kohl's avatar
Eric Kohl committed
3662
	case WM_GETFONT:
3663
	    return REBAR_GetFont (infoPtr);
Alexandre Julliard's avatar
Alexandre Julliard committed
3664

3665 3666
/*      case WM_LBUTTONDBLCLK:  supported according to ControlSpy */

3667
	case WM_LBUTTONDOWN:
3668
	    return REBAR_LButtonDown (infoPtr, lParam);
3669 3670

	case WM_LBUTTONUP:
3671
	    return REBAR_LButtonUp (infoPtr);
3672

3673 3674
/*      case WM_MEASUREITEM:    supported according to ControlSpy */

3675
	case WM_MOUSEMOVE:
3676
	    return REBAR_MouseMove (infoPtr, lParam);
Alexandre Julliard's avatar
Alexandre Julliard committed
3677

Robert Shearman's avatar
Robert Shearman committed
3678
	case WM_MOUSELEAVE:
3679
	    return REBAR_MouseLeave (infoPtr);
Robert Shearman's avatar
Robert Shearman committed
3680

Eric Kohl's avatar
Eric Kohl committed
3681
	case WM_NCCALCSIZE:
3682
	    return REBAR_NCCalcSize (infoPtr, lParam);
Eric Kohl's avatar
Eric Kohl committed
3683

3684
        case WM_NCCREATE:
3685
	    return REBAR_NCCreate (hwnd, lParam);
3686 3687

        case WM_NCHITTEST:
3688
	    return REBAR_NCHitTest (infoPtr, lParam);
3689

Eric Kohl's avatar
Eric Kohl committed
3690
	case WM_NCPAINT:
3691
	    return REBAR_NCPaint (infoPtr);
Eric Kohl's avatar
Eric Kohl committed
3692

3693
        case WM_NOTIFYFORMAT:
3694
	    return REBAR_NotifyFormat (infoPtr, lParam);
Eric Kohl's avatar
Eric Kohl committed
3695

3696
	case WM_PRINTCLIENT:
Alexandre Julliard's avatar
Alexandre Julliard committed
3697
	case WM_PAINT:
3698
	    return REBAR_Paint (infoPtr, wParam);
Alexandre Julliard's avatar
Alexandre Julliard committed
3699

3700 3701 3702 3703 3704
/*      case WM_PALETTECHANGED: supported according to ControlSpy */
/*      case WM_QUERYNEWPALETTE:supported according to ControlSpy */
/*      case WM_RBUTTONDOWN:    supported according to ControlSpy */
/*      case WM_RBUTTONUP:      supported according to ControlSpy */

Eric Kohl's avatar
Eric Kohl committed
3705
	case WM_SETCURSOR:
3706
	    return REBAR_SetCursor (infoPtr, lParam);
Eric Kohl's avatar
Eric Kohl committed
3707 3708

	case WM_SETFONT:
3709
	    return REBAR_SetFont (infoPtr, wParam);
Eric Kohl's avatar
Eric Kohl committed
3710

3711
        case WM_SETREDRAW:
3712
	    return REBAR_SetRedraw (infoPtr, wParam);
3713

Eric Kohl's avatar
Eric Kohl committed
3714
	case WM_SIZE:
3715
	    return REBAR_Size (infoPtr, wParam, lParam);
Alexandre Julliard's avatar
Alexandre Julliard committed
3716

3717
        case WM_STYLECHANGED:
3718
	    return REBAR_StyleChanged (infoPtr, lParam);
3719

3720 3721 3722
        case WM_THEMECHANGED:
            return theme_changed (infoPtr);

3723
/*      case WM_SYSCOLORCHANGE: supported according to ControlSpy */
3724
/*      "Applications that have brushes using the existing system colors
3725
         should delete those brushes and recreate them using the new
3726 3727
         system colors."  per MSDN                                */

3728
/*      case WM_VKEYTOITEM:     supported according to ControlSpy */
3729
/*	case WM_WININICHANGE: */
Alexandre Julliard's avatar
Alexandre Julliard committed
3730

3731 3732 3733
        case WM_WINDOWPOSCHANGED:
	    return REBAR_WindowPosChanged (infoPtr, wParam, lParam);

Alexandre Julliard's avatar
Alexandre Julliard committed
3734
	default:
3735
	    if ((uMsg >= WM_USER) && (uMsg < WM_APP) && !COMCTL32_IsReflectedMessage(uMsg))
3736
		ERR("unknown msg %04x wp=%08lx lp=%08lx\n",
Alexandre Julliard's avatar
Alexandre Julliard committed
3737
		     uMsg, wParam, lParam);
3738
	    return DefWindowProcW (hwnd, uMsg, wParam, lParam);
Alexandre Julliard's avatar
Alexandre Julliard committed
3739 3740 3741 3742
    }
}


Eric Kohl's avatar
Eric Kohl committed
3743
VOID
3744
REBAR_Register (void)
Alexandre Julliard's avatar
Alexandre Julliard committed
3745
{
3746
    WNDCLASSW wndClass;
Alexandre Julliard's avatar
Alexandre Julliard committed
3747

3748
    ZeroMemory (&wndClass, sizeof(WNDCLASSW));
Alexandre Julliard's avatar
Alexandre Julliard committed
3749
    wndClass.style         = CS_GLOBALCLASS | CS_DBLCLKS;
3750
    wndClass.lpfnWndProc   = REBAR_WindowProc;
Alexandre Julliard's avatar
Alexandre Julliard committed
3751 3752
    wndClass.cbClsExtra    = 0;
    wndClass.cbWndExtra    = sizeof(REBAR_INFO *);
Alexandre Julliard's avatar
Alexandre Julliard committed
3753
    wndClass.hCursor       = 0;
3754
    wndClass.hbrBackground = (HBRUSH)(COLOR_BTNFACE + 1);
3755 3756 3757
#if GLATESTING
    wndClass.hbrBackground = CreateSolidBrush(RGB(0,128,0));
#endif
3758
    wndClass.lpszClassName = REBARCLASSNAMEW;
3759

3760
    RegisterClassW (&wndClass);
3761 3762 3763 3764

    mindragx = GetSystemMetrics (SM_CXDRAG);
    mindragy = GetSystemMetrics (SM_CYDRAG);

Alexandre Julliard's avatar
Alexandre Julliard committed
3765 3766
}

Eric Kohl's avatar
Eric Kohl committed
3767 3768

VOID
3769
REBAR_Unregister (void)
Eric Kohl's avatar
Eric Kohl committed
3770
{
3771
    UnregisterClassW (REBARCLASSNAMEW, NULL);
Eric Kohl's avatar
Eric Kohl committed
3772
}