Fix off by one error in TOOLBAR_AddStringW.
[wine.git] / dlls / comctl32 / toolbar.c
blob1ef06aa6d34b93cbe4fa06c0c351f52ef4e1f6dc
1 /*
2 * Toolbar control
4 * Copyright 1998,1999 Eric Kohl
5 * Copyright 2000 Eric Kohl for CodeWeavers
7 * Differences between MSDN and actual native control operation:
8 * 1. MSDN says: "TBSTYLE_LIST: Creates a flat toolbar with button text
9 * to the right of the bitmap. Otherwise, this style is
10 * identical to TBSTYLE_FLAT."
11 * As implemented by both v4.71 and v5.80 of the native COMCTL32.DLL
12 * you can create a TBSTYLE_LIST without TBSTYLE_FLAT and the result
13 * is non-flat non-transparent buttons. Therefore TBSTYLE_LIST does
14 * *not* imply TBSTYLE_FLAT as documented. (GA 8/2001)
17 * TODO:
18 * - A little bug in TOOLBAR_DrawMasked()
19 * - Button wrapping (under construction).
20 * - Messages.
21 * - Notifications (under construction).
22 * - Fix TB_SETROWS.
23 * - Tooltip support (almost complete).
24 * - Unicode suppport (under construction).
25 * - Fix TOOLBAR_SetButtonInfo32A/W.
26 * - TBSTYLE_AUTOSIZE for toolbar and buttons.
27 * - I_IMAGECALLBACK support.
28 * - iString of -1 is undocumented
29 * - Customization dialog:
30 * - Add flat look.
31 * - Minor buglet in 'available buttons' list:
32 * Buttons are not listed in M$-like order. M$ seems to use a single
33 * internal list to store the button information of both listboxes.
34 * - Drag list support.
35 * - Help and Reset button support.
37 * Testing:
38 * - Run tests using Waite Group Windows95 API Bible Volume 2.
39 * The second cdrom contains executables addstr.exe, btncount.exe,
40 * btnstate.exe, butstrsz.exe, chkbtn.exe, chngbmp.exe, customiz.exe,
41 * enablebtn.exe, getbmp.exe, getbtn.exe, getflags.exe, hidebtn.exe,
42 * indetbtn.exe, insbtn.exe, pressbtn.exe, setbtnsz.exe, setcmdid.exe,
43 * setparnt.exe, setrows.exe, toolwnd.exe.
44 * - Microsofts controlspy examples.
45 * - Charles Petzold's 'Programming Windows': gadgets.exe
48 #include <string.h>
50 #include "winbase.h"
51 #include "windef.h"
52 #include "wingdi.h"
53 #include "winuser.h"
54 #include "wine/unicode.h"
55 #include "commctrl.h"
56 #include "imagelist.h"
57 #include "comctl32.h"
58 #include "debugtools.h"
60 DEFAULT_DEBUG_CHANNEL(toolbar);
62 typedef struct
64 INT iBitmap;
65 INT idCommand;
66 BYTE fsState;
67 BYTE fsStyle;
68 DWORD dwData;
69 INT iString;
71 BOOL bHot;
72 INT nRow;
73 RECT rect;
74 } TBUTTON_INFO;
76 typedef struct
78 DWORD dwStructSize; /* size of TBBUTTON struct */
79 INT nHeight; /* height of the toolbar */
80 INT nWidth; /* width of the toolbar */
81 INT nButtonHeight;
82 INT nButtonWidth;
83 INT nBitmapHeight;
84 INT nBitmapWidth;
85 INT nIndent;
86 INT nRows; /* number of button rows */
87 INT nMaxTextRows; /* maximum number of text rows */
88 INT cxMin; /* minimum button width */
89 INT cxMax; /* maximum button width */
90 INT nNumButtons; /* number of buttons */
91 INT nNumBitmaps; /* number of bitmaps */
92 INT nNumStrings; /* number of strings */
93 BOOL bUnicode; /* ASCII (FALSE) or Unicode (TRUE)? */
94 BOOL bCaptured; /* mouse captured? */
95 INT nButtonDown;
96 INT nOldHit;
97 INT nHotItem; /* index of the "hot" item */
98 HFONT hDefaultFont;
99 HFONT hFont; /* text font */
100 HIMAGELIST himlInt; /* image list created internally */
101 HIMAGELIST himlDef; /* default image list */
102 HIMAGELIST himlHot; /* hot image list */
103 HIMAGELIST himlDis; /* disabled image list */
104 HWND hwndToolTip; /* handle to tool tip control */
105 HWND hwndNotify; /* handle to the window that gets notifications */
106 HWND hwndSelf; /* my own handle */
107 BOOL bTransparent; /* background transparency flag */
108 BOOL bBtnTranspnt; /* button transparency flag */
109 BOOL bAutoSize; /* auto size deadlock indicator */
110 BOOL bAnchor; /* anchor highlight enabled */
111 BOOL bNtfUnicode; /* TRUE if NOTIFYs use {W} */
112 DWORD dwExStyle; /* extended toolbar style */
113 DWORD dwDTFlags; /* DrawText flags */
115 COLORREF clrInsertMark; /* insert mark color */
116 RECT rcBound; /* bounding rectangle */
117 INT iVersion;
119 TBUTTON_INFO *buttons; /* pointer to button array */
120 LPWSTR *strings; /* pointer to string array */
121 } TOOLBAR_INFO, *PTOOLBAR_INFO;
124 /* used by customization dialog */
125 typedef struct
127 PTOOLBAR_INFO tbInfo;
128 HWND tbHwnd;
129 } CUSTDLG_INFO, *PCUSTDLG_INFO;
131 typedef struct
133 TBBUTTON btn;
134 BOOL bVirtual;
135 BOOL bRemovable;
136 CHAR text[64];
137 } CUSTOMBUTTON, *PCUSTOMBUTTON;
140 #define SEPARATOR_WIDTH 8
141 #define TOP_BORDER 2
142 #define BOTTOM_BORDER 2
143 #define DDARROW_WIDTH 11
145 #define TOOLBAR_GetInfoPtr(hwnd) ((TOOLBAR_INFO *)GetWindowLongA(hwnd,0))
146 #define TOOLBAR_HasText(x, y) (TOOLBAR_GetText(x, y) ? TRUE : FALSE)
147 #define TOOLBAR_HasDropDownArrows(exStyle) ((exStyle & TBSTYLE_EX_DRAWDDARROWS) ? TRUE : FALSE)
150 static void
151 TOOLBAR_DumpButton(TOOLBAR_INFO *infoPtr, TBUTTON_INFO *bP, INT btn_num, BOOL internal)
153 if (TRACE_ON(toolbar)){
154 TRACE("button %d id %d, bitmap=%d, state=%02x, style=%02x, data=%08lx, string=%d\n",
155 btn_num, bP->idCommand,
156 bP->iBitmap, bP->fsState, bP->fsStyle, bP->dwData, bP->iString);
157 if (internal)
158 TRACE("button %d id %d, hot=%s, row=%d, rect=(%d,%d)-(%d,%d)\n",
159 btn_num, bP->idCommand,
160 (bP->bHot) ? "TRUE":"FALSE", bP->nRow,
161 bP->rect.left, bP->rect.top,
162 bP->rect.right, bP->rect.bottom);
167 static void
168 TOOLBAR_DumpToolbar(TOOLBAR_INFO *iP, INT line)
170 if (TRACE_ON(toolbar)) {
171 INT i;
172 DWORD dwStyle;
174 dwStyle = GetWindowLongA (iP->hwndSelf, GWL_STYLE);
175 TRACE("toolbar %08x at line %d, exStyle=%08lx, buttons=%d, bitmaps=%d, strings=%d, style=%08lx\n",
176 iP->hwndSelf, line,
177 iP->dwExStyle, iP->nNumButtons, iP->nNumBitmaps,
178 iP->nNumStrings, dwStyle);
179 TRACE("toolbar %08x at line %d, himlInt=%p, himlDef=%p, himlHot=%p, himlDis=%p\n",
180 iP->hwndSelf, line,
181 iP->himlInt, iP->himlDef, iP->himlHot, iP->himlDis);
182 for(i=0; i<iP->nNumButtons; i++) {
183 TOOLBAR_DumpButton(iP, &iP->buttons[i], i, TRUE);
189 /***********************************************************************
190 * TOOLBAR_CheckStyle
192 * This function validates that the styles set are implemented and
193 * issues FIXME's warning of possible problems. In a perfect world this
194 * function should be null.
196 static void
197 TOOLBAR_CheckStyle (HWND hwnd, DWORD dwStyle)
199 if (dwStyle & TBSTYLE_ALTDRAG)
200 FIXME("[%04x] TBSTYLE_ALTDRAG not implemented\n", hwnd);
201 if (dwStyle & TBSTYLE_REGISTERDROP)
202 FIXME("[%04x] TBSTYLE_REGISTERDROP not implemented\n", hwnd);
206 static INT
207 TOOLBAR_SendNotify (NMHDR *nmhdr, TOOLBAR_INFO *infoPtr, UINT code)
209 if(!IsWindow(infoPtr->hwndSelf))
210 return 0; /* we have just been destroyed */
212 nmhdr->idFrom = GetDlgCtrlID (infoPtr->hwndSelf);
213 nmhdr->hwndFrom = infoPtr->hwndSelf;
214 nmhdr->code = code;
216 TRACE("to window %04x, code=%08x, %s\n", infoPtr->hwndNotify, code,
217 (infoPtr->bNtfUnicode) ? "via Unicode" : "via ANSI");
219 if (infoPtr->bNtfUnicode)
220 return SendMessageW (infoPtr->hwndNotify, WM_NOTIFY,
221 (WPARAM) nmhdr->idFrom, (LPARAM)nmhdr);
222 else
223 return SendMessageA (infoPtr->hwndNotify, WM_NOTIFY,
224 (WPARAM) nmhdr->idFrom, (LPARAM)nmhdr);
227 static LPWSTR
228 TOOLBAR_GetText(TOOLBAR_INFO *infoPtr, TBUTTON_INFO *btnPtr)
230 LPWSTR lpText = NULL;
232 /* FIXME: iString == -1 is undocumented */
233 if ((HIWORD(btnPtr->iString) != 0) && (btnPtr->iString != -1))
234 lpText = (LPWSTR)btnPtr->iString;
235 else if ((btnPtr->iString >= 0) && (btnPtr->iString < infoPtr->nNumStrings))
236 lpText = infoPtr->strings[btnPtr->iString];
238 return lpText;
241 /***********************************************************************
242 * TOOLBAR_GetBitmapIndex
244 * This function returns the bitmap index associated with a button.
245 * If the button specifies I_IMAGECALLBACK, then the TBN_GETDISPINFO
246 * is issued to retrieve the index.
248 static INT
249 TOOLBAR_GetBitmapIndex(TOOLBAR_INFO *infoPtr, TBUTTON_INFO *btnPtr)
251 INT ret = btnPtr->iBitmap;
253 if (ret == I_IMAGECALLBACK) {
254 /* issue TBN_GETDISPINFO */
255 NMTBDISPINFOA nmgd;
257 nmgd.idCommand = btnPtr->idCommand;
258 nmgd.lParam = btnPtr->dwData;
259 nmgd.dwMask = TBNF_IMAGE;
260 TOOLBAR_SendNotify ((NMHDR *) &nmgd, infoPtr,
261 (infoPtr->bNtfUnicode) ? TBN_GETDISPINFOW :
262 TBN_GETDISPINFOA);
263 if (nmgd.dwMask & TBNF_DI_SETITEM) {
264 btnPtr->iBitmap = nmgd.iImage;
266 ret = nmgd.iImage;
267 TRACE("TBN_GETDISPINFOA returned bitmap id %d, mask=%08lx, nNumBitmaps=%d\n",
268 ret, nmgd.dwMask, infoPtr->nNumBitmaps);
270 return ret;
274 static BOOL
275 TOOLBAR_IsValidBitmapIndex(TOOLBAR_INFO *infoPtr, INT index)
277 if (((index>=0) && (index <= infoPtr->nNumBitmaps)) ||
278 (index == I_IMAGECALLBACK))
279 return TRUE;
280 else
281 return FALSE;
285 /***********************************************************************
286 * TOOLBAR_DrawImageList
288 * This function validates the bitmap index (including I_IMAGECALLBACK
289 * functionality). It then draws the image via the ImageList_Draw
290 * function. It returns TRUE if the image was drawn, FALSE otherwise.
292 static BOOL
293 TOOLBAR_DrawImageList (TOOLBAR_INFO *infoPtr, TBUTTON_INFO *btnPtr, HIMAGELIST himl,
294 HDC hdc, UINT left, UINT top, UINT draw_flags)
296 INT index;
298 if (!himl) return FALSE;
300 if (!TOOLBAR_IsValidBitmapIndex(infoPtr,btnPtr->iBitmap)) {
301 ERR("index %d is not valid, max %d\n",
302 btnPtr->iBitmap, infoPtr->nNumBitmaps);
303 return FALSE;
306 if ((index = TOOLBAR_GetBitmapIndex(infoPtr, btnPtr)) < 0) {
307 if (index == -1) return FALSE;
308 ERR("TBN_GETDISPINFO returned invalid index %d\n",
309 index);
310 return FALSE;
312 TRACE("drawing index=%d, himl=%p, left=%d, top=%d, flags=%08x\n",
313 index, himl, left, top, draw_flags);
315 ImageList_Draw (himl, index, hdc, left, top, draw_flags);
316 return TRUE;
320 /***********************************************************************
321 * TOOLBAR_TestImageExist
323 * This function is similar to TOOLBAR_DrawImageList, except it does not
324 * draw the image. The I_IMAGECALLBACK functionality is implemented.
326 static BOOL
327 TOOLBAR_TestImageExist (TOOLBAR_INFO *infoPtr, TBUTTON_INFO *btnPtr, HIMAGELIST himl)
329 INT index;
331 if (!himl) return FALSE;
333 if (!TOOLBAR_IsValidBitmapIndex(infoPtr,btnPtr->iBitmap)) {
334 ERR("index %d is not valid, max %d\n",
335 btnPtr->iBitmap, infoPtr->nNumBitmaps);
336 return FALSE;
339 if ((index = TOOLBAR_GetBitmapIndex(infoPtr, btnPtr)) < 0) {
340 if (index == -1) return FALSE;
341 ERR("TBN_GETDISPINFO returned invalid index %d\n",
342 index);
343 return FALSE;
345 return TRUE;
349 static void
350 TOOLBAR_DrawFlatSeparator (LPRECT lpRect, HDC hdc)
352 INT x = (lpRect->left + lpRect->right) / 2 - 1;
353 INT yBottom = lpRect->bottom - 3;
354 INT yTop = lpRect->top + 1;
356 SelectObject ( hdc, GetSysColorPen (COLOR_3DSHADOW));
357 MoveToEx (hdc, x, yBottom, NULL);
358 LineTo (hdc, x, yTop);
359 x++;
360 SelectObject ( hdc, GetSysColorPen (COLOR_3DHILIGHT));
361 MoveToEx (hdc, x, yBottom, NULL);
362 LineTo (hdc, x, yTop);
366 /***********************************************************************
367 * TOOLBAR_DrawDDFlatSeparator
369 * This function draws the separator that was flaged as TBSTYLE_DROPDOWN.
370 * In this case, the separator is a pixel high line of COLOR_BTNSHADOW,
371 * followed by a pixel high line of COLOR_BTNHIGHLIGHT. These separators
372 * are horizontal as opposed to the vertical separators for not dropdown
373 * type.
375 * FIXME: It is possible that the height of each line is really SM_CYBORDER.
377 static void
378 TOOLBAR_DrawDDFlatSeparator (LPRECT lpRect, HDC hdc, TBUTTON_INFO *btnPtr)
380 RECT myrect;
381 COLORREF oldcolor, newcolor;
383 myrect.left = lpRect->left;
384 myrect.right = lpRect->right;
385 myrect.top = lpRect->top + (lpRect->bottom - lpRect->top - 2)/2;
386 myrect.bottom = myrect.top + 1;
388 InflateRect (&myrect, -2, 0);
390 TRACE("rect=(%d,%d)-(%d,%d)\n",
391 myrect.left, myrect.top, myrect.right, myrect.bottom);
393 newcolor = GetSysColor (COLOR_BTNSHADOW);
394 oldcolor = SetBkColor (hdc, newcolor);
395 ExtTextOutA (hdc, 0, 0, ETO_OPAQUE, &myrect, 0, 0, 0);
397 myrect.top = myrect.bottom;
398 myrect.bottom = myrect.top + 1;
400 newcolor = GetSysColor (COLOR_BTNHIGHLIGHT);
401 SetBkColor (hdc, newcolor);
402 ExtTextOutA (hdc, 0, 0, ETO_OPAQUE, &myrect, 0, 0, 0);
404 SetBkColor (hdc, oldcolor);
408 static void
409 TOOLBAR_DrawArrow (HDC hdc, INT left, INT top, INT colorRef)
411 INT x, y;
412 SelectObject ( hdc, GetSysColorPen (colorRef));
413 x = left + 2;
414 y = top + 8;
415 MoveToEx (hdc, x, y, NULL);
416 LineTo (hdc, x+5, y++); x++;
417 MoveToEx (hdc, x, y, NULL);
418 LineTo (hdc, x+3, y++); x++;
419 MoveToEx (hdc, x, y, NULL);
420 LineTo (hdc, x+1, y++);
424 * Draw the text string for this button.
425 * note: infoPtr->himlDis *SHOULD* be non-zero when infoPtr->himlDef
426 * is non-zero, so we can simply check himlDef to see if we have
427 * an image list
429 static void
430 TOOLBAR_DrawString (TOOLBAR_INFO *infoPtr, TBUTTON_INFO *btnPtr,
431 HDC hdc, INT nState, DWORD dwStyle)
433 RECT rcText = btnPtr->rect;
434 HFONT hOldFont;
435 COLORREF clrOld;
436 LPWSTR lpText = NULL;
437 HIMAGELIST himl = infoPtr->himlDef;
439 TRACE ("iString: %x\n", btnPtr->iString);
441 /* get a pointer to the text */
442 lpText = TOOLBAR_GetText(infoPtr, btnPtr);
444 TRACE ("lpText: %s\n", debugstr_w(lpText));
446 /* draw text */
447 if (lpText) {
449 InflateRect (&rcText, -3, -3);
451 if (himl && TOOLBAR_IsValidBitmapIndex(infoPtr,btnPtr->iBitmap)) {
452 /* The following test looked like this before
453 * I changed it. IE4 "Links" toolbar would not
454 * draw correctly with the original code. - GA 8/01
455 * ((dwStyle & TBSTYLE_LIST) &&
456 * ((btnPtr->fsStyle & TBSTYLE_AUTOSIZE) == 0) &&
457 * (btnPtr->iBitmap != I_IMAGENONE))
459 if (dwStyle & TBSTYLE_LIST) {
460 /* LIST style w/ ICON offset is by matching native. */
461 /* Matches IE4 "Links" bar. - GA 8/01 */
462 rcText.left += (infoPtr->nBitmapWidth + 2);
464 else {
465 rcText.top += infoPtr->nBitmapHeight + 1;
468 else {
469 if (dwStyle & TBSTYLE_LIST) {
470 /* LIST style w/o ICON offset is by matching native. */
471 /* Matches IE4 "menu" bar. - GA 8/01 */
472 rcText.left += 4;
476 if (nState & (TBSTATE_PRESSED | TBSTATE_CHECKED))
477 OffsetRect (&rcText, 1, 1);
479 TRACE("string rect=(%d,%d)-(%d,%d)\n",
480 rcText.left, rcText.top, rcText.right, rcText.bottom);
482 hOldFont = SelectObject (hdc, infoPtr->hFont);
483 if (!(nState & TBSTATE_ENABLED)) {
484 clrOld = SetTextColor (hdc, GetSysColor (COLOR_3DHILIGHT));
485 OffsetRect (&rcText, 1, 1);
486 DrawTextW (hdc, lpText, -1, &rcText, infoPtr->dwDTFlags);
487 SetTextColor (hdc, GetSysColor (COLOR_3DSHADOW));
488 OffsetRect (&rcText, -1, -1);
489 DrawTextW (hdc, lpText, -1, &rcText, infoPtr->dwDTFlags);
491 else if (nState & TBSTATE_INDETERMINATE) {
492 clrOld = SetTextColor (hdc, GetSysColor (COLOR_3DSHADOW));
493 DrawTextW (hdc, lpText, -1, &rcText, infoPtr->dwDTFlags);
495 else {
496 clrOld = SetTextColor (hdc, GetSysColor (COLOR_BTNTEXT));
497 DrawTextW (hdc, lpText, -1, &rcText, infoPtr->dwDTFlags);
500 SetTextColor (hdc, clrOld);
501 SelectObject (hdc, hOldFont);
506 static void
507 TOOLBAR_DrawPattern (HDC hdc, LPRECT lpRect)
509 HBRUSH hbr = SelectObject (hdc, COMCTL32_hPattern55AABrush);
510 INT cx = lpRect->right - lpRect->left;
511 INT cy = lpRect->bottom - lpRect->top;
512 PatBlt (hdc, lpRect->left, lpRect->top, cx, cy, 0x00FA0089);
513 SelectObject (hdc, hbr);
517 static void
518 TOOLBAR_DrawMasked (TOOLBAR_INFO *infoPtr, TBUTTON_INFO *btnPtr,
519 HDC hdc, INT x, INT y)
521 /* FIXME: this function is a hack since it uses image list
522 internals directly */
524 HIMAGELIST himl = infoPtr->himlDef;
525 HBITMAP hbmMask;
526 HDC hdcImageList;
527 HDC hdcMask;
529 if (!himl)
530 return;
532 /* create new dc's */
533 hdcImageList = CreateCompatibleDC (0);
534 hdcMask = CreateCompatibleDC (0);
536 /* create new bitmap */
537 hbmMask = CreateBitmap (himl->cx, himl->cy, 1, 1, NULL);
538 SelectObject (hdcMask, hbmMask);
540 /* copy the mask bitmap */
541 SelectObject (hdcImageList, himl->hbmMask);
542 SetBkColor (hdcImageList, RGB(255, 255, 255));
543 SetTextColor (hdcImageList, RGB(0, 0, 0));
544 BitBlt (hdcMask, 0, 0, himl->cx, himl->cy,
545 hdcImageList, himl->cx * btnPtr->iBitmap, 0, SRCCOPY);
547 /* draw the new mask */
548 SelectObject (hdc, GetSysColorBrush (COLOR_3DHILIGHT));
549 BitBlt (hdc, x+1, y+1, himl->cx, himl->cy,
550 hdcMask, 0, 0, 0xB8074A);
552 SelectObject (hdc, GetSysColorBrush (COLOR_3DSHADOW));
553 BitBlt (hdc, x, y, himl->cx, himl->cy,
554 hdcMask, 0, 0, 0xB8074A);
556 DeleteObject (hbmMask);
557 DeleteDC (hdcMask);
558 DeleteDC (hdcImageList);
562 static void
563 TOOLBAR_DrawButton (HWND hwnd, TBUTTON_INFO *btnPtr, HDC hdc)
565 TOOLBAR_INFO *infoPtr = TOOLBAR_GetInfoPtr (hwnd);
566 DWORD dwStyle = GetWindowLongA (hwnd, GWL_STYLE);
567 BOOL hasDropDownArrow = TOOLBAR_HasDropDownArrows(infoPtr->dwExStyle) &&
568 (btnPtr->fsStyle & TBSTYLE_DROPDOWN);
569 RECT rc, rcArrow, rcBitmap;
571 if (btnPtr->fsState & TBSTATE_HIDDEN)
572 return;
574 rc = btnPtr->rect;
575 CopyRect (&rcArrow, &rc);
576 CopyRect(&rcBitmap, &rc);
578 if (!infoPtr->bBtnTranspnt)
579 FillRect( hdc, &rc, GetSysColorBrush(COLOR_BTNFACE));
581 if (hasDropDownArrow)
583 if (dwStyle & TBSTYLE_FLAT)
584 rc.right = max(rc.left, rc.right - DDARROW_WIDTH);
585 else
586 rc.right = max(rc.left, rc.right - DDARROW_WIDTH - 2);
587 rcArrow.left = rc.right;
590 /* Center the bitmap horizontally and vertically */
591 if (dwStyle & TBSTYLE_LIST)
592 rcBitmap.left += 3;
593 else
594 rcBitmap.left+=(infoPtr->nButtonWidth - infoPtr->nBitmapWidth) / 2;
596 if(TOOLBAR_HasText(infoPtr, btnPtr))
597 rcBitmap.top+=2; /* this looks to be the correct value from vmware comparison - cmm */
598 else
599 rcBitmap.top+=(infoPtr->nButtonHeight - infoPtr->nBitmapHeight) / 2;
601 TRACE("iBitmap: %d, start=(%d,%d) w=%d, h=%d\n",
602 btnPtr->iBitmap, rcBitmap.left, rcBitmap.top,
603 infoPtr->nBitmapWidth, infoPtr->nBitmapHeight);
605 /* separator */
606 if (btnPtr->fsStyle & TBSTYLE_SEP) {
607 /* with the FLAT style, iBitmap is the width and has already */
608 /* been taken into consideration in calculating the width */
609 /* so now we need to draw the vertical separator */
610 /* empirical tests show that iBitmap can/will be non-zero */
611 /* when drawing the vertical bar... */
612 if ((dwStyle & TBSTYLE_FLAT) /* && (btnPtr->iBitmap == 0) */) {
613 if (btnPtr->fsStyle & TBSTYLE_DROPDOWN)
614 TOOLBAR_DrawDDFlatSeparator (&rc, hdc, btnPtr);
615 else
616 TOOLBAR_DrawFlatSeparator (&rc, hdc);
618 return;
621 /* disabled */
622 if (!(btnPtr->fsState & TBSTATE_ENABLED)) {
623 if (!(dwStyle & TBSTYLE_FLAT))
625 DrawEdge (hdc, &rc, EDGE_RAISED,
626 BF_SOFT | BF_RECT | BF_MIDDLE | BF_ADJUST);
627 if (hasDropDownArrow)
628 DrawEdge (hdc, &rcArrow, EDGE_RAISED,
629 BF_SOFT | BF_RECT | BF_MIDDLE | BF_ADJUST);
632 if (hasDropDownArrow)
634 TOOLBAR_DrawArrow(hdc, rcArrow.left+1, rcArrow.top+1, COLOR_3DHIGHLIGHT);
635 TOOLBAR_DrawArrow(hdc, rcArrow.left, rcArrow.top, COLOR_3DSHADOW);
638 if (!TOOLBAR_DrawImageList (infoPtr, btnPtr, infoPtr->himlDis,
639 hdc, rcBitmap.left, rcBitmap.top,
640 ILD_NORMAL))
641 TOOLBAR_DrawMasked (infoPtr, btnPtr, hdc, rcBitmap.left, rcBitmap.top);
643 TOOLBAR_DrawString (infoPtr, btnPtr, hdc, btnPtr->fsState, dwStyle);
644 return;
647 /* pressed TBSTYLE_BUTTON */
648 if (btnPtr->fsState & TBSTATE_PRESSED) {
649 if (dwStyle & TBSTYLE_FLAT)
651 DrawEdge (hdc, &rc, BDR_SUNKENOUTER, BF_RECT | BF_ADJUST);
652 if (hasDropDownArrow)
653 DrawEdge (hdc, &rcArrow, BDR_SUNKENOUTER, BF_RECT | BF_ADJUST);
655 else
657 DrawEdge (hdc, &rc, EDGE_SUNKEN, BF_RECT | BF_MIDDLE | BF_ADJUST);
658 if (hasDropDownArrow)
659 DrawEdge (hdc, &rcArrow, EDGE_SUNKEN, BF_RECT | BF_MIDDLE | BF_ADJUST);
662 if (hasDropDownArrow)
663 TOOLBAR_DrawArrow(hdc, rcArrow.left, rcArrow.top, COLOR_WINDOWFRAME);
665 TOOLBAR_DrawImageList (infoPtr, btnPtr, infoPtr->himlDef,
666 hdc, rcBitmap.left+1, rcBitmap.top+1,
667 ILD_NORMAL);
669 TOOLBAR_DrawString (infoPtr, btnPtr, hdc, btnPtr->fsState, dwStyle);
670 return;
673 /* checked TBSTYLE_CHECK */
674 if ((btnPtr->fsStyle & TBSTYLE_CHECK) &&
675 (btnPtr->fsState & TBSTATE_CHECKED)) {
676 if (dwStyle & TBSTYLE_FLAT)
677 DrawEdge (hdc, &rc, BDR_SUNKENOUTER,
678 BF_RECT | BF_ADJUST);
679 else
680 DrawEdge (hdc, &rc, EDGE_SUNKEN,
681 BF_RECT | BF_MIDDLE | BF_ADJUST);
683 TOOLBAR_DrawPattern (hdc, &rc);
685 TOOLBAR_DrawImageList (infoPtr, btnPtr, infoPtr->himlDef,
686 hdc, rcBitmap.left+1, rcBitmap.top+1,
687 ILD_NORMAL);
689 TOOLBAR_DrawString (infoPtr, btnPtr, hdc, btnPtr->fsState, dwStyle);
690 return;
693 /* indeterminate */
694 if (btnPtr->fsState & TBSTATE_INDETERMINATE) {
695 DrawEdge (hdc, &rc, EDGE_RAISED,
696 BF_SOFT | BF_RECT | BF_MIDDLE | BF_ADJUST);
698 TOOLBAR_DrawPattern (hdc, &rc);
699 TOOLBAR_DrawMasked (infoPtr, btnPtr, hdc, rcBitmap.left, rcBitmap.top);
700 TOOLBAR_DrawString (infoPtr, btnPtr, hdc, btnPtr->fsState, dwStyle);
701 return;
704 /* normal state */
705 if (dwStyle & TBSTYLE_FLAT)
707 if (btnPtr->bHot)
709 DrawEdge (hdc, &rc, BDR_RAISEDINNER, BF_RECT);
710 if (hasDropDownArrow)
711 DrawEdge (hdc, &rcArrow, BDR_RAISEDINNER, BF_RECT);
713 #if 1
714 else /* The following code needs to be removed after
715 * "hot item" support has been implemented for the
716 * case where it is being de-selected.
719 FrameRect(hdc, &rc, GetSysColorBrush(COLOR_BTNFACE));
720 if (hasDropDownArrow)
721 FrameRect(hdc, &rcArrow, GetSysColorBrush(COLOR_BTNFACE));
723 #endif
725 if (hasDropDownArrow)
726 TOOLBAR_DrawArrow(hdc, rcArrow.left+1, rcArrow.top, COLOR_WINDOWFRAME);
728 if (btnPtr->bHot) {
729 /* if hot, attempt to draw with himlHot, if fails, use himlDef */
730 if (!TOOLBAR_DrawImageList (infoPtr, btnPtr,
731 infoPtr->himlHot,
732 hdc, rcBitmap.left,
733 rcBitmap.top, ILD_NORMAL))
734 TOOLBAR_DrawImageList (infoPtr, btnPtr, infoPtr->himlDef,
735 hdc, rcBitmap.left, rcBitmap.top,
736 ILD_NORMAL);
738 else
739 TOOLBAR_DrawImageList (infoPtr, btnPtr, infoPtr->himlDef,
740 hdc, rcBitmap.left, rcBitmap.top,
741 ILD_NORMAL);
743 else
745 DrawEdge (hdc, &rc, EDGE_RAISED,
746 BF_SOFT | BF_RECT | BF_MIDDLE | BF_ADJUST);
748 if (hasDropDownArrow)
750 DrawEdge (hdc, &rcArrow, EDGE_RAISED,
751 BF_SOFT | BF_RECT | BF_MIDDLE | BF_ADJUST);
752 TOOLBAR_DrawArrow(hdc, rcArrow.left, rcArrow.top, COLOR_WINDOWFRAME);
755 TOOLBAR_DrawImageList (infoPtr, btnPtr, infoPtr->himlDef,
756 hdc, rcBitmap.left, rcBitmap.top,
757 ILD_NORMAL);
760 TOOLBAR_DrawString (infoPtr, btnPtr, hdc, btnPtr->fsState, dwStyle);
764 static void
765 TOOLBAR_Refresh (HWND hwnd, HDC hdc, PAINTSTRUCT* ps)
767 TOOLBAR_INFO *infoPtr = TOOLBAR_GetInfoPtr (hwnd);
768 TBUTTON_INFO *btnPtr;
769 INT i, oldBKmode = 0;
770 RECT rcTemp;
772 /* if imagelist belongs to the app, it can be changed
773 by the app after setting it */
774 if (infoPtr->himlDef != infoPtr->himlInt)
775 infoPtr->nNumBitmaps = ImageList_GetImageCount(infoPtr->himlDef);
777 TOOLBAR_DumpToolbar (infoPtr, __LINE__);
779 if (infoPtr->bBtnTranspnt)
780 oldBKmode = SetBkMode (hdc, TRANSPARENT);
782 /* redraw necessary buttons */
783 btnPtr = infoPtr->buttons;
784 for (i = 0; i < infoPtr->nNumButtons; i++, btnPtr++)
786 if(IntersectRect(&rcTemp, &(ps->rcPaint), &(btnPtr->rect)))
787 TOOLBAR_DrawButton (hwnd, btnPtr, hdc);
790 if (infoPtr->bBtnTranspnt && (oldBKmode != TRANSPARENT))
791 SetBkMode (hdc, oldBKmode);
794 /***********************************************************************
795 * TOOLBAR_MeasureString
797 * This function gets the width and height of a string in pixels. This
798 * is done first by using GetTextExtentPoint to get the basic width
799 * and height. The DrawText is called with DT_CALCRECT to get the exact
800 * width. The reason is because the text may have more than one "&" (or
801 * prefix characters as M$ likes to call them). The prefix character
802 * indicates where the underline goes, except for the string "&&" which
803 * is reduced to a single "&". GetTextExtentPoint does not process these
804 * only DrawText does. Note that the TBSTYLE_NOPREFIX is handled here.
806 static void
807 TOOLBAR_MeasureString(TOOLBAR_INFO *infoPtr, TBUTTON_INFO *btnPtr,
808 HDC hdc, LPSIZE lpSize)
810 RECT myrect;
812 lpSize->cx = 0;
813 lpSize->cy = 0;
815 if (!(btnPtr->fsState & TBSTATE_HIDDEN) &&
816 (btnPtr->iString > -1) &&
817 (btnPtr->iString < infoPtr->nNumStrings))
819 LPWSTR lpText = infoPtr->strings[btnPtr->iString];
821 /* first get size of all the text */
822 GetTextExtentPoint32W (hdc, lpText, strlenW (lpText), lpSize);
824 /* feed above size into the rectangle for DrawText */
825 myrect.left = myrect.top = 0;
826 myrect.right = lpSize->cx;
827 myrect.bottom = lpSize->cy;
829 /* Use DrawText to get true size as drawn (less pesky "&") */
830 DrawTextW (hdc, lpText, -1, &myrect, DT_VCENTER | DT_SINGLELINE |
831 DT_CALCRECT | ((btnPtr->fsStyle & TBSTYLE_NOPREFIX) ?
832 DT_NOPREFIX : 0));
834 /* feed back to caller */
835 lpSize->cx = myrect.right;
836 lpSize->cy = myrect.bottom;
839 TRACE("string size %ld x %ld!\n", lpSize->cx, lpSize->cy);
842 /***********************************************************************
843 * TOOLBAR_CalcStrings
845 * This function walks through each string and measures it and returns
846 * the largest height and width to caller.
848 static void
849 TOOLBAR_CalcStrings (HWND hwnd, LPSIZE lpSize)
851 TOOLBAR_INFO *infoPtr = TOOLBAR_GetInfoPtr (hwnd);
852 TBUTTON_INFO *btnPtr;
853 INT i;
854 SIZE sz;
855 HDC hdc;
856 HFONT hOldFont;
858 lpSize->cx = 0;
859 lpSize->cy = 0;
861 hdc = GetDC (hwnd);
862 hOldFont = SelectObject (hdc, infoPtr->hFont);
864 btnPtr = infoPtr->buttons;
865 for (i = 0; i < infoPtr->nNumButtons; i++, btnPtr++) {
866 if(TOOLBAR_HasText(infoPtr, btnPtr))
868 TOOLBAR_MeasureString(infoPtr, btnPtr, hdc, &sz);
869 if (sz.cx > lpSize->cx)
870 lpSize->cx = sz.cx;
871 if (sz.cy > lpSize->cy)
872 lpSize->cy = sz.cy;
876 SelectObject (hdc, hOldFont);
877 ReleaseDC (hwnd, hdc);
879 TRACE("max string size %ld x %ld!\n", lpSize->cx, lpSize->cy);
882 /***********************************************************************
883 * TOOLBAR_WrapToolbar
885 * This function walks through the buttons and seperators in the
886 * toolbar, and sets the TBSTATE_WRAP flag only on those items where
887 * wrapping should occur based on the width of the toolbar window.
888 * It does *not* calculate button placement itself. That task
889 * takes place in TOOLBAR_CalcToolbar. If the program wants to manage
890 * the toolbar wrapping on its own, it can use the TBSTYLE_WRAPABLE
891 * flag, and set the TBSTATE_WRAP flags manually on the appropriate items.
894 static void
895 TOOLBAR_WrapToolbar( HWND hwnd, DWORD dwStyle )
897 TOOLBAR_INFO *infoPtr = TOOLBAR_GetInfoPtr (hwnd);
898 TBUTTON_INFO *btnPtr;
899 INT x, cx, i, j;
900 RECT rc;
901 BOOL bWrap, bButtonWrap;
903 /* When the toolbar window style is not TBSTYLE_WRAPABLE, */
904 /* no layout is necessary. Applications may use this style */
905 /* to perform their own layout on the toolbar. */
906 if( !(dwStyle & TBSTYLE_WRAPABLE) )
907 return;
909 btnPtr = infoPtr->buttons;
910 x = infoPtr->nIndent;
912 /* this can get the parents width, to know how far we can extend
913 * this toolbar. We cannot use its height, as there may be multiple
914 * toolbars in a rebar control
916 GetClientRect( GetParent(hwnd), &rc );
917 infoPtr->nWidth = rc.right - rc.left;
918 bButtonWrap = FALSE;
920 TRACE("start ButtonWidth=%d, BitmapWidth=%d, nWidth=%d, nIndent=%d\n",
921 infoPtr->nButtonWidth, infoPtr->nBitmapWidth, infoPtr->nWidth,
922 infoPtr->nIndent);
924 for (i = 0; i < infoPtr->nNumButtons; i++ )
926 bWrap = FALSE;
927 btnPtr[i].fsState &= ~TBSTATE_WRAP;
929 if (btnPtr[i].fsState & TBSTATE_HIDDEN)
930 continue;
932 /* UNDOCUMENTED: If a separator has a non zero bitmap index, */
933 /* it is the actual width of the separator. This is used for */
934 /* custom controls in toolbars. */
935 /* */
936 /* TBSTYLE_DROPDOWN separators are treated as buttons for */
937 /* width. - GA 8/01 */
938 if ((btnPtr[i].fsStyle & TBSTYLE_SEP) &&
939 !(btnPtr[i].fsStyle & TBSTYLE_DROPDOWN))
940 cx = (btnPtr[i].iBitmap > 0) ?
941 btnPtr[i].iBitmap : SEPARATOR_WIDTH;
942 else
943 cx = infoPtr->nButtonWidth;
945 /* Two or more adjacent separators form a separator group. */
946 /* The first separator in a group should be wrapped to the */
947 /* next row if the previous wrapping is on a button. */
948 if( bButtonWrap &&
949 (btnPtr[i].fsStyle & TBSTYLE_SEP) &&
950 (i + 1 < infoPtr->nNumButtons ) &&
951 (btnPtr[i + 1].fsStyle & TBSTYLE_SEP) )
953 TRACE("wrap point 1 btn %d style %02x\n", i, btnPtr[i].fsStyle);
954 btnPtr[i].fsState |= TBSTATE_WRAP;
955 x = infoPtr->nIndent;
956 i++;
957 bButtonWrap = FALSE;
958 continue;
961 /* The layout makes sure the bitmap is visible, but not the button. */
962 /* Test added to also wrap after a button that starts a row but */
963 /* is bigger than the area. - GA 8/01 */
964 if (( x + cx - (infoPtr->nButtonWidth - infoPtr->nBitmapWidth) / 2
965 > infoPtr->nWidth ) ||
966 ((x == infoPtr->nIndent) && (cx > infoPtr->nWidth)))
968 BOOL bFound = FALSE;
970 /* If the current button is a separator and not hidden, */
971 /* go to the next until it reaches a non separator. */
972 /* Wrap the last separator if it is before a button. */
973 while( ( (btnPtr[i].fsStyle & TBSTYLE_SEP) ||
974 (btnPtr[i].fsState & TBSTATE_HIDDEN) ) &&
975 i < infoPtr->nNumButtons )
977 i++;
978 bFound = TRUE;
981 if( bFound && i < infoPtr->nNumButtons )
983 i--;
984 TRACE("wrap point 2 btn %d style %02x, x=%d, cx=%d\n",
985 i, btnPtr[i].fsStyle, x, cx);
986 btnPtr[i].fsState |= TBSTATE_WRAP;
987 x = infoPtr->nIndent;
988 bButtonWrap = FALSE;
989 continue;
991 else if ( i >= infoPtr->nNumButtons)
992 break;
994 /* If the current button is not a separator, find the last */
995 /* separator and wrap it. */
996 for ( j = i - 1; j >= 0 && !(btnPtr[j].fsState & TBSTATE_WRAP); j--)
998 if ((btnPtr[j].fsStyle & TBSTYLE_SEP) &&
999 !(btnPtr[j].fsState & TBSTATE_HIDDEN))
1001 bFound = TRUE;
1002 i = j;
1003 TRACE("wrap point 3 btn %d style %02x, x=%d, cx=%d\n",
1004 i, btnPtr[i].fsStyle, x, cx);
1005 x = infoPtr->nIndent;
1006 btnPtr[j].fsState |= TBSTATE_WRAP;
1007 bButtonWrap = FALSE;
1008 break;
1012 /* If no separator available for wrapping, wrap one of */
1013 /* non-hidden previous button. */
1014 if (!bFound)
1016 for ( j = i - 1;
1017 j >= 0 && !(btnPtr[j].fsState & TBSTATE_WRAP); j--)
1019 if (btnPtr[j].fsState & TBSTATE_HIDDEN)
1020 continue;
1022 bFound = TRUE;
1023 i = j;
1024 TRACE("wrap point 4 btn %d style %02x, x=%d, cx=%d\n",
1025 i, btnPtr[i].fsStyle, x, cx);
1026 x = infoPtr->nIndent;
1027 btnPtr[j].fsState |= TBSTATE_WRAP;
1028 bButtonWrap = TRUE;
1029 break;
1033 /* If all above failed, wrap the current button. */
1034 if (!bFound)
1036 TRACE("wrap point 5 btn %d style %02x, x=%d, cx=%d\n",
1037 i, btnPtr[i].fsStyle, x, cx);
1038 btnPtr[i].fsState |= TBSTATE_WRAP;
1039 bFound = TRUE;
1040 x = infoPtr->nIndent;
1041 if (btnPtr[i].fsStyle & TBSTYLE_SEP )
1042 bButtonWrap = FALSE;
1043 else
1044 bButtonWrap = TRUE;
1047 else {
1048 TRACE("wrap point 6 btn %d style %02x, x=%d, cx=%d\n",
1049 i, btnPtr[i].fsStyle, x, cx);
1050 x += cx;
1056 /***********************************************************************
1057 * TOOLBAR_CalcToolbar
1059 * This function calculates button and separator placement. It first
1060 * calculates the button sizes, gets the toolbar window width and then
1061 * calls TOOLBAR_WrapToolbar to determine which buttons we need to wrap
1062 * on. It assigns a new location to each item and sends this location to
1063 * the tooltip window if appropriate. Finally, it updates the rcBound
1064 * rect and calculates the new required toolbar window height.
1067 static void
1068 TOOLBAR_CalcToolbar (HWND hwnd)
1070 TOOLBAR_INFO *infoPtr = TOOLBAR_GetInfoPtr(hwnd);
1071 DWORD dwStyle = GetWindowLongA (hwnd, GWL_STYLE);
1072 TBUTTON_INFO *btnPtr;
1073 INT i, nRows, nSepRows;
1074 INT x, y, cx, cy;
1075 SIZE sizeString;
1076 BOOL bWrap;
1077 BOOL usesBitmaps = FALSE;
1078 BOOL hasDropDownArrows = TOOLBAR_HasDropDownArrows(infoPtr->dwExStyle);
1080 TOOLBAR_CalcStrings (hwnd, &sizeString);
1082 if (dwStyle & TBSTYLE_LIST)
1084 for (i = 0; i < infoPtr->nNumButtons && !usesBitmaps; i++)
1086 if (infoPtr->buttons[i].iBitmap >= 0)
1087 usesBitmaps = TRUE;
1089 infoPtr->nButtonHeight = max((usesBitmaps) ? infoPtr->nBitmapHeight :
1090 0, sizeString.cy) + 6;
1091 infoPtr->nButtonWidth = ((usesBitmaps) ? infoPtr->nBitmapWidth :
1092 0) + sizeString.cx + 6;
1093 TRACE("LIST style, But w=%d h=%d, useBitmaps=%d, Bit w=%d h=%d\n",
1094 infoPtr->nButtonWidth, infoPtr->nButtonHeight, usesBitmaps,
1095 infoPtr->nBitmapWidth, infoPtr->nBitmapHeight);
1096 TOOLBAR_DumpToolbar (infoPtr, __LINE__);
1098 else {
1099 for (i = 0; i < infoPtr->nNumButtons && !usesBitmaps; i++)
1101 if (TOOLBAR_IsValidBitmapIndex(infoPtr,infoPtr->buttons[i].iBitmap))
1102 usesBitmaps = TRUE;
1105 if (sizeString.cy > 0)
1107 if (usesBitmaps)
1108 infoPtr->nButtonHeight = sizeString.cy +
1109 2 + /* this is the space to separate text from bitmap */
1110 infoPtr->nBitmapHeight + 6;
1111 else
1112 infoPtr->nButtonHeight = sizeString.cy + 6;
1114 else if (infoPtr->nButtonHeight < infoPtr->nBitmapHeight + 6)
1115 infoPtr->nButtonHeight = infoPtr->nBitmapHeight + 6;
1117 if (sizeString.cx > infoPtr->nBitmapWidth)
1118 infoPtr->nButtonWidth = sizeString.cx + 6;
1119 else if (infoPtr->nButtonWidth < infoPtr->nBitmapWidth + 6)
1120 infoPtr->nButtonWidth = infoPtr->nBitmapWidth + 6;
1123 if ( infoPtr->cxMin >= 0 && infoPtr->nButtonWidth < infoPtr->cxMin )
1124 infoPtr->nButtonWidth = infoPtr->cxMin;
1125 if ( infoPtr->cxMax > 0 && infoPtr->nButtonWidth > infoPtr->cxMax )
1126 infoPtr->nButtonWidth = infoPtr->cxMax;
1128 TOOLBAR_WrapToolbar( hwnd, dwStyle );
1130 x = infoPtr->nIndent;
1131 y = 0;
1134 * We will set the height below, and we set the width on entry
1135 * so we do not reset them here..
1137 #if 0
1138 GetClientRect( hwnd, &rc );
1139 /* get initial values for toolbar */
1140 infoPtr->nWidth = rc.right - rc.left;
1141 infoPtr->nHeight = rc.bottom - rc.top;
1142 #endif
1144 /* from above, minimum is a button, and possible text */
1145 cx = infoPtr->nButtonWidth;
1147 /* cannot use just ButtonHeight, we may have no buttons! */
1148 if (infoPtr->nNumButtons > 0)
1149 infoPtr->nHeight = infoPtr->nButtonHeight;
1151 cy = infoPtr->nHeight;
1153 nRows = nSepRows = 0;
1155 infoPtr->rcBound.top = y;
1156 infoPtr->rcBound.left = x;
1157 infoPtr->rcBound.bottom = y + cy;
1158 infoPtr->rcBound.right = x;
1160 btnPtr = infoPtr->buttons;
1162 /* do not base height/width on parent, if the parent is a */
1163 /* rebar control it could have multiple rows of toolbars */
1164 /* GetClientRect( GetParent(hwnd), &rc ); */
1165 /* cx = rc.right - rc.left; */
1166 /* cy = rc.bottom - rc.top; */
1168 TRACE("cy=%d\n", cy);
1170 for (i = 0; i < infoPtr->nNumButtons; i++, btnPtr++ )
1172 bWrap = FALSE;
1173 if (btnPtr->fsState & TBSTATE_HIDDEN)
1175 SetRectEmpty (&btnPtr->rect);
1176 continue;
1179 cy = infoPtr->nHeight;
1181 /* UNDOCUMENTED: If a separator has a non zero bitmap index, */
1182 /* it is the actual width of the separator. This is used for */
1183 /* custom controls in toolbars. */
1184 if (btnPtr->fsStyle & TBSTYLE_SEP) {
1185 if (btnPtr->fsStyle & TBSTYLE_DROPDOWN) {
1186 cy = (btnPtr->iBitmap > 0) ?
1187 btnPtr->iBitmap : SEPARATOR_WIDTH;
1188 cx = infoPtr->nButtonWidth;
1190 else
1191 cx = (btnPtr->iBitmap > 0) ?
1192 btnPtr->iBitmap : SEPARATOR_WIDTH;
1194 else
1196 if (btnPtr->fsStyle & TBSTYLE_AUTOSIZE)
1198 SIZE sz;
1199 HDC hdc;
1200 HFONT hOldFont;
1202 hdc = GetDC (hwnd);
1203 hOldFont = SelectObject (hdc, infoPtr->hFont);
1205 TOOLBAR_MeasureString(infoPtr, btnPtr, hdc, &sz);
1207 SelectObject (hdc, hOldFont);
1208 ReleaseDC (hwnd, hdc);
1210 /* Fudge amount measured against IE4 "menu" and "Links" */
1211 /* toolbars with native control (v4.71). - GA 8/01 */
1212 cx = sz.cx + 6 + 5 + 5;
1213 if ((dwStyle & TBSTYLE_LIST) &&
1214 (TOOLBAR_TestImageExist (infoPtr, btnPtr, infoPtr->himlDef)))
1215 cx += infoPtr->nBitmapWidth;
1217 else
1218 cx = infoPtr->nButtonWidth;
1220 if (hasDropDownArrows && (btnPtr->fsStyle & TBSTYLE_DROPDOWN))
1221 cx += DDARROW_WIDTH;
1223 if (btnPtr->fsState & TBSTATE_WRAP )
1224 bWrap = TRUE;
1226 SetRect (&btnPtr->rect, x, y, x + cx, y + cy);
1228 if (infoPtr->rcBound.left > x)
1229 infoPtr->rcBound.left = x;
1230 if (infoPtr->rcBound.right < x + cx)
1231 infoPtr->rcBound.right = x + cx;
1232 if (infoPtr->rcBound.bottom < y + cy)
1233 infoPtr->rcBound.bottom = y + cy;
1235 /* Set the toolTip only for non-hidden, non-separator button */
1236 if (infoPtr->hwndToolTip && !(btnPtr->fsStyle & TBSTYLE_SEP ))
1238 TTTOOLINFOA ti;
1240 ZeroMemory (&ti, sizeof(TTTOOLINFOA));
1241 ti.cbSize = sizeof(TTTOOLINFOA);
1242 ti.hwnd = hwnd;
1243 ti.uId = btnPtr->idCommand;
1244 ti.rect = btnPtr->rect;
1245 SendMessageA (infoPtr->hwndToolTip, TTM_NEWTOOLRECTA,
1246 0, (LPARAM)&ti);
1249 /* btnPtr->nRow is zero based. The space between the rows is */
1250 /* also considered as a row. */
1251 btnPtr->nRow = nRows + nSepRows;
1253 TRACE("button %d style=%x, bWrap=%d, nRows=%d, nSepRows=%d, btnrow=%d\n",
1254 i, btnPtr->fsStyle, bWrap, nRows, nSepRows, btnPtr->nRow);
1256 if( bWrap )
1258 if ( !(btnPtr->fsStyle & TBSTYLE_SEP) )
1259 y += cy;
1260 else
1262 /* UNDOCUMENTED: If a separator has a non zero bitmap index, */
1263 /* it is the actual width of the separator. This is used for */
1264 /* custom controls in toolbars. */
1265 if ( !(btnPtr->fsStyle & TBSTYLE_DROPDOWN))
1266 y += cy + ( (btnPtr->iBitmap > 0 ) ?
1267 btnPtr->iBitmap : SEPARATOR_WIDTH) * 2 /3;
1268 else
1269 y += cy;
1271 /* nSepRows is used to calculate the extra height follwoing */
1272 /* the last row. */
1273 nSepRows++;
1275 x = infoPtr->nIndent;
1276 nRows++;
1278 else
1279 x += cx;
1282 /* infoPtr->nRows is the number of rows on the toolbar */
1283 infoPtr->nRows = nRows + nSepRows + 1;
1285 /* nSepRows * (infoPtr->nBitmapHeight + 1) is the space following */
1286 /* the last row. */
1287 infoPtr->nHeight = TOP_BORDER + (nRows + 1) * infoPtr->nButtonHeight +
1288 nSepRows * (SEPARATOR_WIDTH * 2 / 3) +
1289 nSepRows * (infoPtr->nBitmapHeight + 1) +
1290 BOTTOM_BORDER;
1291 TRACE("toolbar height %d, button width %d\n", infoPtr->nHeight, infoPtr->nButtonWidth);
1295 static INT
1296 TOOLBAR_InternalHitTest (HWND hwnd, LPPOINT lpPt)
1298 TOOLBAR_INFO *infoPtr = TOOLBAR_GetInfoPtr (hwnd);
1299 TBUTTON_INFO *btnPtr;
1300 INT i;
1302 btnPtr = infoPtr->buttons;
1303 for (i = 0; i < infoPtr->nNumButtons; i++, btnPtr++) {
1304 if (btnPtr->fsState & TBSTATE_HIDDEN)
1305 continue;
1307 if (btnPtr->fsStyle & TBSTYLE_SEP) {
1308 if (PtInRect (&btnPtr->rect, *lpPt)) {
1309 TRACE(" ON SEPARATOR %d!\n", i);
1310 return -i;
1313 else {
1314 if (PtInRect (&btnPtr->rect, *lpPt)) {
1315 TRACE(" ON BUTTON %d!\n", i);
1316 return i;
1321 TRACE(" NOWHERE!\n");
1322 return -1;
1326 static INT
1327 TOOLBAR_GetButtonIndex (TOOLBAR_INFO *infoPtr, INT idCommand, BOOL CommandIsIndex)
1329 TBUTTON_INFO *btnPtr;
1330 INT i;
1332 if (CommandIsIndex) {
1333 TRACE("command is really index command=%d\n", idCommand);
1334 return idCommand;
1336 btnPtr = infoPtr->buttons;
1337 for (i = 0; i < infoPtr->nNumButtons; i++, btnPtr++) {
1338 if (btnPtr->idCommand == idCommand) {
1339 TRACE("command=%d index=%d\n", idCommand, i);
1340 return i;
1343 TRACE("no index found for command=%d\n", idCommand);
1344 return -1;
1348 static INT
1349 TOOLBAR_GetCheckedGroupButtonIndex (TOOLBAR_INFO *infoPtr, INT nIndex)
1351 TBUTTON_INFO *btnPtr;
1352 INT nRunIndex;
1354 if ((nIndex < 0) || (nIndex > infoPtr->nNumButtons))
1355 return -1;
1357 /* check index button */
1358 btnPtr = &infoPtr->buttons[nIndex];
1359 if ((btnPtr->fsStyle & TBSTYLE_CHECKGROUP) == TBSTYLE_CHECKGROUP) {
1360 if (btnPtr->fsState & TBSTATE_CHECKED)
1361 return nIndex;
1364 /* check previous buttons */
1365 nRunIndex = nIndex - 1;
1366 while (nRunIndex >= 0) {
1367 btnPtr = &infoPtr->buttons[nRunIndex];
1368 if ((btnPtr->fsStyle & TBSTYLE_CHECKGROUP) == TBSTYLE_CHECKGROUP) {
1369 if (btnPtr->fsState & TBSTATE_CHECKED)
1370 return nRunIndex;
1372 else
1373 break;
1374 nRunIndex--;
1377 /* check next buttons */
1378 nRunIndex = nIndex + 1;
1379 while (nRunIndex < infoPtr->nNumButtons) {
1380 btnPtr = &infoPtr->buttons[nRunIndex];
1381 if ((btnPtr->fsStyle & TBSTYLE_CHECKGROUP) == TBSTYLE_CHECKGROUP) {
1382 if (btnPtr->fsState & TBSTATE_CHECKED)
1383 return nRunIndex;
1385 else
1386 break;
1387 nRunIndex++;
1390 return -1;
1394 static VOID
1395 TOOLBAR_RelayEvent (HWND hwndTip, HWND hwndMsg, UINT uMsg,
1396 WPARAM wParam, LPARAM lParam)
1398 MSG msg;
1400 msg.hwnd = hwndMsg;
1401 msg.message = uMsg;
1402 msg.wParam = wParam;
1403 msg.lParam = lParam;
1404 msg.time = GetMessageTime ();
1405 msg.pt.x = LOWORD(GetMessagePos ());
1406 msg.pt.y = HIWORD(GetMessagePos ());
1408 SendMessageA (hwndTip, TTM_RELAYEVENT, 0, (LPARAM)&msg);
1412 /***********************************************************************
1413 * TOOLBAR_CustomizeDialogProc
1414 * This function implements the toolbar customization dialog.
1416 static BOOL WINAPI
1417 TOOLBAR_CustomizeDialogProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
1419 PCUSTDLG_INFO custInfo = (PCUSTDLG_INFO)GetWindowLongA (hwnd, DWL_USER);
1420 PCUSTOMBUTTON btnInfo;
1421 NMTOOLBARA nmtb;
1422 TOOLBAR_INFO *infoPtr = custInfo ? custInfo->tbInfo : NULL;
1424 switch (uMsg)
1426 case WM_INITDIALOG:
1427 custInfo = (PCUSTDLG_INFO)lParam;
1428 SetWindowLongA (hwnd, DWL_USER, (DWORD)custInfo);
1430 if (custInfo)
1432 char Buffer[256];
1433 int i = 0;
1434 int index;
1436 infoPtr = custInfo->tbInfo;
1438 /* send TBN_QUERYINSERT notification */
1439 nmtb.iItem = custInfo->tbInfo->nNumButtons;
1441 if (!TOOLBAR_SendNotify ((NMHDR *) &nmtb, infoPtr, TBN_QUERYINSERT))
1442 return FALSE;
1444 /* add items to 'toolbar buttons' list and check if removable */
1445 for (i = 0; i < custInfo->tbInfo->nNumButtons; i++)
1447 btnInfo = (PCUSTOMBUTTON)COMCTL32_Alloc(sizeof(CUSTOMBUTTON));
1448 memset (&btnInfo->btn, 0, sizeof(TBBUTTON));
1449 btnInfo->btn.fsStyle = TBSTYLE_SEP;
1450 btnInfo->bVirtual = FALSE;
1451 LoadStringA (COMCTL32_hModule, IDS_SEPARATOR, btnInfo->text, 64);
1453 /* send TBN_QUERYDELETE notification */
1454 nmtb.iItem = i;
1455 btnInfo->bRemovable = TOOLBAR_SendNotify ((NMHDR *) &nmtb,
1456 infoPtr,
1457 TBN_QUERYDELETE);
1459 index = (int)SendDlgItemMessageA (hwnd, IDC_TOOLBARBTN_LBOX, LB_ADDSTRING, 0, 0);
1460 SendDlgItemMessageA (hwnd, IDC_TOOLBARBTN_LBOX, LB_SETITEMDATA, index, (LPARAM)btnInfo);
1463 /* insert separator button into 'available buttons' list */
1464 btnInfo = (PCUSTOMBUTTON)COMCTL32_Alloc(sizeof(CUSTOMBUTTON));
1465 memset (&btnInfo->btn, 0, sizeof(TBBUTTON));
1466 btnInfo->btn.fsStyle = TBSTYLE_SEP;
1467 btnInfo->bVirtual = FALSE;
1468 btnInfo->bRemovable = TRUE;
1469 LoadStringA (COMCTL32_hModule, IDS_SEPARATOR, btnInfo->text, 64);
1470 index = (int)SendDlgItemMessageA (hwnd, IDC_AVAILBTN_LBOX, LB_ADDSTRING, 0, (LPARAM)btnInfo);
1471 SendDlgItemMessageA (hwnd, IDC_AVAILBTN_LBOX, LB_SETITEMDATA, index, (LPARAM)btnInfo);
1473 /* insert all buttons into dsa */
1474 for (i = 0;; i++)
1476 /* send TBN_GETBUTTONINFO notification */
1477 nmtb.iItem = i;
1478 nmtb.pszText = Buffer;
1479 nmtb.cchText = 256;
1481 if (!TOOLBAR_SendNotify ((NMHDR *) &nmtb, infoPtr, TBN_GETBUTTONINFOA))
1482 break;
1484 TRACE("style: %x\n", nmtb.tbButton.fsStyle);
1486 /* insert button into the apropriate list */
1487 index = TOOLBAR_GetButtonIndex (custInfo->tbInfo, nmtb.tbButton.idCommand, FALSE);
1488 if (index == -1)
1490 btnInfo = (PCUSTOMBUTTON)COMCTL32_Alloc(sizeof(CUSTOMBUTTON));
1491 memcpy (&btnInfo->btn, &nmtb.tbButton, sizeof(TBBUTTON));
1492 btnInfo->bVirtual = FALSE;
1493 btnInfo->bRemovable = TRUE;
1494 if (!(nmtb.tbButton.fsStyle & TBSTYLE_SEP))
1495 strcpy (btnInfo->text, nmtb.pszText);
1497 index = SendDlgItemMessageA (hwnd, IDC_AVAILBTN_LBOX, LB_ADDSTRING, 0, 0);
1498 SendDlgItemMessageA (hwnd, IDC_AVAILBTN_LBOX, LB_SETITEMDATA, index, (LPARAM)btnInfo);
1500 else
1502 btnInfo = (PCUSTOMBUTTON)SendDlgItemMessageA (hwnd, IDC_TOOLBARBTN_LBOX, LB_GETITEMDATA, index, 0);
1503 memcpy (&btnInfo->btn, &nmtb.tbButton, sizeof(TBBUTTON));
1504 if (!(nmtb.tbButton.fsStyle & TBSTYLE_SEP))
1505 strcpy (btnInfo->text, nmtb.pszText);
1507 SendDlgItemMessageA (hwnd, IDC_TOOLBARBTN_LBOX, LB_SETITEMDATA, index, (LPARAM)btnInfo);
1511 /* select first item in the 'available' list */
1512 SendDlgItemMessageA (hwnd, IDC_AVAILBTN_LBOX, LB_SETCURSEL, 0, 0);
1514 /* append 'virtual' separator button to the 'toolbar buttons' list */
1515 btnInfo = (PCUSTOMBUTTON)COMCTL32_Alloc(sizeof(CUSTOMBUTTON));
1516 memset (&btnInfo->btn, 0, sizeof(TBBUTTON));
1517 btnInfo->btn.fsStyle = TBSTYLE_SEP;
1518 btnInfo->bVirtual = TRUE;
1519 btnInfo->bRemovable = FALSE;
1520 LoadStringA (COMCTL32_hModule, IDS_SEPARATOR, btnInfo->text, 64);
1521 index = (int)SendDlgItemMessageA (hwnd, IDC_TOOLBARBTN_LBOX, LB_ADDSTRING, 0, (LPARAM)btnInfo);
1522 SendDlgItemMessageA (hwnd, IDC_TOOLBARBTN_LBOX, LB_SETITEMDATA, index, (LPARAM)btnInfo);
1524 /* select last item in the 'toolbar' list */
1525 SendDlgItemMessageA (hwnd, IDC_TOOLBARBTN_LBOX, LB_SETCURSEL, index, 0);
1526 SendDlgItemMessageA (hwnd, IDC_TOOLBARBTN_LBOX, LB_SETTOPINDEX, index, 0);
1528 /* set focus and disable buttons */
1529 PostMessageA (hwnd, WM_USER, 0, 0);
1531 return TRUE;
1533 case WM_USER:
1534 EnableWindow (GetDlgItem (hwnd,IDC_MOVEUP_BTN), FALSE);
1535 EnableWindow (GetDlgItem (hwnd,IDC_MOVEDN_BTN), FALSE);
1536 EnableWindow (GetDlgItem (hwnd,IDC_REMOVE_BTN), FALSE);
1537 SetFocus (GetDlgItem (hwnd, IDC_TOOLBARBTN_LBOX));
1538 return TRUE;
1540 case WM_CLOSE:
1541 EndDialog(hwnd, FALSE);
1542 return TRUE;
1544 case WM_COMMAND:
1545 switch (LOWORD(wParam))
1547 case IDC_TOOLBARBTN_LBOX:
1548 if (HIWORD(wParam) == LBN_SELCHANGE)
1550 PCUSTOMBUTTON btnInfo;
1551 NMTOOLBARA nmtb;
1552 int count;
1553 int index;
1555 count = SendDlgItemMessageA (hwnd, IDC_TOOLBARBTN_LBOX, LB_GETCOUNT, 0, 0);
1556 index = SendDlgItemMessageA (hwnd, IDC_TOOLBARBTN_LBOX, LB_GETCURSEL, 0, 0);
1558 /* send TBN_QUERYINSERT notification */
1559 nmtb.iItem = index;
1560 TOOLBAR_SendNotify ((NMHDR *) &nmtb, infoPtr,
1561 TBN_QUERYINSERT);
1563 /* get list box item */
1564 btnInfo = (PCUSTOMBUTTON)SendDlgItemMessageA (hwnd, IDC_TOOLBARBTN_LBOX, LB_GETITEMDATA, index, 0);
1566 if (index == (count - 1))
1568 /* last item (virtual separator) */
1569 EnableWindow (GetDlgItem (hwnd,IDC_MOVEUP_BTN), FALSE);
1570 EnableWindow (GetDlgItem (hwnd,IDC_MOVEDN_BTN), FALSE);
1572 else if (index == (count - 2))
1574 /* second last item (last non-virtual item) */
1575 EnableWindow (GetDlgItem (hwnd,IDC_MOVEUP_BTN), TRUE);
1576 EnableWindow (GetDlgItem (hwnd,IDC_MOVEDN_BTN), FALSE);
1578 else if (index == 0)
1580 /* first item */
1581 EnableWindow (GetDlgItem (hwnd,IDC_MOVEUP_BTN), FALSE);
1582 EnableWindow (GetDlgItem (hwnd,IDC_MOVEDN_BTN), TRUE);
1584 else
1586 EnableWindow (GetDlgItem (hwnd,IDC_MOVEUP_BTN), TRUE);
1587 EnableWindow (GetDlgItem (hwnd,IDC_MOVEDN_BTN), TRUE);
1590 EnableWindow (GetDlgItem (hwnd,IDC_REMOVE_BTN), btnInfo->bRemovable);
1592 break;
1594 case IDC_MOVEUP_BTN:
1596 PCUSTOMBUTTON btnInfo;
1597 int index;
1598 int count;
1600 count = SendDlgItemMessageA (hwnd, IDC_TOOLBARBTN_LBOX, LB_GETCOUNT, 0, 0);
1601 index = SendDlgItemMessageA (hwnd, IDC_TOOLBARBTN_LBOX, LB_GETCURSEL, 0, 0);
1602 TRACE("Move up: index %d\n", index);
1604 /* send TBN_QUERYINSERT notification */
1605 nmtb.iItem = index;
1607 if (TOOLBAR_SendNotify ((NMHDR *) &nmtb, infoPtr,
1608 TBN_QUERYINSERT))
1610 btnInfo = (PCUSTOMBUTTON)SendDlgItemMessageA (hwnd, IDC_TOOLBARBTN_LBOX, LB_GETITEMDATA, index, 0);
1612 SendDlgItemMessageA (hwnd, IDC_TOOLBARBTN_LBOX, LB_DELETESTRING, index, 0);
1613 SendDlgItemMessageA (hwnd, IDC_TOOLBARBTN_LBOX, LB_INSERTSTRING, index-1, 0);
1614 SendDlgItemMessageA (hwnd, IDC_TOOLBARBTN_LBOX, LB_SETITEMDATA, index-1, (LPARAM)btnInfo);
1615 SendDlgItemMessageA (hwnd, IDC_TOOLBARBTN_LBOX, LB_SETCURSEL, index-1 , 0);
1617 if (index <= 1)
1618 EnableWindow (GetDlgItem (hwnd,IDC_MOVEUP_BTN), FALSE);
1619 else if (index >= (count - 3))
1620 EnableWindow (GetDlgItem (hwnd,IDC_MOVEDN_BTN), TRUE);
1622 SendMessageA (custInfo->tbHwnd, TB_DELETEBUTTON, index, 0);
1623 SendMessageA (custInfo->tbHwnd, TB_INSERTBUTTONA, index-1, (LPARAM)&(btnInfo->btn));
1626 break;
1628 case IDC_MOVEDN_BTN: /* move down */
1630 PCUSTOMBUTTON btnInfo;
1631 int index;
1632 int count;
1634 count = SendDlgItemMessageA (hwnd, IDC_TOOLBARBTN_LBOX, LB_GETCOUNT, 0, 0);
1635 index = SendDlgItemMessageA (hwnd, IDC_TOOLBARBTN_LBOX, LB_GETCURSEL, 0, 0);
1636 TRACE("Move up: index %d\n", index);
1638 /* send TBN_QUERYINSERT notification */
1639 nmtb.iItem = index;
1640 if (TOOLBAR_SendNotify ((NMHDR *) &nmtb, infoPtr,
1641 TBN_QUERYINSERT))
1643 btnInfo = (PCUSTOMBUTTON)SendDlgItemMessageA (hwnd, IDC_TOOLBARBTN_LBOX, LB_GETITEMDATA, index, 0);
1645 /* move button down */
1646 SendDlgItemMessageA (hwnd, IDC_TOOLBARBTN_LBOX, LB_DELETESTRING, index, 0);
1647 SendDlgItemMessageA (hwnd, IDC_TOOLBARBTN_LBOX, LB_INSERTSTRING, index+1, 0);
1648 SendDlgItemMessageA (hwnd, IDC_TOOLBARBTN_LBOX, LB_SETITEMDATA, index+1, (LPARAM)btnInfo);
1649 SendDlgItemMessageA (hwnd, IDC_TOOLBARBTN_LBOX, LB_SETCURSEL, index+1 , 0);
1651 if (index == 0)
1652 EnableWindow (GetDlgItem (hwnd,IDC_MOVEUP_BTN), TRUE);
1653 else if (index >= (count - 3))
1654 EnableWindow (GetDlgItem (hwnd,IDC_MOVEDN_BTN), FALSE);
1656 SendMessageA (custInfo->tbHwnd, TB_DELETEBUTTON, index, 0);
1657 SendMessageA (custInfo->tbHwnd, TB_INSERTBUTTONA, index+1, (LPARAM)&(btnInfo->btn));
1660 break;
1662 case IDC_REMOVE_BTN: /* remove button */
1664 PCUSTOMBUTTON btnInfo;
1665 int index;
1667 index = SendDlgItemMessageA (hwnd, IDC_TOOLBARBTN_LBOX, LB_GETCURSEL, 0, 0);
1668 TRACE("Remove: index %d\n", index);
1670 /* send TBN_QUERYDELETE notification */
1671 nmtb.iItem = index;
1672 if (TOOLBAR_SendNotify ((NMHDR *) &nmtb, infoPtr,
1673 TBN_QUERYDELETE))
1675 btnInfo = (PCUSTOMBUTTON)SendDlgItemMessageA (hwnd, IDC_TOOLBARBTN_LBOX, LB_GETITEMDATA, index, 0);
1676 SendDlgItemMessageA (hwnd, IDC_TOOLBARBTN_LBOX, LB_DELETESTRING, index, 0);
1677 SendDlgItemMessageA (hwnd, IDC_TOOLBARBTN_LBOX, LB_SETCURSEL, index , 0);
1679 SendMessageA (custInfo->tbHwnd, TB_DELETEBUTTON, index, 0);
1681 /* insert into 'available button' list */
1682 if (!(btnInfo->btn.fsStyle & TBSTYLE_SEP))
1684 index = (int)SendDlgItemMessageA (hwnd, IDC_AVAILBTN_LBOX, LB_ADDSTRING, 0, 0);
1685 SendDlgItemMessageA (hwnd, IDC_AVAILBTN_LBOX, LB_SETITEMDATA, index, (LPARAM)btnInfo);
1687 else
1688 COMCTL32_Free (btnInfo);
1691 break;
1693 case IDOK: /* Add button */
1695 int index;
1696 int count;
1698 count = SendDlgItemMessageA (hwnd, IDC_AVAILBTN_LBOX, LB_GETCOUNT, 0, 0);
1699 index = SendDlgItemMessageA (hwnd, IDC_AVAILBTN_LBOX, LB_GETCURSEL, 0, 0);
1700 TRACE("Add: index %d\n", index);
1702 /* send TBN_QUERYINSERT notification */
1703 nmtb.iItem = index;
1704 if (TOOLBAR_SendNotify ((NMHDR *) &nmtb, infoPtr,
1705 TBN_QUERYINSERT))
1707 btnInfo = (PCUSTOMBUTTON)SendDlgItemMessageA (hwnd, IDC_AVAILBTN_LBOX, LB_GETITEMDATA, index, 0);
1709 if (index != 0)
1711 /* remove from 'available buttons' list */
1712 SendDlgItemMessageA (hwnd, IDC_AVAILBTN_LBOX, LB_DELETESTRING, index, 0);
1713 if (index == count-1)
1714 SendDlgItemMessageA (hwnd, IDC_AVAILBTN_LBOX, LB_SETCURSEL, index-1 , 0);
1715 else
1716 SendDlgItemMessageA (hwnd, IDC_AVAILBTN_LBOX, LB_SETCURSEL, index , 0);
1718 else
1720 PCUSTOMBUTTON btnNew;
1722 /* duplicate 'separator' button */
1723 btnNew = (PCUSTOMBUTTON)COMCTL32_Alloc (sizeof(CUSTOMBUTTON));
1724 memcpy (btnNew, btnInfo, sizeof(CUSTOMBUTTON));
1725 btnInfo = btnNew;
1728 /* insert into 'toolbar button' list */
1729 index = SendDlgItemMessageA (hwnd, IDC_TOOLBARBTN_LBOX, LB_GETCURSEL, 0, 0);
1730 SendDlgItemMessageA (hwnd, IDC_TOOLBARBTN_LBOX, LB_INSERTSTRING, index, 0);
1731 SendDlgItemMessageA (hwnd, IDC_TOOLBARBTN_LBOX, LB_SETITEMDATA, index, (LPARAM)btnInfo);
1733 SendMessageA (custInfo->tbHwnd, TB_INSERTBUTTONA, index, (LPARAM)&(btnInfo->btn));
1736 break;
1738 case IDCANCEL:
1739 EndDialog(hwnd, FALSE);
1740 break;
1742 return TRUE;
1744 case WM_DESTROY:
1746 int count;
1747 int i;
1749 /* delete items from 'toolbar buttons' listbox*/
1750 count = SendDlgItemMessageA (hwnd, IDC_TOOLBARBTN_LBOX, LB_GETCOUNT, 0, 0);
1751 for (i = 0; i < count; i++)
1753 btnInfo = (PCUSTOMBUTTON)SendDlgItemMessageA (hwnd, IDC_TOOLBARBTN_LBOX, LB_GETITEMDATA, i, 0);
1754 COMCTL32_Free(btnInfo);
1755 SendDlgItemMessageA (hwnd, IDC_TOOLBARBTN_LBOX, LB_SETITEMDATA, 0, 0);
1757 SendDlgItemMessageA (hwnd, IDC_TOOLBARBTN_LBOX, LB_RESETCONTENT, 0, 0);
1760 /* delete items from 'available buttons' listbox*/
1761 count = SendDlgItemMessageA (hwnd, IDC_AVAILBTN_LBOX, LB_GETCOUNT, 0, 0);
1762 for (i = 0; i < count; i++)
1764 btnInfo = (PCUSTOMBUTTON)SendDlgItemMessageA (hwnd, IDC_AVAILBTN_LBOX, LB_GETITEMDATA, i, 0);
1765 COMCTL32_Free(btnInfo);
1766 SendDlgItemMessageA (hwnd, IDC_AVAILBTN_LBOX, LB_SETITEMDATA, i, 0);
1768 SendDlgItemMessageA (hwnd, IDC_AVAILBTN_LBOX, LB_RESETCONTENT, 0, 0);
1770 return TRUE;
1772 case WM_DRAWITEM:
1773 if (wParam == IDC_AVAILBTN_LBOX || wParam == IDC_TOOLBARBTN_LBOX)
1775 LPDRAWITEMSTRUCT lpdis = (LPDRAWITEMSTRUCT)lParam;
1776 RECT rcButton;
1777 RECT rcText;
1778 HPEN hOldPen;
1779 HBRUSH hOldBrush;
1780 COLORREF oldText = 0;
1781 COLORREF oldBk = 0;
1783 /* get item data */
1784 btnInfo = (PCUSTOMBUTTON)SendDlgItemMessageA (hwnd, wParam, LB_GETITEMDATA, (WPARAM)lpdis->itemID, 0);
1785 if (btnInfo == NULL)
1787 FIXME("btnInfo invalid!\n");
1788 return TRUE;
1791 /* set colors and select objects */
1792 oldBk = SetBkColor (lpdis->hDC, GetSysColor((lpdis->itemState & ODS_FOCUS)?COLOR_HIGHLIGHT:COLOR_WINDOW));
1793 if (btnInfo->bVirtual)
1794 oldText = SetTextColor (lpdis->hDC, GetSysColor(COLOR_GRAYTEXT));
1795 else
1796 oldText = SetTextColor (lpdis->hDC, GetSysColor((lpdis->itemState & ODS_FOCUS)?COLOR_HIGHLIGHTTEXT:COLOR_WINDOWTEXT));
1797 hOldPen = SelectObject (lpdis->hDC, GetSysColorPen ((lpdis->itemState & ODS_SELECTED)?COLOR_HIGHLIGHT:COLOR_WINDOW));
1798 hOldBrush = SelectObject (lpdis->hDC, GetSysColorBrush ((lpdis->itemState & ODS_FOCUS)?COLOR_HIGHLIGHT:COLOR_WINDOW));
1800 /* fill background rectangle */
1801 Rectangle (lpdis->hDC, lpdis->rcItem.left, lpdis->rcItem.top,
1802 lpdis->rcItem.right, lpdis->rcItem.bottom);
1804 /* calculate button and text rectangles */
1805 CopyRect (&rcButton, &lpdis->rcItem);
1806 InflateRect (&rcButton, -1, -1);
1807 CopyRect (&rcText, &rcButton);
1808 rcButton.right = rcButton.left + custInfo->tbInfo->nBitmapWidth + 6;
1809 rcText.left = rcButton.right + 2;
1811 /* draw focus rectangle */
1812 if (lpdis->itemState & ODS_FOCUS)
1813 DrawFocusRect (lpdis->hDC, &lpdis->rcItem);
1815 /* draw button */
1816 DrawEdge (lpdis->hDC, &rcButton, EDGE_RAISED, BF_RECT|BF_MIDDLE|BF_SOFT);
1818 /* draw image and text */
1819 if ((btnInfo->btn.fsStyle & TBSTYLE_SEP) == 0)
1820 ImageList_Draw (custInfo->tbInfo->himlDef, btnInfo->btn.iBitmap, lpdis->hDC,
1821 rcButton.left+3, rcButton.top+3, ILD_NORMAL);
1822 DrawTextA (lpdis->hDC, btnInfo->text, -1, &rcText,
1823 DT_LEFT | DT_VCENTER | DT_SINGLELINE);
1825 /* delete objects and reset colors */
1826 SelectObject (lpdis->hDC, hOldBrush);
1827 SelectObject (lpdis->hDC, hOldPen);
1828 SetBkColor (lpdis->hDC, oldBk);
1829 SetTextColor (lpdis->hDC, oldText);
1831 return TRUE;
1833 return FALSE;
1835 case WM_MEASUREITEM:
1836 if (wParam == IDC_AVAILBTN_LBOX || wParam == IDC_TOOLBARBTN_LBOX)
1838 MEASUREITEMSTRUCT *lpmis = (MEASUREITEMSTRUCT*)lParam;
1840 if (custInfo && custInfo->tbInfo)
1841 lpmis->itemHeight = custInfo->tbInfo->nBitmapHeight + 8;
1842 else
1843 lpmis->itemHeight = 15 + 8; /* default height */
1845 return TRUE;
1847 return FALSE;
1849 default:
1850 return FALSE;
1855 /***********************************************************************
1856 * TOOLBAR_AddBitmap: Add the bitmaps to the default image list.
1859 static LRESULT
1860 TOOLBAR_AddBitmap (HWND hwnd, WPARAM wParam, LPARAM lParam)
1862 TOOLBAR_INFO *infoPtr = TOOLBAR_GetInfoPtr (hwnd);
1863 LPTBADDBITMAP lpAddBmp = (LPTBADDBITMAP)lParam;
1864 INT nIndex = 0, nButtons, nCount;
1865 HBITMAP hbmLoad;
1867 TRACE("hwnd=%x wParam=%x lParam=%lx\n", hwnd, wParam, lParam);
1868 if (!lpAddBmp)
1869 return -1;
1871 if (lpAddBmp->hInst == HINST_COMMCTRL)
1873 if ((lpAddBmp->nID & ~1) == IDB_STD_SMALL_COLOR)
1874 nButtons = 15;
1875 else if ((lpAddBmp->nID & ~1) == IDB_VIEW_SMALL_COLOR)
1876 nButtons = 13;
1877 else if ((lpAddBmp->nID & ~1) == IDB_HIST_SMALL_COLOR)
1878 nButtons = 5;
1879 else
1880 return -1;
1882 TRACE ("adding %d internal bitmaps!\n", nButtons);
1884 /* Windows resize all the buttons to the size of a newly added standard image */
1885 if (lpAddBmp->nID & 1)
1887 /* large icons */
1888 /* FIXME: on windows the size of the images is 25x24 but the size of the bitmap
1889 * in rsrc is only 24x24. Fix the bitmap (how?) and then fix this
1891 SendMessageA (hwnd, TB_SETBITMAPSIZE, 0,
1892 MAKELPARAM((WORD)24, (WORD)24));
1893 SendMessageA (hwnd, TB_SETBUTTONSIZE, 0,
1894 MAKELPARAM((WORD)31, (WORD)30));
1896 else
1898 /* small icons */
1899 SendMessageA (hwnd, TB_SETBITMAPSIZE, 0,
1900 MAKELPARAM((WORD)16, (WORD)16));
1901 SendMessageA (hwnd, TB_SETBUTTONSIZE, 0,
1902 MAKELPARAM((WORD)22, (WORD)22));
1905 TOOLBAR_CalcToolbar (hwnd);
1907 else
1909 nButtons = (INT)wParam;
1910 if (nButtons <= 0)
1911 return -1;
1913 TRACE ("adding %d bitmaps!\n", nButtons);
1916 if (!(infoPtr->himlDef)) {
1917 /* create new default image list */
1918 TRACE ("creating default image list!\n");
1920 infoPtr->himlDef =
1921 ImageList_Create (infoPtr->nBitmapWidth, infoPtr->nBitmapHeight,
1922 ILC_COLOR | ILC_MASK, nButtons, 2);
1923 infoPtr->himlInt = infoPtr->himlDef;
1926 nCount = ImageList_GetImageCount(infoPtr->himlDef);
1928 /* Add bitmaps to the default image list */
1929 if (lpAddBmp->hInst == (HINSTANCE)0)
1931 nIndex =
1932 ImageList_AddMasked (infoPtr->himlDef, (HBITMAP)lpAddBmp->nID,
1933 CLR_DEFAULT);
1935 else if (lpAddBmp->hInst == HINST_COMMCTRL)
1937 /* Add system bitmaps */
1938 switch (lpAddBmp->nID)
1940 case IDB_STD_SMALL_COLOR:
1941 hbmLoad = LoadBitmapA (COMCTL32_hModule,
1942 MAKEINTRESOURCEA(IDB_STD_SMALL));
1943 nIndex = ImageList_AddMasked (infoPtr->himlDef,
1944 hbmLoad, CLR_DEFAULT);
1945 DeleteObject (hbmLoad);
1946 break;
1948 case IDB_STD_LARGE_COLOR:
1949 hbmLoad = LoadBitmapA (COMCTL32_hModule,
1950 MAKEINTRESOURCEA(IDB_STD_LARGE));
1951 nIndex = ImageList_AddMasked (infoPtr->himlDef,
1952 hbmLoad, CLR_DEFAULT);
1953 DeleteObject (hbmLoad);
1954 break;
1956 case IDB_VIEW_SMALL_COLOR:
1957 hbmLoad = LoadBitmapA (COMCTL32_hModule,
1958 MAKEINTRESOURCEA(IDB_VIEW_SMALL));
1959 nIndex = ImageList_AddMasked (infoPtr->himlDef,
1960 hbmLoad, CLR_DEFAULT);
1961 DeleteObject (hbmLoad);
1962 break;
1964 case IDB_VIEW_LARGE_COLOR:
1965 hbmLoad = LoadBitmapA (COMCTL32_hModule,
1966 MAKEINTRESOURCEA(IDB_VIEW_LARGE));
1967 nIndex = ImageList_AddMasked (infoPtr->himlDef,
1968 hbmLoad, CLR_DEFAULT);
1969 DeleteObject (hbmLoad);
1970 break;
1972 case IDB_HIST_SMALL_COLOR:
1973 hbmLoad = LoadBitmapA (COMCTL32_hModule,
1974 MAKEINTRESOURCEA(IDB_HIST_SMALL));
1975 nIndex = ImageList_AddMasked (infoPtr->himlDef,
1976 hbmLoad, CLR_DEFAULT);
1977 DeleteObject (hbmLoad);
1978 break;
1980 case IDB_HIST_LARGE_COLOR:
1981 hbmLoad = LoadBitmapA (COMCTL32_hModule,
1982 MAKEINTRESOURCEA(IDB_HIST_LARGE));
1983 nIndex = ImageList_AddMasked (infoPtr->himlDef,
1984 hbmLoad, CLR_DEFAULT);
1985 DeleteObject (hbmLoad);
1986 break;
1988 default:
1989 nIndex = ImageList_GetImageCount (infoPtr->himlDef);
1990 ERR ("invalid imagelist!\n");
1991 break;
1994 else
1996 hbmLoad = LoadBitmapA (lpAddBmp->hInst, (LPSTR)lpAddBmp->nID);
1997 nIndex = ImageList_AddMasked (infoPtr->himlDef, hbmLoad, CLR_DEFAULT);
1998 DeleteObject (hbmLoad);
2001 if (nIndex != -1)
2003 INT imagecount = ImageList_GetImageCount(infoPtr->himlDef);
2005 if (infoPtr->nNumBitmaps + nButtons != imagecount)
2007 WARN("Desired images do not match received images : Previous image number %i Previous images in list %i added %i expecting total %i, Images in list %i\n",
2008 infoPtr->nNumBitmaps, nCount, imagecount - nCount,
2009 infoPtr->nNumBitmaps+nButtons,imagecount);
2011 infoPtr->nNumBitmaps = imagecount;
2013 else
2014 infoPtr->nNumBitmaps += nButtons;
2017 InvalidateRect(hwnd, NULL, FALSE);
2019 return nIndex;
2023 static LRESULT
2024 TOOLBAR_AddButtonsA (HWND hwnd, WPARAM wParam, LPARAM lParam)
2026 TOOLBAR_INFO *infoPtr = TOOLBAR_GetInfoPtr (hwnd);
2027 LPTBBUTTON lpTbb = (LPTBBUTTON)lParam;
2028 INT nOldButtons, nNewButtons, nAddButtons, nCount;
2030 TRACE("adding %d buttons!\n", wParam);
2032 nAddButtons = (UINT)wParam;
2033 nOldButtons = infoPtr->nNumButtons;
2034 nNewButtons = nOldButtons + nAddButtons;
2036 if (infoPtr->nNumButtons == 0) {
2037 infoPtr->buttons =
2038 COMCTL32_Alloc (sizeof(TBUTTON_INFO) * nNewButtons);
2040 else {
2041 TBUTTON_INFO *oldButtons = infoPtr->buttons;
2042 infoPtr->buttons =
2043 COMCTL32_Alloc (sizeof(TBUTTON_INFO) * nNewButtons);
2044 memcpy (&infoPtr->buttons[0], &oldButtons[0],
2045 nOldButtons * sizeof(TBUTTON_INFO));
2046 COMCTL32_Free (oldButtons);
2049 infoPtr->nNumButtons = nNewButtons;
2051 /* insert new button data */
2052 for (nCount = 0; nCount < nAddButtons; nCount++) {
2053 TBUTTON_INFO *btnPtr = &infoPtr->buttons[nOldButtons+nCount];
2054 btnPtr->iBitmap = lpTbb[nCount].iBitmap;
2055 btnPtr->idCommand = lpTbb[nCount].idCommand;
2056 btnPtr->fsState = lpTbb[nCount].fsState;
2057 btnPtr->fsStyle = lpTbb[nCount].fsStyle;
2058 btnPtr->dwData = lpTbb[nCount].dwData;
2059 btnPtr->iString = lpTbb[nCount].iString;
2060 btnPtr->bHot = FALSE;
2062 if ((infoPtr->hwndToolTip) && !(btnPtr->fsStyle & TBSTYLE_SEP)) {
2063 TTTOOLINFOA ti;
2065 ZeroMemory (&ti, sizeof(TTTOOLINFOA));
2066 ti.cbSize = sizeof (TTTOOLINFOA);
2067 ti.hwnd = hwnd;
2068 ti.uId = btnPtr->idCommand;
2069 ti.hinst = 0;
2070 ti.lpszText = LPSTR_TEXTCALLBACKA;
2072 SendMessageA (infoPtr->hwndToolTip, TTM_ADDTOOLA,
2073 0, (LPARAM)&ti);
2077 TOOLBAR_CalcToolbar (hwnd);
2079 InvalidateRect(hwnd, NULL, FALSE);
2081 return TRUE;
2085 static LRESULT
2086 TOOLBAR_AddButtonsW (HWND hwnd, WPARAM wParam, LPARAM lParam)
2088 TOOLBAR_INFO *infoPtr = TOOLBAR_GetInfoPtr (hwnd);
2089 LPTBBUTTON lpTbb = (LPTBBUTTON)lParam;
2090 INT nOldButtons, nNewButtons, nAddButtons, nCount;
2092 TRACE("adding %d buttons!\n", wParam);
2094 nAddButtons = (UINT)wParam;
2095 nOldButtons = infoPtr->nNumButtons;
2096 nNewButtons = nOldButtons + nAddButtons;
2098 if (infoPtr->nNumButtons == 0) {
2099 infoPtr->buttons =
2100 COMCTL32_Alloc (sizeof(TBUTTON_INFO) * nNewButtons);
2102 else {
2103 TBUTTON_INFO *oldButtons = infoPtr->buttons;
2104 infoPtr->buttons =
2105 COMCTL32_Alloc (sizeof(TBUTTON_INFO) * nNewButtons);
2106 memcpy (&infoPtr->buttons[0], &oldButtons[0],
2107 nOldButtons * sizeof(TBUTTON_INFO));
2108 COMCTL32_Free (oldButtons);
2111 infoPtr->nNumButtons = nNewButtons;
2113 /* insert new button data */
2114 for (nCount = 0; nCount < nAddButtons; nCount++) {
2115 TBUTTON_INFO *btnPtr = &infoPtr->buttons[nOldButtons+nCount];
2116 btnPtr->iBitmap = lpTbb[nCount].iBitmap;
2117 btnPtr->idCommand = lpTbb[nCount].idCommand;
2118 btnPtr->fsState = lpTbb[nCount].fsState;
2119 btnPtr->fsStyle = lpTbb[nCount].fsStyle;
2120 btnPtr->dwData = lpTbb[nCount].dwData;
2121 btnPtr->iString = lpTbb[nCount].iString;
2122 btnPtr->bHot = FALSE;
2124 if ((infoPtr->hwndToolTip) && !(btnPtr->fsStyle & TBSTYLE_SEP)) {
2125 TTTOOLINFOW ti;
2127 ZeroMemory (&ti, sizeof(TTTOOLINFOW));
2128 ti.cbSize = sizeof (TTTOOLINFOW);
2129 ti.hwnd = hwnd;
2130 ti.uId = btnPtr->idCommand;
2131 ti.hinst = 0;
2132 ti.lpszText = LPSTR_TEXTCALLBACKW;
2134 SendMessageW (infoPtr->hwndToolTip, TTM_ADDTOOLW,
2135 0, (LPARAM)&ti);
2139 TOOLBAR_CalcToolbar (hwnd);
2141 InvalidateRect(hwnd, NULL, FALSE);
2143 return TRUE;
2147 static LRESULT
2148 TOOLBAR_AddStringA (HWND hwnd, WPARAM wParam, LPARAM lParam)
2150 TOOLBAR_INFO *infoPtr = TOOLBAR_GetInfoPtr (hwnd);
2151 INT nIndex;
2153 if ((wParam) && (HIWORD(lParam) == 0)) {
2154 char szString[256];
2155 INT len, lenW;
2156 TRACE("adding string from resource!\n");
2158 len = LoadStringA ((HINSTANCE)wParam, (UINT)lParam,
2159 szString, 256);
2161 TRACE("len=%d \"%s\"\n", len, szString);
2162 nIndex = infoPtr->nNumStrings;
2163 if (infoPtr->nNumStrings == 0) {
2164 infoPtr->strings =
2165 COMCTL32_Alloc (sizeof(LPWSTR));
2167 else {
2168 LPWSTR *oldStrings = infoPtr->strings;
2169 infoPtr->strings =
2170 COMCTL32_Alloc (sizeof(LPWSTR) * (infoPtr->nNumStrings + 1));
2171 memcpy (&infoPtr->strings[0], &oldStrings[0],
2172 sizeof(LPWSTR) * infoPtr->nNumStrings);
2173 COMCTL32_Free (oldStrings);
2176 lenW = MultiByteToWideChar( CP_ACP, 0, szString, -1, NULL, 0 );
2177 infoPtr->strings[infoPtr->nNumStrings] = COMCTL32_Alloc (sizeof(WCHAR)*lenW);
2178 MultiByteToWideChar( CP_ACP, 0, szString, -1,
2179 infoPtr->strings[infoPtr->nNumStrings], lenW );
2180 infoPtr->nNumStrings++;
2182 else {
2183 LPSTR p = (LPSTR)lParam;
2184 INT len, lenW;
2186 if (p == NULL)
2187 return -1;
2188 TRACE("adding string(s) from array!\n");
2190 nIndex = infoPtr->nNumStrings;
2191 while (*p) {
2192 len = strlen (p);
2193 TRACE("len=%d \"%s\"\n", len, p);
2195 if (infoPtr->nNumStrings == 0) {
2196 infoPtr->strings =
2197 COMCTL32_Alloc (sizeof(LPWSTR));
2199 else {
2200 LPWSTR *oldStrings = infoPtr->strings;
2201 infoPtr->strings =
2202 COMCTL32_Alloc (sizeof(LPWSTR) * (infoPtr->nNumStrings + 1));
2203 memcpy (&infoPtr->strings[0], &oldStrings[0],
2204 sizeof(LPWSTR) * infoPtr->nNumStrings);
2205 COMCTL32_Free (oldStrings);
2208 lenW = MultiByteToWideChar( CP_ACP, 0, p, -1, NULL, 0 );
2209 infoPtr->strings[infoPtr->nNumStrings] = COMCTL32_Alloc (sizeof(WCHAR)*lenW);
2210 MultiByteToWideChar( CP_ACP, 0, p, -1,
2211 infoPtr->strings[infoPtr->nNumStrings], lenW );
2212 infoPtr->nNumStrings++;
2214 p += (len+1);
2218 return nIndex;
2222 static LRESULT
2223 TOOLBAR_AddStringW (HWND hwnd, WPARAM wParam, LPARAM lParam)
2225 #define MAX_RESOURCE_STRING_LENGTH 512
2226 TOOLBAR_INFO *infoPtr = TOOLBAR_GetInfoPtr (hwnd);
2227 INT nIndex;
2229 if ((wParam) && (HIWORD(lParam) == 0)) {
2230 WCHAR szString[MAX_RESOURCE_STRING_LENGTH];
2231 INT len;
2232 TRACE("adding string from resource!\n");
2234 len = LoadStringW ((HINSTANCE)wParam, (UINT)lParam,
2235 szString, MAX_RESOURCE_STRING_LENGTH);
2237 TRACE("len=%d %s\n", len, debugstr_w(szString));
2238 TRACE("First char: 0x%x\n", *szString);
2239 if (szString[0] == L'|')
2241 PWSTR p = szString + 1;
2243 nIndex = infoPtr->nNumStrings;
2244 while (*p != L'|') {
2246 if (infoPtr->nNumStrings == 0) {
2247 infoPtr->strings =
2248 COMCTL32_Alloc (sizeof(LPWSTR));
2250 else {
2251 LPWSTR *oldStrings = infoPtr->strings;
2252 infoPtr->strings =
2253 COMCTL32_Alloc (sizeof(LPWSTR) * (infoPtr->nNumStrings + 1));
2254 memcpy (&infoPtr->strings[0], &oldStrings[0],
2255 sizeof(LPWSTR) * infoPtr->nNumStrings);
2256 COMCTL32_Free (oldStrings);
2259 len = COMCTL32_StrChrW (p, L'|') - p;
2260 TRACE("len=%d %s\n", len, debugstr_w(p));
2261 infoPtr->strings[infoPtr->nNumStrings] =
2262 COMCTL32_Alloc (sizeof(WCHAR)*(len+1));
2263 lstrcpynW (infoPtr->strings[infoPtr->nNumStrings], p, len+1);
2264 infoPtr->nNumStrings++;
2266 p += (len+1);
2269 else
2271 nIndex = infoPtr->nNumStrings;
2272 if (infoPtr->nNumStrings == 0) {
2273 infoPtr->strings =
2274 COMCTL32_Alloc (sizeof(LPWSTR));
2276 else {
2277 LPWSTR *oldStrings = infoPtr->strings;
2278 infoPtr->strings =
2279 COMCTL32_Alloc (sizeof(LPWSTR) * (infoPtr->nNumStrings + 1));
2280 memcpy (&infoPtr->strings[0], &oldStrings[0],
2281 sizeof(LPWSTR) * infoPtr->nNumStrings);
2282 COMCTL32_Free (oldStrings);
2285 infoPtr->strings[infoPtr->nNumStrings] =
2286 COMCTL32_Alloc (sizeof(WCHAR)*(len+1));
2287 strcpyW (infoPtr->strings[infoPtr->nNumStrings], szString);
2288 infoPtr->nNumStrings++;
2291 else {
2292 LPWSTR p = (LPWSTR)lParam;
2293 INT len;
2295 if (p == NULL)
2296 return -1;
2297 TRACE("adding string(s) from array!\n");
2298 nIndex = infoPtr->nNumStrings;
2299 while (*p) {
2300 len = strlenW (p);
2302 TRACE("len=%d %s\n", len, debugstr_w(p));
2303 if (infoPtr->nNumStrings == 0) {
2304 infoPtr->strings =
2305 COMCTL32_Alloc (sizeof(LPWSTR));
2307 else {
2308 LPWSTR *oldStrings = infoPtr->strings;
2309 infoPtr->strings =
2310 COMCTL32_Alloc (sizeof(LPWSTR) * (infoPtr->nNumStrings + 1));
2311 memcpy (&infoPtr->strings[0], &oldStrings[0],
2312 sizeof(LPWSTR) * infoPtr->nNumStrings);
2313 COMCTL32_Free (oldStrings);
2316 infoPtr->strings[infoPtr->nNumStrings] =
2317 COMCTL32_Alloc (sizeof(WCHAR)*(len+1));
2318 strcpyW (infoPtr->strings[infoPtr->nNumStrings], p);
2319 infoPtr->nNumStrings++;
2321 p += (len+1);
2325 return nIndex;
2329 static LRESULT
2330 TOOLBAR_AutoSize (HWND hwnd)
2332 TOOLBAR_INFO *infoPtr = TOOLBAR_GetInfoPtr (hwnd);
2333 DWORD dwStyle = GetWindowLongA (hwnd, GWL_STYLE);
2334 RECT parent_rect;
2335 RECT window_rect;
2336 HWND parent;
2337 INT x, y;
2338 INT cx, cy;
2339 UINT uPosFlags = SWP_NOZORDER;
2341 TRACE("resize forced, style=%lx!\n", dwStyle);
2343 parent = GetParent (hwnd);
2344 GetClientRect(parent, &parent_rect);
2346 x = parent_rect.left;
2347 y = parent_rect.top;
2349 /* FIXME: we should be able to early out if nothing */
2350 /* has changed with nWidth != parent_rect width */
2352 if (dwStyle & CCS_NORESIZE) {
2353 uPosFlags |= (SWP_NOSIZE | SWP_NOMOVE);
2354 cx = 0;
2355 cy = 0;
2357 else {
2358 infoPtr->nWidth = parent_rect.right - parent_rect.left;
2359 TOOLBAR_CalcToolbar (hwnd);
2360 InvalidateRect( hwnd, NULL, TRUE );
2361 cy = infoPtr->nHeight;
2362 cx = infoPtr->nWidth;
2364 if (dwStyle & CCS_NOMOVEY) {
2365 GetWindowRect(hwnd, &window_rect);
2366 ScreenToClient(parent, (LPPOINT)&window_rect.left);
2367 y = window_rect.top;
2371 if (dwStyle & CCS_NOPARENTALIGN)
2372 uPosFlags |= SWP_NOMOVE;
2374 if (!(dwStyle & CCS_NODIVIDER))
2375 cy += GetSystemMetrics(SM_CYEDGE);
2377 if (dwStyle & WS_BORDER)
2379 x = y = 1;
2380 cy += GetSystemMetrics(SM_CYEDGE);
2381 cx += GetSystemMetrics(SM_CYEDGE);
2384 infoPtr->bAutoSize = TRUE;
2385 SetWindowPos (hwnd, HWND_TOP, parent_rect.left - x, parent_rect.top - y,
2386 cx, cy, uPosFlags);
2387 /* The following line makes sure that the infoPtr->bAutoSize is turned off after
2388 * the setwindowpos calls */
2389 infoPtr->bAutoSize = FALSE;
2391 return 0;
2395 static LRESULT
2396 TOOLBAR_ButtonCount (HWND hwnd, WPARAM wParam, LPARAM lParam)
2398 TOOLBAR_INFO *infoPtr = TOOLBAR_GetInfoPtr (hwnd);
2400 return infoPtr->nNumButtons;
2404 static LRESULT
2405 TOOLBAR_ButtonStructSize (HWND hwnd, WPARAM wParam, LPARAM lParam)
2407 TOOLBAR_INFO *infoPtr = TOOLBAR_GetInfoPtr (hwnd);
2409 if (infoPtr == NULL) {
2410 ERR("(0x%x, 0x%x, 0x%lx)\n", hwnd, wParam, lParam);
2411 ERR("infoPtr == NULL!\n");
2412 return 0;
2415 infoPtr->dwStructSize = (DWORD)wParam;
2417 return 0;
2421 static LRESULT
2422 TOOLBAR_ChangeBitmap (HWND hwnd, WPARAM wParam, LPARAM lParam)
2424 TOOLBAR_INFO *infoPtr = TOOLBAR_GetInfoPtr (hwnd);
2425 TBUTTON_INFO *btnPtr;
2426 INT nIndex;
2428 nIndex = TOOLBAR_GetButtonIndex (infoPtr, (INT)wParam, FALSE);
2429 if (nIndex == -1)
2430 return FALSE;
2432 btnPtr = &infoPtr->buttons[nIndex];
2433 btnPtr->iBitmap = LOWORD(lParam);
2435 /* we HAVE to erase the background, the new bitmap could be */
2436 /* transparent */
2437 InvalidateRect(hwnd, &btnPtr->rect, TRUE);
2439 return TRUE;
2443 static LRESULT
2444 TOOLBAR_CheckButton (HWND hwnd, WPARAM wParam, LPARAM lParam)
2446 TOOLBAR_INFO *infoPtr = TOOLBAR_GetInfoPtr (hwnd);
2447 TBUTTON_INFO *btnPtr;
2448 INT nIndex;
2449 INT nOldIndex = -1;
2450 BOOL bChecked = FALSE;
2452 nIndex = TOOLBAR_GetButtonIndex (infoPtr, (INT)wParam, FALSE);
2453 if (nIndex == -1)
2454 return FALSE;
2456 btnPtr = &infoPtr->buttons[nIndex];
2458 if (!(btnPtr->fsStyle & TBSTYLE_CHECK))
2459 return FALSE;
2461 bChecked = (btnPtr->fsState & TBSTATE_CHECKED) ? TRUE : FALSE;
2463 if (LOWORD(lParam) == FALSE)
2464 btnPtr->fsState &= ~TBSTATE_CHECKED;
2465 else {
2466 if (btnPtr->fsStyle & TBSTYLE_GROUP) {
2467 nOldIndex =
2468 TOOLBAR_GetCheckedGroupButtonIndex (infoPtr, nIndex);
2469 if (nOldIndex == nIndex)
2470 return 0;
2471 if (nOldIndex != -1)
2472 infoPtr->buttons[nOldIndex].fsState &= ~TBSTATE_CHECKED;
2474 btnPtr->fsState |= TBSTATE_CHECKED;
2477 if( bChecked != LOWORD(lParam) )
2479 if (nOldIndex != -1)
2481 InvalidateRect(hwnd, &infoPtr->buttons[nOldIndex].rect,
2482 TOOLBAR_HasText(infoPtr, &infoPtr->buttons[nOldIndex]));
2484 InvalidateRect(hwnd, &btnPtr->rect, TRUE);
2487 /* FIXME: Send a WM_NOTIFY?? */
2489 return TRUE;
2493 static LRESULT
2494 TOOLBAR_CommandToIndex (HWND hwnd, WPARAM wParam, LPARAM lParam)
2496 TOOLBAR_INFO *infoPtr = TOOLBAR_GetInfoPtr (hwnd);
2498 return TOOLBAR_GetButtonIndex (infoPtr, (INT)wParam, FALSE);
2502 static LRESULT
2503 TOOLBAR_Customize (HWND hwnd)
2505 TOOLBAR_INFO *infoPtr = TOOLBAR_GetInfoPtr (hwnd);
2506 CUSTDLG_INFO custInfo;
2507 LRESULT ret;
2508 LPCVOID template;
2509 HRSRC hRes;
2510 NMHDR nmhdr;
2512 custInfo.tbInfo = infoPtr;
2513 custInfo.tbHwnd = hwnd;
2515 /* send TBN_BEGINADJUST notification */
2516 TOOLBAR_SendNotify ((NMHDR *) &nmhdr, infoPtr,
2517 TBN_BEGINADJUST);
2519 if (!(hRes = FindResourceA (COMCTL32_hModule,
2520 MAKEINTRESOURCEA(IDD_TBCUSTOMIZE),
2521 RT_DIALOGA)))
2522 return FALSE;
2524 if(!(template = (LPVOID)LoadResource (COMCTL32_hModule, hRes)))
2525 return FALSE;
2527 ret = DialogBoxIndirectParamA (GetWindowLongA (hwnd, GWL_HINSTANCE),
2528 (LPDLGTEMPLATEA)template,
2529 hwnd,
2530 (DLGPROC)TOOLBAR_CustomizeDialogProc,
2531 (LPARAM)&custInfo);
2533 /* send TBN_ENDADJUST notification */
2534 TOOLBAR_SendNotify ((NMHDR *) &nmhdr, infoPtr,
2535 TBN_ENDADJUST);
2537 return ret;
2541 static LRESULT
2542 TOOLBAR_DeleteButton (HWND hwnd, WPARAM wParam, LPARAM lParam)
2544 TOOLBAR_INFO *infoPtr = TOOLBAR_GetInfoPtr (hwnd);
2545 INT nIndex = (INT)wParam;
2547 if ((nIndex < 0) || (nIndex >= infoPtr->nNumButtons))
2548 return FALSE;
2550 if ((infoPtr->hwndToolTip) &&
2551 !(infoPtr->buttons[nIndex].fsStyle & TBSTYLE_SEP)) {
2552 TTTOOLINFOA ti;
2554 ZeroMemory (&ti, sizeof(TTTOOLINFOA));
2555 ti.cbSize = sizeof (TTTOOLINFOA);
2556 ti.hwnd = hwnd;
2557 ti.uId = infoPtr->buttons[nIndex].idCommand;
2559 SendMessageA (infoPtr->hwndToolTip, TTM_DELTOOLA, 0, (LPARAM)&ti);
2562 if (infoPtr->nNumButtons == 1) {
2563 TRACE(" simple delete!\n");
2564 COMCTL32_Free (infoPtr->buttons);
2565 infoPtr->buttons = NULL;
2566 infoPtr->nNumButtons = 0;
2568 else {
2569 TBUTTON_INFO *oldButtons = infoPtr->buttons;
2570 TRACE("complex delete! [nIndex=%d]\n", nIndex);
2572 infoPtr->nNumButtons--;
2573 infoPtr->buttons = COMCTL32_Alloc (sizeof (TBUTTON_INFO) * infoPtr->nNumButtons);
2574 if (nIndex > 0) {
2575 memcpy (&infoPtr->buttons[0], &oldButtons[0],
2576 nIndex * sizeof(TBUTTON_INFO));
2579 if (nIndex < infoPtr->nNumButtons) {
2580 memcpy (&infoPtr->buttons[nIndex], &oldButtons[nIndex+1],
2581 (infoPtr->nNumButtons - nIndex) * sizeof(TBUTTON_INFO));
2584 COMCTL32_Free (oldButtons);
2587 TOOLBAR_CalcToolbar (hwnd);
2589 InvalidateRect (hwnd, NULL, TRUE);
2591 return TRUE;
2595 static LRESULT
2596 TOOLBAR_EnableButton (HWND hwnd, WPARAM wParam, LPARAM lParam)
2598 TOOLBAR_INFO *infoPtr = TOOLBAR_GetInfoPtr (hwnd);
2599 TBUTTON_INFO *btnPtr;
2600 INT nIndex;
2601 DWORD bState;
2603 nIndex = TOOLBAR_GetButtonIndex (infoPtr, (INT)wParam, FALSE);
2604 if (nIndex == -1)
2605 return FALSE;
2607 btnPtr = &infoPtr->buttons[nIndex];
2609 bState = btnPtr->fsState & TBSTATE_ENABLED;
2611 /* update the toolbar button state */
2612 if(LOWORD(lParam) == FALSE) {
2613 btnPtr->fsState &= ~(TBSTATE_ENABLED | TBSTATE_PRESSED);
2614 } else {
2615 btnPtr->fsState |= TBSTATE_ENABLED;
2618 /* redraw the button only if the state of the button changed */
2619 if(bState != (btnPtr->fsState & TBSTATE_ENABLED))
2621 InvalidateRect(hwnd, &btnPtr->rect,
2622 TOOLBAR_HasText(infoPtr, btnPtr));
2625 return TRUE;
2629 static inline LRESULT
2630 TOOLBAR_GetAnchorHighlight (HWND hwnd)
2632 TOOLBAR_INFO *infoPtr = TOOLBAR_GetInfoPtr (hwnd);
2634 return infoPtr->bAnchor;
2638 static LRESULT
2639 TOOLBAR_GetBitmap (HWND hwnd, WPARAM wParam, LPARAM lParam)
2641 TOOLBAR_INFO *infoPtr = TOOLBAR_GetInfoPtr (hwnd);
2642 INT nIndex;
2644 nIndex = TOOLBAR_GetButtonIndex (infoPtr, (INT)wParam, FALSE);
2645 if (nIndex == -1)
2646 return -1;
2648 return infoPtr->buttons[nIndex].iBitmap;
2652 static inline LRESULT
2653 TOOLBAR_GetBitmapFlags (HWND hwnd, WPARAM wParam, LPARAM lParam)
2655 return (GetDeviceCaps (0, LOGPIXELSX) >= 120) ? TBBF_LARGE : 0;
2659 static LRESULT
2660 TOOLBAR_GetButton (HWND hwnd, WPARAM wParam, LPARAM lParam)
2662 TOOLBAR_INFO *infoPtr = TOOLBAR_GetInfoPtr (hwnd);
2663 LPTBBUTTON lpTbb = (LPTBBUTTON)lParam;
2664 INT nIndex = (INT)wParam;
2665 TBUTTON_INFO *btnPtr;
2667 if (infoPtr == NULL)
2668 return FALSE;
2670 if (lpTbb == NULL)
2671 return FALSE;
2673 if ((nIndex < 0) || (nIndex >= infoPtr->nNumButtons))
2674 return FALSE;
2676 btnPtr = &infoPtr->buttons[nIndex];
2677 lpTbb->iBitmap = btnPtr->iBitmap;
2678 lpTbb->idCommand = btnPtr->idCommand;
2679 lpTbb->fsState = btnPtr->fsState;
2680 lpTbb->fsStyle = btnPtr->fsStyle;
2681 lpTbb->dwData = btnPtr->dwData;
2682 lpTbb->iString = btnPtr->iString;
2684 return TRUE;
2688 static LRESULT
2689 TOOLBAR_GetButtonInfoA (HWND hwnd, WPARAM wParam, LPARAM lParam)
2691 TOOLBAR_INFO *infoPtr = TOOLBAR_GetInfoPtr (hwnd);
2692 LPTBBUTTONINFOA lpTbInfo = (LPTBBUTTONINFOA)lParam;
2693 TBUTTON_INFO *btnPtr;
2694 INT nIndex;
2696 if (infoPtr == NULL)
2697 return -1;
2698 if (lpTbInfo == NULL)
2699 return -1;
2700 if (lpTbInfo->cbSize < sizeof(TBBUTTONINFOA))
2701 return -1;
2703 nIndex = TOOLBAR_GetButtonIndex (infoPtr, (INT)wParam,
2704 lpTbInfo->dwMask & 0x80000000);
2705 if (nIndex == -1)
2706 return -1;
2708 btnPtr = &infoPtr->buttons[nIndex];
2710 if (lpTbInfo->dwMask & TBIF_COMMAND)
2711 lpTbInfo->idCommand = btnPtr->idCommand;
2712 if (lpTbInfo->dwMask & TBIF_IMAGE)
2713 lpTbInfo->iImage = btnPtr->iBitmap;
2714 if (lpTbInfo->dwMask & TBIF_LPARAM)
2715 lpTbInfo->lParam = btnPtr->dwData;
2716 if (lpTbInfo->dwMask & TBIF_SIZE)
2717 lpTbInfo->cx = (WORD)(btnPtr->rect.right - btnPtr->rect.left);
2718 if (lpTbInfo->dwMask & TBIF_STATE)
2719 lpTbInfo->fsState = btnPtr->fsState;
2720 if (lpTbInfo->dwMask & TBIF_STYLE)
2721 lpTbInfo->fsStyle = btnPtr->fsStyle;
2722 if (lpTbInfo->dwMask & TBIF_TEXT) {
2723 if ((btnPtr->iString >= 0) && (btnPtr->iString < infoPtr->nNumStrings))
2725 if (!WideCharToMultiByte( CP_ACP, 0, (LPWSTR)infoPtr->strings[btnPtr->iString], -1,
2726 lpTbInfo->pszText, lpTbInfo->cchText, NULL, NULL ))
2727 lpTbInfo->pszText[lpTbInfo->cchText-1] = 0;
2729 else lpTbInfo->pszText[0]=0;
2731 return nIndex;
2735 static LRESULT
2736 TOOLBAR_GetButtonInfoW (HWND hwnd, WPARAM wParam, LPARAM lParam)
2738 TOOLBAR_INFO *infoPtr = TOOLBAR_GetInfoPtr (hwnd);
2739 LPTBBUTTONINFOW lpTbInfo = (LPTBBUTTONINFOW)lParam;
2740 TBUTTON_INFO *btnPtr;
2741 INT nIndex;
2743 if (infoPtr == NULL)
2744 return -1;
2745 if (lpTbInfo == NULL)
2746 return -1;
2747 if (lpTbInfo->cbSize < sizeof(TBBUTTONINFOW))
2748 return -1;
2750 nIndex = TOOLBAR_GetButtonIndex (infoPtr, (INT)wParam,
2751 lpTbInfo->dwMask & 0x80000000);
2752 if (nIndex == -1)
2753 return -1;
2755 btnPtr = &infoPtr->buttons[nIndex];
2757 if (lpTbInfo->dwMask & TBIF_COMMAND)
2758 lpTbInfo->idCommand = btnPtr->idCommand;
2759 if (lpTbInfo->dwMask & TBIF_IMAGE)
2760 lpTbInfo->iImage = btnPtr->iBitmap;
2761 if (lpTbInfo->dwMask & TBIF_LPARAM)
2762 lpTbInfo->lParam = btnPtr->dwData;
2763 if (lpTbInfo->dwMask & TBIF_SIZE)
2764 lpTbInfo->cx = (WORD)(btnPtr->rect.right - btnPtr->rect.left);
2765 if (lpTbInfo->dwMask & TBIF_STATE)
2766 lpTbInfo->fsState = btnPtr->fsState;
2767 if (lpTbInfo->dwMask & TBIF_STYLE)
2768 lpTbInfo->fsStyle = btnPtr->fsStyle;
2769 if (lpTbInfo->dwMask & TBIF_TEXT) {
2770 if ((btnPtr->iString >= 0) || (btnPtr->iString < infoPtr->nNumStrings))
2771 lstrcpynW (lpTbInfo->pszText,
2772 (LPWSTR)infoPtr->strings[btnPtr->iString],
2773 lpTbInfo->cchText);
2776 return nIndex;
2780 static LRESULT
2781 TOOLBAR_GetButtonSize (HWND hwnd)
2783 TOOLBAR_INFO *infoPtr = TOOLBAR_GetInfoPtr (hwnd);
2785 if (infoPtr->nNumButtons > 0)
2786 return MAKELONG((WORD)infoPtr->nButtonWidth,
2787 (WORD)infoPtr->nButtonHeight);
2788 else
2789 return MAKELONG(8,7);
2793 static LRESULT
2794 TOOLBAR_GetButtonTextA (HWND hwnd, WPARAM wParam, LPARAM lParam)
2796 TOOLBAR_INFO *infoPtr = TOOLBAR_GetInfoPtr (hwnd);
2797 INT nIndex, nStringIndex;
2799 nIndex = TOOLBAR_GetButtonIndex (infoPtr, (INT)wParam, FALSE);
2800 if (nIndex == -1)
2801 return -1;
2803 nStringIndex = infoPtr->buttons[nIndex].iString;
2805 TRACE("index=%d stringIndex=%d\n", nIndex, nStringIndex);
2807 if ((nStringIndex < 0) || (nStringIndex >= infoPtr->nNumStrings))
2808 return -1;
2810 if (lParam == 0)
2811 return -1;
2813 return WideCharToMultiByte( CP_ACP, 0, (LPWSTR)infoPtr->strings[nStringIndex], -1,
2814 (LPSTR)lParam, 0x7fffffff, NULL, NULL ) - 1;
2818 static LRESULT
2819 TOOLBAR_GetButtonTextW (HWND hwnd, WPARAM wParam, LPARAM lParam)
2821 TOOLBAR_INFO *infoPtr = TOOLBAR_GetInfoPtr (hwnd);
2822 INT nIndex, nStringIndex;
2824 nIndex = TOOLBAR_GetButtonIndex (infoPtr, (INT)wParam, FALSE);
2825 if (nIndex == -1)
2826 return -1;
2828 nStringIndex = infoPtr->buttons[nIndex].iString;
2830 TRACE("index=%d stringIndex=%d\n", nIndex, nStringIndex);
2832 if ((nStringIndex < 0) || (nStringIndex >= infoPtr->nNumStrings))
2833 return -1;
2835 if (lParam == 0)
2836 return -1;
2838 strcpyW ((LPWSTR)lParam, (LPWSTR)infoPtr->strings[nStringIndex]);
2840 return strlenW ((LPWSTR)infoPtr->strings[nStringIndex]);
2844 /* << TOOLBAR_GetColorScheme >> */
2847 static LRESULT
2848 TOOLBAR_GetDisabledImageList (HWND hwnd, WPARAM wParam, LPARAM lParam)
2850 TOOLBAR_INFO *infoPtr = TOOLBAR_GetInfoPtr (hwnd);
2852 return (LRESULT)infoPtr->himlDis;
2856 inline static LRESULT
2857 TOOLBAR_GetExtendedStyle (HWND hwnd)
2859 TOOLBAR_INFO *infoPtr = TOOLBAR_GetInfoPtr (hwnd);
2861 return infoPtr->dwExStyle;
2865 static LRESULT
2866 TOOLBAR_GetHotImageList (HWND hwnd, WPARAM wParam, LPARAM lParam)
2868 TOOLBAR_INFO *infoPtr = TOOLBAR_GetInfoPtr (hwnd);
2870 return (LRESULT)infoPtr->himlHot;
2874 static LRESULT
2875 TOOLBAR_GetHotItem (HWND hwnd)
2877 TOOLBAR_INFO *infoPtr = TOOLBAR_GetInfoPtr (hwnd);
2879 if (!(GetWindowLongA (hwnd, GWL_STYLE) & TBSTYLE_FLAT))
2880 return -1;
2882 if (infoPtr->nHotItem < 0)
2883 return -1;
2885 return (LRESULT)infoPtr->nHotItem;
2889 static LRESULT
2890 TOOLBAR_GetImageList (HWND hwnd, WPARAM wParam, LPARAM lParam)
2892 TOOLBAR_INFO *infoPtr = TOOLBAR_GetInfoPtr (hwnd);
2894 return (LRESULT)infoPtr->himlDef;
2898 /* << TOOLBAR_GetInsertMark >> */
2899 /* << TOOLBAR_GetInsertMarkColor >> */
2902 static LRESULT
2903 TOOLBAR_GetItemRect (HWND hwnd, WPARAM wParam, LPARAM lParam)
2905 TOOLBAR_INFO *infoPtr = TOOLBAR_GetInfoPtr (hwnd);
2906 TBUTTON_INFO *btnPtr;
2907 LPRECT lpRect;
2908 INT nIndex;
2910 if (infoPtr == NULL)
2911 return FALSE;
2912 nIndex = (INT)wParam;
2913 btnPtr = &infoPtr->buttons[nIndex];
2914 if ((nIndex < 0) || (nIndex >= infoPtr->nNumButtons))
2915 return FALSE;
2916 lpRect = (LPRECT)lParam;
2917 if (lpRect == NULL)
2918 return FALSE;
2919 if (btnPtr->fsState & TBSTATE_HIDDEN)
2920 return FALSE;
2922 lpRect->left = btnPtr->rect.left;
2923 lpRect->right = btnPtr->rect.right;
2924 lpRect->bottom = btnPtr->rect.bottom;
2925 lpRect->top = btnPtr->rect.top;
2927 return TRUE;
2931 static LRESULT
2932 TOOLBAR_GetMaxSize (HWND hwnd, WPARAM wParam, LPARAM lParam)
2934 TOOLBAR_INFO *infoPtr = TOOLBAR_GetInfoPtr (hwnd);
2935 LPSIZE lpSize = (LPSIZE)lParam;
2937 if (lpSize == NULL)
2938 return FALSE;
2940 lpSize->cx = infoPtr->rcBound.right - infoPtr->rcBound.left;
2941 lpSize->cy = infoPtr->rcBound.bottom - infoPtr->rcBound.top;
2943 TRACE("maximum size %d x %d\n",
2944 infoPtr->rcBound.right - infoPtr->rcBound.left,
2945 infoPtr->rcBound.bottom - infoPtr->rcBound.top);
2947 return TRUE;
2951 /* << TOOLBAR_GetObject >> */
2952 /* << TOOLBAR_GetPadding >> */
2955 static LRESULT
2956 TOOLBAR_GetRect (HWND hwnd, WPARAM wParam, LPARAM lParam)
2958 TOOLBAR_INFO *infoPtr = TOOLBAR_GetInfoPtr (hwnd);
2959 TBUTTON_INFO *btnPtr;
2960 LPRECT lpRect;
2961 INT nIndex;
2963 if (infoPtr == NULL)
2964 return FALSE;
2965 nIndex = TOOLBAR_GetButtonIndex (infoPtr, (INT)wParam, FALSE);
2966 btnPtr = &infoPtr->buttons[nIndex];
2967 if ((nIndex < 0) || (nIndex >= infoPtr->nNumButtons))
2968 return FALSE;
2969 lpRect = (LPRECT)lParam;
2970 if (lpRect == NULL)
2971 return FALSE;
2973 lpRect->left = btnPtr->rect.left;
2974 lpRect->right = btnPtr->rect.right;
2975 lpRect->bottom = btnPtr->rect.bottom;
2976 lpRect->top = btnPtr->rect.top;
2978 return TRUE;
2982 static LRESULT
2983 TOOLBAR_GetRows (HWND hwnd, WPARAM wParam, LPARAM lParam)
2985 TOOLBAR_INFO *infoPtr = TOOLBAR_GetInfoPtr (hwnd);
2987 if (GetWindowLongA (hwnd, GWL_STYLE) & TBSTYLE_WRAPABLE)
2988 return infoPtr->nRows;
2989 else
2990 return 1;
2994 static LRESULT
2995 TOOLBAR_GetState (HWND hwnd, WPARAM wParam, LPARAM lParam)
2997 TOOLBAR_INFO *infoPtr = TOOLBAR_GetInfoPtr (hwnd);
2998 INT nIndex;
3000 nIndex = TOOLBAR_GetButtonIndex (infoPtr, (INT)wParam, FALSE);
3001 if (nIndex == -1)
3002 return -1;
3004 return infoPtr->buttons[nIndex].fsState;
3008 static LRESULT
3009 TOOLBAR_GetStyle (HWND hwnd, WPARAM wParam, LPARAM lParam)
3011 TOOLBAR_INFO *infoPtr = TOOLBAR_GetInfoPtr (hwnd);
3012 INT nIndex;
3014 nIndex = TOOLBAR_GetButtonIndex (infoPtr, (INT)wParam, FALSE);
3015 if (nIndex == -1)
3016 return -1;
3018 return infoPtr->buttons[nIndex].fsStyle;
3022 static LRESULT
3023 TOOLBAR_GetTextRows (HWND hwnd, WPARAM wParam, LPARAM lParam)
3025 TOOLBAR_INFO *infoPtr = TOOLBAR_GetInfoPtr (hwnd);
3027 if (infoPtr == NULL)
3028 return 0;
3030 return infoPtr->nMaxTextRows;
3034 static LRESULT
3035 TOOLBAR_GetToolTips (HWND hwnd, WPARAM wParam, LPARAM lParam)
3037 TOOLBAR_INFO *infoPtr = TOOLBAR_GetInfoPtr (hwnd);
3039 if (infoPtr == NULL)
3040 return 0;
3041 return infoPtr->hwndToolTip;
3045 static LRESULT
3046 TOOLBAR_GetUnicodeFormat (HWND hwnd, WPARAM wParam, LPARAM lParam)
3048 TOOLBAR_INFO *infoPtr = TOOLBAR_GetInfoPtr (hwnd);
3050 TRACE("%s hwnd=0x%x stub!\n",
3051 infoPtr->bUnicode ? "TRUE" : "FALSE", hwnd);
3053 return infoPtr->bUnicode;
3057 inline static LRESULT
3058 TOOLBAR_GetVersion (HWND hwnd)
3060 TOOLBAR_INFO *infoPtr = TOOLBAR_GetInfoPtr (hwnd);
3061 return infoPtr->iVersion;
3065 static LRESULT
3066 TOOLBAR_HideButton (HWND hwnd, WPARAM wParam, LPARAM lParam)
3068 TOOLBAR_INFO *infoPtr = TOOLBAR_GetInfoPtr (hwnd);
3069 TBUTTON_INFO *btnPtr;
3070 INT nIndex;
3072 TRACE("\n");
3074 nIndex = TOOLBAR_GetButtonIndex (infoPtr, (INT)wParam, FALSE);
3075 if (nIndex == -1)
3076 return FALSE;
3078 btnPtr = &infoPtr->buttons[nIndex];
3079 if (LOWORD(lParam) == FALSE)
3080 btnPtr->fsState &= ~TBSTATE_HIDDEN;
3081 else
3082 btnPtr->fsState |= TBSTATE_HIDDEN;
3084 TOOLBAR_CalcToolbar (hwnd);
3086 InvalidateRect (hwnd, NULL, TRUE);
3088 return TRUE;
3092 inline static LRESULT
3093 TOOLBAR_HitTest (HWND hwnd, WPARAM wParam, LPARAM lParam)
3095 return TOOLBAR_InternalHitTest (hwnd, (LPPOINT)lParam);
3099 static LRESULT
3100 TOOLBAR_Indeterminate (HWND hwnd, WPARAM wParam, LPARAM lParam)
3102 TOOLBAR_INFO *infoPtr = TOOLBAR_GetInfoPtr (hwnd);
3103 TBUTTON_INFO *btnPtr;
3104 INT nIndex;
3106 nIndex = TOOLBAR_GetButtonIndex (infoPtr, (INT)wParam, FALSE);
3107 if (nIndex == -1)
3108 return FALSE;
3110 btnPtr = &infoPtr->buttons[nIndex];
3111 if (LOWORD(lParam) == FALSE)
3112 btnPtr->fsState &= ~TBSTATE_INDETERMINATE;
3113 else
3114 btnPtr->fsState |= TBSTATE_INDETERMINATE;
3116 InvalidateRect(hwnd, &btnPtr->rect, TOOLBAR_HasText(infoPtr, btnPtr));
3118 return TRUE;
3122 static LRESULT
3123 TOOLBAR_InsertButtonA (HWND hwnd, WPARAM wParam, LPARAM lParam)
3125 TOOLBAR_INFO *infoPtr = TOOLBAR_GetInfoPtr (hwnd);
3126 LPTBBUTTON lpTbb = (LPTBBUTTON)lParam;
3127 INT nIndex = (INT)wParam;
3128 TBUTTON_INFO *oldButtons;
3130 if (lpTbb == NULL)
3131 return FALSE;
3133 TOOLBAR_DumpButton(infoPtr, (TBUTTON_INFO *)lpTbb, nIndex, FALSE);
3135 if (nIndex == -1) {
3136 /* EPP: this seems to be an undocumented call (from my IE4)
3137 * I assume in that case that:
3138 * - lpTbb->iString is a string pointer (not a string index in strings[] table
3139 * - index of insertion is at the end of existing buttons
3140 * I only see this happen with nIndex == -1, but it could have a special
3141 * meaning (like -nIndex (or ~nIndex) to get the real position of insertion).
3143 int len;
3144 LPSTR ptr;
3146 /* FIXME: iString == -1 is undocumented */
3147 if(lpTbb->iString && lpTbb->iString!=-1) {
3148 len = strlen((char*)lpTbb->iString) + 2;
3149 ptr = COMCTL32_Alloc(len);
3150 nIndex = infoPtr->nNumButtons;
3151 strcpy(ptr, (char*)lpTbb->iString);
3152 ptr[len - 1] = 0; /* ended by two '\0' */
3153 lpTbb->iString = TOOLBAR_AddStringA(hwnd, 0, (LPARAM)ptr);
3154 COMCTL32_Free(ptr);
3156 else {
3157 ERR("lpTbb->iString is NULL\n");
3158 return FALSE;
3161 } else if (nIndex < 0)
3162 return FALSE;
3164 TRACE("inserting button index=%d\n", nIndex);
3165 if (nIndex > infoPtr->nNumButtons) {
3166 nIndex = infoPtr->nNumButtons;
3167 TRACE("adjust index=%d\n", nIndex);
3170 oldButtons = infoPtr->buttons;
3171 infoPtr->nNumButtons++;
3172 infoPtr->buttons = COMCTL32_Alloc (sizeof (TBUTTON_INFO) * infoPtr->nNumButtons);
3173 /* pre insert copy */
3174 if (nIndex > 0) {
3175 memcpy (&infoPtr->buttons[0], &oldButtons[0],
3176 nIndex * sizeof(TBUTTON_INFO));
3179 /* insert new button */
3180 infoPtr->buttons[nIndex].iBitmap = lpTbb->iBitmap;
3181 infoPtr->buttons[nIndex].idCommand = lpTbb->idCommand;
3182 infoPtr->buttons[nIndex].fsState = lpTbb->fsState;
3183 infoPtr->buttons[nIndex].fsStyle = lpTbb->fsStyle;
3184 infoPtr->buttons[nIndex].dwData = lpTbb->dwData;
3185 infoPtr->buttons[nIndex].iString = lpTbb->iString;
3187 if ((infoPtr->hwndToolTip) && !(lpTbb->fsStyle & TBSTYLE_SEP)) {
3188 TTTOOLINFOA ti;
3190 ZeroMemory (&ti, sizeof(TTTOOLINFOA));
3191 ti.cbSize = sizeof (TTTOOLINFOA);
3192 ti.hwnd = hwnd;
3193 ti.uId = lpTbb->idCommand;
3194 ti.hinst = 0;
3195 ti.lpszText = LPSTR_TEXTCALLBACKA;
3197 SendMessageA (infoPtr->hwndToolTip, TTM_ADDTOOLA,
3198 0, (LPARAM)&ti);
3201 /* post insert copy */
3202 if (nIndex < infoPtr->nNumButtons - 1) {
3203 memcpy (&infoPtr->buttons[nIndex+1], &oldButtons[nIndex],
3204 (infoPtr->nNumButtons - nIndex - 1) * sizeof(TBUTTON_INFO));
3207 COMCTL32_Free (oldButtons);
3209 TOOLBAR_CalcToolbar (hwnd);
3211 InvalidateRect (hwnd, NULL, FALSE);
3213 return TRUE;
3217 static LRESULT
3218 TOOLBAR_InsertButtonW (HWND hwnd, WPARAM wParam, LPARAM lParam)
3220 TOOLBAR_INFO *infoPtr = TOOLBAR_GetInfoPtr (hwnd);
3221 LPTBBUTTON lpTbb = (LPTBBUTTON)lParam;
3222 INT nIndex = (INT)wParam;
3223 TBUTTON_INFO *oldButtons;
3225 if (lpTbb == NULL)
3226 return FALSE;
3227 if (nIndex < 0)
3228 return FALSE;
3230 TRACE("inserting button index=%d\n", nIndex);
3231 if (nIndex > infoPtr->nNumButtons) {
3232 nIndex = infoPtr->nNumButtons;
3233 TRACE("adjust index=%d\n", nIndex);
3236 oldButtons = infoPtr->buttons;
3237 infoPtr->nNumButtons++;
3238 infoPtr->buttons = COMCTL32_Alloc (sizeof (TBUTTON_INFO) * infoPtr->nNumButtons);
3239 /* pre insert copy */
3240 if (nIndex > 0) {
3241 memcpy (&infoPtr->buttons[0], &oldButtons[0],
3242 nIndex * sizeof(TBUTTON_INFO));
3245 /* insert new button */
3246 infoPtr->buttons[nIndex].iBitmap = lpTbb->iBitmap;
3247 infoPtr->buttons[nIndex].idCommand = lpTbb->idCommand;
3248 infoPtr->buttons[nIndex].fsState = lpTbb->fsState;
3249 infoPtr->buttons[nIndex].fsStyle = lpTbb->fsStyle;
3250 infoPtr->buttons[nIndex].dwData = lpTbb->dwData;
3251 infoPtr->buttons[nIndex].iString = lpTbb->iString;
3253 if ((infoPtr->hwndToolTip) && !(lpTbb->fsStyle & TBSTYLE_SEP)) {
3254 TTTOOLINFOW ti;
3256 ZeroMemory (&ti, sizeof(TTTOOLINFOW));
3257 ti.cbSize = sizeof (TTTOOLINFOW);
3258 ti.hwnd = hwnd;
3259 ti.uId = lpTbb->idCommand;
3260 ti.hinst = 0;
3261 ti.lpszText = LPSTR_TEXTCALLBACKW;
3263 SendMessageW (infoPtr->hwndToolTip, TTM_ADDTOOLW,
3264 0, (LPARAM)&ti);
3267 /* post insert copy */
3268 if (nIndex < infoPtr->nNumButtons - 1) {
3269 memcpy (&infoPtr->buttons[nIndex+1], &oldButtons[nIndex],
3270 (infoPtr->nNumButtons - nIndex - 1) * sizeof(TBUTTON_INFO));
3273 COMCTL32_Free (oldButtons);
3275 InvalidateRect (hwnd, NULL, FALSE);
3277 return TRUE;
3281 /* << TOOLBAR_InsertMarkHitTest >> */
3284 static LRESULT
3285 TOOLBAR_IsButtonChecked (HWND hwnd, WPARAM wParam, LPARAM lParam)
3287 TOOLBAR_INFO *infoPtr = TOOLBAR_GetInfoPtr (hwnd);
3288 INT nIndex;
3290 nIndex = TOOLBAR_GetButtonIndex (infoPtr, (INT)wParam, FALSE);
3291 if (nIndex == -1)
3292 return FALSE;
3294 return (infoPtr->buttons[nIndex].fsState & TBSTATE_CHECKED);
3298 static LRESULT
3299 TOOLBAR_IsButtonEnabled (HWND hwnd, WPARAM wParam, LPARAM lParam)
3301 TOOLBAR_INFO *infoPtr = TOOLBAR_GetInfoPtr (hwnd);
3302 INT nIndex;
3304 nIndex = TOOLBAR_GetButtonIndex (infoPtr, (INT)wParam, FALSE);
3305 if (nIndex == -1)
3306 return FALSE;
3308 return (infoPtr->buttons[nIndex].fsState & TBSTATE_ENABLED);
3312 static LRESULT
3313 TOOLBAR_IsButtonHidden (HWND hwnd, WPARAM wParam, LPARAM lParam)
3315 TOOLBAR_INFO *infoPtr = TOOLBAR_GetInfoPtr (hwnd);
3316 INT nIndex;
3318 nIndex = TOOLBAR_GetButtonIndex (infoPtr, (INT)wParam, FALSE);
3319 if (nIndex == -1)
3320 return TRUE;
3322 return (infoPtr->buttons[nIndex].fsState & TBSTATE_HIDDEN);
3326 static LRESULT
3327 TOOLBAR_IsButtonHighlighted (HWND hwnd, WPARAM wParam, LPARAM lParam)
3329 TOOLBAR_INFO *infoPtr = TOOLBAR_GetInfoPtr (hwnd);
3330 INT nIndex;
3332 nIndex = TOOLBAR_GetButtonIndex (infoPtr, (INT)wParam, FALSE);
3333 if (nIndex == -1)
3334 return FALSE;
3336 return (infoPtr->buttons[nIndex].fsState & TBSTATE_MARKED);
3340 static LRESULT
3341 TOOLBAR_IsButtonIndeterminate (HWND hwnd, WPARAM wParam, LPARAM lParam)
3343 TOOLBAR_INFO *infoPtr = TOOLBAR_GetInfoPtr (hwnd);
3344 INT nIndex;
3346 nIndex = TOOLBAR_GetButtonIndex (infoPtr, (INT)wParam, FALSE);
3347 if (nIndex == -1)
3348 return FALSE;
3350 return (infoPtr->buttons[nIndex].fsState & TBSTATE_INDETERMINATE);
3354 static LRESULT
3355 TOOLBAR_IsButtonPressed (HWND hwnd, WPARAM wParam, LPARAM lParam)
3357 TOOLBAR_INFO *infoPtr = TOOLBAR_GetInfoPtr (hwnd);
3358 INT nIndex;
3360 nIndex = TOOLBAR_GetButtonIndex (infoPtr, (INT)wParam, FALSE);
3361 if (nIndex == -1)
3362 return FALSE;
3364 return (infoPtr->buttons[nIndex].fsState & TBSTATE_PRESSED);
3368 /* << TOOLBAR_LoadImages >> */
3369 /* << TOOLBAR_MapAccelerator >> */
3370 /* << TOOLBAR_MarkButton >> */
3371 /* << TOOLBAR_MoveButton >> */
3374 static LRESULT
3375 TOOLBAR_PressButton (HWND hwnd, WPARAM wParam, LPARAM lParam)
3377 TOOLBAR_INFO *infoPtr = TOOLBAR_GetInfoPtr (hwnd);
3378 TBUTTON_INFO *btnPtr;
3379 INT nIndex;
3381 nIndex = TOOLBAR_GetButtonIndex (infoPtr, (INT)wParam, FALSE);
3382 if (nIndex == -1)
3383 return FALSE;
3385 btnPtr = &infoPtr->buttons[nIndex];
3386 if (LOWORD(lParam) == FALSE)
3387 btnPtr->fsState &= ~TBSTATE_PRESSED;
3388 else
3389 btnPtr->fsState |= TBSTATE_PRESSED;
3391 InvalidateRect(hwnd, &btnPtr->rect, TOOLBAR_HasText(infoPtr, btnPtr));
3393 return TRUE;
3397 /* << TOOLBAR_ReplaceBitmap >> */
3400 static LRESULT
3401 TOOLBAR_SaveRestoreA (HWND hwnd, WPARAM wParam, LPARAM lParam)
3403 #if 0
3404 TOOLBAR_INFO *infoPtr = TOOLBAR_GetInfoPtr (hwnd);
3405 LPTBSAVEPARAMSA lpSave = (LPTBSAVEPARAMSA)lParam;
3407 if (lpSave == NULL) return 0;
3409 if ((BOOL)wParam) {
3410 /* save toolbar information */
3411 FIXME("save to \"%s\" \"%s\"\n",
3412 lpSave->pszSubKey, lpSave->pszValueName);
3416 else {
3417 /* restore toolbar information */
3419 FIXME("restore from \"%s\" \"%s\"\n",
3420 lpSave->pszSubKey, lpSave->pszValueName);
3424 #endif
3426 return 0;
3430 static LRESULT
3431 TOOLBAR_SaveRestoreW (HWND hwnd, WPARAM wParam, LPARAM lParam)
3433 #if 0
3434 TOOLBAR_INFO *infoPtr = TOOLBAR_GetInfoPtr (hwnd);
3435 LPTBSAVEPARAMSW lpSave = (LPTBSAVEPARAMSW)lParam;
3437 if (lpSave == NULL)
3438 return 0;
3440 if ((BOOL)wParam) {
3441 /* save toolbar information */
3442 FIXME("save to \"%s\" \"%s\"\n",
3443 lpSave->pszSubKey, lpSave->pszValueName);
3447 else {
3448 /* restore toolbar information */
3450 FIXME("restore from \"%s\" \"%s\"\n",
3451 lpSave->pszSubKey, lpSave->pszValueName);
3455 #endif
3457 return 0;
3461 static LRESULT
3462 TOOLBAR_SetAnchorHighlight (HWND hwnd, WPARAM wParam)
3464 TOOLBAR_INFO *infoPtr = TOOLBAR_GetInfoPtr (hwnd);
3465 BOOL bOldAnchor = infoPtr->bAnchor;
3467 infoPtr->bAnchor = (BOOL)wParam;
3469 return (LRESULT)bOldAnchor;
3473 static LRESULT
3474 TOOLBAR_SetBitmapSize (HWND hwnd, WPARAM wParam, LPARAM lParam)
3476 TOOLBAR_INFO *infoPtr = TOOLBAR_GetInfoPtr (hwnd);
3478 if ((LOWORD(lParam) <= 0) || (HIWORD(lParam)<=0))
3479 return FALSE;
3481 if (infoPtr->nNumButtons > 0)
3482 WARN("%d buttons, undoc increase to bitmap size : %d-%d -> %d-%d\n",
3483 infoPtr->nNumButtons,
3484 infoPtr->nBitmapWidth, infoPtr->nBitmapHeight,
3485 LOWORD(lParam), HIWORD(lParam));
3487 infoPtr->nBitmapWidth = (INT)LOWORD(lParam);
3488 infoPtr->nBitmapHeight = (INT)HIWORD(lParam);
3490 /* uses image list internals directly */
3491 if (infoPtr->himlDef) {
3492 infoPtr->himlDef->cx = infoPtr->nBitmapWidth;
3493 infoPtr->himlDef->cy = infoPtr->nBitmapHeight;
3496 return TRUE;
3500 static LRESULT
3501 TOOLBAR_SetButtonInfoA (HWND hwnd, WPARAM wParam, LPARAM lParam)
3503 TOOLBAR_INFO *infoPtr = TOOLBAR_GetInfoPtr (hwnd);
3504 LPTBBUTTONINFOA lptbbi = (LPTBBUTTONINFOA)lParam;
3505 TBUTTON_INFO *btnPtr;
3506 INT nIndex;
3508 if (lptbbi == NULL)
3509 return FALSE;
3510 if (lptbbi->cbSize < sizeof(TBBUTTONINFOA))
3511 return FALSE;
3513 nIndex = TOOLBAR_GetButtonIndex (infoPtr, (INT)wParam,
3514 lptbbi->dwMask & 0x80000000);
3515 if (nIndex == -1)
3516 return FALSE;
3518 btnPtr = &infoPtr->buttons[nIndex];
3519 if (lptbbi->dwMask & TBIF_COMMAND)
3520 btnPtr->idCommand = lptbbi->idCommand;
3521 if (lptbbi->dwMask & TBIF_IMAGE)
3522 btnPtr->iBitmap = lptbbi->iImage;
3523 if (lptbbi->dwMask & TBIF_LPARAM)
3524 btnPtr->dwData = lptbbi->lParam;
3525 /* if (lptbbi->dwMask & TBIF_SIZE) */
3526 /* btnPtr->cx = lptbbi->cx; */
3527 if (lptbbi->dwMask & TBIF_STATE)
3528 btnPtr->fsState = lptbbi->fsState;
3529 if (lptbbi->dwMask & TBIF_STYLE)
3530 btnPtr->fsStyle = lptbbi->fsStyle;
3532 if (lptbbi->dwMask & TBIF_TEXT) {
3533 if ((btnPtr->iString >= 0) ||
3534 (btnPtr->iString < infoPtr->nNumStrings)) {
3535 TRACE("Ooooooch\n");
3536 #if 0
3537 WCHAR **lpString = &infoPtr->strings[btnPtr->iString];
3538 INT len = lstrlenA (lptbbi->pszText);
3539 *lpString = COMCTL32_ReAlloc (lpString, sizeof(WCHAR)*(len+1));
3540 #endif
3542 /* this is the ultimate sollution */
3543 /* Str_SetPtrA (&infoPtr->strings[btnPtr->iString], lptbbi->pszText); */
3547 return TRUE;
3551 static LRESULT
3552 TOOLBAR_SetButtonInfoW (HWND hwnd, WPARAM wParam, LPARAM lParam)
3554 TOOLBAR_INFO *infoPtr = TOOLBAR_GetInfoPtr (hwnd);
3555 LPTBBUTTONINFOW lptbbi = (LPTBBUTTONINFOW)lParam;
3556 TBUTTON_INFO *btnPtr;
3557 INT nIndex;
3559 if (lptbbi == NULL)
3560 return FALSE;
3561 if (lptbbi->cbSize < sizeof(TBBUTTONINFOW))
3562 return FALSE;
3564 nIndex = TOOLBAR_GetButtonIndex (infoPtr, (INT)wParam,
3565 lptbbi->dwMask & 0x80000000);
3566 if (nIndex == -1)
3567 return FALSE;
3569 btnPtr = &infoPtr->buttons[nIndex];
3570 if (lptbbi->dwMask & TBIF_COMMAND)
3571 btnPtr->idCommand = lptbbi->idCommand;
3572 if (lptbbi->dwMask & TBIF_IMAGE)
3573 btnPtr->iBitmap = lptbbi->iImage;
3574 if (lptbbi->dwMask & TBIF_LPARAM)
3575 btnPtr->dwData = lptbbi->lParam;
3576 /* if (lptbbi->dwMask & TBIF_SIZE) */
3577 /* btnPtr->cx = lptbbi->cx; */
3578 if (lptbbi->dwMask & TBIF_STATE)
3579 btnPtr->fsState = lptbbi->fsState;
3580 if (lptbbi->dwMask & TBIF_STYLE)
3581 btnPtr->fsStyle = lptbbi->fsStyle;
3583 if (lptbbi->dwMask & TBIF_TEXT) {
3584 if ((btnPtr->iString >= 0) ||
3585 (btnPtr->iString < infoPtr->nNumStrings)) {
3586 #if 0
3587 WCHAR **lpString = &infoPtr->strings[btnPtr->iString];
3588 INT len = lstrlenW (lptbbi->pszText);
3589 *lpString = COMCTL32_ReAlloc (lpString, sizeof(WCHAR)*(len+1));
3590 #endif
3592 /* this is the ultimate solution */
3593 /* Str_SetPtrA (&infoPtr->strings[btnPtr->iString], lptbbi->pszText); */
3597 return TRUE;
3601 static LRESULT
3602 TOOLBAR_SetButtonSize (HWND hwnd, WPARAM wParam, LPARAM lParam)
3604 TOOLBAR_INFO *infoPtr = TOOLBAR_GetInfoPtr (hwnd);
3606 if ((LOWORD(lParam) <= 0) || (HIWORD(lParam)<=0))
3608 ERR("invalid parameter\n");
3609 return FALSE;
3612 /* The documentation claims you can only change the button size before
3613 * any button has been added. But this is wrong.
3614 * WINZIP32.EXE (ver 8) calls this on one of its buttons after adding
3615 * it to the toolbar, and it checks that the return value is nonzero - mjm
3616 * Further testing shows that we must actually perform the change too.
3618 infoPtr->nButtonWidth = (INT)LOWORD(lParam);
3619 infoPtr->nButtonHeight = (INT)HIWORD(lParam);
3620 return TRUE;
3624 static LRESULT
3625 TOOLBAR_SetButtonWidth (HWND hwnd, WPARAM wParam, LPARAM lParam)
3627 TOOLBAR_INFO *infoPtr = TOOLBAR_GetInfoPtr (hwnd);
3629 if (infoPtr == NULL) {
3630 TRACE("Toolbar not initialized yet?????\n");
3631 return FALSE;
3634 /* if setting to current values, ignore */
3635 if ((infoPtr->cxMin == (INT)LOWORD(lParam)) &&
3636 (infoPtr->cxMax == (INT)HIWORD(lParam))) {
3637 TRACE("matches current width, min=%d, max=%d, no recalc\n",
3638 infoPtr->cxMin, infoPtr->cxMax);
3639 return TRUE;
3642 /* save new values */
3643 infoPtr->cxMin = (INT)LOWORD(lParam);
3644 infoPtr->cxMax = (INT)HIWORD(lParam);
3646 /* if both values are 0 then we are done */
3647 if (lParam == 0) {
3648 TRACE("setting both min and max to 0, norecalc\n");
3649 return TRUE;
3652 /* otherwise we need to recalc the toolbar and in some cases
3653 recalc the bounding rectangle (does DrawText w/ DT_CALCRECT
3654 which doesn't actually draw - GA). */
3655 TRACE("number of buttons %d, cx=%d, cy=%d, recalcing\n",
3656 infoPtr->nNumButtons, infoPtr->cxMin, infoPtr->cxMax);
3658 TOOLBAR_CalcToolbar (hwnd);
3660 InvalidateRect (hwnd, NULL, TRUE);
3662 return TRUE;
3666 static LRESULT
3667 TOOLBAR_SetCmdId (HWND hwnd, WPARAM wParam, LPARAM lParam)
3669 TOOLBAR_INFO *infoPtr = TOOLBAR_GetInfoPtr (hwnd);
3670 INT nIndex = (INT)wParam;
3672 if ((nIndex < 0) || (nIndex >= infoPtr->nNumButtons))
3673 return FALSE;
3675 infoPtr->buttons[nIndex].idCommand = (INT)lParam;
3677 if (infoPtr->hwndToolTip) {
3679 FIXME("change tool tip!\n");
3683 return TRUE;
3687 /* << TOOLBAR_SetColorScheme >> */
3690 static LRESULT
3691 TOOLBAR_SetDisabledImageList (HWND hwnd, WPARAM wParam, LPARAM lParam)
3693 TOOLBAR_INFO *infoPtr = TOOLBAR_GetInfoPtr (hwnd);
3694 HIMAGELIST himlTemp;
3697 himlTemp = infoPtr->himlDis;
3698 infoPtr->himlDis = (HIMAGELIST)lParam;
3700 /* FIXME: redraw ? */
3702 return (LRESULT)himlTemp;
3706 static LRESULT
3707 TOOLBAR_SetDrawTextFlags (HWND hwnd, WPARAM wParam, LPARAM lParam)
3709 TOOLBAR_INFO *infoPtr = TOOLBAR_GetInfoPtr (hwnd);
3710 DWORD dwTemp;
3712 dwTemp = infoPtr->dwDTFlags;
3713 infoPtr->dwDTFlags =
3714 (infoPtr->dwDTFlags & (DWORD)wParam) | (DWORD)lParam;
3716 return (LRESULT)dwTemp;
3720 static LRESULT
3721 TOOLBAR_SetExtendedStyle (HWND hwnd, WPARAM wParam, LPARAM lParam)
3723 TOOLBAR_INFO *infoPtr = TOOLBAR_GetInfoPtr (hwnd);
3724 DWORD dwTemp;
3726 dwTemp = infoPtr->dwExStyle;
3727 infoPtr->dwExStyle = (DWORD)lParam;
3729 return (LRESULT)dwTemp;
3733 static LRESULT
3734 TOOLBAR_SetHotImageList (HWND hwnd, WPARAM wParam, LPARAM lParam)
3736 TOOLBAR_INFO *infoPtr = TOOLBAR_GetInfoPtr(hwnd);
3737 HIMAGELIST himlTemp;
3739 himlTemp = infoPtr->himlHot;
3740 infoPtr->himlHot = (HIMAGELIST)lParam;
3742 /* FIXME: redraw ? */
3744 return (LRESULT)himlTemp;
3748 static LRESULT
3749 TOOLBAR_SetHotItem (HWND hwnd, WPARAM wParam)
3751 TOOLBAR_INFO *infoPtr = TOOLBAR_GetInfoPtr(hwnd);
3752 INT nOldHotItem = infoPtr->nHotItem;
3753 TBUTTON_INFO *btnPtr;
3755 if ((INT) wParam < 0 || (INT)wParam > infoPtr->nNumButtons)
3756 wParam = -2;
3758 if (GetWindowLongA (hwnd, GWL_STYLE) & TBSTYLE_FLAT)
3761 infoPtr->nHotItem = (INT)wParam;
3762 if ((INT)wParam >=0)
3764 btnPtr = &infoPtr->buttons[(INT)wParam];
3765 btnPtr->bHot = TRUE;
3766 InvalidateRect (hwnd, &btnPtr->rect,
3767 TOOLBAR_HasText(infoPtr, btnPtr));
3769 if (nOldHotItem>=0)
3771 btnPtr = &infoPtr->buttons[nOldHotItem];
3772 btnPtr->bHot = FALSE;
3773 InvalidateRect (hwnd, &btnPtr->rect,
3774 TOOLBAR_HasText(infoPtr, btnPtr));
3778 if (nOldHotItem < 0)
3779 return -1;
3781 return (LRESULT)nOldHotItem;
3785 static LRESULT
3786 TOOLBAR_SetImageList (HWND hwnd, WPARAM wParam, LPARAM lParam)
3788 TOOLBAR_INFO *infoPtr = TOOLBAR_GetInfoPtr (hwnd);
3789 HIMAGELIST himlTemp;
3791 himlTemp = infoPtr->himlDef;
3792 infoPtr->himlDef = (HIMAGELIST)lParam;
3794 infoPtr->nNumBitmaps = ImageList_GetImageCount(infoPtr->himlDef);
3796 ImageList_GetIconSize(infoPtr->himlDef, &infoPtr->nBitmapWidth,
3797 &infoPtr->nBitmapHeight);
3798 TRACE("hwnd %08x, new himl=%08x, count=%d, bitmap w=%d, h=%d\n",
3799 hwnd, (INT)infoPtr->himlDef, infoPtr->nNumBitmaps,
3800 infoPtr->nBitmapWidth, infoPtr->nBitmapHeight);
3802 /* FIXME: redraw ? */
3804 return (LRESULT)himlTemp;
3808 static LRESULT
3809 TOOLBAR_SetIndent (HWND hwnd, WPARAM wParam, LPARAM lParam)
3811 TOOLBAR_INFO *infoPtr = TOOLBAR_GetInfoPtr (hwnd);
3813 infoPtr->nIndent = (INT)wParam;
3815 TRACE("\n");
3817 /* process only on indent changing */
3818 if(infoPtr->nIndent != (INT)wParam)
3820 infoPtr->nIndent = (INT)wParam;
3821 TOOLBAR_CalcToolbar (hwnd);
3822 InvalidateRect(hwnd, NULL, FALSE);
3825 return TRUE;
3829 /* << TOOLBAR_SetInsertMark >> */
3832 static LRESULT
3833 TOOLBAR_SetInsertMarkColor (HWND hwnd, WPARAM wParam, LPARAM lParam)
3835 TOOLBAR_INFO *infoPtr = TOOLBAR_GetInfoPtr (hwnd);
3837 infoPtr->clrInsertMark = (COLORREF)lParam;
3839 /* FIXME : redraw ??*/
3841 return 0;
3845 static LRESULT
3846 TOOLBAR_SetMaxTextRows (HWND hwnd, WPARAM wParam, LPARAM lParam)
3848 TOOLBAR_INFO *infoPtr = TOOLBAR_GetInfoPtr (hwnd);
3850 if (infoPtr == NULL)
3851 return FALSE;
3853 infoPtr->nMaxTextRows = (INT)wParam;
3855 return TRUE;
3859 /* << TOOLBAR_SetPadding >> */
3862 static LRESULT
3863 TOOLBAR_SetParent (HWND hwnd, WPARAM wParam, LPARAM lParam)
3865 TOOLBAR_INFO *infoPtr = TOOLBAR_GetInfoPtr (hwnd);
3866 HWND hwndOldNotify;
3868 TRACE("\n");
3870 if (infoPtr == NULL)
3871 return 0;
3872 hwndOldNotify = infoPtr->hwndNotify;
3873 infoPtr->hwndNotify = (HWND)wParam;
3875 return hwndOldNotify;
3879 static LRESULT
3880 TOOLBAR_SetRows (HWND hwnd, WPARAM wParam, LPARAM lParam)
3882 TOOLBAR_INFO *infoPtr = TOOLBAR_GetInfoPtr (hwnd);
3883 LPRECT lprc = (LPRECT)lParam;
3885 TRACE("\n");
3887 if (LOWORD(wParam) > 1) {
3888 FIXME("multiple rows not supported!\n");
3891 if(infoPtr->nRows != LOWORD(wParam))
3893 infoPtr->nRows = LOWORD(wParam);
3895 /* recalculate toolbar */
3896 TOOLBAR_CalcToolbar (hwnd);
3898 /* repaint toolbar */
3899 InvalidateRect(hwnd, NULL, FALSE);
3902 /* return bounding rectangle */
3903 if (lprc) {
3904 lprc->left = infoPtr->rcBound.left;
3905 lprc->right = infoPtr->rcBound.right;
3906 lprc->top = infoPtr->rcBound.top;
3907 lprc->bottom = infoPtr->rcBound.bottom;
3910 return 0;
3914 static LRESULT
3915 TOOLBAR_SetState (HWND hwnd, WPARAM wParam, LPARAM lParam)
3917 TOOLBAR_INFO *infoPtr = TOOLBAR_GetInfoPtr (hwnd);
3918 TBUTTON_INFO *btnPtr;
3919 INT nIndex;
3921 nIndex = TOOLBAR_GetButtonIndex (infoPtr, (INT)wParam, FALSE);
3922 if (nIndex == -1)
3923 return FALSE;
3925 btnPtr = &infoPtr->buttons[nIndex];
3927 /* if hidden state has changed the invalidate entire window and recalc */
3928 if ((btnPtr->fsState & TBSTATE_HIDDEN) != (LOWORD(lParam) & TBSTATE_HIDDEN)) {
3929 btnPtr->fsState = LOWORD(lParam);
3930 TOOLBAR_CalcToolbar (hwnd);
3931 InvalidateRect(hwnd, 0, TOOLBAR_HasText(infoPtr, btnPtr));
3932 return TRUE;
3935 /* process state changing if current state doesn't match new state */
3936 if(btnPtr->fsState != LOWORD(lParam))
3938 btnPtr->fsState = LOWORD(lParam);
3939 InvalidateRect(hwnd, &btnPtr->rect, TOOLBAR_HasText(infoPtr,
3940 btnPtr));
3943 return TRUE;
3947 static LRESULT
3948 TOOLBAR_SetStyle (HWND hwnd, WPARAM wParam, LPARAM lParam)
3950 TOOLBAR_INFO *infoPtr = TOOLBAR_GetInfoPtr (hwnd);
3951 TBUTTON_INFO *btnPtr;
3952 INT nIndex;
3954 nIndex = TOOLBAR_GetButtonIndex (infoPtr, (INT)wParam, FALSE);
3955 if (nIndex == -1)
3956 return FALSE;
3958 btnPtr = &infoPtr->buttons[nIndex];
3960 /* process style change if current style doesn't match new style */
3961 if(btnPtr->fsStyle != LOWORD(lParam))
3963 btnPtr->fsStyle = LOWORD(lParam);
3964 InvalidateRect(hwnd, &btnPtr->rect, TOOLBAR_HasText(infoPtr,
3965 btnPtr));
3967 if (infoPtr->hwndToolTip) {
3968 FIXME("change tool tip!\n");
3972 return TRUE;
3976 inline static LRESULT
3977 TOOLBAR_SetToolTips (HWND hwnd, WPARAM wParam, LPARAM lParam)
3979 TOOLBAR_INFO *infoPtr = TOOLBAR_GetInfoPtr (hwnd);
3981 if (infoPtr == NULL)
3982 return 0;
3983 infoPtr->hwndToolTip = (HWND)wParam;
3984 return 0;
3988 static LRESULT
3989 TOOLBAR_SetUnicodeFormat (HWND hwnd, WPARAM wParam, LPARAM lParam)
3991 TOOLBAR_INFO *infoPtr = TOOLBAR_GetInfoPtr (hwnd);
3992 BOOL bTemp;
3994 TRACE("%s hwnd=0x%04x stub!\n",
3995 ((BOOL)wParam) ? "TRUE" : "FALSE", hwnd);
3997 bTemp = infoPtr->bUnicode;
3998 infoPtr->bUnicode = (BOOL)wParam;
4000 return bTemp;
4004 static LRESULT
4005 TOOLBAR_SetVersion (HWND hwnd, INT iVersion)
4007 TOOLBAR_INFO *infoPtr = TOOLBAR_GetInfoPtr (hwnd);
4008 INT iOldVersion = infoPtr->iVersion;
4010 infoPtr->iVersion = iVersion;
4012 return iOldVersion;
4016 static LRESULT
4017 TOOLBAR_Create (HWND hwnd, WPARAM wParam, LPARAM lParam)
4019 TOOLBAR_INFO *infoPtr = TOOLBAR_GetInfoPtr (hwnd);
4020 DWORD dwStyle = GetWindowLongA (hwnd, GWL_STYLE);
4021 LOGFONTA logFont;
4023 /* initialize info structure */
4024 infoPtr->nButtonHeight = 22;
4025 infoPtr->nButtonWidth = 24;
4026 infoPtr->nBitmapHeight = 15;
4027 infoPtr->nBitmapWidth = 16;
4029 infoPtr->nHeight = infoPtr->nButtonHeight + TOP_BORDER + BOTTOM_BORDER;
4030 infoPtr->nRows = 1;
4031 infoPtr->nMaxTextRows = 1;
4032 infoPtr->cxMin = -1;
4033 infoPtr->cxMax = -1;
4034 infoPtr->nNumBitmaps = 0;
4035 infoPtr->nNumStrings = 0;
4037 infoPtr->bCaptured = FALSE;
4038 infoPtr->bUnicode = IsWindowUnicode (hwnd);
4039 infoPtr->nButtonDown = -1;
4040 infoPtr->nOldHit = -1;
4041 infoPtr->nHotItem = -2; /* It has to be initially different from nOldHit */
4042 infoPtr->hwndNotify = GetParent (hwnd);
4043 infoPtr->bTransparent = (dwStyle & TBSTYLE_TRANSPARENT);
4044 infoPtr->bBtnTranspnt = (dwStyle & (TBSTYLE_FLAT | TBSTYLE_LIST));
4045 infoPtr->dwDTFlags = (dwStyle & TBSTYLE_LIST) ? DT_LEFT | DT_VCENTER | DT_SINGLELINE : DT_CENTER;
4046 infoPtr->bAnchor = FALSE; /* no anchor highlighting */
4047 infoPtr->iVersion = 0;
4048 infoPtr->bNtfUnicode = FALSE;
4049 infoPtr->hwndSelf = hwnd;
4051 SystemParametersInfoA (SPI_GETICONTITLELOGFONT, 0, &logFont, 0);
4052 infoPtr->hFont = infoPtr->hDefaultFont = CreateFontIndirectA (&logFont);
4054 if (dwStyle & TBSTYLE_TOOLTIPS) {
4055 /* Create tooltip control */
4056 infoPtr->hwndToolTip =
4057 CreateWindowExA (0, TOOLTIPS_CLASSA, NULL, 0,
4058 CW_USEDEFAULT, CW_USEDEFAULT,
4059 CW_USEDEFAULT, CW_USEDEFAULT,
4060 hwnd, 0, 0, 0);
4062 /* Send NM_TOOLTIPSCREATED notification */
4063 if (infoPtr->hwndToolTip) {
4064 NMTOOLTIPSCREATED nmttc;
4066 nmttc.hwndToolTips = infoPtr->hwndToolTip;
4068 TOOLBAR_SendNotify ((NMHDR *) &nmttc, infoPtr,
4069 NM_TOOLTIPSCREATED);
4073 TOOLBAR_CheckStyle (hwnd, dwStyle);
4075 TOOLBAR_CalcToolbar(hwnd);
4077 return 0;
4081 static LRESULT
4082 TOOLBAR_Destroy (HWND hwnd, WPARAM wParam, LPARAM lParam)
4084 TOOLBAR_INFO *infoPtr = TOOLBAR_GetInfoPtr (hwnd);
4086 /* delete tooltip control */
4087 if (infoPtr->hwndToolTip)
4088 DestroyWindow (infoPtr->hwndToolTip);
4090 /* delete button data */
4091 if (infoPtr->buttons)
4092 COMCTL32_Free (infoPtr->buttons);
4094 /* delete strings */
4095 if (infoPtr->strings) {
4096 INT i;
4097 for (i = 0; i < infoPtr->nNumStrings; i++)
4098 if (infoPtr->strings[i])
4099 COMCTL32_Free (infoPtr->strings[i]);
4101 COMCTL32_Free (infoPtr->strings);
4104 /* destroy internal image list */
4105 if (infoPtr->himlInt)
4106 ImageList_Destroy (infoPtr->himlInt);
4108 /* delete default font */
4109 if (infoPtr->hFont)
4110 DeleteObject (infoPtr->hDefaultFont);
4112 /* free toolbar info data */
4113 COMCTL32_Free (infoPtr);
4114 SetWindowLongA (hwnd, 0, 0);
4116 return 0;
4120 static LRESULT
4121 TOOLBAR_EraseBackground (HWND hwnd, WPARAM wParam, LPARAM lParam)
4123 TOOLBAR_INFO *infoPtr = TOOLBAR_GetInfoPtr (hwnd);
4124 DWORD dwStyle = GetWindowLongA (hwnd, GWL_STYLE);
4125 NMTBCUSTOMDRAW tbcd;
4126 INT ret, ntfret;
4128 if (dwStyle & TBSTYLE_CUSTOMERASE) {
4129 ZeroMemory (&tbcd, sizeof(NMTBCUSTOMDRAW));
4130 tbcd.nmcd.dwDrawStage = CDDS_PREERASE;
4131 tbcd.nmcd.hdc = (HDC)wParam;
4132 ntfret = TOOLBAR_SendNotify ((NMHDR *)&tbcd, infoPtr, NM_CUSTOMDRAW);
4133 /* FIXME: in general the return flags *can* be or'ed together */
4134 switch (ntfret)
4136 case CDRF_DODEFAULT:
4137 break;
4138 case CDRF_SKIPDEFAULT:
4139 return TRUE;
4140 default:
4141 FIXME("[%04x] response %d not handled to NM_CUSTOMDRAW (CDDS_PREERASE)\n",
4142 hwnd, ntfret);
4146 /* If the toolbar is "transparent" then pass the WM_ERASEBKGND up
4147 * to my parent for processing.
4149 if (infoPtr->bTransparent) {
4150 POINT pt, ptorig;
4151 HDC hdc = (HDC)wParam;
4152 HWND parent;
4154 pt.x = 0;
4155 pt.y = 0;
4156 parent = GetParent(hwnd);
4157 MapWindowPoints(hwnd, parent, &pt, 1);
4158 OffsetWindowOrgEx (hdc, pt.x, pt.y, &ptorig);
4159 SendMessageA (parent, WM_ERASEBKGND, wParam, lParam);
4160 SetWindowOrgEx (hdc, ptorig.x, ptorig.y, 0);
4161 return TRUE;
4163 ret = DefWindowProcA (hwnd, WM_ERASEBKGND, wParam, lParam);
4165 if (dwStyle & TBSTYLE_CUSTOMERASE) {
4166 ZeroMemory (&tbcd, sizeof(NMTBCUSTOMDRAW));
4167 tbcd.nmcd.dwDrawStage = CDDS_POSTERASE;
4168 tbcd.nmcd.hdc = (HDC)wParam;
4169 ntfret = TOOLBAR_SendNotify ((NMHDR *)&tbcd, infoPtr, NM_CUSTOMDRAW);
4170 switch (ntfret)
4172 case CDRF_DODEFAULT:
4173 break;
4174 case CDRF_SKIPDEFAULT:
4175 return TRUE;
4176 default:
4177 FIXME("[%04x] response %d not handled to NM_CUSTOMDRAW (CDDS_PREERASE)\n",
4178 hwnd, ntfret);
4181 return ret;
4185 static LRESULT
4186 TOOLBAR_GetFont (HWND hwnd, WPARAM wParam, LPARAM lParam)
4188 TOOLBAR_INFO *infoPtr = TOOLBAR_GetInfoPtr (hwnd);
4190 return infoPtr->hFont;
4194 static LRESULT
4195 TOOLBAR_LButtonDblClk (HWND hwnd, WPARAM wParam, LPARAM lParam)
4197 TOOLBAR_INFO *infoPtr = TOOLBAR_GetInfoPtr (hwnd);
4198 TBUTTON_INFO *btnPtr;
4199 POINT pt;
4200 INT nHit;
4202 pt.x = (INT)LOWORD(lParam);
4203 pt.y = (INT)HIWORD(lParam);
4204 nHit = TOOLBAR_InternalHitTest (hwnd, &pt);
4206 if (nHit >= 0) {
4207 btnPtr = &infoPtr->buttons[nHit];
4208 if (!(btnPtr->fsState & TBSTATE_ENABLED))
4209 return 0;
4210 SetCapture (hwnd);
4211 infoPtr->bCaptured = TRUE;
4212 infoPtr->nButtonDown = nHit;
4214 btnPtr->fsState |= TBSTATE_PRESSED;
4216 InvalidateRect(hwnd, &btnPtr->rect, TOOLBAR_HasText(infoPtr,
4217 btnPtr));
4219 else if (GetWindowLongA (hwnd, GWL_STYLE) & CCS_ADJUSTABLE)
4220 TOOLBAR_Customize (hwnd);
4222 return 0;
4226 static LRESULT
4227 TOOLBAR_LButtonDown (HWND hwnd, WPARAM wParam, LPARAM lParam)
4229 TOOLBAR_INFO *infoPtr = TOOLBAR_GetInfoPtr (hwnd);
4230 TBUTTON_INFO *btnPtr;
4231 POINT pt;
4232 INT nHit;
4233 NMTOOLBARA nmtb;
4235 if (infoPtr->hwndToolTip)
4236 TOOLBAR_RelayEvent (infoPtr->hwndToolTip, hwnd,
4237 WM_LBUTTONDOWN, wParam, lParam);
4239 pt.x = (INT)LOWORD(lParam);
4240 pt.y = (INT)HIWORD(lParam);
4241 nHit = TOOLBAR_InternalHitTest (hwnd, &pt);
4243 if (nHit >= 0) {
4244 RECT arrowRect;
4245 btnPtr = &infoPtr->buttons[nHit];
4246 if (!(btnPtr->fsState & TBSTATE_ENABLED))
4247 return 0;
4249 infoPtr->nOldHit = nHit;
4251 CopyRect(&arrowRect, &btnPtr->rect);
4252 arrowRect.left = max(btnPtr->rect.left, btnPtr->rect.right - DDARROW_WIDTH);
4254 /* for EX_DRAWDDARROWS style, click must be in the drop-down arrow rect */
4255 if ((btnPtr->fsStyle & TBSTYLE_DROPDOWN) &&
4256 ((TOOLBAR_HasDropDownArrows(infoPtr->dwExStyle) && PtInRect(&arrowRect, pt)) ||
4257 (!TOOLBAR_HasDropDownArrows(infoPtr->dwExStyle))))
4259 LRESULT res;
4261 * this time we must force a Redraw, so the btn is
4262 * painted down before CaptureChanged repaints it up
4264 RedrawWindow(hwnd,&btnPtr->rect,0,
4265 RDW_ERASE|RDW_INVALIDATE|RDW_UPDATENOW);
4267 nmtb.iItem = btnPtr->idCommand;
4268 memset(&nmtb.tbButton, 0, sizeof(TBBUTTON));
4269 nmtb.cchText = 0;
4270 nmtb.pszText = 0;
4271 memset(&nmtb.rcButton, 0, sizeof(RECT));
4272 res = TOOLBAR_SendNotify ((NMHDR *) &nmtb, infoPtr,
4273 TBN_DROPDOWN);
4274 if (res != TBDDRET_TREATPRESSED)
4275 /* ??? guess (GA) */
4276 return 0;
4277 /* otherwise drop through and process as pushed */
4279 /* SetCapture (hwnd); */
4280 infoPtr->bCaptured = TRUE;
4281 infoPtr->nButtonDown = nHit;
4283 btnPtr->fsState |= TBSTATE_PRESSED;
4284 btnPtr->bHot = FALSE;
4286 InvalidateRect(hwnd, &btnPtr->rect,
4287 TOOLBAR_HasText(infoPtr, btnPtr));
4288 UpdateWindow(hwnd);
4289 SetCapture (hwnd);
4291 /* native issues the TBN_BEGINDRAG here */
4292 nmtb.iItem = btnPtr->idCommand;
4293 nmtb.tbButton.iBitmap = btnPtr->iBitmap;
4294 nmtb.tbButton.idCommand = btnPtr->idCommand;
4295 nmtb.tbButton.fsState = btnPtr->fsState;
4296 nmtb.tbButton.fsStyle = btnPtr->fsStyle;
4297 nmtb.tbButton.dwData = btnPtr->dwData;
4298 nmtb.tbButton.iString = btnPtr->iString;
4299 nmtb.cchText = 0; /* !!! not correct */
4300 nmtb.pszText = 0; /* !!! not correct */
4301 TOOLBAR_SendNotify ((NMHDR *) &nmtb, infoPtr,
4302 TBN_BEGINDRAG);
4305 return 0;
4308 static LRESULT
4309 TOOLBAR_LButtonUp (HWND hwnd, WPARAM wParam, LPARAM lParam)
4311 TOOLBAR_INFO *infoPtr = TOOLBAR_GetInfoPtr (hwnd);
4312 TBUTTON_INFO *btnPtr;
4313 POINT pt;
4314 INT nHit;
4315 INT nOldIndex = -1;
4316 BOOL bSendMessage = TRUE;
4317 NMHDR hdr;
4318 NMMOUSE nmmouse;
4319 NMTOOLBARA nmtb;
4321 if (infoPtr->hwndToolTip)
4322 TOOLBAR_RelayEvent (infoPtr->hwndToolTip, hwnd,
4323 WM_LBUTTONUP, wParam, lParam);
4325 pt.x = (INT)LOWORD(lParam);
4326 pt.y = (INT)HIWORD(lParam);
4327 nHit = TOOLBAR_InternalHitTest (hwnd, &pt);
4329 /* restore hot effect to hot button disabled by TOOLBAR_LButtonDown() */
4330 /* if the cursor is still inside of the toolbar */
4331 if((infoPtr->nHotItem >= 0) && (nHit != -1))
4332 infoPtr->buttons[infoPtr->nHotItem].bHot = TRUE;
4334 if ((infoPtr->bCaptured) && (infoPtr->nButtonDown >= 0)) {
4335 btnPtr = &infoPtr->buttons[infoPtr->nButtonDown];
4336 btnPtr->fsState &= ~TBSTATE_PRESSED;
4338 if (nHit == infoPtr->nButtonDown) {
4339 if (btnPtr->fsStyle & TBSTYLE_CHECK) {
4340 if (btnPtr->fsStyle & TBSTYLE_GROUP) {
4341 nOldIndex = TOOLBAR_GetCheckedGroupButtonIndex (infoPtr,
4342 infoPtr->nButtonDown);
4343 if (nOldIndex == infoPtr->nButtonDown)
4344 bSendMessage = FALSE;
4345 if ((nOldIndex != infoPtr->nButtonDown) &&
4346 (nOldIndex != -1))
4347 infoPtr->buttons[nOldIndex].fsState &= ~TBSTATE_CHECKED;
4348 btnPtr->fsState |= TBSTATE_CHECKED;
4350 else {
4351 if (btnPtr->fsState & TBSTATE_CHECKED)
4352 btnPtr->fsState &= ~TBSTATE_CHECKED;
4353 else
4354 btnPtr->fsState |= TBSTATE_CHECKED;
4358 else
4359 bSendMessage = FALSE;
4361 if (nOldIndex != -1)
4363 InvalidateRect(hwnd, &infoPtr->buttons[nOldIndex].rect,
4364 TOOLBAR_HasText(infoPtr, &infoPtr->buttons[nOldIndex]));
4368 * now we can ReleaseCapture, which triggers CAPTURECHANGED msg,
4369 * that resets bCaptured and btn TBSTATE_PRESSED flags,
4370 * and obliterates nButtonDown and nOldHit (see TOOLBAR_CaptureChanged)
4372 ReleaseCapture ();
4374 /* Issue NM_RELEASEDCAPTURE to parent to let him know it is released */
4375 TOOLBAR_SendNotify ((NMHDR *) &hdr, infoPtr,
4376 NM_RELEASEDCAPTURE);
4378 /* native issues TBN_ENDDRAG here, if _LBUTTONDOWN issued the
4379 * TBN_BEGINDRAG
4381 nmtb.iItem = btnPtr->idCommand;
4382 nmtb.tbButton.iBitmap = btnPtr->iBitmap;
4383 nmtb.tbButton.idCommand = btnPtr->idCommand;
4384 nmtb.tbButton.fsState = btnPtr->fsState;
4385 nmtb.tbButton.fsStyle = btnPtr->fsStyle;
4386 nmtb.tbButton.dwData = btnPtr->dwData;
4387 nmtb.tbButton.iString = btnPtr->iString;
4388 nmtb.cchText = 0; /* !!! not correct */
4389 nmtb.pszText = 0; /* !!! not correct */
4390 TOOLBAR_SendNotify ((NMHDR *) &nmtb, infoPtr,
4391 TBN_ENDDRAG);
4393 if (bSendMessage)
4394 SendMessageA (infoPtr->hwndNotify, WM_COMMAND,
4395 MAKEWPARAM(btnPtr->idCommand, 0), (LPARAM)hwnd);
4397 /* !!! Undocumented - toolbar at 4.71 level and above sends
4398 * either NMRCLICK or NM_CLICK with the NMMOUSE structure.
4399 * Only NM_RCLICK is documented.
4401 nmmouse.dwItemSpec = btnPtr->idCommand;
4402 nmmouse.dwItemData = btnPtr->dwData;
4403 TOOLBAR_SendNotify ((NMHDR *) &nmmouse, infoPtr,
4404 NM_CLICK);
4407 return 0;
4410 static LRESULT
4411 TOOLBAR_CaptureChanged(HWND hwnd)
4413 TOOLBAR_INFO *infoPtr = TOOLBAR_GetInfoPtr (hwnd);
4414 TBUTTON_INFO *btnPtr;
4416 infoPtr->bCaptured = FALSE;
4418 if (infoPtr->nButtonDown >= 0)
4420 btnPtr = &infoPtr->buttons[infoPtr->nButtonDown];
4421 btnPtr->fsState &= ~TBSTATE_PRESSED;
4423 infoPtr->nButtonDown = -1;
4424 infoPtr->nOldHit = -1;
4426 InvalidateRect(hwnd, &btnPtr->rect, TOOLBAR_HasText(infoPtr,
4427 btnPtr));
4429 return 0;
4432 static LRESULT
4433 TOOLBAR_MouseLeave (HWND hwnd, WPARAM wParam, LPARAM lParam)
4435 TOOLBAR_INFO *infoPtr = TOOLBAR_GetInfoPtr (hwnd);
4436 TBUTTON_INFO *hotBtnPtr, *btnPtr;
4437 RECT rc1;
4439 if (infoPtr->nOldHit < 0)
4440 return TRUE;
4442 hotBtnPtr = &infoPtr->buttons[infoPtr->nOldHit];
4444 /* Redraw the button if the last button we were over is the hot button and it
4445 is enabled */
4446 if((infoPtr->nOldHit == infoPtr->nHotItem) && (hotBtnPtr->fsState & TBSTATE_ENABLED))
4448 hotBtnPtr->bHot = FALSE;
4449 rc1 = hotBtnPtr->rect;
4450 InflateRect (&rc1, 1, 1);
4451 InvalidateRect (hwnd, &rc1, TOOLBAR_HasText(infoPtr,
4452 hotBtnPtr));
4455 /* If the last button we were over is depressed then make it not */
4456 /* depressed and redraw it */
4457 if(infoPtr->nOldHit == infoPtr->nButtonDown)
4459 btnPtr = &infoPtr->buttons[infoPtr->nButtonDown];
4461 btnPtr->fsState &= ~TBSTATE_PRESSED;
4463 rc1 = hotBtnPtr->rect;
4464 InflateRect (&rc1, 1, 1);
4465 InvalidateRect (hwnd, &rc1, TRUE);
4468 infoPtr->nOldHit = -1; /* reset the old hit index as we've left the toolbar */
4469 infoPtr->nHotItem = -2; /* It has to be initially different from nOldHit */
4471 return TRUE;
4474 static LRESULT
4475 TOOLBAR_MouseMove (HWND hwnd, WPARAM wParam, LPARAM lParam)
4477 TBUTTON_INFO *btnPtr, *oldBtnPtr;
4478 TOOLBAR_INFO *infoPtr = TOOLBAR_GetInfoPtr (hwnd);
4479 POINT pt;
4480 INT nHit;
4481 TRACKMOUSEEVENT trackinfo;
4483 /* fill in the TRACKMOUSEEVENT struct */
4484 trackinfo.cbSize = sizeof(TRACKMOUSEEVENT);
4485 trackinfo.dwFlags = TME_QUERY;
4486 trackinfo.hwndTrack = hwnd;
4487 trackinfo.dwHoverTime = HOVER_DEFAULT;
4489 /* call _TrackMouseEvent to see if we are currently tracking for this hwnd */
4490 _TrackMouseEvent(&trackinfo);
4492 /* Make sure tracking is enabled so we receive a WM_MOUSELEAVE message */
4493 if(!(trackinfo.dwFlags & TME_LEAVE)) {
4494 trackinfo.dwFlags = TME_LEAVE; /* notify upon leaving */
4496 /* call TRACKMOUSEEVENT so we receive a WM_MOUSELEAVE message */
4497 /* and can properly deactivate the hot toolbar button */
4498 _TrackMouseEvent(&trackinfo);
4501 if (infoPtr->hwndToolTip)
4502 TOOLBAR_RelayEvent (infoPtr->hwndToolTip, hwnd,
4503 WM_MOUSEMOVE, wParam, lParam);
4505 pt.x = (INT)LOWORD(lParam);
4506 pt.y = (INT)HIWORD(lParam);
4508 nHit = TOOLBAR_InternalHitTest (hwnd, &pt);
4510 if (infoPtr->nOldHit != nHit)
4512 /* Remove the effect of an old hot button if the button was enabled and was
4513 drawn with the hot button effect */
4514 if(infoPtr->nOldHit >= 0 && infoPtr->nOldHit == infoPtr->nHotItem &&
4515 (infoPtr->buttons[infoPtr->nOldHit].fsState & TBSTATE_ENABLED))
4517 oldBtnPtr = &infoPtr->buttons[infoPtr->nOldHit];
4518 oldBtnPtr->bHot = FALSE;
4520 InvalidateRect (hwnd, &oldBtnPtr->rect,
4521 TOOLBAR_HasText(infoPtr, oldBtnPtr));
4524 /* It's not a separator or in nowhere. It's a hot button. */
4525 if (nHit >= 0)
4527 btnPtr = &infoPtr->buttons[nHit];
4529 infoPtr->nHotItem = nHit;
4531 /* only enabled buttons show hot effect */
4532 if(infoPtr->buttons[nHit].fsState & TBSTATE_ENABLED)
4534 btnPtr->bHot = TRUE;
4535 InvalidateRect(hwnd, &btnPtr->rect,
4536 TOOLBAR_HasText(infoPtr, btnPtr));
4541 if (infoPtr->bCaptured) {
4542 btnPtr = &infoPtr->buttons[infoPtr->nButtonDown];
4543 if (infoPtr->nOldHit == infoPtr->nButtonDown) {
4544 btnPtr->fsState &= ~TBSTATE_PRESSED;
4545 InvalidateRect(hwnd, &btnPtr->rect, TRUE);
4547 else if (nHit == infoPtr->nButtonDown) {
4548 btnPtr->fsState |= TBSTATE_PRESSED;
4549 InvalidateRect(hwnd, &btnPtr->rect, TRUE);
4552 infoPtr->nOldHit = nHit;
4554 return 0;
4558 inline static LRESULT
4559 TOOLBAR_NCActivate (HWND hwnd, WPARAM wParam, LPARAM lParam)
4561 /* if (wndPtr->dwStyle & CCS_NODIVIDER) */
4562 return DefWindowProcA (hwnd, WM_NCACTIVATE, wParam, lParam);
4563 /* else */
4564 /* return TOOLBAR_NCPaint (wndPtr, wParam, lParam); */
4568 inline static LRESULT
4569 TOOLBAR_NCCalcSize (HWND hwnd, WPARAM wParam, LPARAM lParam)
4571 if (!(GetWindowLongA (hwnd, GWL_STYLE) & CCS_NODIVIDER))
4572 ((LPRECT)lParam)->top += GetSystemMetrics(SM_CYEDGE);
4574 return DefWindowProcA (hwnd, WM_NCCALCSIZE, wParam, lParam);
4578 static LRESULT
4579 TOOLBAR_NCCreate (HWND hwnd, WPARAM wParam, LPARAM lParam)
4581 TOOLBAR_INFO *infoPtr;
4582 LPCREATESTRUCTA cs = (LPCREATESTRUCTA)lParam;
4583 DWORD styleadd = 0;
4585 /* allocate memory for info structure */
4586 infoPtr = (TOOLBAR_INFO *)COMCTL32_Alloc (sizeof(TOOLBAR_INFO));
4587 SetWindowLongA (hwnd, 0, (DWORD)infoPtr);
4589 /* paranoid!! */
4590 infoPtr->dwStructSize = sizeof(TBBUTTON);
4592 /* fix instance handle, if the toolbar was created by CreateToolbarEx() */
4593 if (!GetWindowLongA (hwnd, GWL_HINSTANCE)) {
4594 HINSTANCE hInst = (HINSTANCE)GetWindowLongA (GetParent (hwnd), GWL_HINSTANCE);
4595 SetWindowLongA (hwnd, GWL_HINSTANCE, (DWORD)hInst);
4598 /* native control does:
4599 * Get a lot of colors and brushes
4600 * WM_NOTIFYFORMAT
4601 * SystemParametersInfoA(0x1f, 0x3c, adr1, 0)
4602 * CreateFontIndirectA(adr1)
4603 * CreateBitmap(0x27, 0x24, 1, 1, 0)
4604 * hdc = GetDC(toolbar)
4605 * GetSystemMetrics(0x48)
4606 * fnt2=CreateFontA(0xe, 0, 0, 0, 0x190, 0, 0, 0, 0, 2,
4607 * 0, 0, 0, 0, "MARLETT")
4608 * oldfnt = SelectObject(hdc, fnt2)
4609 * GetCharWidthA(hdc, 0x36, 0x36, adr2)
4610 * GetTextMetricsA(hdc, adr3)
4611 * SelectObject(hdc, oldfnt)
4612 * DeleteObject(fnt2)
4613 * ReleaseDC(hdc)
4614 * InvalidateRect(toolbar, 0, 1)
4615 * SetWindowLongA(toolbar, 0, addr)
4616 * SetWindowLongA(toolbar, -16, xxx) **sometimes**
4617 * WM_STYLECHANGING
4618 * CallWinEx old new
4619 * ie 1 0x56000a4c 0x46000a4c 0x56008a4d
4620 * ie 2 0x4600094c 0x4600094c 0x4600894d
4621 * ie 3 0x56000b4c 0x46000b4c 0x56008b4d
4622 * rebar 0x50008844 0x40008844 0x50008845
4623 * pager 0x50000844 0x40000844 0x50008845
4624 * IC35mgr 0x5400084e **nochange**
4625 * on entry to _NCCREATE 0x5400084e
4626 * rowlist 0x5400004e **nochange**
4627 * on entry to _NCCREATE 0x5400004e
4631 /* I think the code below is a bug, but it is the way that the native
4632 * controls seem to work. The effect is that if the user of TBSTYLE_FLAT
4633 * forgets to specify TBSTYLE_TRANSPARENT but does specify either
4634 * CCS_TOP or CCS_BOTTOM (_NOMOVEY and _TOP), then the control
4635 * does *not* set TBSTYLE_TRANSPARENT even though it should!!!!
4636 * Some how, the only cases of this seem to be MFC programs.
4638 * Note also that the addition of _TRANSPARENT occurs *only* here. It
4639 * does not occur in the WM_STYLECHANGING routine.
4640 * (Guy Albertelli 9/2001)
4643 if ((cs->style & TBSTYLE_FLAT) && !(cs->style & TBSTYLE_TRANSPARENT))
4644 styleadd |= TBSTYLE_TRANSPARENT;
4645 if (!(cs->style & (CCS_TOP | CCS_NOMOVEY))) {
4646 styleadd |= CCS_TOP; /* default to top */
4647 SetWindowLongA (hwnd, GWL_STYLE, cs->style | styleadd);
4650 return DefWindowProcA (hwnd, WM_NCCREATE, wParam, lParam);
4654 static LRESULT
4655 TOOLBAR_NCPaint (HWND hwnd, WPARAM wParam, LPARAM lParam)
4657 DWORD dwStyle = GetWindowLongA (hwnd, GWL_STYLE);
4658 RECT rcWindow;
4659 HDC hdc;
4661 if (dwStyle & WS_MINIMIZE)
4662 return 0; /* Nothing to do */
4664 DefWindowProcA (hwnd, WM_NCPAINT, wParam, lParam);
4666 if (!(hdc = GetDCEx (hwnd, 0, DCX_USESTYLE | DCX_WINDOW)))
4667 return 0;
4669 if (!(dwStyle & CCS_NODIVIDER))
4671 GetWindowRect (hwnd, &rcWindow);
4672 OffsetRect (&rcWindow, -rcWindow.left, -rcWindow.top);
4673 if( dwStyle & WS_BORDER )
4674 OffsetRect (&rcWindow, 1, 1);
4675 DrawEdge (hdc, &rcWindow, EDGE_ETCHED, BF_TOP);
4678 ReleaseDC( hwnd, hdc );
4680 return 0;
4684 inline static LRESULT
4685 TOOLBAR_Notify (HWND hwnd, WPARAM wParam, LPARAM lParam)
4687 TOOLBAR_INFO *infoPtr = TOOLBAR_GetInfoPtr (hwnd);
4688 LPNMHDR lpnmh = (LPNMHDR)lParam;
4690 if (lpnmh->code == PGN_CALCSIZE) {
4691 LPNMPGCALCSIZE lppgc = (LPNMPGCALCSIZE)lParam;
4693 if (lppgc->dwFlag == PGF_CALCWIDTH) {
4694 lppgc->iWidth = infoPtr->nWidth;
4695 TRACE("processed PGN_CALCSIZE, returning horz size = %d\n",
4696 infoPtr->nWidth);
4698 else {
4699 lppgc->iHeight = infoPtr->nHeight;
4700 TRACE("processed PGN_CALCSIZE, returning vert size = %d\n",
4701 infoPtr->nHeight);
4703 return 0;
4707 TRACE("passing WM_NOTIFY!\n");
4709 if ((infoPtr->hwndToolTip) && (lpnmh->hwndFrom == infoPtr->hwndToolTip)) {
4710 SendMessageA (infoPtr->hwndNotify, WM_NOTIFY, wParam, lParam);
4712 #if 0
4713 if (lpnmh->code == TTN_GETDISPINFOA) {
4714 LPNMTTDISPINFOA lpdi = (LPNMTTDISPINFOA)lParam;
4716 FIXME("retrieving ASCII string\n");
4719 else if (lpnmh->code == TTN_GETDISPINFOW) {
4720 LPNMTTDISPINFOW lpdi = (LPNMTTDISPINFOW)lParam;
4722 FIXME("retrieving UNICODE string\n");
4725 #endif
4728 return 0;
4732 static LRESULT
4733 TOOLBAR_Paint (HWND hwnd, WPARAM wParam)
4735 TOOLBAR_INFO *infoPtr = TOOLBAR_GetInfoPtr(hwnd);
4736 HDC hdc;
4737 PAINTSTRUCT ps;
4739 /* fill ps.rcPaint with a default rect */
4740 memcpy(&(ps.rcPaint), &(infoPtr->rcBound), sizeof(infoPtr->rcBound));
4742 hdc = wParam==0 ? BeginPaint(hwnd, &ps) : (HDC)wParam;
4744 TRACE("psrect=(%d,%d)-(%d,%d)\n",
4745 ps.rcPaint.left, ps.rcPaint.top,
4746 ps.rcPaint.right, ps.rcPaint.bottom);
4748 TOOLBAR_Refresh (hwnd, hdc, &ps);
4749 if (!wParam) EndPaint (hwnd, &ps);
4751 return 0;
4755 static LRESULT
4756 TOOLBAR_Size (HWND hwnd, WPARAM wParam, LPARAM lParam)
4758 TOOLBAR_INFO *infoPtr = TOOLBAR_GetInfoPtr (hwnd);
4759 DWORD dwStyle = GetWindowLongA (hwnd, GWL_STYLE);
4760 RECT parent_rect;
4761 RECT window_rect;
4762 HWND parent;
4763 INT x, y;
4764 INT cx, cy;
4765 INT flags;
4766 UINT uPosFlags = 0;
4768 /* Resize deadlock check */
4769 if (infoPtr->bAutoSize) {
4770 infoPtr->bAutoSize = FALSE;
4771 return 0;
4774 /* FIXME: optimize to only update size if the new size doesn't */
4775 /* match the current size */
4777 flags = (INT) wParam;
4779 /* FIXME for flags =
4780 * SIZE_MAXIMIZED, SIZE_MAXSHOW, SIZE_MINIMIZED
4783 TRACE("sizing toolbar!\n");
4785 if (flags == SIZE_RESTORED) {
4786 /* width and height don't apply */
4787 parent = GetParent (hwnd);
4788 GetClientRect(parent, &parent_rect);
4789 x = parent_rect.left;
4790 y = parent_rect.top;
4792 if (dwStyle & CCS_NORESIZE) {
4793 uPosFlags |= (SWP_NOSIZE | SWP_NOMOVE);
4796 * this sets the working width of the toolbar, and
4797 * Calc Toolbar will not adjust it, only the height
4799 infoPtr->nWidth = parent_rect.right - parent_rect.left;
4800 cy = infoPtr->nHeight;
4801 cx = infoPtr->nWidth;
4802 TOOLBAR_CalcToolbar (hwnd);
4803 infoPtr->nWidth = cx;
4804 infoPtr->nHeight = cy;
4806 else {
4807 infoPtr->nWidth = parent_rect.right - parent_rect.left;
4808 TOOLBAR_CalcToolbar (hwnd);
4809 cy = infoPtr->nHeight;
4810 cx = infoPtr->nWidth;
4812 if (dwStyle & CCS_NOMOVEY) {
4813 GetWindowRect(hwnd, &window_rect);
4814 ScreenToClient(parent, (LPPOINT)&window_rect.left);
4815 y = window_rect.top;
4819 if (dwStyle & CCS_NOPARENTALIGN) {
4820 uPosFlags |= SWP_NOMOVE;
4821 cy = infoPtr->nHeight;
4822 cx = infoPtr->nWidth;
4825 if (!(dwStyle & CCS_NODIVIDER))
4826 cy += GetSystemMetrics(SM_CYEDGE);
4828 if (dwStyle & WS_BORDER)
4830 x = y = 1;
4831 cy += GetSystemMetrics(SM_CYEDGE);
4832 cx += GetSystemMetrics(SM_CYEDGE);
4835 SetWindowPos (hwnd, 0, parent_rect.left - x, parent_rect.top - y,
4836 cx, cy, uPosFlags | SWP_NOZORDER);
4838 return 0;
4842 static LRESULT
4843 TOOLBAR_StyleChanged (HWND hwnd, INT nType, LPSTYLESTRUCT lpStyle)
4845 TOOLBAR_INFO *infoPtr = TOOLBAR_GetInfoPtr (hwnd);
4847 if (nType == GWL_STYLE) {
4848 if (lpStyle->styleNew & TBSTYLE_LIST) {
4849 infoPtr->dwDTFlags = DT_LEFT | DT_VCENTER | DT_SINGLELINE;
4851 else {
4852 infoPtr->dwDTFlags = DT_CENTER;
4854 infoPtr->bTransparent = (lpStyle->styleNew & TBSTYLE_TRANSPARENT);
4855 infoPtr->bBtnTranspnt = (lpStyle->styleNew &
4856 (TBSTYLE_FLAT | TBSTYLE_LIST));
4857 TOOLBAR_CheckStyle (hwnd, lpStyle->styleNew);
4860 TOOLBAR_AutoSize (hwnd);
4862 InvalidateRect(hwnd, NULL, FALSE);
4864 return 0;
4869 static LRESULT WINAPI
4870 ToolbarWindowProc (HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
4872 TRACE("hwnd=%x msg=%x wparam=%x lparam=%lx\n",
4873 hwnd, uMsg, /* SPY_GetMsgName(uMsg), */ wParam, lParam);
4875 if (!TOOLBAR_GetInfoPtr(hwnd) && (uMsg != WM_NCCREATE))
4876 return DefWindowProcA( hwnd, uMsg, wParam, lParam );
4878 switch (uMsg)
4880 case TB_ADDBITMAP:
4881 return TOOLBAR_AddBitmap (hwnd, wParam, lParam);
4883 case TB_ADDBUTTONSA:
4884 return TOOLBAR_AddButtonsA (hwnd, wParam, lParam);
4886 case TB_ADDBUTTONSW:
4887 return TOOLBAR_AddButtonsW (hwnd, wParam, lParam);
4889 case TB_ADDSTRINGA:
4890 return TOOLBAR_AddStringA (hwnd, wParam, lParam);
4892 case TB_ADDSTRINGW:
4893 return TOOLBAR_AddStringW (hwnd, wParam, lParam);
4895 case TB_AUTOSIZE:
4896 return TOOLBAR_AutoSize (hwnd);
4898 case TB_BUTTONCOUNT:
4899 return TOOLBAR_ButtonCount (hwnd, wParam, lParam);
4901 case TB_BUTTONSTRUCTSIZE:
4902 return TOOLBAR_ButtonStructSize (hwnd, wParam, lParam);
4904 case TB_CHANGEBITMAP:
4905 return TOOLBAR_ChangeBitmap (hwnd, wParam, lParam);
4907 case TB_CHECKBUTTON:
4908 return TOOLBAR_CheckButton (hwnd, wParam, lParam);
4910 case TB_COMMANDTOINDEX:
4911 return TOOLBAR_CommandToIndex (hwnd, wParam, lParam);
4913 case TB_CUSTOMIZE:
4914 return TOOLBAR_Customize (hwnd);
4916 case TB_DELETEBUTTON:
4917 return TOOLBAR_DeleteButton (hwnd, wParam, lParam);
4919 case TB_ENABLEBUTTON:
4920 return TOOLBAR_EnableButton (hwnd, wParam, lParam);
4922 case TB_GETANCHORHIGHLIGHT:
4923 return TOOLBAR_GetAnchorHighlight (hwnd);
4925 case TB_GETBITMAP:
4926 return TOOLBAR_GetBitmap (hwnd, wParam, lParam);
4928 case TB_GETBITMAPFLAGS:
4929 return TOOLBAR_GetBitmapFlags (hwnd, wParam, lParam);
4931 case TB_GETBUTTON:
4932 return TOOLBAR_GetButton (hwnd, wParam, lParam);
4934 case TB_GETBUTTONINFOA:
4935 return TOOLBAR_GetButtonInfoA (hwnd, wParam, lParam);
4937 case TB_GETBUTTONINFOW:
4938 return TOOLBAR_GetButtonInfoW (hwnd, wParam, lParam);
4940 case TB_GETBUTTONSIZE:
4941 return TOOLBAR_GetButtonSize (hwnd);
4943 case TB_GETBUTTONTEXTA:
4944 return TOOLBAR_GetButtonTextA (hwnd, wParam, lParam);
4946 case TB_GETBUTTONTEXTW:
4947 return TOOLBAR_GetButtonTextW (hwnd, wParam, lParam);
4949 /* case TB_GETCOLORSCHEME: */ /* 4.71 */
4951 case TB_GETDISABLEDIMAGELIST:
4952 return TOOLBAR_GetDisabledImageList (hwnd, wParam, lParam);
4954 case TB_GETEXTENDEDSTYLE:
4955 return TOOLBAR_GetExtendedStyle (hwnd);
4957 case TB_GETHOTIMAGELIST:
4958 return TOOLBAR_GetHotImageList (hwnd, wParam, lParam);
4960 case TB_GETHOTITEM:
4961 return TOOLBAR_GetHotItem (hwnd);
4963 case TB_GETIMAGELIST:
4964 return TOOLBAR_GetImageList (hwnd, wParam, lParam);
4966 /* case TB_GETINSERTMARK: */ /* 4.71 */
4967 /* case TB_GETINSERTMARKCOLOR: */ /* 4.71 */
4969 case TB_GETITEMRECT:
4970 return TOOLBAR_GetItemRect (hwnd, wParam, lParam);
4972 case TB_GETMAXSIZE:
4973 return TOOLBAR_GetMaxSize (hwnd, wParam, lParam);
4975 /* case TB_GETOBJECT: */ /* 4.71 */
4976 /* case TB_GETPADDING: */ /* 4.71 */
4978 case TB_GETRECT:
4979 return TOOLBAR_GetRect (hwnd, wParam, lParam);
4981 case TB_GETROWS:
4982 return TOOLBAR_GetRows (hwnd, wParam, lParam);
4984 case TB_GETSTATE:
4985 return TOOLBAR_GetState (hwnd, wParam, lParam);
4987 case TB_GETSTYLE:
4988 return TOOLBAR_GetStyle (hwnd, wParam, lParam);
4990 case TB_GETTEXTROWS:
4991 return TOOLBAR_GetTextRows (hwnd, wParam, lParam);
4993 case TB_GETTOOLTIPS:
4994 return TOOLBAR_GetToolTips (hwnd, wParam, lParam);
4996 case TB_GETUNICODEFORMAT:
4997 return TOOLBAR_GetUnicodeFormat (hwnd, wParam, lParam);
4999 case CCM_GETVERSION:
5000 return TOOLBAR_GetVersion (hwnd);
5002 case TB_HIDEBUTTON:
5003 return TOOLBAR_HideButton (hwnd, wParam, lParam);
5005 case TB_HITTEST:
5006 return TOOLBAR_HitTest (hwnd, wParam, lParam);
5008 case TB_INDETERMINATE:
5009 return TOOLBAR_Indeterminate (hwnd, wParam, lParam);
5011 case TB_INSERTBUTTONA:
5012 return TOOLBAR_InsertButtonA (hwnd, wParam, lParam);
5014 case TB_INSERTBUTTONW:
5015 return TOOLBAR_InsertButtonW (hwnd, wParam, lParam);
5017 /* case TB_INSERTMARKHITTEST: */ /* 4.71 */
5019 case TB_ISBUTTONCHECKED:
5020 return TOOLBAR_IsButtonChecked (hwnd, wParam, lParam);
5022 case TB_ISBUTTONENABLED:
5023 return TOOLBAR_IsButtonEnabled (hwnd, wParam, lParam);
5025 case TB_ISBUTTONHIDDEN:
5026 return TOOLBAR_IsButtonHidden (hwnd, wParam, lParam);
5028 case TB_ISBUTTONHIGHLIGHTED:
5029 return TOOLBAR_IsButtonHighlighted (hwnd, wParam, lParam);
5031 case TB_ISBUTTONINDETERMINATE:
5032 return TOOLBAR_IsButtonIndeterminate (hwnd, wParam, lParam);
5034 case TB_ISBUTTONPRESSED:
5035 return TOOLBAR_IsButtonPressed (hwnd, wParam, lParam);
5037 case TB_LOADIMAGES: /* 4.70 */
5038 FIXME("missing standard imagelists\n");
5039 return 0;
5041 /* case TB_MAPACCELERATORA: */ /* 4.71 */
5042 /* case TB_MAPACCELERATORW: */ /* 4.71 */
5043 /* case TB_MARKBUTTON: */ /* 4.71 */
5044 /* case TB_MOVEBUTTON: */ /* 4.71 */
5046 case TB_PRESSBUTTON:
5047 return TOOLBAR_PressButton (hwnd, wParam, lParam);
5049 /* case TB_REPLACEBITMAP: */
5051 case TB_SAVERESTOREA:
5052 return TOOLBAR_SaveRestoreA (hwnd, wParam, lParam);
5054 case TB_SAVERESTOREW:
5055 return TOOLBAR_SaveRestoreW (hwnd, wParam, lParam);
5057 case TB_SETANCHORHIGHLIGHT:
5058 return TOOLBAR_SetAnchorHighlight (hwnd, wParam);
5060 case TB_SETBITMAPSIZE:
5061 return TOOLBAR_SetBitmapSize (hwnd, wParam, lParam);
5063 case TB_SETBUTTONINFOA:
5064 return TOOLBAR_SetButtonInfoA (hwnd, wParam, lParam);
5066 case TB_SETBUTTONINFOW:
5067 return TOOLBAR_SetButtonInfoW (hwnd, wParam, lParam);
5069 case TB_SETBUTTONSIZE:
5070 return TOOLBAR_SetButtonSize (hwnd, wParam, lParam);
5072 case TB_SETBUTTONWIDTH:
5073 return TOOLBAR_SetButtonWidth (hwnd, wParam, lParam);
5075 case TB_SETCMDID:
5076 return TOOLBAR_SetCmdId (hwnd, wParam, lParam);
5078 /* case TB_SETCOLORSCHEME: */ /* 4.71 */
5080 case TB_SETDISABLEDIMAGELIST:
5081 return TOOLBAR_SetDisabledImageList (hwnd, wParam, lParam);
5083 case TB_SETDRAWTEXTFLAGS:
5084 return TOOLBAR_SetDrawTextFlags (hwnd, wParam, lParam);
5086 case TB_SETEXTENDEDSTYLE:
5087 return TOOLBAR_SetExtendedStyle (hwnd, wParam, lParam);
5089 case TB_SETHOTIMAGELIST:
5090 return TOOLBAR_SetHotImageList (hwnd, wParam, lParam);
5092 case TB_SETHOTITEM:
5093 return TOOLBAR_SetHotItem (hwnd, wParam);
5095 case TB_SETIMAGELIST:
5096 return TOOLBAR_SetImageList (hwnd, wParam, lParam);
5098 case TB_SETINDENT:
5099 return TOOLBAR_SetIndent (hwnd, wParam, lParam);
5101 /* case TB_SETINSERTMARK: */ /* 4.71 */
5103 case TB_SETINSERTMARKCOLOR:
5104 return TOOLBAR_SetInsertMarkColor (hwnd, wParam, lParam);
5106 case TB_SETMAXTEXTROWS:
5107 return TOOLBAR_SetMaxTextRows (hwnd, wParam, lParam);
5109 /* case TB_SETPADDING: */ /* 4.71 */
5111 case TB_SETPARENT:
5112 return TOOLBAR_SetParent (hwnd, wParam, lParam);
5114 case TB_SETROWS:
5115 return TOOLBAR_SetRows (hwnd, wParam, lParam);
5117 case TB_SETSTATE:
5118 return TOOLBAR_SetState (hwnd, wParam, lParam);
5120 case TB_SETSTYLE:
5121 return TOOLBAR_SetStyle (hwnd, wParam, lParam);
5123 case TB_SETTOOLTIPS:
5124 return TOOLBAR_SetToolTips (hwnd, wParam, lParam);
5126 case TB_SETUNICODEFORMAT:
5127 return TOOLBAR_SetUnicodeFormat (hwnd, wParam, lParam);
5129 case CCM_SETVERSION:
5130 return TOOLBAR_SetVersion (hwnd, (INT)wParam);
5133 /* case WM_CHAR: */
5135 case WM_CREATE:
5136 return TOOLBAR_Create (hwnd, wParam, lParam);
5138 case WM_DESTROY:
5139 return TOOLBAR_Destroy (hwnd, wParam, lParam);
5141 case WM_ERASEBKGND:
5142 return TOOLBAR_EraseBackground (hwnd, wParam, lParam);
5144 case WM_GETFONT:
5145 return TOOLBAR_GetFont (hwnd, wParam, lParam);
5147 /* case WM_KEYDOWN: */
5148 /* case WM_KILLFOCUS: */
5150 case WM_LBUTTONDBLCLK:
5151 return TOOLBAR_LButtonDblClk (hwnd, wParam, lParam);
5153 case WM_LBUTTONDOWN:
5154 return TOOLBAR_LButtonDown (hwnd, wParam, lParam);
5156 case WM_LBUTTONUP:
5157 return TOOLBAR_LButtonUp (hwnd, wParam, lParam);
5159 case WM_MOUSEMOVE:
5160 return TOOLBAR_MouseMove (hwnd, wParam, lParam);
5162 case WM_MOUSELEAVE:
5163 return TOOLBAR_MouseLeave (hwnd, wParam, lParam);
5165 case WM_CAPTURECHANGED:
5166 return TOOLBAR_CaptureChanged(hwnd);
5168 case WM_NCACTIVATE:
5169 return TOOLBAR_NCActivate (hwnd, wParam, lParam);
5171 case WM_NCCALCSIZE:
5172 return TOOLBAR_NCCalcSize (hwnd, wParam, lParam);
5174 case WM_NCCREATE:
5175 return TOOLBAR_NCCreate (hwnd, wParam, lParam);
5177 case WM_NCPAINT:
5178 return TOOLBAR_NCPaint (hwnd, wParam, lParam);
5180 case WM_NOTIFY:
5181 return TOOLBAR_Notify (hwnd, wParam, lParam);
5183 /* case WM_NOTIFYFORMAT: */
5185 case WM_PAINT:
5186 return TOOLBAR_Paint (hwnd, wParam);
5188 case WM_SIZE:
5189 return TOOLBAR_Size (hwnd, wParam, lParam);
5191 case WM_STYLECHANGED:
5192 return TOOLBAR_StyleChanged (hwnd, (INT)wParam, (LPSTYLESTRUCT)lParam);
5194 /* case WM_SYSCOLORCHANGE: */
5196 /* case WM_WININICHANGE: */
5198 case WM_CHARTOITEM:
5199 case WM_COMMAND:
5200 case WM_DRAWITEM:
5201 case WM_MEASUREITEM:
5202 case WM_VKEYTOITEM:
5204 TOOLBAR_INFO *infoPtr = TOOLBAR_GetInfoPtr (hwnd);
5205 if(infoPtr != NULL)
5206 return SendMessageA (infoPtr->hwndNotify, uMsg, wParam, lParam);
5207 else
5208 return SendMessageA (GetParent (hwnd), uMsg, wParam, lParam);
5211 default:
5212 if (uMsg >= WM_USER)
5213 ERR("unknown msg %04x wp=%08x lp=%08lx\n",
5214 uMsg, wParam, lParam);
5215 return DefWindowProcA (hwnd, uMsg, wParam, lParam);
5217 return 0;
5221 VOID
5222 TOOLBAR_Register (void)
5224 WNDCLASSA wndClass;
5226 ZeroMemory (&wndClass, sizeof(WNDCLASSA));
5227 wndClass.style = CS_GLOBALCLASS | CS_DBLCLKS;
5228 wndClass.lpfnWndProc = (WNDPROC)ToolbarWindowProc;
5229 wndClass.cbClsExtra = 0;
5230 wndClass.cbWndExtra = sizeof(TOOLBAR_INFO *);
5231 wndClass.hCursor = LoadCursorA (0, IDC_ARROWA);
5232 wndClass.hbrBackground = (HBRUSH)(COLOR_3DFACE + 1);
5233 wndClass.lpszClassName = TOOLBARCLASSNAMEA;
5235 RegisterClassA (&wndClass);
5239 VOID
5240 TOOLBAR_Unregister (void)
5242 UnregisterClassA (TOOLBARCLASSNAMEA, (HINSTANCE)NULL);