ReactOS 0.4.16-dev-340-g0540c21
rebar.c
Go to the documentation of this file.
1/*
2 * Rebar control
3 *
4 * Copyright 1998, 1999 Eric Kohl
5 * Copyright 2007, 2008 Mikolaj Zalewski
6 *
7 * This library is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU Lesser General Public
9 * License as published by the Free Software Foundation; either
10 * version 2.1 of the License, or (at your option) any later version.
11 *
12 * This library is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 * Lesser General Public License for more details.
16 *
17 * You should have received a copy of the GNU Lesser General Public
18 * 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
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 * Unless otherwise noted, we believe this code to be complete, as per
27 * the specification mentioned above.
28 * If you discover missing features or bugs please note them below.
29 *
30 * TODO
31 * Styles:
32 * - RBS_DBLCLKTOGGLE
33 * - RBS_FIXEDORDER
34 * - RBS_REGISTERDROP
35 * - RBS_TOOLTIPS
36 * Messages:
37 * - RB_BEGINDRAG
38 * - RB_DRAGMOVE
39 * - RB_ENDDRAG
40 * - RB_GETBANDMARGINS
41 * - RB_GETCOLORSCHEME
42 * - RB_GETDROPTARGET
43 * - RB_GETPALETTE
44 * - RB_SETCOLORSCHEME
45 * - RB_SETPALETTE
46 * - RB_SETTOOLTIPS
47 * - WM_CHARTOITEM
48 * - WM_LBUTTONDBLCLK
49 * - WM_PALETTECHANGED
50 * - WM_QUERYNEWPALETTE
51 * - WM_RBUTTONDOWN
52 * - WM_RBUTTONUP
53 * - WM_VKEYTOITEM
54 * - WM_WININICHANGE
55 * Notifications:
56 * - NM_HCHITTEST
57 * - NM_RELEASEDCAPTURE
58 * - RBN_AUTOBREAK
59 * - RBN_GETOBJECT
60 * - RBN_MINMAX
61 * Band styles:
62 * - RBBS_FIXEDBMP
63 * Native uses (on each draw!!) SM_CYBORDER (or SM_CXBORDER for CCS_VERT)
64 * to set the size of the separator width (the value SEP_WIDTH_SIZE
65 * in here). Should be fixed!!
66 */
67
68/*
69 * Testing: set to 1 to make background brush *always* green
70 */
71#define GLATESTING 0
72
73/*
74 * 3. REBAR_MoveChildWindows should have a loop because more than
75 * one pass (together with the RBN_CHILDSIZEs) is made on
76 * at least RB_INSERTBAND
77 */
78
79#include <assert.h>
80#include <stdarg.h>
81#include <stdlib.h>
82#include <string.h>
83
84#include "windef.h"
85#include "winbase.h"
86#include "wingdi.h"
87#include "winuser.h"
88#include "winnls.h"
89#include "commctrl.h"
90#include "comctl32.h"
91#include "uxtheme.h"
92#include "vssym32.h"
93#include "wine/debug.h"
94
96
97typedef struct
98{
105 UINT cxMinChild; /* valid if _CHILDSIZE */
106 UINT cyMinChild; /* valid if _CHILDSIZE */
107 UINT cx; /* valid if _SIZE */
110 UINT cyChild; /* valid if _CHILDSIZE */
111 UINT cyMaxChild; /* valid if _CHILDSIZE */
112 UINT cyIntegral; /* valid if _CHILDSIZE */
116
117 INT cxEffective; /* current cx for band */
118 UINT cyHeader; /* the height of the header */
119 UINT cxMinBand; /* minimum cx for band */
120 UINT cyMinBand; /* minimum cy for band */
121
122 UINT cyRowSoFar; /* for RBS_VARHEIGHT - the height of the row if it would break on this band (set by _Layout) */
123 INT iRow; /* zero-based index of the row this band assigned to */
124 UINT fStatus; /* status flags, reset only by _Validate */
125 UINT fDraw; /* drawing flags, reset only by _Layout */
126 UINT uCDret; /* last return from NM_CUSTOMDRAW */
127 RECT rcBand; /* calculated band rectangle - coordinates swapped for CCS_VERT */
128 RECT rcGripper; /* calculated gripper rectangle */
129 RECT rcCapImage; /* calculated caption image rectangle */
130 RECT rcCapText; /* calculated caption text rectangle */
131 RECT rcChild; /* calculated child rectangle */
132 RECT rcChevron; /* calculated chevron rectangle */
133
136} REBAR_BAND;
137
138/* has a value of: 0, CCS_TOP, CCS_NOMOVEY, CCS_BOTTOM */
139#define CCS_LAYOUT_MASK 0x3
140
141/* fStatus flags */
142#define HAS_GRIPPER 0x00000001
143#define HAS_IMAGE 0x00000002
144#define HAS_TEXT 0x00000004
145
146/* fDraw flags */
147#define DRAW_GRIPPER 0x00000001
148#define DRAW_IMAGE 0x00000002
149#define DRAW_TEXT 0x00000004
150#define DRAW_CHEVRONHOT 0x00000040
151#define DRAW_CHEVRONPUSHED 0x00000080
152#define NTF_INVALIDATE 0x01000000
153
154typedef struct
155{
156 COLORREF clrBk; /* background color */
157 COLORREF clrText; /* text color */
158 COLORREF clrBtnText; /* system color for BTNTEXT */
159 COLORREF clrBtnFace; /* system color for BTNFACE */
160 HIMAGELIST himl; /* handle to imagelist */
161 UINT uNumBands; /* # of bands in rebar (first=0, last=uNumBands-1 */
162 UINT uNumRows; /* # of rows of bands (first=1, last=uNumRows */
163 HWND hwndSelf; /* handle of REBAR window itself */
164 HWND hwndToolTip; /* handle to the tool tip control */
165 HWND hwndNotify; /* notification window (parent) */
167 HFONT hFont; /* handle to the rebar's font */
168 SIZE imageSize; /* image size (image list) */
169 DWORD dwStyle; /* window style */
170 DWORD orgStyle; /* original style (dwStyle may change) */
171 SIZE calcSize; /* calculated rebar size - coordinates swapped for CCS_VERT */
172 BOOL bUnicode; /* TRUE if parent wants notify in W format */
173 BOOL DoRedraw; /* TRUE to actually draw bands */
174 UINT fStatus; /* Status flags (see below) */
175 HCURSOR hcurArrow; /* handle to the arrow cursor */
176 HCURSOR hcurHorz; /* handle to the EW cursor */
177 HCURSOR hcurVert; /* handle to the NS cursor */
178 HCURSOR hcurDrag; /* handle to the drag cursor */
179 INT iVersion; /* version number */
180 POINT dragStart; /* x,y of button down */
181 POINT dragNow; /* x,y of this MouseMove */
182 INT iOldBand; /* last band that had the mouse cursor over it */
183 INT ihitoffset; /* offset of hotspot from gripper.left */
184 INT ichevronhotBand; /* last band that had a hot chevron */
185 INT iGrabbedBand;/* band number of band whose gripper was grabbed */
186
187 HDPA bands; /* pointer to the array of rebar bands */
188} REBAR_INFO;
189
190/* fStatus flags */
191#define BEGIN_DRAG_ISSUED 0x00000001
192#define SELF_RESIZE 0x00000002
193#define BAND_NEEDS_REDRAW 0x00000020
194
195/* used by Windows to mark that the header size has been set by the user and shouldn't be changed */
196#define RBBS_UNDOC_FIXEDHEADER 0x40000000
197
198/* ---- REBAR layout constants. Mostly determined by ---- */
199/* ---- experiment on WIN 98. ---- */
200
201/* Width (or height) of separators between bands (either horz. or */
202/* vert.). True only if RBS_BANDBORDERS is set */
203#define SEP_WIDTH_SIZE 2
204#define SEP_WIDTH ((infoPtr->dwStyle & RBS_BANDBORDERS) ? SEP_WIDTH_SIZE : 0)
205
206/* Blank (background color) space between Gripper (if present) */
207/* and next item (image, text, or window). Always present */
208#define REBAR_ALWAYS_SPACE 4
209
210/* Blank (background color) space after Image (if present). */
211#define REBAR_POST_IMAGE 2
212
213/* Blank (background color) space after Text (if present). */
214#define REBAR_POST_TEXT 4
215
216/* Height of vertical gripper in a CCS_VERT rebar. */
217#define GRIPPER_HEIGHT 16
218
219/* Blank (background color) space before Gripper (if present). */
220#define REBAR_PRE_GRIPPER 2
221
222/* Width (of normal vertical gripper) or height (of horz. gripper) */
223/* if present. */
224#define GRIPPER_WIDTH 3
225
226/* Width of the chevron button if present */
227#define CHEVRON_WIDTH 10
228
229/* the gap between the child and the next band */
230#define REBAR_POST_CHILD 4
231
232/* Height of divider for Rebar if not disabled (CCS_NODIVIDER) */
233/* either top or bottom */
234#define REBAR_DIVIDER 2
235
236/* height of a rebar without a child */
237#define REBAR_NO_CHILD_HEIGHT 4
238
239/* minimum vertical height of a normal bar */
240/* or minimum width of a CCS_VERT bar - from experiment on Win2k */
241#define REBAR_MINSIZE 23
242
243/* This is the increment that is used over the band height */
244#define REBARSPACE(a) ((a->fStyle & RBBS_CHILDEDGE) ? 2*REBAR_DIVIDER : 0)
245
246/* ---- End of REBAR layout constants. ---- */
247
248#define RB_GETBANDINFO_OLD (WM_USER+5) /* obsoleted after IE3, but we have to support it anyway */
249
250/* The following define determines if a given band is hidden */
251#define HIDDENBAND(a) (((a)->fStyle & RBBS_HIDDEN) || \
252 ((infoPtr->dwStyle & CCS_VERT) && \
253 ((a)->fStyle & RBBS_NOVERT)))
254
255#define REBAR_GetInfoPtr(wndPtr) ((REBAR_INFO *)GetWindowLongPtrW (hwnd, 0))
256
258static void REBAR_AutoSize(REBAR_INFO *infoPtr, BOOL needsLayout);
259
260/* no index check here */
261static inline REBAR_BAND* REBAR_GetBand(const REBAR_INFO *infoPtr, INT i)
262{
263 assert(i >= 0 && i < infoPtr->uNumBands);
264 return DPA_GetPtr(infoPtr->bands, i);
265}
266
267/* "constant values" retrieved when DLL was initialized */
268/* FIXME we do this when the classes are registered. */
269static UINT mindragx = 0;
270static UINT mindragy = 0;
271
272static const char * const band_stylename[] = {
273 "RBBS_BREAK", /* 0001 */
274 "RBBS_FIXEDSIZE", /* 0002 */
275 "RBBS_CHILDEDGE", /* 0004 */
276 "RBBS_HIDDEN", /* 0008 */
277 "RBBS_NOVERT", /* 0010 */
278 "RBBS_FIXEDBMP", /* 0020 */
279 "RBBS_VARIABLEHEIGHT", /* 0040 */
280 "RBBS_GRIPPERALWAYS", /* 0080 */
281 "RBBS_NOGRIPPER", /* 0100 */
282 "RBBS_USECHEVRON", /* 0200 */
283 "RBBS_HIDETITLE", /* 0400 */
284 "RBBS_TOPALIGN", /* 0800 */
285 NULL };
286
287static const char * const band_maskname[] = {
288 "RBBIM_STYLE", /* 0x00000001 */
289 "RBBIM_COLORS", /* 0x00000002 */
290 "RBBIM_TEXT", /* 0x00000004 */
291 "RBBIM_IMAGE", /* 0x00000008 */
292 "RBBIM_CHILD", /* 0x00000010 */
293 "RBBIM_CHILDSIZE", /* 0x00000020 */
294 "RBBIM_SIZE", /* 0x00000040 */
295 "RBBIM_BACKGROUND", /* 0x00000080 */
296 "RBBIM_ID", /* 0x00000100 */
297 "RBBIM_IDEALSIZE", /* 0x00000200 */
298 "RBBIM_LPARAM", /* 0x00000400 */
299 "RBBIM_HEADERSIZE", /* 0x00000800 */
300 "RBBIM_CHEVRONLOCATION", /* 0x00001000 */
301 "RBBIM_CHEVRONSTATE", /* 0x00002000 */
302 NULL };
303
304
305static const WCHAR themeClass[] = { 'R','e','b','a','r',0 };
306
307static CHAR *
309{
310 INT i = 0;
311
312 *buffer = 0;
313 while (band_stylename[i]) {
314 if (style & (1<<i)) {
315 if (*buffer) strcat(buffer, " | ");
317 }
318 i++;
319 }
320 return buffer;
321}
322
323
324static CHAR *
326{
327 INT i = 0;
328
329 *buffer = 0;
330 while (band_maskname[i]) {
331 if (mask & (1<<i)) {
332 if (*buffer) strcat(buffer, " | ");
334 }
335 i++;
336 }
337 return buffer;
338}
339
340
341static VOID
343{
344 char buff[300];
345
346 if( !TRACE_ON(rebar) ) return;
347 TRACE("band info: ");
348 if (pB->fMask & RBBIM_ID)
349 TRACE("ID=%u, ", pB->wID);
350 TRACE("size=%u, child=%p", pB->cbSize, pB->hwndChild);
351 if (pB->fMask & RBBIM_COLORS)
352 TRACE(", clrF=0x%06x, clrB=0x%06x", pB->clrFore, pB->clrBack);
353 TRACE("\n");
354
355 TRACE("band info: mask=0x%08x (%s)\n", pB->fMask, REBAR_FmtMask(buff, pB->fMask));
356 if (pB->fMask & RBBIM_STYLE)
357 TRACE("band info: style=0x%08x (%s)\n", pB->fStyle, REBAR_FmtStyle(buff, pB->fStyle));
359 TRACE("band info:");
360 if (pB->fMask & RBBIM_SIZE)
361 TRACE(" cx=%u", pB->cx);
362 if (pB->fMask & RBBIM_IDEALSIZE)
363 TRACE(" xIdeal=%u", pB->cxIdeal);
364 if (pB->fMask & RBBIM_HEADERSIZE)
365 TRACE(" xHeader=%u", pB->cxHeader);
366 if (pB->fMask & RBBIM_LPARAM)
367 TRACE(" lParam=0x%08lx", pB->lParam);
368 TRACE("\n");
369 }
370 if (pB->fMask & RBBIM_CHILDSIZE)
371 TRACE("band info: xMin=%u, yMin=%u, yChild=%u, yMax=%u, yIntgl=%u\n",
372 pB->cxMinChild,
373 pB->cyMinChild, pB->cyChild, pB->cyMaxChild, pB->cyIntegral);
374}
375
376static VOID
378{
379 char buff[300];
380 REBAR_BAND *pB;
381 UINT i;
382
383 if(! TRACE_ON(rebar) ) return;
384
385 TRACE("hwnd=%p: color=%08x/%08x, bands=%u, rows=%u, cSize=%d,%d\n",
386 iP->hwndSelf, iP->clrText, iP->clrBk, iP->uNumBands, iP->uNumRows,
387 iP->calcSize.cx, iP->calcSize.cy);
388 TRACE("hwnd=%p: flags=%08x, dragStart=%d,%d, dragNow=%d,%d, iGrabbedBand=%d\n",
389 iP->hwndSelf, iP->fStatus, iP->dragStart.x, iP->dragStart.y,
390 iP->dragNow.x, iP->dragNow.y,
391 iP->iGrabbedBand);
392 TRACE("hwnd=%p: style=%08x, notify in Unicode=%s, redraw=%s\n",
393 iP->hwndSelf, iP->dwStyle, (iP->bUnicode)?"TRUE":"FALSE",
394 (iP->DoRedraw)?"TRUE":"FALSE");
395 for (i = 0; i < iP->uNumBands; i++) {
396 pB = REBAR_GetBand(iP, i);
397 TRACE("band # %u:", i);
398 if (pB->fMask & RBBIM_ID)
399 TRACE(" ID=%u", pB->wID);
400 if (pB->fMask & RBBIM_CHILD)
401 TRACE(" child=%p", pB->hwndChild);
402 if (pB->fMask & RBBIM_COLORS)
403 TRACE(" clrF=0x%06x clrB=0x%06x", pB->clrFore, pB->clrBack);
404 TRACE("\n");
405 TRACE("band # %u: mask=0x%08x (%s)\n", i, pB->fMask, REBAR_FmtMask(buff, pB->fMask));
406 if (pB->fMask & RBBIM_STYLE)
407 TRACE("band # %u: style=0x%08x (%s)\n", i, pB->fStyle, REBAR_FmtStyle(buff, pB->fStyle));
408 TRACE("band # %u: xHeader=%u",
409 i, pB->cxHeader);
410 if (pB->fMask & (RBBIM_SIZE | RBBIM_IDEALSIZE | RBBIM_LPARAM )) {
411 if (pB->fMask & RBBIM_SIZE)
412 TRACE(" cx=%u", pB->cx);
413 if (pB->fMask & RBBIM_IDEALSIZE)
414 TRACE(" xIdeal=%u", pB->cxIdeal);
415 if (pB->fMask & RBBIM_LPARAM)
416 TRACE(" lParam=0x%08lx", pB->lParam);
417 }
418 TRACE("\n");
419 if (RBBIM_CHILDSIZE)
420 TRACE("band # %u: xMin=%u, yMin=%u, yChild=%u, yMax=%u, yIntgl=%u\n",
421 i, pB->cxMinChild, pB->cyMinChild, pB->cyChild, pB->cyMaxChild, pB->cyIntegral);
422 if (pB->fMask & RBBIM_TEXT)
423 TRACE("band # %u: text=%s\n",
424 i, (pB->lpText) ? debugstr_w(pB->lpText) : "(null)");
425 TRACE("band # %u: cxMinBand=%u, cxEffective=%u, cyMinBand=%u\n",
426 i, pB->cxMinBand, pB->cxEffective, pB->cyMinBand);
427 TRACE("band # %u: fStatus=%08x, fDraw=%08x, Band=(%s), Grip=(%s)\n",
428 i, pB->fStatus, pB->fDraw, wine_dbgstr_rect(&pB->rcBand),
430 TRACE("band # %u: Img=(%s), Txt=(%s), Child=(%s)\n",
433 }
434
435}
436
437/* dest can be equal to src */
438static void translate_rect(const REBAR_INFO *infoPtr, RECT *dest, const RECT *src)
439{
440 if (infoPtr->dwStyle & CCS_VERT) {
441 int tmp;
442 tmp = src->left;
443 dest->left = src->top;
444 dest->top = tmp;
445
446 tmp = src->right;
447 dest->right = src->bottom;
448 dest->bottom = tmp;
449 } else {
450 *dest = *src;
451 }
452}
453
454static int get_rect_cx(const REBAR_INFO *infoPtr, const RECT *lpRect)
455{
456 if (infoPtr->dwStyle & CCS_VERT)
457 return lpRect->bottom - lpRect->top;
458 return lpRect->right - lpRect->left;
459}
460
461static int get_rect_cy(const REBAR_INFO *infoPtr, const RECT *lpRect)
462{
463 if (infoPtr->dwStyle & CCS_VERT)
464 return lpRect->right - lpRect->left;
465 return lpRect->bottom - lpRect->top;
466}
467
468static int round_child_height(const REBAR_BAND *lpBand, int cyHeight)
469{
470 int cy = 0;
471 if (lpBand->cyIntegral == 0)
472 return cyHeight;
473 cy = max(cyHeight - (int)lpBand->cyMinChild, 0);
474 cy = lpBand->cyMinChild + (cy/lpBand->cyIntegral) * lpBand->cyIntegral;
475 cy = min(cy, lpBand->cyMaxChild);
476 return cy;
477}
478
479static void update_min_band_height(const REBAR_INFO *infoPtr, REBAR_BAND *lpBand)
480{
481 lpBand->cyMinBand = max(lpBand->cyHeader,
482 (lpBand->hwndChild ? lpBand->cyChild + REBARSPACE(lpBand) : REBAR_NO_CHILD_HEIGHT));
483}
484
485static void
487{
488 INT x, y;
489 HPEN hPen, hOldPen;
490
491 if (!(hPen = CreatePen( PS_SOLID, 1, GetSysColor( colorRef )))) return;
492 hOldPen = SelectObject ( hdc, hPen );
493 x = left + 2;
494 y = top;
495 MoveToEx (hdc, x, y, NULL);
496 LineTo (hdc, x+5, y++); x++;
497 MoveToEx (hdc, x, y, NULL);
498 LineTo (hdc, x+3, y++); x++;
499 MoveToEx (hdc, x, y, NULL);
500 LineTo (hdc, x+1, y);
501 SelectObject( hdc, hOldPen );
502 DeleteObject( hPen );
503}
504
505static HWND
507{
508 HWND parent, owner;
509
510 parent = infoPtr->hwndNotify;
511 if (!parent) {
512 parent = GetParent (infoPtr->hwndSelf);
513 owner = GetWindow (infoPtr->hwndSelf, GW_OWNER);
514 if (owner) parent = owner;
515 }
516 return parent;
517}
518
519
520static INT
521REBAR_Notify (NMHDR *nmhdr, const REBAR_INFO *infoPtr, UINT code)
522{
523 HWND parent;
524
525 parent = REBAR_GetNotifyParent (infoPtr);
526 nmhdr->idFrom = GetDlgCtrlID (infoPtr->hwndSelf);
527 nmhdr->hwndFrom = infoPtr->hwndSelf;
528 nmhdr->code = code;
529
530 TRACE("window %p, code=%08x, via %s\n", parent, code, (infoPtr->bUnicode)?"Unicode":"ANSI");
531
532 return SendMessageW(parent, WM_NOTIFY, nmhdr->idFrom, (LPARAM)nmhdr);
533}
534
535static INT
537{
538 NMREBAR notify_rebar;
539
540 notify_rebar.dwMask = 0;
541 if (uBand != -1) {
542 REBAR_BAND *lpBand = REBAR_GetBand(infoPtr, uBand);
543
544 if (lpBand->fMask & RBBIM_ID) {
545 notify_rebar.dwMask |= RBNM_ID;
546 notify_rebar.wID = lpBand->wID;
547 }
548 if (lpBand->fMask & RBBIM_LPARAM) {
549 notify_rebar.dwMask |= RBNM_LPARAM;
550 notify_rebar.lParam = lpBand->lParam;
551 }
552 if (lpBand->fMask & RBBIM_STYLE) {
553 notify_rebar.dwMask |= RBNM_STYLE;
554 notify_rebar.fStyle = lpBand->fStyle;
555 }
556 }
557 notify_rebar.uBand = uBand;
558 return REBAR_Notify ((NMHDR *)&notify_rebar, infoPtr, code);
559}
560
561static VOID
562REBAR_DrawBand (HDC hdc, const REBAR_INFO *infoPtr, REBAR_BAND *lpBand)
563{
564 HFONT hOldFont = 0;
565 INT oldBkMode = 0;
566 NMCUSTOMDRAW nmcd;
567 HTHEME theme = GetWindowTheme (infoPtr->hwndSelf);
568 RECT rcBand;
569
570 translate_rect(infoPtr, &rcBand, &lpBand->rcBand);
571
572 if (lpBand->fDraw & DRAW_TEXT) {
573 hOldFont = SelectObject (hdc, infoPtr->hFont);
574 oldBkMode = SetBkMode (hdc, TRANSPARENT);
575 }
576
577 /* should test for CDRF_NOTIFYITEMDRAW here */
579 nmcd.hdc = hdc;
580 nmcd.rc = rcBand;
581 nmcd.rc.right = lpBand->rcCapText.right;
582 nmcd.rc.bottom = lpBand->rcCapText.bottom;
583 nmcd.dwItemSpec = lpBand->wID;
584 nmcd.uItemState = 0;
585 nmcd.lItemlParam = lpBand->lParam;
586 lpBand->uCDret = REBAR_Notify ((NMHDR *)&nmcd, infoPtr, NM_CUSTOMDRAW);
587 if (lpBand->uCDret == CDRF_SKIPDEFAULT) {
588 if (oldBkMode != TRANSPARENT)
589 SetBkMode (hdc, oldBkMode);
590 SelectObject (hdc, hOldFont);
591 return;
592 }
593
594 /* draw gripper */
595 if (lpBand->fDraw & DRAW_GRIPPER)
596 {
597 if (theme)
598 {
599 RECT rcGripper = lpBand->rcGripper;
600 int partId = (infoPtr->dwStyle & CCS_VERT) ? RP_GRIPPERVERT : RP_GRIPPER;
601 GetThemeBackgroundExtent (theme, hdc, partId, 0, &rcGripper, &rcGripper);
602 OffsetRect (&rcGripper, lpBand->rcGripper.left - rcGripper.left,
603 lpBand->rcGripper.top - rcGripper.top);
604 DrawThemeBackground (theme, hdc, partId, 0, &rcGripper, NULL);
605 }
606 else
608 }
609
610 /* draw caption image */
611 if (lpBand->fDraw & DRAW_IMAGE) {
612 POINT pt;
613
614 /* center image */
615 pt.y = (lpBand->rcCapImage.bottom + lpBand->rcCapImage.top - infoPtr->imageSize.cy)/2;
616 pt.x = (lpBand->rcCapImage.right + lpBand->rcCapImage.left - infoPtr->imageSize.cx)/2;
617
618 ImageList_Draw (infoPtr->himl, lpBand->iImage, hdc,
619 pt.x, pt.y,
621 }
622
623 /* draw caption text */
624 if (lpBand->fDraw & DRAW_TEXT) {
625 /* need to handle CDRF_NEWFONT here */
626 INT oldBkMode = SetBkMode (hdc, TRANSPARENT);
627 COLORREF oldcolor = CLR_NONE;
628 COLORREF new;
629 if (lpBand->clrFore != CLR_NONE) {
630 new = (lpBand->clrFore == CLR_DEFAULT) ? infoPtr->clrBtnText :
631 lpBand->clrFore;
632 oldcolor = SetTextColor (hdc, new);
633 }
634
635#ifdef __REACTOS__
636 if (!theme)
637 {
638 DrawTextW (hdc, lpBand->lpText, -1, &lpBand->rcCapText, DT_CENTER | DT_VCENTER | DT_SINGLELINE);
639 }
640 else
641 {
642 DrawThemeText(theme, hdc, 0, 0, lpBand->lpText, -1, DT_CENTER | DT_VCENTER | DT_SINGLELINE, 0, &lpBand->rcCapText);
643 }
644#else
645 DrawTextW (hdc, lpBand->lpText, -1, &lpBand->rcCapText,
647#endif
648
649 if (oldBkMode != TRANSPARENT)
650 SetBkMode (hdc, oldBkMode);
651 if (lpBand->clrFore != CLR_NONE)
652 SetTextColor (hdc, oldcolor);
653 SelectObject (hdc, hOldFont);
654 }
655
656 if (!IsRectEmpty(&lpBand->rcChevron))
657 {
658 if (theme)
659 {
660 int stateId;
661 if (lpBand->fDraw & DRAW_CHEVRONPUSHED)
662 stateId = CHEVS_PRESSED;
663 else if (lpBand->fDraw & DRAW_CHEVRONHOT)
664 stateId = CHEVS_HOT;
665 else
666 stateId = CHEVS_NORMAL;
667 DrawThemeBackground (theme, hdc, RP_CHEVRON, stateId, &lpBand->rcChevron, NULL);
668 }
669 else
670 {
671 if (lpBand->fDraw & DRAW_CHEVRONPUSHED)
672 {
675 }
676 else if (lpBand->fDraw & DRAW_CHEVRONHOT)
677 {
680 }
681 else
683 }
684 }
685
688 nmcd.hdc = hdc;
689 nmcd.rc = rcBand;
690 nmcd.rc.right = lpBand->rcCapText.right;
691 nmcd.rc.bottom = lpBand->rcCapText.bottom;
692 nmcd.dwItemSpec = lpBand->wID;
693 nmcd.uItemState = 0;
694 nmcd.lItemlParam = lpBand->lParam;
695 lpBand->uCDret = REBAR_Notify ((NMHDR *)&nmcd, infoPtr, NM_CUSTOMDRAW);
696 }
697}
698
699
700static VOID
702{
703 REBAR_BAND *lpBand;
704 UINT i;
705
706 if (!infoPtr->DoRedraw) return;
707
708 for (i = 0; i < infoPtr->uNumBands; i++) {
709 lpBand = REBAR_GetBand(infoPtr, i);
710
711 if (HIDDENBAND(lpBand)) continue;
712
713 /* now draw the band */
714 TRACE("[%p] drawing band %i, flags=%08x\n",
715 infoPtr->hwndSelf, i, lpBand->fDraw);
716 REBAR_DrawBand (hdc, infoPtr, lpBand);
717 }
718}
719
720
721static void
722REBAR_CalcHorzBand (const REBAR_INFO *infoPtr, UINT rstart, UINT rend)
723 /* Function: this routine initializes all the rectangles in */
724 /* each band in a row to fit in the adjusted rcBand rect. */
725 /* *** Supports only Horizontal bars. *** */
726{
727 REBAR_BAND *lpBand;
728 UINT i, xoff;
729 RECT work;
730
731 for(i=rstart; i<rend; i++){
732 lpBand = REBAR_GetBand(infoPtr, i);
733 if (HIDDENBAND(lpBand)) {
734 SetRect (&lpBand->rcChild,
735 lpBand->rcBand.right, lpBand->rcBand.top,
736 lpBand->rcBand.right, lpBand->rcBand.bottom);
737 continue;
738 }
739
740 /* set initial gripper rectangle */
741 SetRect (&lpBand->rcGripper, lpBand->rcBand.left, lpBand->rcBand.top,
742 lpBand->rcBand.left, lpBand->rcBand.bottom);
743
744 /* calculate gripper rectangle */
745 if ( lpBand->fStatus & HAS_GRIPPER) {
746 lpBand->fDraw |= DRAW_GRIPPER;
748 lpBand->rcGripper.right = lpBand->rcGripper.left + GRIPPER_WIDTH;
749 InflateRect(&lpBand->rcGripper, 0, -2);
750
751 SetRect (&lpBand->rcCapImage,
754 }
755 else { /* no gripper will be drawn */
756 xoff = 0;
757 if (lpBand->fStatus & (HAS_IMAGE | HAS_TEXT))
758 /* if no gripper but either image or text, then leave space */
759 xoff = REBAR_ALWAYS_SPACE;
760 SetRect (&lpBand->rcCapImage,
761 lpBand->rcBand.left+xoff, lpBand->rcBand.top,
762 lpBand->rcBand.left+xoff, lpBand->rcBand.bottom);
763 }
764
765 /* image is visible */
766 if (lpBand->fStatus & HAS_IMAGE) {
767 lpBand->fDraw |= DRAW_IMAGE;
768 lpBand->rcCapImage.right += infoPtr->imageSize.cx;
769 lpBand->rcCapImage.bottom = lpBand->rcCapImage.top + infoPtr->imageSize.cy;
770
771 /* set initial caption text rectangle */
772 SetRect (&lpBand->rcCapText,
773 lpBand->rcCapImage.right+REBAR_POST_IMAGE, lpBand->rcBand.top+1,
774 lpBand->rcBand.left+lpBand->cxHeader, lpBand->rcBand.bottom-1);
775 }
776 else {
777 /* set initial caption text rectangle */
778 SetRect (&lpBand->rcCapText, lpBand->rcCapImage.right, lpBand->rcBand.top+1,
779 lpBand->rcBand.left+lpBand->cxHeader, lpBand->rcBand.bottom-1);
780 }
781
782 /* text is visible */
783 if ((lpBand->fStatus & HAS_TEXT) && !(lpBand->fStyle & RBBS_HIDETITLE)) {
784 lpBand->fDraw |= DRAW_TEXT;
785 lpBand->rcCapText.right = max(lpBand->rcCapText.left,
787 }
788
789 /* set initial child window rectangle if there is a child */
790 if (lpBand->hwndChild) {
791
792 lpBand->rcChild.left = lpBand->rcBand.left + lpBand->cxHeader;
793 lpBand->rcChild.right = lpBand->rcBand.right - REBAR_POST_CHILD;
794
795 if (lpBand->cyChild > 0) {
796
797 UINT yoff = (lpBand->rcBand.bottom - lpBand->rcBand.top - lpBand->cyChild) / 2;
798
799 /* center child if height is known */
800 lpBand->rcChild.top = lpBand->rcBand.top + yoff;
801 lpBand->rcChild.bottom = lpBand->rcBand.top + yoff + lpBand->cyChild;
802 }
803 else {
804 lpBand->rcChild.top = lpBand->rcBand.top;
805 lpBand->rcChild.bottom = lpBand->rcBand.bottom;
806 }
807
808 if ((lpBand->fStyle & RBBS_USECHEVRON) && (lpBand->rcChild.right - lpBand->rcChild.left < lpBand->cxIdeal))
809 {
810 lpBand->rcChild.right -= CHEVRON_WIDTH;
811 SetRect(&lpBand->rcChevron, lpBand->rcChild.right,
812 lpBand->rcChild.top, lpBand->rcChild.right + CHEVRON_WIDTH,
813 lpBand->rcChild.bottom);
814 }
815 }
816 else {
817 SetRect (&lpBand->rcChild,
818 lpBand->rcBand.left+lpBand->cxHeader, lpBand->rcBand.top,
819 lpBand->rcBand.right, lpBand->rcBand.bottom);
820 }
821
822 /* flag if notify required and invalidate rectangle */
823 if (lpBand->fDraw & NTF_INVALIDATE) {
824 lpBand->fDraw &= ~NTF_INVALIDATE;
825 work = lpBand->rcBand;
826 work.right += SEP_WIDTH;
827 work.bottom += SEP_WIDTH;
828 TRACE("invalidating %s\n", wine_dbgstr_rect(&work));
829 InvalidateRect(infoPtr->hwndSelf, &work, TRUE);
830 if (lpBand->hwndChild) InvalidateRect(lpBand->hwndChild, NULL, TRUE);
831 }
832
833 }
834
835}
836
837
838static VOID
839REBAR_CalcVertBand (const REBAR_INFO *infoPtr, UINT rstart, UINT rend)
840 /* Function: this routine initializes all the rectangles in */
841 /* each band in a row to fit in the adjusted rcBand rect. */
842 /* *** Supports only Vertical bars. *** */
843{
844 REBAR_BAND *lpBand;
845 UINT i, xoff;
846 RECT work;
847
848 for(i=rstart; i<rend; i++){
849 RECT rcBand;
850 lpBand = REBAR_GetBand(infoPtr, i);
851 if (HIDDENBAND(lpBand)) continue;
852
853 translate_rect(infoPtr, &rcBand, &lpBand->rcBand);
854
855 /* set initial gripper rectangle */
856 SetRect (&lpBand->rcGripper, rcBand.left, rcBand.top, rcBand.right, rcBand.top);
857
858 /* calculate gripper rectangle */
859 if (lpBand->fStatus & HAS_GRIPPER) {
860 lpBand->fDraw |= DRAW_GRIPPER;
861
862 if (infoPtr->dwStyle & RBS_VERTICALGRIPPER) {
863 /* vertical gripper */
864 lpBand->rcGripper.left += 3;
865 lpBand->rcGripper.right = lpBand->rcGripper.left + GRIPPER_WIDTH;
867 lpBand->rcGripper.bottom = lpBand->rcGripper.top + GRIPPER_HEIGHT;
868
869 /* initialize Caption image rectangle */
870 SetRect (&lpBand->rcCapImage, rcBand.left,
872 rcBand.right,
874 }
875 else {
876 /* horizontal gripper */
877 InflateRect(&lpBand->rcGripper, -2, 0);
879 lpBand->rcGripper.bottom = lpBand->rcGripper.top + GRIPPER_WIDTH;
880
881 /* initialize Caption image rectangle */
882 SetRect (&lpBand->rcCapImage, rcBand.left,
884 rcBand.right,
886 }
887 }
888 else { /* no gripper will be drawn */
889 xoff = 0;
890 if (lpBand->fStatus & (HAS_IMAGE | HAS_TEXT))
891 /* if no gripper but either image or text, then leave space */
892 xoff = REBAR_ALWAYS_SPACE;
893 /* initialize Caption image rectangle */
894 SetRect (&lpBand->rcCapImage,
895 rcBand.left, rcBand.top+xoff,
896 rcBand.right, rcBand.top+xoff);
897 }
898
899 /* image is visible */
900 if (lpBand->fStatus & HAS_IMAGE) {
901 lpBand->fDraw |= DRAW_IMAGE;
902
903 lpBand->rcCapImage.right = lpBand->rcCapImage.left + infoPtr->imageSize.cx;
904 lpBand->rcCapImage.bottom += infoPtr->imageSize.cy;
905
906 /* set initial caption text rectangle */
907 SetRect (&lpBand->rcCapText,
908 rcBand.left, lpBand->rcCapImage.bottom+REBAR_POST_IMAGE,
909 rcBand.right, rcBand.top+lpBand->cxHeader);
910 }
911 else {
912 /* set initial caption text rectangle */
913 SetRect (&lpBand->rcCapText,
914 rcBand.left, lpBand->rcCapImage.bottom,
915 rcBand.right, rcBand.top+lpBand->cxHeader);
916 }
917
918 /* text is visible */
919 if ((lpBand->fStatus & HAS_TEXT) && !(lpBand->fStyle & RBBS_HIDETITLE)) {
920 lpBand->fDraw |= DRAW_TEXT;
921 lpBand->rcCapText.bottom = max(lpBand->rcCapText.top,
922 lpBand->rcCapText.bottom);
923 }
924
925 /* set initial child window rectangle if there is a child */
926 if (lpBand->hwndChild) {
927 int cxBand = rcBand.right - rcBand.left;
928 xoff = (cxBand - lpBand->cyChild) / 2;
929 SetRect (&lpBand->rcChild,
930 rcBand.left + xoff, rcBand.top + lpBand->cxHeader,
931 rcBand.left + xoff + lpBand->cyChild, rcBand.bottom - REBAR_POST_CHILD);
932 }
933 else {
934 SetRect (&lpBand->rcChild,
935 rcBand.left, rcBand.top+lpBand->cxHeader,
936 rcBand.right, rcBand.bottom);
937 }
938
939 if (lpBand->fDraw & NTF_INVALIDATE) {
940 lpBand->fDraw &= ~NTF_INVALIDATE;
941 work = rcBand;
942 work.bottom += SEP_WIDTH;
943 work.right += SEP_WIDTH;
944 TRACE("invalidating %s\n", wine_dbgstr_rect(&work));
945 InvalidateRect(infoPtr->hwndSelf, &work, TRUE);
946 if (lpBand->hwndChild) InvalidateRect(lpBand->hwndChild, NULL, TRUE);
947 }
948
949 }
950}
951
952
953static VOID
955 /* Function: This changes the size of the REBAR window to that */
956 /* calculated by REBAR_Layout. */
957{
958 INT x, y, width, height;
959 INT xedge = 0, yedge = 0;
960 RECT rcSelf;
961
962 TRACE("new size [%d x %d]\n", infoPtr->calcSize.cx, infoPtr->calcSize.cy);
963
964 if (infoPtr->dwStyle & CCS_NORESIZE)
965 return;
966
967 if (infoPtr->dwStyle & WS_BORDER)
968 {
971 /* swap for CCS_VERT? */
972 }
973
974 /* compute rebar window rect in parent client coordinates */
975 GetWindowRect(infoPtr->hwndSelf, &rcSelf);
976 MapWindowPoints(HWND_DESKTOP, GetParent(infoPtr->hwndSelf), (LPPOINT)&rcSelf, 2);
977 translate_rect(infoPtr, &rcSelf, &rcSelf);
978
979 height = infoPtr->calcSize.cy + 2*yedge;
980 if (!(infoPtr->dwStyle & CCS_NOPARENTALIGN)) {
981 RECT rcParent;
982
983 x = -xedge;
984 width = infoPtr->calcSize.cx + 2*xedge;
985 y = 0; /* quiet compiler warning */
986 switch ( infoPtr->dwStyle & CCS_LAYOUT_MASK) {
987 case 0: /* shouldn't happen - see NCCreate */
988 case CCS_TOP:
989 y = ((infoPtr->dwStyle & CCS_NODIVIDER) ? 0 : REBAR_DIVIDER) - yedge;
990 break;
991 case CCS_NOMOVEY:
992 y = rcSelf.top;
993 break;
994 case CCS_BOTTOM:
995 GetClientRect(GetParent(infoPtr->hwndSelf), &rcParent);
996 translate_rect(infoPtr, &rcParent, &rcParent);
997 y = rcParent.bottom - infoPtr->calcSize.cy - yedge;
998 break;
999 }
1000 }
1001 else {
1002 x = rcSelf.left;
1003 /* As on Windows if the CCS_NODIVIDER is not present the control will move
1004 * 2 pixel down after every layout */
1005 y = rcSelf.top + ((infoPtr->dwStyle & CCS_NODIVIDER) ? 0 : REBAR_DIVIDER);
1006 width = rcSelf.right - rcSelf.left;
1007 }
1008
1009 TRACE("hwnd %p, style=%08x, setting at (%d,%d) for (%d,%d)\n",
1010 infoPtr->hwndSelf, infoPtr->dwStyle, x, y, width, height);
1011
1012 /* Set flag to ignore next WM_SIZE message and resize the window */
1013 infoPtr->fStatus |= SELF_RESIZE;
1014 if ((infoPtr->dwStyle & CCS_VERT) == 0)
1015 SetWindowPos(infoPtr->hwndSelf, 0, x, y, width, height, SWP_NOZORDER);
1016 else
1017 SetWindowPos(infoPtr->hwndSelf, 0, y, x, height, width, SWP_NOZORDER);
1018 infoPtr->fStatus &= ~SELF_RESIZE;
1019}
1020
1021
1022static VOID
1024{
1025 static const WCHAR strComboBox[] = { 'C','o','m','b','o','B','o','x',0 };
1026 REBAR_BAND *lpBand;
1027 WCHAR szClassName[40];
1028 UINT i;
1029 NMREBARCHILDSIZE rbcz;
1030 HDWP deferpos;
1031
1032 if (!(deferpos = BeginDeferWindowPos(infoPtr->uNumBands)))
1033 ERR("BeginDeferWindowPos returned NULL\n");
1034
1035 for (i = start; i < endplus; i++) {
1036 lpBand = REBAR_GetBand(infoPtr, i);
1037
1038 if (HIDDENBAND(lpBand)) continue;
1039 if (lpBand->hwndChild) {
1040 TRACE("hwndChild = %p\n", lpBand->hwndChild);
1041
1042 /* Always generate the RBN_CHILDSIZE even if child
1043 did not change */
1044 rbcz.uBand = i;
1045 rbcz.wID = lpBand->wID;
1046 rbcz.rcChild = lpBand->rcChild;
1047 translate_rect(infoPtr, &rbcz.rcBand, &lpBand->rcBand);
1048 if (infoPtr->dwStyle & CCS_VERT)
1049 rbcz.rcBand.top += lpBand->cxHeader;
1050 else
1051 rbcz.rcBand.left += lpBand->cxHeader;
1052 REBAR_Notify ((NMHDR *)&rbcz, infoPtr, RBN_CHILDSIZE);
1053 if (!EqualRect (&lpBand->rcChild, &rbcz.rcChild)) {
1054 TRACE("Child rect changed by NOTIFY for band %u\n", i);
1055 TRACE(" from (%s) to (%s)\n",
1056 wine_dbgstr_rect(&lpBand->rcChild),
1057 wine_dbgstr_rect(&rbcz.rcChild));
1058 lpBand->rcChild = rbcz.rcChild; /* *** ??? */
1059 }
1060
1062 if (!lstrcmpW (szClassName, strComboBox) ||
1064 INT nEditHeight, yPos;
1065 RECT rc;
1066
1067 /* special placement code for combo or comboex box */
1068
1069
1070 /* get size of edit line */
1071 GetWindowRect (lpBand->hwndChild, &rc);
1072 nEditHeight = rc.bottom - rc.top;
1073 yPos = (lpBand->rcChild.bottom + lpBand->rcChild.top - nEditHeight)/2;
1074
1075 /* center combo box inside child area */
1076 TRACE("moving child (Combo(Ex)) %p to (%d,%d) for (%d,%d)\n",
1077 lpBand->hwndChild,
1078 lpBand->rcChild.left, yPos,
1079 lpBand->rcChild.right - lpBand->rcChild.left,
1080 nEditHeight);
1081 deferpos = DeferWindowPos (deferpos, lpBand->hwndChild, HWND_TOP,
1082 lpBand->rcChild.left,
1083 /*lpBand->rcChild.top*/ yPos,
1084 lpBand->rcChild.right - lpBand->rcChild.left,
1085 nEditHeight,
1086 SWP_NOZORDER);
1087 if (!deferpos)
1088 ERR("DeferWindowPos returned NULL\n");
1089 }
1090 else {
1091 TRACE("moving child (Other) %p to (%d,%d) for (%d,%d)\n",
1092 lpBand->hwndChild,
1093 lpBand->rcChild.left, lpBand->rcChild.top,
1094 lpBand->rcChild.right - lpBand->rcChild.left,
1095 lpBand->rcChild.bottom - lpBand->rcChild.top);
1096 deferpos = DeferWindowPos (deferpos, lpBand->hwndChild, HWND_TOP,
1097 lpBand->rcChild.left,
1098 lpBand->rcChild.top,
1099 lpBand->rcChild.right - lpBand->rcChild.left,
1100 lpBand->rcChild.bottom - lpBand->rcChild.top,
1101 SWP_NOZORDER);
1102 if (!deferpos)
1103 ERR("DeferWindowPos returned NULL\n");
1104 }
1105 }
1106 }
1107 if (!EndDeferWindowPos(deferpos))
1108 ERR("EndDeferWindowPos returned NULL\n");
1109
1110 if (infoPtr->DoRedraw)
1111 UpdateWindow (infoPtr->hwndSelf);
1112}
1113
1114/* Returns the next visible band (the first visible band in [i+1; infoPtr->uNumBands) )
1115 * or infoPtr->uNumBands if none */
1116static int next_visible(const REBAR_INFO *infoPtr, int i)
1117{
1118 unsigned int n;
1119 for (n = i + 1; n < infoPtr->uNumBands; n++)
1120 if (!HIDDENBAND(REBAR_GetBand(infoPtr, n)))
1121 break;
1122 return n;
1123}
1124
1125/* Returns the previous visible band (the last visible band in [0; i) )
1126 * or -1 if none */
1127static int prev_visible(const REBAR_INFO *infoPtr, int i)
1128{
1129 int n;
1130 for (n = i - 1; n >= 0; n--)
1131 if (!HIDDENBAND(REBAR_GetBand(infoPtr, n)))
1132 break;
1133 return n;
1134}
1135
1136/* Returns the first visible band or infoPtr->uNumBands if none */
1137static int first_visible(const REBAR_INFO *infoPtr)
1138{
1139 return next_visible(infoPtr, -1); /* this works*/
1140}
1141
1142/* Returns the first visible band for the given row (or iBand if none) */
1143static int get_row_begin_for_band(const REBAR_INFO *infoPtr, INT iBand)
1144{
1145 int iLastBand = iBand;
1146 int iRow = REBAR_GetBand(infoPtr, iBand)->iRow;
1147 while ((iBand = prev_visible(infoPtr, iBand)) >= 0) {
1148 if (REBAR_GetBand(infoPtr, iBand)->iRow != iRow)
1149 break;
1150 else
1151 iLastBand = iBand;
1152 }
1153 return iLastBand;
1154}
1155
1156/* Returns the first visible band for the next row (or infoPtr->uNumBands if none) */
1157static int get_row_end_for_band(const REBAR_INFO *infoPtr, INT iBand)
1158{
1159 int iRow = REBAR_GetBand(infoPtr, iBand)->iRow;
1160 while ((iBand = next_visible(infoPtr, iBand)) < infoPtr->uNumBands)
1161 if (REBAR_GetBand(infoPtr, iBand)->iRow != iRow)
1162 break;
1163 return iBand;
1164}
1165
1166/* Compute the rcBand.{left,right} from the cxEffective bands widths computed earlier.
1167 * iBeginBand must be visible */
1168static void REBAR_SetRowRectsX(const REBAR_INFO *infoPtr, INT iBeginBand, INT iEndBand)
1169{
1170 int xPos = 0, i;
1171 for (i = iBeginBand; i < iEndBand; i = next_visible(infoPtr, i))
1172 {
1173 REBAR_BAND *lpBand = REBAR_GetBand(infoPtr, i);
1174 if (lpBand->rcBand.left != xPos || lpBand->rcBand.right != xPos + lpBand->cxEffective) {
1175 lpBand->fDraw |= NTF_INVALIDATE;
1176 TRACE("Setting rect %d to %d,%d\n", i, xPos, xPos + lpBand->cxEffective);
1177 lpBand->rcBand.left = xPos;
1178 lpBand->rcBand.right = xPos + lpBand->cxEffective;
1179 }
1180 xPos += lpBand->cxEffective + SEP_WIDTH;
1181 }
1182}
1183
1184/* The rationale of this function is probably as follows: if we have some space
1185 * to distribute we want to add it to a band on the right. However we don't want
1186 * to unminimize a minimized band so we search for a band that is big enough.
1187 * For some reason "big enough" is defined as bigger than the minimum size of the
1188 * first band in the row
1189 */
1190static REBAR_BAND *REBAR_FindBandToGrow(const REBAR_INFO *infoPtr, INT iBeginBand, INT iEndBand)
1191{
1192 INT cxMinFirstBand = 0, i;
1193
1194 cxMinFirstBand = REBAR_GetBand(infoPtr, iBeginBand)->cxMinBand;
1195
1196 for (i = prev_visible(infoPtr, iEndBand); i >= iBeginBand; i = prev_visible(infoPtr, i))
1197 if (REBAR_GetBand(infoPtr, i)->cxEffective > cxMinFirstBand &&
1198 !(REBAR_GetBand(infoPtr, i)->fStyle & RBBS_FIXEDSIZE))
1199 break;
1200
1201 if (i < iBeginBand)
1202 for (i = prev_visible(infoPtr, iEndBand); i >= iBeginBand; i = prev_visible(infoPtr, i))
1203 if (REBAR_GetBand(infoPtr, i)->cxMinBand == cxMinFirstBand)
1204 break;
1205
1206 TRACE("Extra space for row [%d..%d) should be added to band %d\n", iBeginBand, iEndBand, i);
1207 return REBAR_GetBand(infoPtr, i);
1208}
1209
1210/* Try to shrink the visible bands in [iBeginBand; iEndBand) by cxShrink, starting from the right */
1211static int REBAR_ShrinkBandsRTL(const REBAR_INFO *infoPtr, INT iBeginBand, INT iEndBand, INT cxShrink, BOOL bEnforce)
1212{
1213 REBAR_BAND *lpBand;
1214 INT width, i;
1215
1216 TRACE("Shrinking bands [%d..%d) by %d, right-to-left\n", iBeginBand, iEndBand, cxShrink);
1217 for (i = prev_visible(infoPtr, iEndBand); i >= iBeginBand; i = prev_visible(infoPtr, i))
1218 {
1219 lpBand = REBAR_GetBand(infoPtr, i);
1220
1221 width = max(lpBand->cxEffective - cxShrink, (int)lpBand->cxMinBand);
1222 cxShrink -= lpBand->cxEffective - width;
1223 lpBand->cxEffective = width;
1224 if (bEnforce && lpBand->cx > lpBand->cxEffective)
1225 lpBand->cx = lpBand->cxEffective;
1226 if (cxShrink == 0)
1227 break;
1228 }
1229 return cxShrink;
1230}
1231
1232
1233/* Try to shrink the visible bands in [iBeginBand; iEndBand) by cxShrink, starting from the left.
1234 * iBeginBand must be visible */
1235static int REBAR_ShrinkBandsLTR(const REBAR_INFO *infoPtr, INT iBeginBand, INT iEndBand, INT cxShrink, BOOL bEnforce)
1236{
1237 REBAR_BAND *lpBand;
1238 INT width, i;
1239
1240 TRACE("Shrinking bands [%d..%d) by %d, left-to-right\n", iBeginBand, iEndBand, cxShrink);
1241 for (i = iBeginBand; i < iEndBand; i = next_visible(infoPtr, i))
1242 {
1243 lpBand = REBAR_GetBand(infoPtr, i);
1244
1245 width = max(lpBand->cxEffective - cxShrink, (int)lpBand->cxMinBand);
1246 cxShrink -= lpBand->cxEffective - width;
1247 lpBand->cxEffective = width;
1248 if (bEnforce)
1249 lpBand->cx = lpBand->cxEffective;
1250 if (cxShrink == 0)
1251 break;
1252 }
1253 return cxShrink;
1254}
1255
1256/* Tries to move a band to a given offset within a row. */
1257static int REBAR_MoveBandToRowOffset(REBAR_INFO *infoPtr, INT iBand, INT iFirstBand,
1258 INT iLastBand, INT xOff, BOOL reorder)
1259{
1260 REBAR_BAND *insertBand = REBAR_GetBand(infoPtr, iBand);
1261 int xPos = 0, i;
1262 const BOOL setBreak = REBAR_GetBand(infoPtr, iFirstBand)->fStyle & RBBS_BREAK;
1263
1264 /* Find the band's new position */
1265 if(reorder)
1266 {
1267 /* Used during an LR band reorder drag */
1268 for (i = iFirstBand; i < iLastBand; i = next_visible(infoPtr, i))
1269 {
1270 if(xPos > xOff)
1271 break;
1272 xPos += REBAR_GetBand(infoPtr, i)->cxEffective + SEP_WIDTH;
1273 }
1274 }
1275 else
1276 {
1277 /* Used during a UD band insertion drag */
1278 for (i = iFirstBand; i < iLastBand; i = next_visible(infoPtr, i))
1279 {
1280 const REBAR_BAND *band = REBAR_GetBand(infoPtr, i);
1281 if(xPos + band->cxMinBand / 2 > xOff)
1282 break;
1283 xPos += band->cxEffective + SEP_WIDTH;
1284 }
1285 }
1286
1287 /* Move the band to its new position */
1288 DPA_DeletePtr(infoPtr->bands, iBand);
1289 if(i > iBand)
1290 i--;
1291 DPA_InsertPtr(infoPtr->bands, i, insertBand);
1292
1293 /* Ensure only the last band has the RBBS_BREAK flag set */
1294 insertBand->fStyle &= ~RBBS_BREAK;
1295 if(setBreak)
1296 REBAR_GetBand(infoPtr, iFirstBand)->fStyle |= RBBS_BREAK;
1297
1298 /* Return the currently grabbed band */
1299 if(infoPtr->iGrabbedBand == iBand)
1300 {
1301 infoPtr->iGrabbedBand = i;
1302 return i;
1303 }
1304 else return -1;
1305}
1306
1307/* Set the heights of the visible bands in [iBeginBand; iEndBand) to the max height. iBeginBand must be visible */
1308static int REBAR_SetBandsHeight(const REBAR_INFO *infoPtr, INT iBeginBand, INT iEndBand, INT yStart)
1309{
1310 REBAR_BAND *lpBand;
1311 int yMaxHeight = 0;
1312 int yPos = yStart;
1313 int row, i;
1314
1315 for (i = iBeginBand; i < iEndBand; i = next_visible(infoPtr, i))
1316 {
1317 lpBand = REBAR_GetBand(infoPtr, i);
1318 lpBand->cyRowSoFar = yMaxHeight;
1319 yMaxHeight = max(yMaxHeight, lpBand->cyMinBand);
1320 }
1321 TRACE("Bands [%d; %d) height: %d\n", iBeginBand, iEndBand, yMaxHeight);
1322
1323 row = iBeginBand < iEndBand ? REBAR_GetBand(infoPtr, iBeginBand)->iRow : 0;
1324
1325 for (i = iBeginBand; i < iEndBand; i = next_visible(infoPtr, i))
1326 {
1327 lpBand = REBAR_GetBand(infoPtr, i);
1328 /* we may be called for multiple rows if RBS_VARHEIGHT not set */
1329 if (lpBand->iRow != row) {
1330 yPos += yMaxHeight + SEP_WIDTH;
1331 row = lpBand->iRow;
1332 }
1333
1334 if (lpBand->rcBand.top != yPos || lpBand->rcBand.bottom != yPos + yMaxHeight) {
1335 lpBand->fDraw |= NTF_INVALIDATE;
1336 lpBand->rcBand.top = yPos;
1337 lpBand->rcBand.bottom = yPos + yMaxHeight;
1338 TRACE("Band %d: %s\n", i, wine_dbgstr_rect(&lpBand->rcBand));
1339 }
1340 }
1341 return yPos + yMaxHeight;
1342}
1343
1344/* Layout the row [iBeginBand; iEndBand). iBeginBand must be visible */
1345static void REBAR_LayoutRow(const REBAR_INFO *infoPtr, int iBeginBand, int iEndBand, int cx, int *piRow, int *pyPos)
1346{
1347 REBAR_BAND *lpBand;
1348 int i, extra;
1349 int width = 0;
1350
1351 TRACE("Adjusting row [%d;%d). Width: %d\n", iBeginBand, iEndBand, cx);
1352 for (i = iBeginBand; i < iEndBand; i++)
1353 REBAR_GetBand(infoPtr, i)->iRow = *piRow;
1354
1355 /* compute the extra space */
1356 for (i = iBeginBand; i < iEndBand; i = next_visible(infoPtr, i))
1357 {
1358 lpBand = REBAR_GetBand(infoPtr, i);
1359 if (i > iBeginBand)
1360 width += SEP_WIDTH;
1361 lpBand->cxEffective = max(lpBand->cxMinBand, lpBand->cx);
1362 width += lpBand->cxEffective;
1363 }
1364
1365 extra = cx - width;
1366 TRACE("Extra space: %d\n", extra);
1367 if (extra < 0) {
1368 int ret = REBAR_ShrinkBandsRTL(infoPtr, iBeginBand, iEndBand, -extra, FALSE);
1369 if (ret > 0 && next_visible(infoPtr, iBeginBand) != iEndBand) /* one band may be longer than expected... */
1370 ERR("Error layouting row %d - couldn't shrink for %d pixels (%d total shrink)\n", *piRow, ret, -extra);
1371 } else
1372 if (extra > 0) {
1373 lpBand = REBAR_FindBandToGrow(infoPtr, iBeginBand, iEndBand);
1374 lpBand->cxEffective += extra;
1375 }
1376
1377 REBAR_SetRowRectsX(infoPtr, iBeginBand, iEndBand);
1378 if (infoPtr->dwStyle & RBS_VARHEIGHT)
1379 {
1380 if (*piRow > 0)
1381 *pyPos += SEP_WIDTH;
1382 *pyPos = REBAR_SetBandsHeight(infoPtr, iBeginBand, iEndBand, *pyPos);
1383 }
1384 (*piRow)++;
1385}
1386
1387static VOID
1389{
1390 REBAR_BAND *lpBand;
1391 RECT rcAdj;
1392 SIZE oldSize;
1393 INT adjcx, i;
1394 INT rowstart;
1395 INT row = 0;
1396 INT xMin, yPos;
1397
1398 if (infoPtr->dwStyle & (CCS_NORESIZE | CCS_NOPARENTALIGN) || GetParent(infoPtr->hwndSelf) == NULL)
1399 GetClientRect(infoPtr->hwndSelf, &rcAdj);
1400 else
1401 GetClientRect(GetParent(infoPtr->hwndSelf), &rcAdj);
1402 TRACE("adjustment rect is (%s)\n", wine_dbgstr_rect(&rcAdj));
1403
1404 adjcx = get_rect_cx(infoPtr, &rcAdj);
1405
1406 if (infoPtr->uNumBands == 0) {
1407 TRACE("No bands - setting size to (0,%d), style: %x\n", adjcx, infoPtr->dwStyle);
1408 infoPtr->calcSize.cx = adjcx;
1409 /* the calcSize.cy won't change for a 0 band rebar */
1410 infoPtr->uNumRows = 0;
1411 REBAR_ForceResize(infoPtr);
1412 return;
1413 }
1414
1415 yPos = 0;
1416 xMin = 0;
1417 rowstart = first_visible(infoPtr);
1418 /* divide rows */
1419 for (i = rowstart; i < infoPtr->uNumBands; i = next_visible(infoPtr, i))
1420 {
1421 lpBand = REBAR_GetBand(infoPtr, i);
1422
1423 if (i > rowstart && (lpBand->fStyle & RBBS_BREAK || xMin + lpBand->cxMinBand > adjcx)) {
1424 TRACE("%s break on band %d\n", (lpBand->fStyle & RBBS_BREAK ? "Hard" : "Soft"), i - 1);
1425 REBAR_LayoutRow(infoPtr, rowstart, i, adjcx, &row, &yPos);
1426 rowstart = i;
1427 xMin = 0;
1428 }
1429 else
1430 xMin += SEP_WIDTH;
1431
1432 xMin += lpBand->cxMinBand;
1433 }
1434 if (rowstart < infoPtr->uNumBands)
1435 REBAR_LayoutRow(infoPtr, rowstart, infoPtr->uNumBands, adjcx, &row, &yPos);
1436
1437 if (!(infoPtr->dwStyle & RBS_VARHEIGHT))
1438 yPos = REBAR_SetBandsHeight(infoPtr, first_visible(infoPtr), infoPtr->uNumBands, 0);
1439
1440 infoPtr->uNumRows = row;
1441
1442 if (infoPtr->dwStyle & CCS_VERT)
1443 REBAR_CalcVertBand(infoPtr, 0, infoPtr->uNumBands);
1444 else
1445 REBAR_CalcHorzBand(infoPtr, 0, infoPtr->uNumBands);
1446 /* now compute size of Rebar itself */
1447 oldSize = infoPtr->calcSize;
1448
1449 infoPtr->calcSize.cx = adjcx;
1450 infoPtr->calcSize.cy = yPos;
1451 TRACE("calcsize size=(%d, %d), origheight=(%d,%d)\n",
1452 infoPtr->calcSize.cx, infoPtr->calcSize.cy,
1453 oldSize.cx, oldSize.cy);
1454
1455 REBAR_DumpBand (infoPtr);
1456 REBAR_MoveChildWindows (infoPtr, 0, infoPtr->uNumBands);
1457 REBAR_ForceResize (infoPtr);
1458
1459 /* note: after a RBN_HEIGHTCHANGE native sends once again all the RBN_CHILDSIZE
1460 * and does another ForceResize */
1461 if (oldSize.cy != infoPtr->calcSize.cy)
1462 {
1463 NMHDR heightchange;
1464 REBAR_Notify(&heightchange, infoPtr, RBN_HEIGHTCHANGE);
1465 REBAR_AutoSize(infoPtr, FALSE);
1466 }
1467}
1468
1469/* iBeginBand must be visible */
1470static int
1471REBAR_SizeChildrenToHeight(const REBAR_INFO *infoPtr, int iBeginBand, int iEndBand, int extra, BOOL *fChanged)
1472{
1473 int cyBandsOld;
1474 int cyBandsNew = 0;
1475 int i;
1476
1477 TRACE("[%d;%d) by %d\n", iBeginBand, iEndBand, extra);
1478
1479 cyBandsOld = REBAR_GetBand(infoPtr, iBeginBand)->rcBand.bottom -
1480 REBAR_GetBand(infoPtr, iBeginBand)->rcBand.top;
1481 for (i = iBeginBand; i < iEndBand; i = next_visible(infoPtr, i))
1482 {
1483 REBAR_BAND *lpBand = REBAR_GetBand(infoPtr, i);
1484 int cyMaxChild = cyBandsOld - REBARSPACE(lpBand) + extra;
1485 int cyChild = round_child_height(lpBand, cyMaxChild);
1486
1487 if (lpBand->hwndChild && cyChild != lpBand->cyChild && (lpBand->fStyle & RBBS_VARIABLEHEIGHT))
1488 {
1489 TRACE("Resizing %d: %d -> %d [%d]\n", i, lpBand->cyChild, cyChild, lpBand->cyMaxChild);
1490 *fChanged = TRUE;
1491 lpBand->cyChild = cyChild;
1492 lpBand->fDraw |= NTF_INVALIDATE;
1493 update_min_band_height(infoPtr, lpBand);
1494 }
1495 cyBandsNew = max(cyBandsNew, lpBand->cyMinBand);
1496 }
1497 return cyBandsNew - cyBandsOld;
1498}
1499
1500/* worker function for RB_SIZETORECT and RBS_AUTOSIZE */
1501static VOID
1503{
1504 int extra = height - infoPtr->calcSize.cy; /* may be negative */
1505 BOOL fChanged = FALSE;
1506 UINT uNumRows = infoPtr->uNumRows;
1507 int i;
1508
1509 if (uNumRows == 0) /* avoid division by 0 */
1510 return;
1511
1512 /* That's not exactly what Windows does but should be similar */
1513
1514 /* Pass one: break-up/glue rows */
1515 if (extra > 0)
1516 {
1517 for (i = prev_visible(infoPtr, infoPtr->uNumBands); i > 0; i = prev_visible(infoPtr, i))
1518 {
1519 REBAR_BAND *lpBand = REBAR_GetBand(infoPtr, i);
1520 int cyBreakExtra; /* additional cy for the rebar after a RBBS_BREAK on this band */
1521
1522 height = lpBand->rcBand.bottom - lpBand->rcBand.top;
1523
1524 if (infoPtr->dwStyle & RBS_VARHEIGHT)
1525 cyBreakExtra = lpBand->cyRowSoFar; /* 'height' => 'lpBand->cyRowSoFar' + 'height'*/
1526 else
1527 cyBreakExtra = height; /* 'height' => 'height' + 'height'*/
1528 cyBreakExtra += SEP_WIDTH;
1529
1530 if (extra <= cyBreakExtra / 2)
1531 break;
1532
1533 if (!(lpBand->fStyle & RBBS_BREAK))
1534 {
1535 TRACE("Adding break on band %d - extra %d -> %d\n", i, extra, extra - cyBreakExtra);
1536 lpBand->fStyle |= RBBS_BREAK;
1537 lpBand->fDraw |= NTF_INVALIDATE;
1538 fChanged = TRUE;
1539 extra -= cyBreakExtra;
1540 uNumRows++;
1541 /* temporary change for _SizeControlsToHeight. The true values will be computed in _Layout */
1542 if (infoPtr->dwStyle & RBS_VARHEIGHT)
1543 lpBand->rcBand.bottom = lpBand->rcBand.top + lpBand->cyMinBand;
1544 }
1545 }
1546 }
1547 /* TODO: else if (extra < 0) { try to remove some RBBS_BREAKs } */
1548
1549 /* Pass two: increase/decrease control height */
1550 if (infoPtr->dwStyle & RBS_VARHEIGHT)
1551 {
1552 int i = first_visible(infoPtr);
1553 int iRow = 0;
1554 while (i < infoPtr->uNumBands)
1555 {
1556 REBAR_BAND *lpBand = REBAR_GetBand(infoPtr, i);
1557 int extraForRow = extra / (int)(uNumRows - iRow);
1558 int rowEnd;
1559
1560 /* we can't use get_row_end_for_band as we might have added RBBS_BREAK in the first phase */
1561 for (rowEnd = next_visible(infoPtr, i); rowEnd < infoPtr->uNumBands; rowEnd = next_visible(infoPtr, rowEnd))
1562 if (REBAR_GetBand(infoPtr, rowEnd)->iRow != lpBand->iRow ||
1563 REBAR_GetBand(infoPtr, rowEnd)->fStyle & RBBS_BREAK)
1564 break;
1565
1566 extra -= REBAR_SizeChildrenToHeight(infoPtr, i, rowEnd, extraForRow, &fChanged);
1567 TRACE("extra = %d\n", extra);
1568 i = rowEnd;
1569 iRow++;
1570 }
1571 }
1572 else
1573 REBAR_SizeChildrenToHeight(infoPtr, first_visible(infoPtr), infoPtr->uNumBands, extra / infoPtr->uNumRows, &fChanged);
1574
1575 if (fChanged)
1576 REBAR_Layout(infoPtr);
1577}
1578
1579static VOID
1580REBAR_AutoSize(REBAR_INFO *infoPtr, BOOL needsLayout)
1581{
1582 RECT rc, rcNew;
1583 NMRBAUTOSIZE autosize;
1584
1585 if (needsLayout)
1586 REBAR_Layout(infoPtr);
1587 GetClientRect(infoPtr->hwndSelf, &rc);
1588 REBAR_SizeToHeight(infoPtr, get_rect_cy(infoPtr, &rc));
1589 GetClientRect(infoPtr->hwndSelf, &rcNew);
1590
1591 GetClientRect(infoPtr->hwndSelf, &autosize.rcTarget);
1592 autosize.fChanged = EqualRect(&rc, &rcNew);
1593 autosize.rcTarget = rc;
1594 autosize.rcActual = rcNew;
1595 REBAR_Notify((NMHDR *)&autosize, infoPtr, RBN_AUTOSIZE);
1596}
1597
1598static VOID
1600 /* Function: This routine evaluates the band specs supplied */
1601 /* by the user and updates the following 5 fields in */
1602 /* the internal band structure: cxHeader, cyHeader, cxMinBand, cyMinBand, fStatus */
1603{
1604 UINT header=0;
1605 UINT textheight=0, imageheight = 0;
1606 UINT i, nonfixed;
1607 REBAR_BAND *tBand;
1608
1609 lpBand->fStatus = 0;
1610 lpBand->cxMinBand = 0;
1611 lpBand->cyMinBand = 0;
1612
1613 /* Data coming in from users into the cx... and cy... fields */
1614 /* may be bad, just garbage, because the user never clears */
1615 /* the fields. RB_{SET|INSERT}BAND{A|W} just passes the data */
1616 /* along if the fields exist in the input area. Here we must */
1617 /* determine if the data is valid. I have no idea how MS does */
1618 /* the validation, but it does because the RB_GETBANDINFO */
1619 /* returns a 0 when I know the sample program passed in an */
1620 /* address. Here I will use the algorithm that if the value */
1621 /* is greater than 65535 then it is bad and replace it with */
1622 /* a zero. Feel free to improve the algorithm. - GA 12/2000 */
1623 if (lpBand->cxMinChild > 65535) lpBand->cxMinChild = 0;
1624 if (lpBand->cyMinChild > 65535) lpBand->cyMinChild = 0;
1625 if (lpBand->cx > 65535) lpBand->cx = 0;
1626 if (lpBand->cyChild > 65535) lpBand->cyChild = 0;
1627 if (lpBand->cyIntegral > 65535) lpBand->cyIntegral = 0;
1628 if (lpBand->cxIdeal > 65535) lpBand->cxIdeal = 0;
1629 if (lpBand->cxHeader > 65535) lpBand->cxHeader = 0;
1630
1631 /* TODO : we could try return to the caller if a value changed so that */
1632 /* a REBAR_Layout is needed. Till now the caller should call it */
1633 /* it always (we should also check what native does) */
1634
1635 /* Header is where the image, text and gripper exist */
1636 /* in the band and precede the child window. */
1637
1638 /* count number of non-FIXEDSIZE and non-Hidden bands */
1639 nonfixed = 0;
1640 for (i=0; i<infoPtr->uNumBands; i++){
1641 tBand = REBAR_GetBand(infoPtr, i);
1642 if (!HIDDENBAND(tBand) && !(tBand->fStyle & RBBS_FIXEDSIZE))
1643 nonfixed++;
1644 }
1645
1646 /* calculate gripper rectangle */
1647 if ( (!(lpBand->fStyle & RBBS_NOGRIPPER)) &&
1648 ( (lpBand->fStyle & RBBS_GRIPPERALWAYS) ||
1649 ( !(lpBand->fStyle & RBBS_FIXEDSIZE) && (nonfixed > 1)))
1650 ) {
1651 lpBand->fStatus |= HAS_GRIPPER;
1652 if (infoPtr->dwStyle & CCS_VERT)
1653 if (infoPtr->dwStyle & RBS_VERTICALGRIPPER)
1655 else
1657 else
1659 /* Always have 4 pixels before anything else */
1661 }
1662
1663 /* image is visible */
1664 if (lpBand->iImage != -1 && (infoPtr->himl)) {
1665 lpBand->fStatus |= HAS_IMAGE;
1666 if (infoPtr->dwStyle & CCS_VERT) {
1667 header += (infoPtr->imageSize.cy + REBAR_POST_IMAGE);
1668 imageheight = infoPtr->imageSize.cx + 4;
1669 }
1670 else {
1671 header += (infoPtr->imageSize.cx + REBAR_POST_IMAGE);
1672 imageheight = infoPtr->imageSize.cy + 4;
1673 }
1674 }
1675
1676 /* text is visible */
1677 if ((lpBand->fMask & RBBIM_TEXT) && (lpBand->lpText) &&
1678 !(lpBand->fStyle & RBBS_HIDETITLE)) {
1679 HDC hdc = GetDC (0);
1680 HFONT hOldFont = SelectObject (hdc, infoPtr->hFont);
1681 SIZE size;
1682
1683 lpBand->fStatus |= HAS_TEXT;
1685 lstrlenW (lpBand->lpText), &size);
1686 header += ((infoPtr->dwStyle & CCS_VERT) ? (size.cy + REBAR_POST_TEXT) : (size.cx + REBAR_POST_TEXT));
1687 textheight = (infoPtr->dwStyle & CCS_VERT) ? 0 : size.cy;
1688
1689 SelectObject (hdc, hOldFont);
1690 ReleaseDC (0, hdc);
1691 }
1692
1693 /* if no gripper but either image or text, then leave space */
1694 if ((lpBand->fStatus & (HAS_IMAGE | HAS_TEXT)) &&
1695 !(lpBand->fStatus & HAS_GRIPPER)) {
1697 }
1698
1699 /* check if user overrode the header value */
1700 if (!(lpBand->fStyle & RBBS_UNDOC_FIXEDHEADER))
1701 lpBand->cxHeader = header;
1702 lpBand->cyHeader = max(textheight, imageheight);
1703
1704 /* Now compute minimum size of child window */
1705 update_min_band_height(infoPtr, lpBand); /* update lpBand->cyMinBand from cyHeader and cyChild*/
1706
1707 lpBand->cxMinBand = lpBand->cxMinChild + lpBand->cxHeader + REBAR_POST_CHILD;
1708 if (lpBand->fStyle & RBBS_USECHEVRON && lpBand->cxMinChild < lpBand->cxIdeal)
1709 lpBand->cxMinBand += CHEVRON_WIDTH;
1710}
1711
1712static UINT
1714 /* Function: This routine copies the supplied values from */
1715 /* user input (lprbbi) to the internal band structure. */
1716 /* It returns the mask of what changed. */
1717{
1718 UINT uChanged = 0x0;
1719
1720 lpBand->fMask |= lprbbi->fMask;
1721
1722 if( (lprbbi->fMask & RBBIM_STYLE) &&
1723 (lpBand->fStyle != lprbbi->fStyle ) )
1724 {
1725 lpBand->fStyle = lprbbi->fStyle;
1726 uChanged |= RBBIM_STYLE;
1727 }
1728
1729 if( (lprbbi->fMask & RBBIM_COLORS) &&
1730 ( ( lpBand->clrFore != lprbbi->clrFore ) ||
1731 ( lpBand->clrBack != lprbbi->clrBack ) ) )
1732 {
1733 lpBand->clrFore = lprbbi->clrFore;
1734 lpBand->clrBack = lprbbi->clrBack;
1735 uChanged |= RBBIM_COLORS;
1736 }
1737
1738 if( (lprbbi->fMask & RBBIM_IMAGE) &&
1739 ( lpBand->iImage != lprbbi->iImage ) )
1740 {
1741 lpBand->iImage = lprbbi->iImage;
1742 uChanged |= RBBIM_IMAGE;
1743 }
1744
1745 if( (lprbbi->fMask & RBBIM_CHILD) &&
1746 (lprbbi->hwndChild != lpBand->hwndChild ) )
1747 {
1748 if (lprbbi->hwndChild) {
1749 lpBand->hwndChild = lprbbi->hwndChild;
1750 lpBand->hwndPrevParent =
1751 SetParent (lpBand->hwndChild, hwnd);
1752 /* below in trace from WinRAR */
1754 /* above in trace from WinRAR */
1755 }
1756 else {
1757 TRACE("child: %p prev parent: %p\n",
1758 lpBand->hwndChild, lpBand->hwndPrevParent);
1759 lpBand->hwndChild = 0;
1760 lpBand->hwndPrevParent = 0;
1761 }
1762 uChanged |= RBBIM_CHILD;
1763 }
1764
1765 if( (lprbbi->fMask & RBBIM_CHILDSIZE) &&
1766 ( (lpBand->cxMinChild != lprbbi->cxMinChild) ||
1767 (lpBand->cyMinChild != lprbbi->cyMinChild ) ||
1768 ( (lprbbi->cbSize >= REBARBANDINFOA_V6_SIZE && (lpBand->fStyle & RBBS_VARIABLEHEIGHT)) &&
1769 ( (lpBand->cyChild != lprbbi->cyChild ) ||
1770 (lpBand->cyMaxChild != lprbbi->cyMaxChild ) ||
1771 (lpBand->cyIntegral != lprbbi->cyIntegral ) ) ) ||
1772 ( (lprbbi->cbSize < REBARBANDINFOA_V6_SIZE) &&
1773 ( (lpBand->cyChild ||
1774 lpBand->cyMaxChild ||
1775 lpBand->cyIntegral ) ) ) ) )
1776 {
1777 lpBand->cxMinChild = lprbbi->cxMinChild;
1778 lpBand->cyMinChild = lprbbi->cyMinChild;
1779 /* These fields where added in WIN32_IE == 0x400 and are set only for RBBS_VARIABLEHEIGHT bands */
1780 if (lprbbi->cbSize >= REBARBANDINFOA_V6_SIZE && (lpBand->fStyle & RBBS_VARIABLEHEIGHT)) {
1781 lpBand->cyMaxChild = lprbbi->cyMaxChild;
1782 lpBand->cyIntegral = lprbbi->cyIntegral;
1783
1784 lpBand->cyChild = round_child_height(lpBand, lprbbi->cyChild); /* make (cyChild - cyMinChild) a multiple of cyIntergral */
1785 }
1786 else {
1787 lpBand->cyChild = lpBand->cyMinChild;
1788 lpBand->cyMaxChild = 0x7fffffff;
1789 lpBand->cyIntegral = 0;
1790 }
1791 uChanged |= RBBIM_CHILDSIZE;
1792 }
1793
1794 if( (lprbbi->fMask & RBBIM_SIZE) &&
1795 (lpBand->cx != lprbbi->cx ) )
1796 {
1797 lpBand->cx = lprbbi->cx;
1798 uChanged |= RBBIM_SIZE;
1799 }
1800
1801 if( (lprbbi->fMask & RBBIM_BACKGROUND) &&
1802 ( lpBand->hbmBack != lprbbi->hbmBack ) )
1803 {
1804 lpBand->hbmBack = lprbbi->hbmBack;
1805 uChanged |= RBBIM_BACKGROUND;
1806 }
1807
1808 if( (lprbbi->fMask & RBBIM_ID) &&
1809 (lpBand->wID != lprbbi->wID ) )
1810 {
1811 lpBand->wID = lprbbi->wID;
1812 uChanged |= RBBIM_ID;
1813 }
1814
1815 /* check for additional data */
1816 if (lprbbi->cbSize >= REBARBANDINFOA_V6_SIZE) {
1817 if( (lprbbi->fMask & RBBIM_IDEALSIZE) &&
1818 ( lpBand->cxIdeal != lprbbi->cxIdeal ) )
1819 {
1820 lpBand->cxIdeal = lprbbi->cxIdeal;
1821 uChanged |= RBBIM_IDEALSIZE;
1822 }
1823
1824 if( (lprbbi->fMask & RBBIM_LPARAM) &&
1825 (lpBand->lParam != lprbbi->lParam ) )
1826 {
1827 lpBand->lParam = lprbbi->lParam;
1828 uChanged |= RBBIM_LPARAM;
1829 }
1830
1831 if( (lprbbi->fMask & RBBIM_HEADERSIZE) &&
1832 (lpBand->cxHeader != lprbbi->cxHeader ) )
1833 {
1834 lpBand->cxHeader = lprbbi->cxHeader;
1835 lpBand->fStyle |= RBBS_UNDOC_FIXEDHEADER;
1836 uChanged |= RBBIM_HEADERSIZE;
1837 }
1838 }
1839
1840 return uChanged;
1841}
1842
1844 /* Function: This erases the background rectangle by drawing */
1845 /* each band with its background color (or the default) and */
1846 /* draws each bands right separator if necessary. The row */
1847 /* separators are drawn on the first band of the next row. */
1848{
1849 REBAR_BAND *lpBand;
1850 UINT i;
1851 INT oldrow;
1852 RECT cr;
1853 COLORREF old = CLR_NONE, new;
1854 HTHEME theme = GetWindowTheme (infoPtr->hwndSelf);
1855
1856 GetClientRect (infoPtr->hwndSelf, &cr);
1857
1858#ifdef __REACTOS__
1859 if (theme)
1860 {
1862 {
1863 DrawThemeParentBackground (infoPtr->hwndSelf, hdc, &cr);
1864 }
1865 DrawThemeBackground (theme, hdc, 0, 0, &cr, NULL);
1866 }
1867#endif
1868
1869 oldrow = -1;
1870 for(i=0; i<infoPtr->uNumBands; i++) {
1871 RECT rcBand;
1872 lpBand = REBAR_GetBand(infoPtr, i);
1873 if (HIDDENBAND(lpBand)) continue;
1874 translate_rect(infoPtr, &rcBand, &lpBand->rcBand);
1875
1876 /* draw band separator between rows */
1877 if (lpBand->iRow != oldrow) {
1878 oldrow = lpBand->iRow;
1879 if (infoPtr->dwStyle & RBS_BANDBORDERS) {
1880 RECT rcRowSep;
1881 rcRowSep = rcBand;
1882 if (infoPtr->dwStyle & CCS_VERT) {
1883 rcRowSep.right += SEP_WIDTH_SIZE;
1884 rcRowSep.bottom = infoPtr->calcSize.cx;
1885 if (theme)
1886 DrawThemeEdge (theme, hdc, RP_BAND, 0, &rcRowSep, EDGE_ETCHED, BF_RIGHT, NULL);
1887 else
1888 DrawEdge (hdc, &rcRowSep, EDGE_ETCHED, BF_RIGHT);
1889 }
1890 else {
1891 rcRowSep.bottom += SEP_WIDTH_SIZE;
1892 rcRowSep.right = infoPtr->calcSize.cx;
1893 if (theme)
1894 DrawThemeEdge (theme, hdc, RP_BAND, 0, &rcRowSep, EDGE_ETCHED, BF_BOTTOM, NULL);
1895 else
1896 DrawEdge (hdc, &rcRowSep, EDGE_ETCHED, BF_BOTTOM);
1897 }
1898 TRACE ("drawing band separator bottom (%s)\n",
1899 wine_dbgstr_rect(&rcRowSep));
1900 }
1901 }
1902
1903 /* draw band separator between bands in a row */
1904 if (infoPtr->dwStyle & RBS_BANDBORDERS && lpBand->rcBand.left > 0) {
1905 RECT rcSep;
1906 rcSep = rcBand;
1907 if (infoPtr->dwStyle & CCS_VERT) {
1908 rcSep.bottom = rcSep.top;
1909 rcSep.top -= SEP_WIDTH_SIZE;
1910 if (theme)
1911 DrawThemeEdge (theme, hdc, RP_BAND, 0, &rcSep, EDGE_ETCHED, BF_BOTTOM, NULL);
1912 else
1913 DrawEdge (hdc, &rcSep, EDGE_ETCHED, BF_BOTTOM);
1914 }
1915 else {
1916 rcSep.right = rcSep.left;
1917 rcSep.left -= SEP_WIDTH_SIZE;
1918 if (theme)
1919 DrawThemeEdge (theme, hdc, RP_BAND, 0, &rcSep, EDGE_ETCHED, BF_RIGHT, NULL);
1920 else
1921 DrawEdge (hdc, &rcSep, EDGE_ETCHED, BF_RIGHT);
1922 }
1923 TRACE("drawing band separator right (%s)\n",
1924 wine_dbgstr_rect(&rcSep));
1925 }
1926
1927 /* draw the actual background */
1928 if (lpBand->clrBack != CLR_NONE) {
1929 new = (lpBand->clrBack == CLR_DEFAULT) ? infoPtr->clrBtnFace :
1930 lpBand->clrBack;
1931#if GLATESTING
1932 /* testing only - make background green to see it */
1933 new = RGB(0,128,0);
1934#endif
1935 }
1936 else {
1937 /* In the absence of documentation for Rebar vs. CLR_NONE,
1938 * we will use the default BtnFace color. Note documentation
1939 * exists for Listview and Imagelist.
1940 */
1941 new = infoPtr->clrBtnFace;
1942#if GLATESTING
1943 /* testing only - make background green to see it */
1944 new = RGB(0,128,0);
1945#endif
1946 }
1947
1948 if (theme)
1949 {
1950 /* When themed, the background color is ignored (but not a
1951 * background bitmap */
1952 DrawThemeBackground (theme, hdc, 0, 0, &cr, &rcBand);
1953 }
1954 else
1955 {
1956 old = SetBkColor (hdc, new);
1957 TRACE("%s background color=0x%06x, band %s\n",
1958 (lpBand->clrBack == CLR_NONE) ? "none" :
1959 ((lpBand->clrBack == CLR_DEFAULT) ? "dft" : ""),
1960 GetBkColor(hdc), wine_dbgstr_rect(&rcBand));
1961 ExtTextOutW (hdc, 0, 0, ETO_OPAQUE, &rcBand, NULL, 0, 0);
1962 if (lpBand->clrBack != CLR_NONE)
1963 SetBkColor (hdc, old);
1964 }
1965 }
1966 return TRUE;
1967}
1968
1969static void
1970REBAR_InternalHitTest (const REBAR_INFO *infoPtr, const POINT *lpPt, UINT *pFlags, INT *pBand)
1971{
1972 REBAR_BAND *lpBand;
1973 RECT rect;
1974 UINT iCount;
1975
1976 GetClientRect (infoPtr->hwndSelf, &rect);
1977
1978 *pFlags = RBHT_NOWHERE;
1979 if (PtInRect (&rect, *lpPt))
1980 {
1981 if (infoPtr->uNumBands == 0) {
1982 *pFlags = RBHT_NOWHERE;
1983 if (pBand)
1984 *pBand = -1;
1985 TRACE("NOWHERE\n");
1986 return;
1987 }
1988 else {
1989 /* somewhere inside */
1990 for (iCount = 0; iCount < infoPtr->uNumBands; iCount++) {
1991 RECT rcBand;
1992 lpBand = REBAR_GetBand(infoPtr, iCount);
1993 translate_rect(infoPtr, &rcBand, &lpBand->rcBand);
1994 if (HIDDENBAND(lpBand)) continue;
1995 if (PtInRect (&rcBand, *lpPt)) {
1996 if (pBand)
1997 *pBand = iCount;
1998 if (PtInRect (&lpBand->rcGripper, *lpPt)) {
1999 *pFlags = RBHT_GRABBER;
2000 TRACE("ON GRABBER %d\n", iCount);
2001 return;
2002 }
2003 else if (PtInRect (&lpBand->rcCapImage, *lpPt)) {
2004 *pFlags = RBHT_CAPTION;
2005 TRACE("ON CAPTION %d\n", iCount);
2006 return;
2007 }
2008 else if (PtInRect (&lpBand->rcCapText, *lpPt)) {
2009 *pFlags = RBHT_CAPTION;
2010 TRACE("ON CAPTION %d\n", iCount);
2011 return;
2012 }
2013 else if (PtInRect (&lpBand->rcChild, *lpPt)) {
2014 *pFlags = RBHT_CLIENT;
2015 TRACE("ON CLIENT %d\n", iCount);
2016 return;
2017 }
2018 else if (PtInRect (&lpBand->rcChevron, *lpPt)) {
2019 *pFlags = RBHT_CHEVRON;
2020 TRACE("ON CHEVRON %d\n", iCount);
2021 return;
2022 }
2023 else {
2024 *pFlags = RBHT_NOWHERE;
2025 TRACE("NOWHERE %d\n", iCount);
2026 return;
2027 }
2028 }
2029 }
2030
2031 *pFlags = RBHT_NOWHERE;
2032 if (pBand)
2033 *pBand = -1;
2034
2035 TRACE("NOWHERE\n");
2036 return;
2037 }
2038 }
2039 else {
2040 *pFlags = RBHT_NOWHERE;
2041 if (pBand)
2042 *pBand = -1;
2043 TRACE("NOWHERE\n");
2044 return;
2045 }
2046}
2047
2048static void
2049REBAR_HandleLRDrag (REBAR_INFO *infoPtr, const POINT *ptsmove)
2050 /* Function: This will implement the functionality of a */
2051 /* Gripper drag within a row. It will not implement "out- */
2052 /* of-row" drags. (They are detected and handled in */
2053 /* REBAR_MouseMove.) */
2054{
2055 REBAR_BAND *hitBand;
2056 INT iHitBand, iRowBegin, iRowEnd;
2057 INT movement, xBand, cxLeft = 0;
2058 BOOL shrunkBands = FALSE;
2059
2060 iHitBand = infoPtr->iGrabbedBand;
2061 iRowBegin = get_row_begin_for_band(infoPtr, iHitBand);
2062 iRowEnd = get_row_end_for_band(infoPtr, iHitBand);
2063 hitBand = REBAR_GetBand(infoPtr, iHitBand);
2064
2065 xBand = hitBand->rcBand.left;
2066 movement = (infoPtr->dwStyle&CCS_VERT ? ptsmove->y : ptsmove->x)
2067 - (xBand + REBAR_PRE_GRIPPER - infoPtr->ihitoffset);
2068
2069 /* Dragging the first band in a row cannot cause shrinking */
2070 if(iHitBand != iRowBegin)
2071 {
2072 if (movement < 0) {
2073 cxLeft = REBAR_ShrinkBandsRTL(infoPtr, iRowBegin, iHitBand, -movement, TRUE);
2074
2075 if(cxLeft < -movement)
2076 {
2077 hitBand->cxEffective += -movement - cxLeft;
2078 hitBand->cx = hitBand->cxEffective;
2079 shrunkBands = TRUE;
2080 }
2081
2082 } else if (movement > 0) {
2083
2084 cxLeft = movement;
2085 if (prev_visible(infoPtr, iHitBand) >= 0)
2086 cxLeft = REBAR_ShrinkBandsLTR(infoPtr, iHitBand, iRowEnd, movement, TRUE);
2087
2088 if(cxLeft < movement)
2089 {
2090 REBAR_BAND *lpPrev = REBAR_GetBand(infoPtr, prev_visible(infoPtr, iHitBand));
2091 lpPrev->cxEffective += movement - cxLeft;
2092 lpPrev->cx = hitBand->cxEffective;
2093 shrunkBands = TRUE;
2094 }
2095
2096 }
2097 }
2098
2099 if(!shrunkBands)
2100 {
2101 /* It was not possible to move the band by shrinking bands.
2102 * Try relocating the band instead. */
2103 REBAR_MoveBandToRowOffset(infoPtr, iHitBand, iRowBegin,
2104 iRowEnd, xBand + movement, TRUE);
2105 }
2106
2107 REBAR_SetRowRectsX(infoPtr, iRowBegin, iRowEnd);
2108 if (infoPtr->dwStyle & CCS_VERT)
2109 REBAR_CalcVertBand(infoPtr, 0, infoPtr->uNumBands);
2110 else
2111 REBAR_CalcHorzBand(infoPtr, 0, infoPtr->uNumBands);
2112 REBAR_MoveChildWindows(infoPtr, iRowBegin, iRowEnd);
2113}
2114
2115static void
2116REBAR_HandleUDDrag (REBAR_INFO *infoPtr, const POINT *ptsmove)
2117{
2118 INT yOff = (infoPtr->dwStyle & CCS_VERT) ? ptsmove->x : ptsmove->y;
2119 INT iHitBand, iRowBegin, iNextRowBegin;
2120 REBAR_BAND *hitBand, *rowBeginBand;
2121
2122 if(infoPtr->uNumBands <= 0)
2123 ERR("There are no bands in this rebar\n");
2124
2125 /* Up/down dragging can only occur when there is more than one
2126 * band in the rebar */
2127 if(infoPtr->uNumBands <= 1)
2128 return;
2129
2130 iHitBand = infoPtr->iGrabbedBand;
2131 hitBand = REBAR_GetBand(infoPtr, iHitBand);
2132
2133 /* If we're taking a band that has the RBBS_BREAK style set, this
2134 * style needs to be reapplied to the band that is going to become
2135 * the new start of the row. */
2136 if((hitBand->fStyle & RBBS_BREAK) &&
2137 (iHitBand < infoPtr->uNumBands - 1))
2138 REBAR_GetBand(infoPtr, iHitBand + 1)->fStyle |= RBBS_BREAK;
2139
2140 if(yOff < 0)
2141 {
2142 /* Place the band above the current top row */
2143 if(iHitBand==0 && (infoPtr->uNumBands==1 || REBAR_GetBand(infoPtr, 1)->fStyle&RBBS_BREAK))
2144 return;
2145 DPA_DeletePtr(infoPtr->bands, iHitBand);
2146 hitBand->fStyle &= ~RBBS_BREAK;
2147 REBAR_GetBand(infoPtr, 0)->fStyle |= RBBS_BREAK;
2148 infoPtr->iGrabbedBand = DPA_InsertPtr(
2149 infoPtr->bands, 0, hitBand);
2150 }
2151 else if(yOff > REBAR_GetBand(infoPtr, infoPtr->uNumBands - 1)->rcBand.bottom)
2152 {
2153 /* Place the band below the current bottom row */
2154 if(iHitBand == infoPtr->uNumBands-1 && hitBand->fStyle&RBBS_BREAK)
2155 return;
2156 DPA_DeletePtr(infoPtr->bands, iHitBand);
2157 hitBand->fStyle |= RBBS_BREAK;
2158 infoPtr->iGrabbedBand = DPA_InsertPtr(
2159 infoPtr->bands, infoPtr->uNumBands - 1, hitBand);
2160 }
2161 else
2162 {
2163 /* Place the band in the preexisting row the mouse is hovering over */
2164 iRowBegin = first_visible(infoPtr);
2165 while(iRowBegin < infoPtr->uNumBands)
2166 {
2167 iNextRowBegin = get_row_end_for_band(infoPtr, iRowBegin);
2168 rowBeginBand = REBAR_GetBand(infoPtr, iRowBegin);
2169 if(rowBeginBand->rcBand.bottom > yOff)
2170 {
2172 infoPtr, iHitBand, iRowBegin, iNextRowBegin,
2173 ((infoPtr->dwStyle & CCS_VERT) ? ptsmove->y : ptsmove->x)
2174 - REBAR_PRE_GRIPPER - infoPtr->ihitoffset, FALSE);
2175 break;
2176 }
2177
2178 iRowBegin = iNextRowBegin;
2179 }
2180 }
2181
2182 REBAR_Layout(infoPtr);
2183}
2184
2185
2186/* << REBAR_BeginDrag >> */
2187
2188
2189static LRESULT
2191{
2192 UINT uBand = (UINT)wParam;
2193 REBAR_BAND *lpBand;
2194
2195 if (uBand >= infoPtr->uNumBands)
2196 return FALSE;
2197
2198 TRACE("deleting band %u!\n", uBand);
2199 lpBand = REBAR_GetBand(infoPtr, uBand);
2200 REBAR_Notify_NMREBAR (infoPtr, uBand, RBN_DELETINGBAND);
2201 /* TODO: a return of 1 should probably cancel the deletion */
2202
2203 if (lpBand->hwndChild)
2204 ShowWindow(lpBand->hwndChild, SW_HIDE);
2205 Free(lpBand->lpText);
2206 Free(lpBand);
2207
2208 infoPtr->uNumBands--;
2209 DPA_DeletePtr(infoPtr->bands, uBand);
2210
2212
2213 /* if only 1 band left the re-validate to possible eliminate gripper */
2214 if (infoPtr->uNumBands == 1)
2215 REBAR_ValidateBand (infoPtr, REBAR_GetBand(infoPtr, 0));
2216
2217 REBAR_Layout(infoPtr);
2218
2219 return TRUE;
2220}
2221
2222
2223/* << REBAR_DragMove >> */
2224/* << REBAR_EndDrag >> */
2225
2226
2227static LRESULT
2228REBAR_GetBandBorders (const REBAR_INFO *infoPtr, UINT uBand, RECT *lpRect)
2229{
2230 REBAR_BAND *lpBand;
2231
2232 if (!lpRect)
2233 return 0;
2234 if (uBand >= infoPtr->uNumBands)
2235 return 0;
2236
2237 lpBand = REBAR_GetBand(infoPtr, uBand);
2238
2239 /* FIXME - the following values were determined by experimentation */
2240 /* with the REBAR Control Spy. I have guesses as to what the 4 and */
2241 /* 1 are, but I am not sure. There doesn't seem to be any actual */
2242 /* difference in size of the control area with and without the */
2243 /* style. - GA */
2244 if (infoPtr->dwStyle & RBS_BANDBORDERS) {
2245 if (infoPtr->dwStyle & CCS_VERT) {
2246 lpRect->left = 1;
2247 lpRect->top = lpBand->cxHeader + 4;
2248 lpRect->right = 1;
2249 lpRect->bottom = 0;
2250 }
2251 else {
2252 lpRect->left = lpBand->cxHeader + 4;
2253 lpRect->top = 1;
2254 lpRect->right = 0;
2255 lpRect->bottom = 1;
2256 }
2257 }
2258 else {
2259 lpRect->left = lpBand->cxHeader;
2260 }
2261 return 0;
2262}
2263
2264
2265static inline LRESULT
2267{
2268 TRACE("band count %u!\n", infoPtr->uNumBands);
2269
2270 return infoPtr->uNumBands;
2271}
2272
2273
2274static LRESULT
2275REBAR_GetBandInfoT(const REBAR_INFO *infoPtr, UINT uIndex, LPREBARBANDINFOW lprbbi, BOOL bUnicode)
2276{
2277 REBAR_BAND *lpBand;
2278
2279 if (!lprbbi || lprbbi->cbSize < REBARBANDINFOA_V3_SIZE)
2280 return FALSE;
2281
2282 if (uIndex >= infoPtr->uNumBands)
2283 return FALSE;
2284
2285 TRACE("index %u (bUnicode=%d)\n", uIndex, bUnicode);
2286
2287 /* copy band information */
2288 lpBand = REBAR_GetBand(infoPtr, uIndex);
2289
2290 if (lprbbi->fMask & RBBIM_STYLE)
2291 lprbbi->fStyle = lpBand->fStyle;
2292
2293 if (lprbbi->fMask & RBBIM_COLORS) {
2294 lprbbi->clrFore = lpBand->clrFore;
2295 lprbbi->clrBack = lpBand->clrBack;
2296 if (lprbbi->clrBack == CLR_DEFAULT)
2297 lprbbi->clrBack = infoPtr->clrBtnFace;
2298 }
2299
2300 if (lprbbi->fMask & RBBIM_TEXT) {
2301 if (bUnicode)
2302 Str_GetPtrW(lpBand->lpText, lprbbi->lpText, lprbbi->cch);
2303 else
2304 Str_GetPtrWtoA(lpBand->lpText, (LPSTR)lprbbi->lpText, lprbbi->cch);
2305 }
2306
2307 if (lprbbi->fMask & RBBIM_IMAGE)
2308 lprbbi->iImage = lpBand->iImage;
2309
2310 if (lprbbi->fMask & RBBIM_CHILD)
2311 lprbbi->hwndChild = lpBand->hwndChild;
2312
2313 if (lprbbi->fMask & RBBIM_CHILDSIZE) {
2314 lprbbi->cxMinChild = lpBand->cxMinChild;
2315 lprbbi->cyMinChild = lpBand->cyMinChild;
2316 /* to make tests pass we follow Windows' behaviour and allow reading these fields only
2317 * for RBBS_VARIABLEHEIGHTS bands */
2318 if (lprbbi->cbSize >= REBARBANDINFOW_V6_SIZE && (lpBand->fStyle & RBBS_VARIABLEHEIGHT)) {
2319 lprbbi->cyChild = lpBand->cyChild;
2320 lprbbi->cyMaxChild = lpBand->cyMaxChild;
2321 lprbbi->cyIntegral = lpBand->cyIntegral;
2322 }
2323 }
2324
2325 if (lprbbi->fMask & RBBIM_SIZE)
2326 lprbbi->cx = lpBand->cx;
2327
2328 if (lprbbi->fMask & RBBIM_BACKGROUND)
2329 lprbbi->hbmBack = lpBand->hbmBack;
2330
2331 if (lprbbi->fMask & RBBIM_ID)
2332 lprbbi->wID = lpBand->wID;
2333
2334 /* check for additional data */
2335 if (lprbbi->cbSize >= REBARBANDINFOW_V6_SIZE) {
2336 if (lprbbi->fMask & RBBIM_IDEALSIZE)
2337 lprbbi->cxIdeal = lpBand->cxIdeal;
2338
2339 if (lprbbi->fMask & RBBIM_LPARAM)
2340 lprbbi->lParam = lpBand->lParam;
2341
2342 if (lprbbi->fMask & RBBIM_HEADERSIZE)
2343 lprbbi->cxHeader = lpBand->cxHeader;
2344 }
2345
2346 REBAR_DumpBandInfo(lprbbi);
2347
2348 return TRUE;
2349}
2350
2351
2352static LRESULT
2354{
2355 INT nHeight;
2356
2357 nHeight = infoPtr->calcSize.cy;
2358
2359 TRACE("height = %d\n", nHeight);
2360
2361 return nHeight;
2362}
2363
2364
2365static LRESULT
2367{
2368 if (!lpInfo || lpInfo->cbSize < sizeof (REBARINFO))
2369 return FALSE;
2370
2371 TRACE("getting bar info!\n");
2372
2373 if (infoPtr->himl) {
2374 lpInfo->himl = infoPtr->himl;
2375 lpInfo->fMask |= RBIM_IMAGELIST;
2376 }
2377
2378 return TRUE;
2379}
2380
2381
2382static inline LRESULT
2384{
2385 COLORREF clr = infoPtr->clrBk;
2386
2387 if (clr == CLR_DEFAULT)
2388 clr = infoPtr->clrBtnFace;
2389
2390 TRACE("background color 0x%06x!\n", clr);
2391
2392 return clr;
2393}
2394
2395
2396/* << REBAR_GetColorScheme >> */
2397/* << REBAR_GetDropTarget >> */
2398
2399
2400static LRESULT
2402{
2403 FIXME("empty stub!\n");
2404
2405 return 0;
2406}
2407
2408
2409static LRESULT
2410REBAR_GetRect (const REBAR_INFO *infoPtr, INT iBand, RECT *lprc)
2411{
2412 REBAR_BAND *lpBand;
2413
2414 if (iBand < 0 || iBand >= infoPtr->uNumBands)
2415 return FALSE;
2416 if (!lprc)
2417 return FALSE;
2418
2419 lpBand = REBAR_GetBand(infoPtr, iBand);
2420 /* For CCS_VERT the coordinates will be swapped - like on Windows */
2421 *lprc = lpBand->rcBand;
2422
2423 TRACE("band %d, (%s)\n", iBand, wine_dbgstr_rect(lprc));
2424
2425 return TRUE;
2426}
2427
2428
2429static inline LRESULT
2431{
2432 TRACE("%u\n", infoPtr->uNumRows);
2433
2434 return infoPtr->uNumRows;
2435}
2436
2437
2438static LRESULT
2439REBAR_GetRowHeight (const REBAR_INFO *infoPtr, INT iRow)
2440{
2441 int j = 0, ret = 0;
2442 UINT i;
2443 REBAR_BAND *lpBand;
2444
2445 for (i=0; i<infoPtr->uNumBands; i++) {
2446 lpBand = REBAR_GetBand(infoPtr, i);
2447 if (HIDDENBAND(lpBand)) continue;
2448 if (lpBand->iRow != iRow) continue;
2449 j = lpBand->rcBand.bottom - lpBand->rcBand.top;
2450 if (j > ret) ret = j;
2451 }
2452
2453 TRACE("row %d, height %d\n", iRow, ret);
2454
2455 return ret;
2456}
2457
2458
2459static inline LRESULT
2461{
2462 TRACE("text color 0x%06x!\n", infoPtr->clrText);
2463
2464 return infoPtr->clrText;
2465}
2466
2467
2468static inline LRESULT
2470{
2471 return (LRESULT)infoPtr->hwndToolTip;
2472}
2473
2474
2475static inline LRESULT
2477{
2478 TRACE("%s hwnd=%p\n",
2479 infoPtr->bUnicode ? "TRUE" : "FALSE", infoPtr->hwndSelf);
2480
2481 return infoPtr->bUnicode;
2482}
2483
2484
2485static inline LRESULT
2487{
2488 TRACE("version %d\n", infoPtr->iVersion);
2489 return infoPtr->iVersion;
2490}
2491
2492
2493static LRESULT
2495{
2496 if (!lprbht)
2497 return -1;
2498
2499 REBAR_InternalHitTest (infoPtr, &lprbht->pt, &lprbht->flags, &lprbht->iBand);
2500
2501 return lprbht->iBand;
2502}
2503
2504
2505static LRESULT
2506REBAR_IdToIndex (const REBAR_INFO *infoPtr, UINT uId)
2507{
2508 UINT i;
2509
2510 if (infoPtr->uNumBands < 1)
2511 return -1;
2512
2513 for (i = 0; i < infoPtr->uNumBands; i++) {
2514 if (REBAR_GetBand(infoPtr, i)->wID == uId) {
2515 TRACE("id %u is band %u found!\n", uId, i);
2516 return i;
2517 }
2518 }
2519
2520 TRACE("id %u is not found\n", uId);
2521 return -1;
2522}
2523
2524
2525static LRESULT
2526REBAR_InsertBandT(REBAR_INFO *infoPtr, INT iIndex, const REBARBANDINFOW *lprbbi, BOOL bUnicode)
2527{
2528 REBAR_BAND *lpBand;
2529
2530 if (!lprbbi || lprbbi->cbSize < REBARBANDINFOA_V3_SIZE)
2531 return FALSE;
2532
2533 /* trace the index as signed to see the -1 */
2534 TRACE("insert band at %d (bUnicode=%d)!\n", iIndex, bUnicode);
2535 REBAR_DumpBandInfo(lprbbi);
2536
2537 if (!(lpBand = Alloc(sizeof(REBAR_BAND)))) return FALSE;
2538 if ((iIndex == -1) || (iIndex > infoPtr->uNumBands))
2539 iIndex = infoPtr->uNumBands;
2540 if (DPA_InsertPtr(infoPtr->bands, iIndex, lpBand) == -1)
2541 {
2542 Free(lpBand);
2543 return FALSE;
2544 }
2545 infoPtr->uNumBands++;
2546
2547 TRACE("index %d!\n", iIndex);
2548
2549 /* initialize band */
2550 memset(lpBand, 0, sizeof(*lpBand));
2551#ifdef __REACTOS__
2552 lpBand->clrFore = infoPtr->clrText == CLR_NONE ? CLR_DEFAULT : infoPtr->clrText;
2553 lpBand->clrBack = infoPtr->clrBk == CLR_NONE ? CLR_DEFAULT : infoPtr->clrBk;
2554#else
2555 lpBand->clrFore = infoPtr->clrText == CLR_NONE ? infoPtr->clrBtnText :
2556 infoPtr->clrText;
2557 lpBand->clrBack = infoPtr->clrBk == CLR_NONE ? infoPtr->clrBtnFace :
2558 infoPtr->clrBk;
2559#endif
2560 lpBand->iImage = -1;
2561
2562 REBAR_CommonSetupBand(infoPtr->hwndSelf, lprbbi, lpBand);
2563
2564 /* Make sure the defaults for these are correct */
2565 if (lprbbi->cbSize < REBARBANDINFOA_V6_SIZE || !(lpBand->fStyle & RBBS_VARIABLEHEIGHT)) {
2566 lpBand->cyChild = lpBand->cyMinChild;
2567 lpBand->cyMaxChild = 0x7fffffff;
2568 lpBand->cyIntegral = 0;
2569 }
2570
2571 if ((lprbbi->fMask & RBBIM_TEXT) && (lprbbi->lpText)) {
2572 if (bUnicode)
2573 Str_SetPtrW(&lpBand->lpText, lprbbi->lpText);
2574 else
2575 Str_SetPtrAtoW(&lpBand->lpText, (LPSTR)lprbbi->lpText);
2576 }
2577
2578 REBAR_ValidateBand (infoPtr, lpBand);
2579 /* On insert of second band, revalidate band 1 to possible add gripper */
2580 if (infoPtr->uNumBands == 2)
2581 REBAR_ValidateBand (infoPtr, REBAR_GetBand(infoPtr, 0));
2582
2583 REBAR_DumpBand (infoPtr);
2584
2585 REBAR_Layout(infoPtr);
2586 InvalidateRect(infoPtr->hwndSelf, NULL, TRUE);
2587
2588 return TRUE;
2589}
2590
2591
2592static LRESULT
2594{
2595 REBAR_BAND *lpBand;
2596 int iRowBegin, iRowEnd;
2597 int cxDesired, extra, extraOrig;
2598 int cxIdealBand;
2599
2600 /* Validate */
2601 if (infoPtr->uNumBands == 0 || iBand < 0 || iBand >= infoPtr->uNumBands) {
2602 /* error !!! */
2603 ERR("Illegal MaximizeBand, requested=%d, current band count=%d\n",
2604 iBand, infoPtr->uNumBands);
2605 return FALSE;
2606 }
2607
2608 lpBand = REBAR_GetBand(infoPtr, iBand);
2609
2610 if (lpBand->fStyle & RBBS_HIDDEN)
2611 {
2612 /* Windows is buggy and creates a hole */
2613 WARN("Ignoring maximize request on a hidden band (%d)\n", iBand);
2614 return FALSE;
2615 }
2616
2617 cxIdealBand = lpBand->cxIdeal + lpBand->cxHeader + REBAR_POST_CHILD;
2618 if (lParam && (lpBand->cxEffective < cxIdealBand))
2619 cxDesired = cxIdealBand;
2620 else
2621 cxDesired = infoPtr->calcSize.cx;
2622
2623 iRowBegin = get_row_begin_for_band(infoPtr, iBand);
2624 iRowEnd = get_row_end_for_band(infoPtr, iBand);
2625 extraOrig = extra = cxDesired - lpBand->cxEffective;
2626 if (extra > 0)
2627 extra = REBAR_ShrinkBandsRTL(infoPtr, iRowBegin, iBand, extra, TRUE);
2628 if (extra > 0)
2629 extra = REBAR_ShrinkBandsLTR(infoPtr, next_visible(infoPtr, iBand), iRowEnd, extra, TRUE);
2630 lpBand->cxEffective += extraOrig - extra;
2631 lpBand->cx = lpBand->cxEffective;
2632 TRACE("(%d, %ld): Wanted size %d, obtained %d (shrink %d, %d)\n", iBand, lParam, cxDesired, lpBand->cx, extraOrig, extra);
2633 REBAR_SetRowRectsX(infoPtr, iRowBegin, iRowEnd);
2634
2635 if (infoPtr->dwStyle & CCS_VERT)
2636 REBAR_CalcVertBand(infoPtr, iRowBegin, iRowEnd);
2637 else
2638 REBAR_CalcHorzBand(infoPtr, iRowBegin, iRowEnd);
2639 REBAR_MoveChildWindows(infoPtr, iRowBegin, iRowEnd);
2640 return TRUE;
2641
2642}
2643
2644
2645static LRESULT
2646REBAR_MinimizeBand (const REBAR_INFO *infoPtr, INT iBand)
2647{
2648 REBAR_BAND *lpBand;
2649 int iPrev, iRowBegin, iRowEnd;
2650
2651 /* A "minimize" band is equivalent to "dragging" the gripper
2652 * of than band to the right till the band is only the size
2653 * of the cxHeader.
2654 */
2655
2656 /* Validate */
2657 if (infoPtr->uNumBands == 0 || iBand < 0 || iBand >= infoPtr->uNumBands) {
2658 /* error !!! */
2659 ERR("Illegal MinimizeBand, requested=%d, current band count=%d\n",
2660 iBand, infoPtr->uNumBands);
2661 return FALSE;
2662 }
2663
2664 /* compute amount of movement and validate */
2665 lpBand = REBAR_GetBand(infoPtr, iBand);
2666
2667 if (lpBand->fStyle & RBBS_HIDDEN)
2668 {
2669 /* Windows is buggy and creates a hole/overlap */
2670 WARN("Ignoring minimize request on a hidden band (%d)\n", iBand);
2671 return FALSE;
2672 }
2673
2674 iPrev = prev_visible(infoPtr, iBand);
2675 /* if first band in row */
2676 if (iPrev < 0 || REBAR_GetBand(infoPtr, iPrev)->iRow != lpBand->iRow) {
2677 int iNext = next_visible(infoPtr, iBand);
2678 if (iNext < infoPtr->uNumBands && REBAR_GetBand(infoPtr, iNext)->iRow == lpBand->iRow) {
2679 TRACE("(%d): Minimizing the first band in row is by maximizing the second\n", iBand);
2680 REBAR_MaximizeBand(infoPtr, iNext, FALSE);
2681 }
2682 else
2683 TRACE("(%d): Only one band in row - nothing to do\n", iBand);
2684 return TRUE;
2685 }
2686
2687 REBAR_GetBand(infoPtr, iPrev)->cxEffective += lpBand->cxEffective - lpBand->cxMinBand;
2688 REBAR_GetBand(infoPtr, iPrev)->cx = REBAR_GetBand(infoPtr, iPrev)->cxEffective;
2689 lpBand->cx = lpBand->cxEffective = lpBand->cxMinBand;
2690
2691 iRowBegin = get_row_begin_for_band(infoPtr, iBand);
2692 iRowEnd = get_row_end_for_band(infoPtr, iBand);
2693 REBAR_SetRowRectsX(infoPtr, iRowBegin, iRowEnd);
2694
2695 if (infoPtr->dwStyle & CCS_VERT)
2696 REBAR_CalcVertBand(infoPtr, iRowBegin, iRowEnd);
2697 else
2698 REBAR_CalcHorzBand(infoPtr, iRowBegin, iRowEnd);
2699 REBAR_MoveChildWindows(infoPtr, iRowBegin, iRowEnd);
2700 return FALSE;
2701}
2702
2703
2704static LRESULT
2705REBAR_MoveBand (REBAR_INFO *infoPtr, INT iFrom, INT iTo)
2706{
2707 REBAR_BAND *lpBand;
2708
2709 /* Validate */
2710 if ((infoPtr->uNumBands == 0) ||
2711 (iFrom < 0) || iFrom >= infoPtr->uNumBands ||
2712 (iTo < 0) || iTo >= infoPtr->uNumBands) {
2713 /* error !!! */
2714 ERR("Illegal MoveBand, from=%d, to=%d, current band count=%d\n",
2715 iFrom, iTo, infoPtr->uNumBands);
2716 return FALSE;
2717 }
2718
2719 lpBand = REBAR_GetBand(infoPtr, iFrom);
2720 DPA_DeletePtr(infoPtr->bands, iFrom);
2721 DPA_InsertPtr(infoPtr->bands, iTo, lpBand);
2722
2723 TRACE("moved band %d to index %d\n", iFrom, iTo);
2724 REBAR_DumpBand (infoPtr);
2725
2726 /* **************************************************** */
2727 /* */
2728 /* We do not do a REBAR_Layout here because the native */
2729 /* control does not do that. The actual layout and */
2730 /* repaint is done by the *next* real action, ex.: */
2731 /* RB_INSERTBAND, RB_DELETEBAND, RB_SIZETORECT, etc. */
2732 /* */
2733 /* **************************************************** */
2734
2735 return TRUE;
2736}
2737
2738
2739/* return TRUE if two strings are different */
2740static BOOL
2742{
2743 return ( (a && !b) || (b && !a) || (a && b && lstrcmpW(a, b) ) );
2744}
2745
2746static LRESULT
2747REBAR_SetBandInfoT(REBAR_INFO *infoPtr, INT iBand, const REBARBANDINFOW *lprbbi, BOOL bUnicode)
2748{
2749 REBAR_BAND *lpBand;
2750 UINT uChanged;
2751
2752 if (!lprbbi || lprbbi->cbSize < REBARBANDINFOA_V3_SIZE)
2753 return FALSE;
2754
2755 if (iBand >= infoPtr->uNumBands)
2756 return FALSE;
2757
2758 TRACE("index %d\n", iBand);
2759 REBAR_DumpBandInfo (lprbbi);
2760
2761 /* set band information */
2762 lpBand = REBAR_GetBand(infoPtr, iBand);
2763
2764 uChanged = REBAR_CommonSetupBand (infoPtr->hwndSelf, lprbbi, lpBand);
2765 if (lprbbi->fMask & RBBIM_TEXT) {
2766 LPWSTR wstr = NULL;
2767 if (bUnicode)
2768 Str_SetPtrW(&wstr, lprbbi->lpText);
2769 else
2770 Str_SetPtrAtoW(&wstr, (LPSTR)lprbbi->lpText);
2771
2772 if (REBAR_strdifW(wstr, lpBand->lpText)) {
2773 Free(lpBand->lpText);
2774 lpBand->lpText = wstr;
2775 uChanged |= RBBIM_TEXT;
2776 }
2777 else
2778 Free(wstr);
2779 }
2780
2781 REBAR_ValidateBand (infoPtr, lpBand);
2782
2783 REBAR_DumpBand (infoPtr);
2784
2785 if (uChanged & (RBBIM_CHILDSIZE | RBBIM_SIZE | RBBIM_STYLE | RBBIM_IMAGE)) {
2786 REBAR_Layout(infoPtr);
2787 InvalidateRect(infoPtr->hwndSelf, NULL, TRUE);
2788 }
2789
2790 return TRUE;
2791}
2792
2793
2794static LRESULT
2795REBAR_SetBarInfo (REBAR_INFO *infoPtr, const REBARINFO *lpInfo)
2796{
2797 REBAR_BAND *lpBand;
2798 UINT i;
2799
2800 if (!lpInfo || lpInfo->cbSize < sizeof (REBARINFO))
2801 return FALSE;
2802
2803 TRACE("setting bar info!\n");
2804
2805 if (lpInfo->fMask & RBIM_IMAGELIST) {
2806 infoPtr->himl = lpInfo->himl;
2807 if (infoPtr->himl) {
2808 INT cx, cy;
2809 ImageList_GetIconSize (infoPtr->himl, &cx, &cy);
2810 infoPtr->imageSize.cx = cx;
2811 infoPtr->imageSize.cy = cy;
2812 }
2813 else {
2814 infoPtr->imageSize.cx = 0;
2815 infoPtr->imageSize.cy = 0;
2816 }
2817 TRACE("new image cx=%d, cy=%d\n", infoPtr->imageSize.cx,
2818 infoPtr->imageSize.cy);
2819 }
2820
2821 /* revalidate all bands to reset flags for images in headers of bands */
2822 for (i=0; i<infoPtr->uNumBands; i++) {
2823 lpBand = REBAR_GetBand(infoPtr, i);
2824 REBAR_ValidateBand (infoPtr, lpBand);
2825 }
2826
2827 return TRUE;
2828}
2829
2830
2831static LRESULT
2833{
2834 COLORREF clrTemp;
2835
2836 clrTemp = infoPtr->clrBk;
2837 infoPtr->clrBk = clr;
2838
2839 TRACE("background color 0x%06x!\n", infoPtr->clrBk);
2840
2841 return clrTemp;
2842}
2843
2844
2845/* << REBAR_SetColorScheme >> */
2846/* << REBAR_SetPalette >> */
2847
2848
2849static LRESULT
2851{
2852 HWND hwndTemp = infoPtr->hwndNotify;
2853
2854 infoPtr->hwndNotify = parent;
2855
2856 return (LRESULT)hwndTemp;
2857}
2858
2859
2860static LRESULT
2862{
2863 COLORREF clrTemp;
2864
2865 clrTemp = infoPtr->clrText;
2866 infoPtr->clrText = clr;
2867
2868 TRACE("text color 0x%06x!\n", infoPtr->clrText);
2869
2870 return clrTemp;
2871}
2872
2873
2874/* << REBAR_SetTooltips >> */
2875
2876
2877static inline LRESULT
2879{
2880 BOOL bTemp = infoPtr->bUnicode;
2881
2882 TRACE("to %s hwnd=%p, was %s\n",
2883 unicode ? "TRUE" : "FALSE", infoPtr->hwndSelf,
2884 (bTemp) ? "TRUE" : "FALSE");
2885
2886 infoPtr->bUnicode = unicode;
2887
2888 return bTemp;
2889}
2890
2891
2892static LRESULT
2893REBAR_SetVersion (REBAR_INFO *infoPtr, INT iVersion)
2894{
2895 INT iOldVersion = infoPtr->iVersion;
2896
2897 if (iVersion > COMCTL32_VERSION)
2898 return -1;
2899
2900 infoPtr->iVersion = iVersion;
2901
2902 TRACE("new version %d\n", iVersion);
2903
2904 return iOldVersion;
2905}
2906
2907
2908static LRESULT
2909REBAR_ShowBand (REBAR_INFO *infoPtr, INT iBand, BOOL show)
2910{
2911 REBAR_BAND *lpBand;
2912
2913 if (iBand < 0 || iBand >= infoPtr->uNumBands)
2914 return FALSE;
2915
2916 lpBand = REBAR_GetBand(infoPtr, iBand);
2917
2918 if (show) {
2919 TRACE("show band %d\n", iBand);
2920 lpBand->fStyle = lpBand->fStyle & ~RBBS_HIDDEN;
2921 if (IsWindow (lpBand->hwndChild))
2922 ShowWindow (lpBand->hwndChild, SW_SHOW);
2923 }
2924 else {
2925 TRACE("hide band %d\n", iBand);
2926 lpBand->fStyle = lpBand->fStyle | RBBS_HIDDEN;
2927 if (IsWindow (lpBand->hwndChild))
2928 ShowWindow (lpBand->hwndChild, SW_HIDE);
2929 }
2930
2931 REBAR_Layout(infoPtr);
2932 InvalidateRect(infoPtr->hwndSelf, NULL, TRUE);
2933
2934 return TRUE;
2935}
2936
2937
2938static LRESULT
2939#ifdef __REACTOS__
2940REBAR_SizeToRect (REBAR_INFO *infoPtr, WPARAM flags, RECT *lpRect)
2941#else
2942REBAR_SizeToRect (REBAR_INFO *infoPtr, const RECT *lpRect)
2943#endif
2944{
2945 if (!lpRect) return FALSE;
2946
2947 TRACE("[%s]\n", wine_dbgstr_rect(lpRect));
2948 REBAR_SizeToHeight(infoPtr, get_rect_cy(infoPtr, lpRect));
2949
2950#ifdef __REACTOS__
2951 /* Note that this undocumented flag is available on comctl32 v6 or later */
2952 if ((flags & RBSTR_CHANGERECT) != 0)
2953 {
2954 RECT rcRebar;
2955 GetClientRect(infoPtr->hwndSelf, &rcRebar);
2956 lpRect->bottom = lpRect->top + (rcRebar.bottom - rcRebar.top);
2957 }
2958#endif
2959 return TRUE;
2960}
2961
2962
2963
2964static LRESULT
2966{
2967 RECT wnrc1, clrc1;
2968
2969 if (TRACE_ON(rebar)) {
2970 GetWindowRect(infoPtr->hwndSelf, &wnrc1);
2971 GetClientRect(infoPtr->hwndSelf, &clrc1);
2972 TRACE("window=(%s) client=(%s) cs=(%d,%d %dx%d)\n",
2973 wine_dbgstr_rect(&wnrc1), wine_dbgstr_rect(&clrc1),
2974 cs->x, cs->y, cs->cx, cs->cy);
2975 }
2976
2977 TRACE("created!\n");
2978
2979 if (OpenThemeData (infoPtr->hwndSelf, themeClass))
2980 {
2981 /* native seems to clear WS_BORDER when themed */
2982 infoPtr->dwStyle &= ~WS_BORDER;
2983 }
2984
2985 return 0;
2986}
2987
2988
2989static LRESULT
2991{
2992 REBAR_BAND *lpBand;
2993 UINT i;
2994
2995 /* clean up each band */
2996 for (i = 0; i < infoPtr->uNumBands; i++) {
2997 lpBand = REBAR_GetBand(infoPtr, i);
2998
2999 /* delete text strings */
3000 Free (lpBand->lpText);
3001 lpBand->lpText = NULL;
3002 /* destroy child window */
3003 DestroyWindow (lpBand->hwndChild);
3004 Free (lpBand);
3005 }
3006
3007 /* free band array */
3008 DPA_Destroy (infoPtr->bands);
3009 infoPtr->bands = NULL;
3010
3011 DestroyCursor (infoPtr->hcurArrow);
3012 DestroyCursor (infoPtr->hcurHorz);
3013 DestroyCursor (infoPtr->hcurVert);
3014 DestroyCursor (infoPtr->hcurDrag);
3015 if (infoPtr->hDefaultFont) DeleteObject (infoPtr->hDefaultFont);
3016 SetWindowLongPtrW (infoPtr->hwndSelf, 0, 0);
3017
3019
3020 /* free rebar info data */
3021 Free (infoPtr);
3022 TRACE("destroyed!\n");
3023 return 0;
3024}
3025
3026static LRESULT
3028{
3029 return (LRESULT)infoPtr->hFont;
3030}
3031
3032static LRESULT
3034{
3035 if (uBand < infoPtr->uNumBands)
3036 {
3037 NMREBARCHEVRON nmrbc;
3038 REBAR_BAND *lpBand = REBAR_GetBand(infoPtr, uBand);
3039
3040 TRACE("Pressed chevron on band %u\n", uBand);
3041
3042 /* redraw chevron in pushed state */
3043 lpBand->fDraw |= DRAW_CHEVRONPUSHED;
3044 RedrawWindow(infoPtr->hwndSelf, &lpBand->rcChevron,0,
3046
3047 /* notify app so it can display a popup menu or whatever */
3048 nmrbc.uBand = uBand;
3049 nmrbc.wID = lpBand->wID;
3050 nmrbc.lParam = lpBand->lParam;
3051 nmrbc.rc = lpBand->rcChevron;
3052 nmrbc.lParamNM = lParam;
3053 REBAR_Notify((NMHDR*)&nmrbc, infoPtr, RBN_CHEVRONPUSHED);
3054
3055 /* redraw chevron in previous state */
3056 lpBand->fDraw &= ~DRAW_CHEVRONPUSHED;
3057 InvalidateRect(infoPtr->hwndSelf, &lpBand->rcChevron, TRUE);
3058
3059 return TRUE;
3060 }
3061 return FALSE;
3062}
3063
3064static LRESULT
3066{
3067 UINT htFlags;
3068 INT iHitBand;
3069 POINT ptMouseDown;
3070 ptMouseDown.x = (short)LOWORD(lParam);
3071 ptMouseDown.y = (short)HIWORD(lParam);
3072
3073 REBAR_InternalHitTest(infoPtr, &ptMouseDown, &htFlags, &iHitBand);
3074
3075 if (htFlags == RBHT_CHEVRON)
3076 {
3077 REBAR_PushChevron(infoPtr, iHitBand, 0);
3078 }
3079 else if (htFlags == RBHT_GRABBER || htFlags == RBHT_CAPTION)
3080 {
3081 REBAR_BAND *lpBand;
3082
3083 TRACE("Starting drag\n");
3084
3085 lpBand = REBAR_GetBand(infoPtr, iHitBand);
3086
3087 SetCapture (infoPtr->hwndSelf);
3088 infoPtr->iGrabbedBand = iHitBand;
3089
3090 /* save off the LOWORD and HIWORD of lParam as initial x,y */
3091 infoPtr->dragStart.x = (short)LOWORD(lParam);
3092 infoPtr->dragStart.y = (short)HIWORD(lParam);
3093 infoPtr->dragNow = infoPtr->dragStart;
3094 if (infoPtr->dwStyle & CCS_VERT)
3095 infoPtr->ihitoffset = infoPtr->dragStart.y - (lpBand->rcBand.left + REBAR_PRE_GRIPPER);
3096 else
3097 infoPtr->ihitoffset = infoPtr->dragStart.x - (lpBand->rcBand.left + REBAR_PRE_GRIPPER);
3098 }
3099 return 0;
3100}
3101
3102static LRESULT
3104{
3105 if (infoPtr->iGrabbedBand >= 0)
3106 {
3107 NMHDR layout;
3108 RECT rect;
3109
3110 infoPtr->dragStart.x = 0;
3111 infoPtr->dragStart.y = 0;
3112 infoPtr->dragNow = infoPtr->dragStart;
3113
3114 ReleaseCapture ();
3115
3116 if (infoPtr->fStatus & BEGIN_DRAG_ISSUED) {
3118 REBAR_Notify_NMREBAR (infoPtr, infoPtr->iGrabbedBand, RBN_ENDDRAG);
3119 infoPtr->fStatus &= ~BEGIN_DRAG_ISSUED;
3120 }
3121
3122 infoPtr->iGrabbedBand = -1;
3123
3124 GetClientRect(infoPtr->hwndSelf, &rect);
3125 InvalidateRect(infoPtr->hwndSelf, NULL, TRUE);
3126 }
3127
3128 return 0;
3129}
3130
3131static LRESULT
3133{
3134 if (infoPtr->ichevronhotBand >= 0)
3135 {
3136 REBAR_BAND *lpChevronBand = REBAR_GetBand(infoPtr, infoPtr->ichevronhotBand);
3137 if (lpChevronBand->fDraw & DRAW_CHEVRONHOT)
3138 {
3139 lpChevronBand->fDraw &= ~DRAW_CHEVRONHOT;
3140 InvalidateRect(infoPtr->hwndSelf, &lpChevronBand->rcChevron, TRUE);
3141 }
3142 }
3143 infoPtr->iOldBand = -1;
3144 infoPtr->ichevronhotBand = -2;
3145
3146 return TRUE;
3147}
3148
3149static LRESULT
3151{
3152 REBAR_BAND *lpChevronBand;
3153 POINT ptMove;
3154
3155 ptMove.x = (short)LOWORD(lParam);
3156 ptMove.y = (short)HIWORD(lParam);
3157
3158 /* if we are currently dragging a band */
3159 if (infoPtr->iGrabbedBand >= 0)
3160 {
3161 REBAR_BAND *band;
3162 int yPtMove = (infoPtr->dwStyle & CCS_VERT ? ptMove.x : ptMove.y);
3163
3164 if (GetCapture() != infoPtr->hwndSelf)
3165 ERR("We are dragging but haven't got capture?!?\n");
3166
3167 band = REBAR_GetBand(infoPtr, infoPtr->iGrabbedBand);
3168
3169 /* if mouse did not move much, exit */
3170 if ((abs(ptMove.x - infoPtr->dragNow.x) <= mindragx) &&
3171 (abs(ptMove.y - infoPtr->dragNow.y) <= mindragy)) return 0;
3172
3173 /* on first significant mouse movement, issue notify */
3174 if (!(infoPtr->fStatus & BEGIN_DRAG_ISSUED)) {
3175 if (REBAR_Notify_NMREBAR (infoPtr, -1, RBN_BEGINDRAG)) {
3176 /* Notify returned TRUE - abort drag */
3177 infoPtr->dragStart.x = 0;
3178 infoPtr->dragStart.y = 0;
3179 infoPtr->dragNow = infoPtr->dragStart;
3180 infoPtr->iGrabbedBand = -1;
3181 ReleaseCapture ();
3182 return 0;
3183 }
3184 infoPtr->fStatus |= BEGIN_DRAG_ISSUED;
3185 }
3186
3187 /* Test for valid drag case - must not be first band in row */
3188 if ((yPtMove < band->rcBand.top) ||
3189 (yPtMove > band->rcBand.bottom)) {
3190 REBAR_HandleUDDrag (infoPtr, &ptMove);
3191 }
3192 else {
3193 REBAR_HandleLRDrag (infoPtr, &ptMove);
3194 }
3195 }
3196 else
3197 {
3198 INT iHitBand;
3199 UINT htFlags;
3200 TRACKMOUSEEVENT trackinfo;
3201
3202 REBAR_InternalHitTest(infoPtr, &ptMove, &htFlags, &iHitBand);
3203
3204 if (infoPtr->iOldBand >= 0 && infoPtr->iOldBand == infoPtr->ichevronhotBand)
3205 {
3206 lpChevronBand = REBAR_GetBand(infoPtr, infoPtr->ichevronhotBand);
3207 if (lpChevronBand->fDraw & DRAW_CHEVRONHOT)
3208 {
3209 lpChevronBand->fDraw &= ~DRAW_CHEVRONHOT;
3210 InvalidateRect(infoPtr->hwndSelf, &lpChevronBand->rcChevron, TRUE);
3211 }
3212 infoPtr->ichevronhotBand = -2;
3213 }
3214
3215 if (htFlags == RBHT_CHEVRON)
3216 {
3217 /* fill in the TRACKMOUSEEVENT struct */
3218 trackinfo.cbSize = sizeof(TRACKMOUSEEVENT);
3219 trackinfo.dwFlags = TME_QUERY;
3220 trackinfo.hwndTrack = infoPtr->hwndSelf;
3221 trackinfo.dwHoverTime = 0;
3222
3223 /* call _TrackMouseEvent to see if we are currently tracking for this hwnd */
3224 _TrackMouseEvent(&trackinfo);
3225
3226 /* Make sure tracking is enabled so we receive a WM_MOUSELEAVE message */
3227 if(!(trackinfo.dwFlags & TME_LEAVE))
3228 {
3229 trackinfo.dwFlags = TME_LEAVE; /* notify upon leaving */
3230
3231 /* call TRACKMOUSEEVENT so we receive a WM_MOUSELEAVE message */
3232 /* and can properly deactivate the hot chevron */
3233 _TrackMouseEvent(&trackinfo);
3234 }
3235
3236 lpChevronBand = REBAR_GetBand(infoPtr, iHitBand);
3237 if (!(lpChevronBand->fDraw & DRAW_CHEVRONHOT))
3238 {
3239 lpChevronBand->fDraw |= DRAW_CHEVRONHOT;
3240 InvalidateRect(infoPtr->hwndSelf, &lpChevronBand->rcChevron, TRUE);
3241 infoPtr->ichevronhotBand = iHitBand;
3242 }
3243 }
3244 infoPtr->iOldBand = iHitBand;
3245 }
3246
3247 return 0;
3248}
3249
3250
3251static inline LRESULT
3253{
3254 HTHEME theme;
3255
3256 if (infoPtr->dwStyle & WS_BORDER) {
3257 rect->left = min(rect->left + GetSystemMetrics(SM_CXEDGE), rect->right);
3258 rect->right = max(rect->right - GetSystemMetrics(SM_CXEDGE), rect->left);
3259 rect->top = min(rect->top + GetSystemMetrics(SM_CYEDGE), rect->bottom);
3260 rect->bottom = max(rect->bottom - GetSystemMetrics(SM_CYEDGE), rect->top);
3261 }
3262 else if ((theme = GetWindowTheme (infoPtr->hwndSelf)))
3263 {
3264 /* FIXME: should use GetThemeInt */
3265#ifdef __REACTOS__
3266 rect->top = (rect->top + 1 < rect->bottom) ? rect->top : rect->bottom;
3267#else
3268 rect->top = min(rect->top + 1, rect->bottom);
3269#endif
3270 }
3271 TRACE("new client=(%s)\n", wine_dbgstr_rect(rect));
3272 return 0;
3273}
3274
3275
3276static LRESULT
3278{
3279 REBAR_INFO *infoPtr = REBAR_GetInfoPtr (hwnd);
3280 RECT wnrc1, clrc1;
3281 NONCLIENTMETRICSW ncm;
3282 HFONT tfont;
3283
3284 if (infoPtr) {
3285 ERR("Strange info structure pointer *not* NULL\n");
3286 return FALSE;
3287 }
3288
3289 if (TRACE_ON(rebar)) {
3290 GetWindowRect(hwnd, &wnrc1);
3291 GetClientRect(hwnd, &clrc1);
3292 TRACE("window=(%s) client=(%s) cs=(%d,%d %dx%d)\n",
3293 wine_dbgstr_rect(&wnrc1), wine_dbgstr_rect(&clrc1),
3294 cs->x, cs->y, cs->cx, cs->cy);
3295 }
3296
3297 /* allocate memory for info structure */
3298 infoPtr = Alloc (sizeof(REBAR_INFO));
3299 SetWindowLongPtrW (hwnd, 0, (DWORD_PTR)infoPtr);
3300
3301 /* initialize info structure - initial values are 0 */
3302 infoPtr->clrBk = CLR_NONE;
3303 infoPtr->clrText = CLR_NONE;
3306 infoPtr->iOldBand = -1;
3307 infoPtr->ichevronhotBand = -2;
3308 infoPtr->iGrabbedBand = -1;
3309 infoPtr->hwndSelf = hwnd;
3310 infoPtr->DoRedraw = TRUE;
3311 infoPtr->hcurArrow = LoadCursorW (0, (LPWSTR)IDC_ARROW);
3312 infoPtr->hcurHorz = LoadCursorW (0, (LPWSTR)IDC_SIZEWE);
3313 infoPtr->hcurVert = LoadCursorW (0, (LPWSTR)IDC_SIZENS);
3314 infoPtr->hcurDrag = LoadCursorW (0, (LPWSTR)IDC_SIZE);
3315 infoPtr->fStatus = 0;
3316 infoPtr->hFont = GetStockObject (SYSTEM_FONT);
3317 infoPtr->bands = DPA_Create(8);
3318
3319 /* issue WM_NOTIFYFORMAT to get unicode status of parent */
3321
3322 /* Stow away the original style */
3323 infoPtr->orgStyle = cs->style;
3324 /* add necessary styles to the requested styles */
3325 infoPtr->dwStyle = cs->style | WS_VISIBLE;
3326 if ((infoPtr->dwStyle & CCS_LAYOUT_MASK) == 0)
3327 infoPtr->dwStyle |= CCS_TOP;
3328 SetWindowLongW (hwnd, GWL_STYLE, infoPtr->dwStyle);
3329
3330 /* get font handle for Caption Font */
3331 ncm.cbSize = sizeof(ncm);
3332 SystemParametersInfoW (SPI_GETNONCLIENTMETRICS, ncm.cbSize, &ncm, 0);
3333 /* if the font is bold, set to normal */
3334 if (ncm.lfCaptionFont.lfWeight > FW_NORMAL) {
3335 ncm.lfCaptionFont.lfWeight = FW_NORMAL;
3336 }
3337 tfont = CreateFontIndirectW (&ncm.lfCaptionFont);
3338 if (tfont) {
3339 infoPtr->hFont = infoPtr->hDefaultFont = tfont;
3340 }
3341
3342 return TRUE;
3343}
3344
3345
3346static LRESULT
3348{
3349 NMMOUSE nmmouse;
3350 POINT clpt;
3351 INT i;
3352 UINT scrap;
3354
3355 /*
3356 * Differences from doc at MSDN (as observed with version 4.71 of
3357 * comctl32.dll
3358 * 1. doc says nmmouse.pt is in screen coord, trace shows client coord.
3359 * 2. if band is not identified .dwItemSpec is 0xffffffff.
3360 * 3. native always seems to return HTCLIENT if notify return is 0.
3361 */
3362
3363 clpt.x = (short)LOWORD(lParam);
3364 clpt.y = (short)HIWORD(lParam);
3365 ScreenToClient (infoPtr->hwndSelf, &clpt);
3366 REBAR_InternalHitTest (infoPtr, &clpt, &scrap,
3367 (INT *)&nmmouse.dwItemSpec);
3368 nmmouse.dwItemData = 0;
3369 nmmouse.pt = clpt;
3370#ifdef __REACTOS__
3371 nmmouse.dwHitInfo = scrap;
3372#else
3373 nmmouse.dwHitInfo = 0;
3374#endif
3375 if ((i = REBAR_Notify((NMHDR *) &nmmouse, infoPtr, NM_NCHITTEST))) {
3376 TRACE("notify changed return value from %ld to %d\n",
3377 ret, i);
3378 ret = (LRESULT) i;
3379 }
3380 TRACE("returning %ld, client point %s\n", ret, wine_dbgstr_point(&clpt));
3381 return ret;
3382}
3383
3384
3385static LRESULT
3387{
3388 RECT rcWindow;
3389 HDC hdc;
3390 HTHEME theme;
3391
3392 if (infoPtr->dwStyle & WS_MINIMIZE)
3393 return 0; /* Nothing to do */
3394
3395 if (infoPtr->dwStyle & WS_BORDER) {
3396
3397 /* adjust rectangle and draw the necessary edge */
3398 if (!(hdc = GetDCEx( infoPtr->hwndSelf, 0, DCX_USESTYLE | DCX_WINDOW )))
3399 return 0;
3400 GetWindowRect (infoPtr->hwndSelf, &rcWindow);
3401 OffsetRect (&rcWindow, -rcWindow.left, -rcWindow.top);
3402 TRACE("rect (%s)\n", wine_dbgstr_rect(&rcWindow));
3403 DrawEdge (hdc, &rcWindow, EDGE_ETCHED, BF_RECT);
3404 ReleaseDC( infoPtr->hwndSelf, hdc );
3405 }
3406 else if ((theme = GetWindowTheme (infoPtr->hwndSelf)))
3407 {
3408 /* adjust rectangle and draw the necessary edge */
3409 if (!(hdc = GetDCEx( infoPtr->hwndSelf, 0, DCX_USESTYLE | DCX_WINDOW )))
3410 return 0;
3411 GetWindowRect (infoPtr->hwndSelf, &rcWindow);
3412 OffsetRect (&rcWindow, -rcWindow.left, -rcWindow.top);
3413 TRACE("rect (%s)\n", wine_dbgstr_rect(&rcWindow));
3414 DrawThemeEdge (theme, hdc, 0, 0, &rcWindow, BDR_RAISEDINNER, BF_TOP, NULL);
3415 ReleaseDC( infoPtr->hwndSelf, hdc );
3416 }
3417
3418 return 0;
3419}
3420
3421
3422static LRESULT
3424{
3425 INT i;
3426
3427 if (cmd == NF_REQUERY) {
3429 WM_NOTIFYFORMAT, (WPARAM)infoPtr->hwndSelf, NF_QUERY);
3430 if ((i != NFR_ANSI) && (i != NFR_UNICODE)) {
3431 ERR("wrong response to WM_NOTIFYFORMAT (%d), assuming ANSI\n", i);
3432 i = NFR_ANSI;
3433 }
3434 infoPtr->bUnicode = (i == NFR_UNICODE);
3435 return (LRESULT)i;
3436 }
3437 return (LRESULT)((infoPtr->bUnicode) ? NFR_UNICODE : NFR_ANSI);
3438}
3439
3440
3441static LRESULT
3443{
3444 if (hdc) {
3445 TRACE("painting\n");
3446#ifdef __REACTOS__
3447 REBAR_EraseBkGnd (infoPtr, hdc);
3448#endif
3449 REBAR_Refresh (infoPtr, hdc);
3450 } else {
3451 PAINTSTRUCT ps;
3452 hdc = BeginPaint (infoPtr->hwndSelf, &ps);
3453 TRACE("painting (%s)\n", wine_dbgstr_rect(&ps.rcPaint));
3454 if (ps.fErase) {
3455 /* Erase area of paint if requested */
3456 REBAR_EraseBkGnd (infoPtr, hdc);
3457 }
3458 REBAR_Refresh (infoPtr, hdc);
3459 EndPaint (infoPtr->hwndSelf, &ps);
3460 }
3461
3462 return 0;
3463}
3464
3465
3466static LRESULT
3468{
3469 POINT pt;
3470 UINT flags;
3471
3472 TRACE("code=0x%X id=0x%X\n", LOWORD(lParam), HIWORD(lParam));
3473
3474 GetCursorPos (&pt);
3475 ScreenToClient (infoPtr->hwndSelf, &pt);
3476
3477 REBAR_InternalHitTest (infoPtr, &pt, &flags, NULL);
3478
3479 if (flags == RBHT_GRABBER) {
3480 if ((infoPtr->dwStyle & CCS_VERT) &&
3481 !(infoPtr->dwStyle & RBS_VERTICALGRIPPER))
3482 SetCursor (infoPtr->hcurVert);
3483 else
3484 SetCursor (infoPtr->hcurHorz);
3485 }
3486 else if (flags != RBHT_CLIENT)
3487 SetCursor (infoPtr->hcurArrow);
3488
3489 return 0;
3490}
3491
3492
3493static LRESULT
3495{
3496 REBAR_BAND *lpBand;
3497 UINT i;
3498
3499 infoPtr->hFont = font;
3500
3501 /* revalidate all bands to change sizes of text in headers of bands */
3502 for (i=0; i<infoPtr->uNumBands; i++) {
3503 lpBand = REBAR_GetBand(infoPtr, i);
3504 REBAR_ValidateBand (infoPtr, lpBand);
3505 }
3506
3507 REBAR_Layout(infoPtr);
3508 return 0;
3509}
3510
3511
3512/*****************************************************
3513 *
3514 * Handles the WM_SETREDRAW message.
3515 *
3516 * Documentation:
3517 * According to testing V4.71 of COMCTL32 returns the
3518 * *previous* status of the redraw flag (either 0 or -1)
3519 * instead of the MSDN documented value of 0 if handled
3520 *
3521 *****************************************************/
3522static inline LRESULT
3524{
3525 BOOL oldredraw = infoPtr->DoRedraw;
3526
3527 TRACE("set to %s, fStatus=%08x\n",
3528 (redraw) ? "TRUE" : "FALSE", infoPtr->fStatus);
3529 infoPtr->DoRedraw = redraw;
3530 if (redraw) {
3531 if (infoPtr->fStatus & BAND_NEEDS_REDRAW) {
3532 REBAR_MoveChildWindows (infoPtr, 0, infoPtr->uNumBands);
3533 REBAR_ForceResize (infoPtr);
3534 InvalidateRect (infoPtr->hwndSelf, NULL, TRUE);
3535 }
3536 infoPtr->fStatus &= ~BAND_NEEDS_REDRAW;
3537 }
3538 return (oldredraw) ? -1 : 0;
3539}
3540
3541
3542static LRESULT
3544{
3545 TRACE("wParam=%lx, lParam=%lx\n", wParam, lParam);
3546
3547 /* avoid _Layout resize recursion (but it shouldn't be infinite and it seems Windows does recurse) */
3548 if (infoPtr->fStatus & SELF_RESIZE) {
3549 infoPtr->fStatus &= ~SELF_RESIZE;
3550 TRACE("SELF_RESIZE was set, reset, fStatus=%08x lparam=%08lx\n",
3551 infoPtr->fStatus, lParam);
3552 return 0;
3553 }
3554
3555 if (infoPtr->dwStyle & RBS_AUTOSIZE)
3556 REBAR_AutoSize(infoPtr, TRUE);
3557 else
3558 REBAR_Layout(infoPtr);
3559
3560 return 0;
3561}
3562
3563
3564static LRESULT
3565REBAR_StyleChanged (REBAR_INFO *infoPtr, INT nType, const STYLESTRUCT *lpStyle)
3566{
3567 TRACE("current style=%08x, styleOld=%08x, style being set to=%08x\n",
3568 infoPtr->dwStyle, lpStyle->styleOld, lpStyle->styleNew);
3569 if (nType == GWL_STYLE)
3570 {
3571 infoPtr->orgStyle = infoPtr->dwStyle = lpStyle->styleNew;
3572 if (GetWindowTheme (infoPtr->hwndSelf))
3573 infoPtr->dwStyle &= ~WS_BORDER;
3574 /* maybe it should be COMMON_STYLES like in toolbar */
3575 if ((lpStyle->styleNew ^ lpStyle->styleOld) & CCS_VERT)
3576 REBAR_Layout(infoPtr);
3577 }
3578 return FALSE;
3579}
3580
3581/* update theme after a WM_THEMECHANGED message */
3583{
3584 HTHEME theme = GetWindowTheme (infoPtr->hwndSelf);
3585 CloseThemeData (theme);
3586 theme = OpenThemeData (infoPtr->hwndSelf, themeClass);
3587 /* WS_BORDER disappears when theming is enabled and reappears when
3588 * disabled... */
3589 infoPtr->dwStyle &= ~WS_BORDER;
3590 infoPtr->dwStyle |= theme ? 0 : (infoPtr->orgStyle & WS_BORDER);
3591 return 0;
3592}
3593
3594static LRESULT
3596{
3597 LRESULT ret;
3598 RECT rc;
3599
3601 wParam, lParam);
3602 GetWindowRect(infoPtr->hwndSelf, &rc);
3603 TRACE("hwnd %p new pos (%s)\n", infoPtr->hwndSelf, wine_dbgstr_rect(&rc));
3604 return ret;
3605}
3606
3607
3608static LRESULT WINAPI
3610{
3611 REBAR_INFO *infoPtr = REBAR_GetInfoPtr (hwnd);
3612
3613 TRACE("hwnd=%p msg=%x wparam=%lx lparam=%lx\n",
3614 hwnd, uMsg, wParam, lParam);
3615 if (!infoPtr && (uMsg != WM_NCCREATE))
3616 return DefWindowProcW (hwnd, uMsg, wParam, lParam);
3617 switch (uMsg)
3618 {
3619/* case RB_BEGINDRAG: */
3620
3621 case RB_DELETEBAND:
3622 return REBAR_DeleteBand (infoPtr, wParam);
3623
3624/* case RB_DRAGMOVE: */
3625/* case RB_ENDDRAG: */
3626
3627 case RB_GETBANDBORDERS:
3628 return REBAR_GetBandBorders (infoPtr, wParam, (LPRECT)lParam);
3629
3630 case RB_GETBANDCOUNT:
3631 return REBAR_GetBandCount (infoPtr);
3632
3633 case RB_GETBANDINFO_OLD:
3634 case RB_GETBANDINFOA:
3635 case RB_GETBANDINFOW:
3637 uMsg == RB_GETBANDINFOW);
3638 case RB_GETBARHEIGHT:
3639 return REBAR_GetBarHeight (infoPtr);
3640
3641 case RB_GETBARINFO:
3642 return REBAR_GetBarInfo (infoPtr, (LPREBARINFO)lParam);
3643
3644 case RB_GETBKCOLOR:
3645 return REBAR_GetBkColor (infoPtr);
3646
3647/* case RB_GETCOLORSCHEME: */
3648/* case RB_GETDROPTARGET: */
3649
3650 case RB_GETPALETTE:
3651 return REBAR_GetPalette (infoPtr);
3652
3653 case RB_GETRECT:
3654 return REBAR_GetRect (infoPtr, wParam, (LPRECT)lParam);
3655
3656 case RB_GETROWCOUNT:
3657 return REBAR_GetRowCount (infoPtr);
3658
3659 case RB_GETROWHEIGHT:
3660 return REBAR_GetRowHeight (infoPtr, wParam);
3661
3662 case RB_GETTEXTCOLOR:
3663 return REBAR_GetTextColor (infoPtr);
3664
3665 case RB_GETTOOLTIPS:
3666 return REBAR_GetToolTips (infoPtr);
3667
3669 return REBAR_GetUnicodeFormat (infoPtr);
3670
3671 case CCM_GETVERSION:
3672 return REBAR_GetVersion (infoPtr);
3673
3674 case RB_HITTEST:
3675 return REBAR_HitTest (infoPtr, (LPRBHITTESTINFO)lParam);
3676
3677 case RB_IDTOINDEX:
3678 return REBAR_IdToIndex (infoPtr, wParam);
3679
3680 case RB_INSERTBANDA:
3681 case RB_INSERTBANDW:
3683 uMsg == RB_INSERTBANDW);
3684 case RB_MAXIMIZEBAND:
3685 return REBAR_MaximizeBand (infoPtr, wParam, lParam);
3686
3687 case RB_MINIMIZEBAND:
3688 return REBAR_MinimizeBand (infoPtr, wParam);
3689
3690 case RB_MOVEBAND:
3691 return REBAR_MoveBand (infoPtr, wParam, lParam);
3692
3693 case RB_PUSHCHEVRON:
3694 return REBAR_PushChevron (infoPtr, wParam, lParam);
3695
3696 case RB_SETBANDINFOA:
3697 case RB_SETBANDINFOW:
3699 uMsg == RB_SETBANDINFOW);
3700 case RB_SETBARINFO:
3701 return REBAR_SetBarInfo (infoPtr, (LPREBARINFO)lParam);
3702
3703 case RB_SETBKCOLOR:
3704 return REBAR_SetBkColor (infoPtr, lParam);
3705
3706/* case RB_SETCOLORSCHEME: */
3707/* case RB_SETPALETTE: */
3708
3709 case RB_SETPARENT:
3710 return REBAR_SetParent (infoPtr, (HWND)wParam);
3711
3712 case RB_SETTEXTCOLOR:
3713 return REBAR_SetTextColor (infoPtr, lParam);
3714
3715/* case RB_SETTOOLTIPS: */
3716
3718 return REBAR_SetUnicodeFormat (infoPtr, wParam);
3719
3720 case CCM_SETVERSION:
3721 return REBAR_SetVersion (infoPtr, (INT)wParam);
3722
3723 case RB_SHOWBAND:
3724 return REBAR_ShowBand (infoPtr, wParam, lParam);
3725
3726 case RB_SIZETORECT:
3727#ifdef __REACTOS__
3728 return REBAR_SizeToRect (infoPtr, wParam, (LPRECT)lParam);
3729#else
3730 return REBAR_SizeToRect (infoPtr, (LPCRECT)lParam);
3731#endif
3732
3733
3734/* Messages passed to parent */
3735 case WM_COMMAND:
3736 case WM_DRAWITEM:
3737 case WM_NOTIFY:
3738 case WM_MEASUREITEM:
3739 return SendMessageW(REBAR_GetNotifyParent (infoPtr), uMsg, wParam, lParam);
3740
3741
3742/* case WM_CHARTOITEM: supported according to ControlSpy */
3743
3744 case WM_CREATE:
3745 return REBAR_Create (infoPtr, (LPCREATESTRUCTW)lParam);
3746
3747 case WM_DESTROY:
3748 return REBAR_Destroy (infoPtr);
3749
3750 case WM_ERASEBKGND:
3751 return REBAR_EraseBkGnd (infoPtr, (HDC)wParam);
3752
3753 case WM_GETFONT:
3754 return REBAR_GetFont (infoPtr);
3755
3756/* case WM_LBUTTONDBLCLK: supported according to ControlSpy */
3757
3758 case WM_LBUTTONDOWN:
3759 return REBAR_LButtonDown (infoPtr, lParam);
3760
3761 case WM_LBUTTONUP:
3762 return REBAR_LButtonUp (infoPtr);
3763
3764 case WM_MOUSEMOVE:
3765 return REBAR_MouseMove (infoPtr, lParam);
3766
3767 case WM_MOUSELEAVE:
3768 return REBAR_MouseLeave (infoPtr);
3769
3770 case WM_NCCALCSIZE:
3771 return REBAR_NCCalcSize (infoPtr, (RECT*)lParam);
3772
3773 case WM_NCCREATE:
3775
3776 case WM_NCHITTEST:
3777 return REBAR_NCHitTest (infoPtr, lParam);
3778
3779 case WM_NCPAINT:
3780 return REBAR_NCPaint (infoPtr);
3781
3782 case WM_NOTIFYFORMAT:
3783 return REBAR_NotifyFormat (infoPtr, lParam);
3784
3785 case WM_PRINTCLIENT:
3786 case WM_PAINT:
3787 return REBAR_Paint (infoPtr, (HDC)wParam);
3788
3789/* case WM_PALETTECHANGED: supported according to ControlSpy */
3790/* case WM_QUERYNEWPALETTE:supported according to ControlSpy */
3791/* case WM_RBUTTONDOWN: supported according to ControlSpy */
3792/* case WM_RBUTTONUP: supported according to ControlSpy */
3793
3794 case WM_SETCURSOR:
3795 return REBAR_SetCursor (infoPtr, lParam);
3796
3797 case WM_SETFONT:
3798 return REBAR_SetFont (infoPtr, (HFONT)wParam);
3799
3800 case WM_SETREDRAW:
3801 return REBAR_SetRedraw (infoPtr, wParam);
3802
3803 case WM_SIZE:
3804 return REBAR_Size (infoPtr, wParam, lParam);
3805
3806 case WM_STYLECHANGED:
3807 return REBAR_StyleChanged (infoPtr, wParam, (LPSTYLESTRUCT)lParam);
3808
3809 case WM_THEMECHANGED:
3810 return theme_changed (infoPtr);
3811
3812 case WM_SYSCOLORCHANGE:
3814#ifdef __REACTOS__
3815 /* r51522 - Properly support WM_SYSCOLORCHANGE */
3818#endif
3819 return 0;
3820
3821/* case WM_VKEYTOITEM: supported according to ControlSpy */
3822/* case WM_WININICHANGE: */
3823
3825 return REBAR_WindowPosChanged (infoPtr, wParam, lParam);
3826
3827 default:
3828 if ((uMsg >= WM_USER) && (uMsg < WM_APP) && !COMCTL32_IsReflectedMessage(uMsg))
3829 ERR("unknown msg %04x wp=%08lx lp=%08lx\n",
3830 uMsg, wParam, lParam);
3831 return DefWindowProcW (hwnd, uMsg, wParam, lParam);
3832 }
3833}
3834
3835
3836VOID
3838{
3839 WNDCLASSW wndClass;
3840
3841 ZeroMemory (&wndClass, sizeof(WNDCLASSW));
3842 wndClass.style = CS_GLOBALCLASS | CS_DBLCLKS;
3843 wndClass.lpfnWndProc = REBAR_WindowProc;
3844 wndClass.cbClsExtra = 0;
3845 wndClass.cbWndExtra = sizeof(REBAR_INFO *);
3846 wndClass.hCursor = 0;
3847 wndClass.hbrBackground = (HBRUSH)(COLOR_BTNFACE + 1);
3848#if GLATESTING
3849 wndClass.hbrBackground = CreateSolidBrush(RGB(0,128,0));
3850#endif
3851 wndClass.lpszClassName = REBARCLASSNAMEW;
3852
3853 RegisterClassW (&wndClass);
3854
3857
3858}
3859
3860
3861VOID
3863{
3865}
#define DCX_USESTYLE
Definition: GetDCEx.c:10
char * strcat(char *DstString, const char *SrcString)
Definition: utclib.c:568
Arabic default style
Definition: afstyles.h:94
static const char * wine_dbgstr_point(const POINT *ppt)
Definition: atltest.h:138
static const char * wine_dbgstr_rect(const RECT *prc)
Definition: atltest.h:160
#define WINE_DEFAULT_DEBUG_CHANNEL(t)
Definition: precomp.h:23
#define ARRAY_SIZE(A)
Definition: main.h:20
#define FIXME(fmt,...)
Definition: precomp.h:53
#define WARN(fmt,...)
Definition: precomp.h:61
#define ERR(fmt,...)
Definition: precomp.h:57
PVOID Alloc(IN DWORD dwFlags, IN SIZE_T dwBytes)
Definition: main.c:63
static const WCHAR szClassName[]
Definition: clipbrd.c:11
WPARAM wParam
Definition: combotst.c:138
LPARAM lParam
Definition: combotst.c:139
INT Str_GetPtrWtoA(LPCWSTR lpSrc, LPSTR lpDest, INT nMaxLen) DECLSPEC_HIDDEN
BOOL COMCTL32_IsReflectedMessage(UINT uMsg) DECLSPEC_HIDDEN
Definition: commctrl.c:1755
BOOL Str_SetPtrAtoW(LPWSTR *lppDest, LPCSTR lpSrc) DECLSPEC_HIDDEN
VOID COMCTL32_RefreshSysColors(void) DECLSPEC_HIDDEN
Definition: commctrl.c:1593
INT WINAPI Str_GetPtrW(LPCWSTR, LPWSTR, INT)
Definition: string.c:200
COMCTL32_SysColor comctl32_color
Definition: commctrl.c:82
BOOL WINAPI _TrackMouseEvent(TRACKMOUSEEVENT *ptme)
Definition: commctrl.c:1214
#define NULL
Definition: types.h:112
#define TRUE
Definition: types.h:120
#define FALSE
Definition: types.h:117
LPVOID WINAPI DPA_DeletePtr(HDPA hdpa, INT i)
Definition: dpa.c:677
BOOL WINAPI DPA_Destroy(HDPA hdpa)
Definition: dpa.c:396
HDPA WINAPI DPA_Create(INT nGrow)
Definition: dpa.c:950
INT WINAPI DPA_InsertPtr(HDPA hdpa, INT i, LPVOID p)
Definition: dpa.c:591
BOOL WINAPI ImageList_Draw(HIMAGELIST himl, INT i, HDC hdc, INT x, INT y, UINT fStyle)
Definition: imagelist.c:1228
BOOL WINAPI ImageList_GetIconSize(HIMAGELIST himl, INT *cx, INT *cy)
Definition: imagelist.c:2037
#define REBAR_POST_TEXT
Definition: rebar.c:214
static void REBAR_HandleUDDrag(REBAR_INFO *infoPtr, const POINT *ptsmove)
Definition: rebar.c:2116
static LRESULT REBAR_GetBarInfo(const REBAR_INFO *infoPtr, LPREBARINFO lpInfo)
Definition: rebar.c:2366
#define DRAW_IMAGE
Definition: rebar.c:148
static LRESULT REBAR_SetCursor(const REBAR_INFO *infoPtr, LPARAM lParam)
Definition: rebar.c:3467
#define HIDDENBAND(a)
Definition: rebar.c:251
#define SELF_RESIZE
Definition: rebar.c:192
static LRESULT WINAPI REBAR_WindowProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
Definition: rebar.c:3609
static void translate_rect(const REBAR_INFO *infoPtr, RECT *dest, const RECT *src)
Definition: rebar.c:438
static LRESULT REBAR_GetBandInfoT(const REBAR_INFO *infoPtr, UINT uIndex, LPREBARBANDINFOW lprbbi, BOOL bUnicode)
Definition: rebar.c:2275
static LRESULT REBAR_SetVersion(REBAR_INFO *infoPtr, INT iVersion)
Definition: rebar.c:2893
#define REBAR_PRE_GRIPPER
Definition: rebar.c:220
static LRESULT REBAR_IdToIndex(const REBAR_INFO *infoPtr, UINT uId)
Definition: rebar.c:2506
static LRESULT REBAR_Create(REBAR_INFO *infoPtr, LPCREATESTRUCTW cs)
Definition: rebar.c:2965
static LRESULT REBAR_NCCalcSize(const REBAR_INFO *infoPtr, RECT *rect)
Definition: rebar.c:3252
static UINT mindragy
Definition: rebar.c:270
static LRESULT REBAR_GetRect(const REBAR_INFO *infoPtr, INT iBand, RECT *lprc)
Definition: rebar.c:2410
static VOID REBAR_ForceResize(REBAR_INFO *infoPtr)
Definition: rebar.c:954
static UINT mindragx
Definition: rebar.c:269
#define REBAR_ALWAYS_SPACE
Definition: rebar.c:208
static HWND REBAR_GetNotifyParent(const REBAR_INFO *infoPtr)
Definition: rebar.c:506
static VOID REBAR_MoveChildWindows(const REBAR_INFO *infoPtr, UINT start, UINT endplus)
Definition: rebar.c:1023
static CHAR * REBAR_FmtStyle(char *buffer, UINT style)
Definition: rebar.c:308
static int REBAR_ShrinkBandsRTL(const REBAR_INFO *infoPtr, INT iBeginBand, INT iEndBand, INT cxShrink, BOOL bEnforce)
Definition: rebar.c:1211
static LRESULT REBAR_SetRedraw(REBAR_INFO *infoPtr, BOOL redraw)
Definition: rebar.c:3523
static VOID REBAR_DumpBandInfo(const REBARBANDINFOW *pB)
Definition: rebar.c:342
static LRESULT REBAR_SetTextColor(REBAR_INFO *infoPtr, COLORREF clr)
Definition: rebar.c:2861
static LRESULT REBAR_SetBkColor(REBAR_INFO *infoPtr, COLORREF clr)
Definition: rebar.c:2832
static LRESULT REBAR_GetRowCount(const REBAR_INFO *infoPtr)
Definition: rebar.c:2430
#define RB_GETBANDINFO_OLD
Definition: rebar.c:248
static REBAR_BAND * REBAR_GetBand(const REBAR_INFO *infoPtr, INT i)
Definition: rebar.c:261
static LRESULT REBAR_GetBandCount(const REBAR_INFO *infoPtr)
Definition: rebar.c:2266
static int get_rect_cx(const REBAR_INFO *infoPtr, const RECT *lpRect)
Definition: rebar.c:454
static LRESULT REBAR_LButtonDown(REBAR_INFO *infoPtr, LPARAM lParam)
Definition: rebar.c:3065
static LRESULT REBAR_GetTextColor(const REBAR_INFO *infoPtr)
Definition: rebar.c:2460
static LRESULT REBAR_InsertBandT(REBAR_INFO *infoPtr, INT iIndex, const REBARBANDINFOW *lprbbi, BOOL bUnicode)
Definition: rebar.c:2526
#define NTF_INVALIDATE