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