There is no need for a private heap in comctl32, memory allocations
[wine/multimedia.git] / dlls / comctl32 / toolbar.c
blob8c1c67ea331c54b1b219f1f644fd851d0030d960
1 /*
2 * Toolbar control
4 * Copyright 1998,1999 Eric Kohl
5 * Copyright 2000 Eric Kohl for CodeWeavers
7 * This library is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU Lesser General Public
9 * License as published by the Free Software Foundation; either
10 * version 2.1 of the License, or (at your option) any later version.
12 * This library is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 * Lesser General Public License for more details.
17 * You should have received a copy of the GNU Lesser General Public
18 * License along with this library; if not, write to the Free Software
19 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
21 * Differences between MSDN and actual native control operation:
22 * 1. MSDN says: "TBSTYLE_LIST: Creates a flat toolbar with button text
23 * to the right of the bitmap. Otherwise, this style is
24 * identical to TBSTYLE_FLAT."
25 * As implemented by both v4.71 and v5.80 of the native COMCTL32.DLL
26 * you can create a TBSTYLE_LIST without TBSTYLE_FLAT and the result
27 * is non-flat non-transparent buttons. Therefore TBSTYLE_LIST does
28 * *not* imply TBSTYLE_FLAT as documented. (GA 8/2001)
31 * TODO:
32 * - Button wrapping (under construction).
33 * - Messages.
34 * - Notifications
35 * - NM_CHAR
36 * - NM_KEYDOWN
37 * - NM_LDOWN
38 * - NM_RCLICK
39 * - NM_RDBLCLICK
40 * - TBN_DELETINGBUTTON
41 * - TBN_DRAGOUT
42 * - TBN_GETOBJECT
43 * - TBN_RESTORE
44 * - TBN_SAVE
45 * - TBN_TOOLBARCHANGE
46 * - Fix TB_SETROWS.
47 * - Tooltip support (almost complete).
48 * - Fix TOOLBAR_SetButtonInfo32A/W.
49 * - iString of -1 is undocumented
50 * - Customization dialog:
51 * - Add flat look.
52 * - Minor buglet in 'available buttons' list:
53 * Buttons are not listed in M$-like order. M$ seems to use a single
54 * internal list to store the button information of both listboxes.
55 * - Drag list support.
57 * Testing:
58 * - Run tests using Waite Group Windows95 API Bible Volume 2.
59 * The second cdrom contains executables addstr.exe, btncount.exe,
60 * btnstate.exe, butstrsz.exe, chkbtn.exe, chngbmp.exe, customiz.exe,
61 * enablebtn.exe, getbmp.exe, getbtn.exe, getflags.exe, hidebtn.exe,
62 * indetbtn.exe, insbtn.exe, pressbtn.exe, setbtnsz.exe, setcmdid.exe,
63 * setparnt.exe, setrows.exe, toolwnd.exe.
64 * - Microsofts controlspy examples.
65 * - Charles Petzold's 'Programming Windows': gadgets.exe
68 #include <stdarg.h>
69 #include <string.h>
71 #include "windef.h"
72 #include "winbase.h"
73 #include "wingdi.h"
74 #include "winuser.h"
75 #include "wine/unicode.h"
76 #include "winnls.h"
77 #include "commctrl.h"
78 #include "imagelist.h"
79 #include "comctl32.h"
80 #include "wine/debug.h"
82 WINE_DEFAULT_DEBUG_CHANNEL(toolbar);
84 typedef struct
86 INT iBitmap;
87 INT idCommand;
88 BYTE fsState;
89 BYTE fsStyle;
90 DWORD dwData;
91 INT iString;
93 BOOL bHot;
94 INT nRow;
95 RECT rect;
96 } TBUTTON_INFO;
98 typedef struct
100 UINT nButtons;
101 HINSTANCE hInst;
102 UINT nID;
103 } TBITMAP_INFO;
105 typedef struct
107 HIMAGELIST himl;
108 INT id;
109 } IMLENTRY, *PIMLENTRY;
111 typedef struct
113 DWORD dwStructSize; /* size of TBBUTTON struct */
114 INT nHeight; /* height of the toolbar */
115 INT nWidth; /* width of the toolbar */
116 INT nButtonHeight;
117 INT nButtonWidth;
118 INT nBitmapHeight;
119 INT nBitmapWidth;
120 INT nIndent;
121 INT nRows; /* number of button rows */
122 INT nMaxTextRows; /* maximum number of text rows */
123 INT cxMin; /* minimum button width */
124 INT cxMax; /* maximum button width */
125 INT nNumButtons; /* number of buttons */
126 INT nNumBitmaps; /* number of bitmaps */
127 INT nNumStrings; /* number of strings */
128 INT nNumBitmapInfos;
129 BOOL bUnicode; /* ASCII (FALSE) or Unicode (TRUE)? */
130 BOOL bCaptured; /* mouse captured? */
131 INT nButtonDown;
132 INT nOldHit;
133 INT nHotItem; /* index of the "hot" item */
134 DWORD dwBaseCustDraw; /* CDRF_ response (w/o TBCDRF_) from PREPAINT */
135 DWORD dwItemCustDraw; /* CDRF_ response (w/o TBCDRF_) from ITEMPREP */
136 DWORD dwItemCDFlag; /* TBCDRF_ flags from last ITEMPREPAINT */
137 SIZE szPadding; /* padding values around button */
138 HFONT hDefaultFont;
139 HFONT hFont; /* text font */
140 HIMAGELIST himlInt; /* image list created internally */
141 PIMLENTRY *himlDef; /* default image list array */
142 INT cimlDef; /* default image list array count */
143 PIMLENTRY *himlHot; /* hot image list array */
144 INT cimlHot; /* hot image list array count */
145 PIMLENTRY *himlDis; /* disabled image list array */
146 INT cimlDis; /* disabled image list array count */
147 HWND hwndToolTip; /* handle to tool tip control */
148 HWND hwndNotify; /* handle to the window that gets notifications */
149 HWND hwndSelf; /* my own handle */
150 BOOL bTransparent; /* background transparency flag */
151 BOOL bBtnTranspnt; /* button transparency flag */
152 BOOL bAutoSize; /* auto size deadlock indicator */
153 BOOL bAnchor; /* anchor highlight enabled */
154 BOOL bNtfUnicode; /* TRUE if NOTIFYs use {W} */
155 BOOL bDoRedraw; /* Redraw status */
156 DWORD dwExStyle; /* extended toolbar style */
157 DWORD dwDTFlags; /* DrawText flags */
159 COLORREF clrInsertMark; /* insert mark color */
160 COLORREF clrBtnHighlight; /* color for Flat Separator */
161 COLORREF clrBtnShadow; /* color for Flag Separator */
162 RECT rcBound; /* bounding rectangle */
163 INT iVersion;
165 TBUTTON_INFO *buttons; /* pointer to button array */
166 LPWSTR *strings; /* pointer to string array */
167 TBITMAP_INFO *bitmaps;
168 } TOOLBAR_INFO, *PTOOLBAR_INFO;
171 /* used by customization dialog */
172 typedef struct
174 PTOOLBAR_INFO tbInfo;
175 HWND tbHwnd;
176 } CUSTDLG_INFO, *PCUSTDLG_INFO;
178 typedef struct
180 TBBUTTON btn;
181 BOOL bVirtual;
182 BOOL bRemovable;
183 WCHAR text[64];
184 } CUSTOMBUTTON, *PCUSTOMBUTTON;
186 typedef enum
188 IMAGE_LIST_DEFAULT,
189 IMAGE_LIST_HOT,
190 IMAGE_LIST_DISABLED
191 } IMAGE_LIST_TYPE;
193 #define SEPARATOR_WIDTH 8
194 #define TOP_BORDER 2
195 #define BOTTOM_BORDER 2
196 #define DDARROW_WIDTH 11
197 #define ARROW_HEIGHT 3
199 /* gap between edge of button and image with TBSTYLE_LIST */
200 #define LIST_IMAGE_OFFSET 3
201 /* gap between bitmap and text (always present) */
202 #define LIST_TEXT_OFFSET 2
203 /* how wide to treat the bitmap if it isn't present */
204 #define LIST_IMAGE_ABSENT_WIDTH 2
206 #define TOOLBAR_GetInfoPtr(hwnd) ((TOOLBAR_INFO *)GetWindowLongA(hwnd,0))
207 #define TOOLBAR_HasText(x, y) (TOOLBAR_GetText(x, y) ? TRUE : FALSE)
208 #define TOOLBAR_HasDropDownArrows(exStyle) ((exStyle & TBSTYLE_EX_DRAWDDARROWS) ? TRUE : FALSE)
210 /* Used to find undocumented extended styles */
211 #define TBSTYLE_EX_ALL (TBSTYLE_EX_DRAWDDARROWS | \
212 TBSTYLE_EX_UNDOC1 | \
213 TBSTYLE_EX_MIXEDBUTTONS | \
214 TBSTYLE_EX_HIDECLIPPEDBUTTONS)
216 #define GETIBITMAP(infoPtr, i) (infoPtr->iVersion >= 5 ? LOWORD(i) : i)
217 #define GETHIMLID(infoPtr, i) (infoPtr->iVersion >= 5 ? HIWORD(i) : 0)
218 #define GETDEFIMAGELIST(infoPtr, id) TOOLBAR_GetImageList(infoPtr->himlDef, infoPtr->cimlDef, id)
219 #define GETHOTIMAGELIST(infoPtr, id) TOOLBAR_GetImageList(infoPtr->himlHot, infoPtr->cimlHot, id)
220 #define GETDISIMAGELIST(infoPtr, id) TOOLBAR_GetImageList(infoPtr->himlDis, infoPtr->cimlDis, id)
222 static BOOL TOOLBAR_GetButtonInfo(TOOLBAR_INFO *infoPtr, NMTOOLBARW *nmtb);
223 static BOOL TOOLBAR_IsButtonRemovable(TOOLBAR_INFO *infoPtr, int iItem, PCUSTOMBUTTON btnInfo);
224 static HIMAGELIST TOOLBAR_GetImageList(PIMLENTRY *pies, INT cies, INT id);
225 static PIMLENTRY TOOLBAR_GetImageListEntry(PIMLENTRY *pies, INT cies, INT id);
226 static VOID TOOLBAR_DeleteImageList(PIMLENTRY **pies, INT *cies);
227 static HIMAGELIST TOOLBAR_InsertImageList(PIMLENTRY **pies, INT *cies, HIMAGELIST himl, INT id);
229 static LRESULT
230 TOOLBAR_NotifyFormat(TOOLBAR_INFO *infoPtr, WPARAM wParam, LPARAM lParam);
233 static LPWSTR
234 TOOLBAR_GetText(TOOLBAR_INFO *infoPtr, TBUTTON_INFO *btnPtr)
236 LPWSTR lpText = NULL;
238 /* FIXME: iString == -1 is undocumented */
239 if ((HIWORD(btnPtr->iString) != 0) && (btnPtr->iString != -1))
240 lpText = (LPWSTR)btnPtr->iString;
241 else if ((btnPtr->iString >= 0) && (btnPtr->iString < infoPtr->nNumStrings))
242 lpText = infoPtr->strings[btnPtr->iString];
244 return lpText;
247 static void
248 TOOLBAR_DumpButton(TOOLBAR_INFO *infoPtr, TBUTTON_INFO *bP, INT btn_num, BOOL internal)
250 if (TRACE_ON(toolbar)){
251 TRACE("button %d id %d, bitmap=%d, state=%02x, style=%02x, data=%08lx, stringid=0x%08x\n",
252 btn_num, bP->idCommand, GETIBITMAP(infoPtr, bP->iBitmap),
253 bP->fsState, bP->fsStyle, bP->dwData, bP->iString);
254 TRACE("string %s\n", debugstr_w(TOOLBAR_GetText(infoPtr,bP)));
255 if (internal)
256 TRACE("button %d id %d, hot=%s, row=%d, rect=(%ld,%ld)-(%ld,%ld)\n",
257 btn_num, bP->idCommand,
258 (bP->bHot) ? "TRUE":"FALSE", bP->nRow,
259 bP->rect.left, bP->rect.top,
260 bP->rect.right, bP->rect.bottom);
265 static void
266 TOOLBAR_DumpToolbar(TOOLBAR_INFO *iP, INT line)
268 if (TRACE_ON(toolbar)) {
269 INT i;
270 DWORD dwStyle;
272 dwStyle = GetWindowLongA (iP->hwndSelf, GWL_STYLE);
273 TRACE("toolbar %p at line %d, exStyle=%08lx, buttons=%d, bitmaps=%d, strings=%d, style=%08lx\n",
274 iP->hwndSelf, line,
275 iP->dwExStyle, iP->nNumButtons, iP->nNumBitmaps,
276 iP->nNumStrings, dwStyle);
277 TRACE("toolbar %p at line %d, himlInt=%p, himlDef=%p, himlHot=%p, himlDis=%p, redrawable=%s\n",
278 iP->hwndSelf, line,
279 iP->himlInt, iP->himlDef, iP->himlHot, iP->himlDis,
280 (iP->bDoRedraw) ? "TRUE" : "FALSE");
281 for(i=0; i<iP->nNumButtons; i++) {
282 TOOLBAR_DumpButton(iP, &iP->buttons[i], i, TRUE);
288 /***********************************************************************
289 * TOOLBAR_CheckStyle
291 * This function validates that the styles set are implemented and
292 * issues FIXME's warning of possible problems. In a perfect world this
293 * function should be null.
295 static void
296 TOOLBAR_CheckStyle (HWND hwnd, DWORD dwStyle)
298 if (dwStyle & TBSTYLE_ALTDRAG)
299 FIXME("[%p] TBSTYLE_ALTDRAG not implemented\n", hwnd);
300 if (dwStyle & TBSTYLE_REGISTERDROP)
301 FIXME("[%p] TBSTYLE_REGISTERDROP not implemented\n", hwnd);
305 static INT
306 TOOLBAR_SendNotify (NMHDR *nmhdr, TOOLBAR_INFO *infoPtr, UINT code)
308 if(!IsWindow(infoPtr->hwndSelf))
309 return 0; /* we have just been destroyed */
311 nmhdr->idFrom = GetDlgCtrlID (infoPtr->hwndSelf);
312 nmhdr->hwndFrom = infoPtr->hwndSelf;
313 nmhdr->code = code;
315 TRACE("to window %p, code=%08x, %s\n", infoPtr->hwndNotify, code,
316 (infoPtr->bNtfUnicode) ? "via Unicode" : "via ANSI");
318 if (infoPtr->bNtfUnicode)
319 return SendMessageW (infoPtr->hwndNotify, WM_NOTIFY,
320 (WPARAM) nmhdr->idFrom, (LPARAM)nmhdr);
321 else
322 return SendMessageA (infoPtr->hwndNotify, WM_NOTIFY,
323 (WPARAM) nmhdr->idFrom, (LPARAM)nmhdr);
326 /***********************************************************************
327 * TOOLBAR_GetBitmapIndex
329 * This function returns the bitmap index associated with a button.
330 * If the button specifies I_IMAGECALLBACK, then the TBN_GETDISPINFO
331 * is issued to retrieve the index.
333 static INT
334 TOOLBAR_GetBitmapIndex(TOOLBAR_INFO *infoPtr, TBUTTON_INFO *btnPtr)
336 INT ret = btnPtr->iBitmap;
338 if (ret == I_IMAGECALLBACK) {
339 /* issue TBN_GETDISPINFO */
340 NMTBDISPINFOA nmgd;
342 nmgd.idCommand = btnPtr->idCommand;
343 nmgd.lParam = btnPtr->dwData;
344 nmgd.dwMask = TBNF_IMAGE;
345 TOOLBAR_SendNotify ((NMHDR *) &nmgd, infoPtr,
346 (infoPtr->bNtfUnicode) ? TBN_GETDISPINFOW :
347 TBN_GETDISPINFOA);
348 if (nmgd.dwMask & TBNF_DI_SETITEM) {
349 btnPtr->iBitmap = nmgd.iImage;
351 ret = nmgd.iImage;
352 TRACE("TBN_GETDISPINFOA returned bitmap id %d, mask=%08lx, nNumBitmaps=%d\n",
353 ret, nmgd.dwMask, infoPtr->nNumBitmaps);
356 if (ret != I_IMAGENONE)
357 ret = GETIBITMAP(infoPtr, ret);
359 return ret;
363 static BOOL
364 TOOLBAR_IsValidBitmapIndex(TOOLBAR_INFO *infoPtr, INT index)
366 HIMAGELIST himl;
367 INT id = GETHIMLID(infoPtr, index);
368 INT iBitmap = GETIBITMAP(infoPtr, index);
370 if (((himl = GETDEFIMAGELIST(infoPtr, id)) &&
371 iBitmap >= 0 && iBitmap < ImageList_GetImageCount(himl)) ||
372 (index == I_IMAGECALLBACK))
373 return TRUE;
374 else
375 return FALSE;
379 /***********************************************************************
380 * TOOLBAR_DrawImageList
382 * This function validates the bitmap index (including I_IMAGECALLBACK
383 * functionality). It then draws the image via the ImageList_Draw
384 * function. It returns TRUE if the image was drawn, FALSE otherwise.
386 static BOOL
387 TOOLBAR_DrawImageList (TOOLBAR_INFO *infoPtr, TBUTTON_INFO *btnPtr, IMAGE_LIST_TYPE imagelist,
388 HDC hdc, UINT left, UINT top, UINT draw_flags)
390 INT index;
391 HIMAGELIST himl;
393 if (!TOOLBAR_IsValidBitmapIndex(infoPtr,btnPtr->iBitmap)) {
394 if (btnPtr->iBitmap == I_IMAGENONE) return FALSE;
395 ERR("index %d is not valid, max %d\n",
396 btnPtr->iBitmap, infoPtr->nNumBitmaps);
397 return FALSE;
400 if ((index = TOOLBAR_GetBitmapIndex(infoPtr, btnPtr)) < 0) {
401 if ((index == I_IMAGECALLBACK) ||
402 (index == I_IMAGENONE)) return FALSE;
403 ERR("TBN_GETDISPINFO returned invalid index %d\n",
404 index);
405 return FALSE;
408 switch(imagelist)
410 case IMAGE_LIST_DEFAULT:
411 himl = GETDEFIMAGELIST(infoPtr, GETHIMLID(infoPtr, btnPtr->iBitmap));
412 break;
413 case IMAGE_LIST_HOT:
414 himl = GETHOTIMAGELIST(infoPtr, GETHIMLID(infoPtr, btnPtr->iBitmap));
415 break;
416 case IMAGE_LIST_DISABLED:
417 himl = GETDISIMAGELIST(infoPtr, GETHIMLID(infoPtr, btnPtr->iBitmap));
418 break;
419 default:
420 himl = NULL;
421 FIXME("Shouldn't reach here\n");
424 if (!himl)
426 TRACE("no image list, returning FALSE\n");
427 return FALSE;
430 TRACE("drawing index=%d, himl=%p, left=%d, top=%d, flags=%08x\n",
431 index, himl, left, top, draw_flags);
433 ImageList_Draw (himl, index, hdc, left, top, draw_flags);
434 return TRUE;
438 /***********************************************************************
439 * TOOLBAR_TestImageExist
441 * This function is similar to TOOLBAR_DrawImageList, except it does not
442 * draw the image. The I_IMAGECALLBACK functionality is implemented.
444 static BOOL
445 TOOLBAR_TestImageExist (TOOLBAR_INFO *infoPtr, TBUTTON_INFO *btnPtr, HIMAGELIST himl)
447 INT index;
449 if (!himl) return FALSE;
451 if (!TOOLBAR_IsValidBitmapIndex(infoPtr,btnPtr->iBitmap)) {
452 if (btnPtr->iBitmap == I_IMAGENONE) return FALSE;
453 ERR("index %d is not valid, max %d\n",
454 btnPtr->iBitmap, infoPtr->nNumBitmaps);
455 return FALSE;
458 if ((index = TOOLBAR_GetBitmapIndex(infoPtr, btnPtr)) < 0) {
459 if ((index == I_IMAGECALLBACK) ||
460 (index == I_IMAGENONE)) return FALSE;
461 ERR("TBN_GETDISPINFO returned invalid index %d\n",
462 index);
463 return FALSE;
465 return TRUE;
469 static void
470 TOOLBAR_DrawFlatSeparator (LPRECT lpRect, HDC hdc, TOOLBAR_INFO *infoPtr)
472 RECT myrect;
473 COLORREF oldcolor, newcolor;
475 myrect.left = (lpRect->left + lpRect->right) / 2 - 1;
476 myrect.right = myrect.left + 1;
477 myrect.top = lpRect->top + 2;
478 myrect.bottom = lpRect->bottom - 2;
480 newcolor = (infoPtr->clrBtnShadow == CLR_DEFAULT) ?
481 comctl32_color.clrBtnShadow : infoPtr->clrBtnShadow;
482 oldcolor = SetBkColor (hdc, newcolor);
483 ExtTextOutA (hdc, 0, 0, ETO_OPAQUE, &myrect, 0, 0, 0);
485 myrect.left = myrect.right;
486 myrect.right = myrect.left + 1;
488 newcolor = (infoPtr->clrBtnHighlight == CLR_DEFAULT) ?
489 comctl32_color.clrBtnHighlight : infoPtr->clrBtnHighlight;
490 SetBkColor (hdc, newcolor);
491 ExtTextOutA (hdc, 0, 0, ETO_OPAQUE, &myrect, 0, 0, 0);
493 SetBkColor (hdc, oldcolor);
497 /***********************************************************************
498 * TOOLBAR_DrawDDFlatSeparator
500 * This function draws the separator that was flaged as TBSTYLE_DROPDOWN.
501 * In this case, the separator is a pixel high line of COLOR_BTNSHADOW,
502 * followed by a pixel high line of COLOR_BTNHIGHLIGHT. These separators
503 * are horizontal as opposed to the vertical separators for not dropdown
504 * type.
506 * FIXME: It is possible that the height of each line is really SM_CYBORDER.
508 static void
509 TOOLBAR_DrawDDFlatSeparator (LPRECT lpRect, HDC hdc, TBUTTON_INFO *btnPtr, TOOLBAR_INFO *infoPtr)
511 RECT myrect;
512 COLORREF oldcolor, newcolor;
514 myrect.left = lpRect->left;
515 myrect.right = lpRect->right;
516 myrect.top = lpRect->top + (lpRect->bottom - lpRect->top - 2)/2;
517 myrect.bottom = myrect.top + 1;
519 InflateRect (&myrect, -2, 0);
521 TRACE("rect=(%ld,%ld)-(%ld,%ld)\n",
522 myrect.left, myrect.top, myrect.right, myrect.bottom);
524 newcolor = (infoPtr->clrBtnShadow == CLR_DEFAULT) ?
525 comctl32_color.clrBtnShadow : infoPtr->clrBtnShadow;
526 oldcolor = SetBkColor (hdc, newcolor);
527 ExtTextOutA (hdc, 0, 0, ETO_OPAQUE, &myrect, 0, 0, 0);
529 myrect.top = myrect.bottom;
530 myrect.bottom = myrect.top + 1;
532 newcolor = (infoPtr->clrBtnHighlight == CLR_DEFAULT) ?
533 comctl32_color.clrBtnHighlight : infoPtr->clrBtnHighlight;
534 SetBkColor (hdc, newcolor);
535 ExtTextOutA (hdc, 0, 0, ETO_OPAQUE, &myrect, 0, 0, 0);
537 SetBkColor (hdc, oldcolor);
541 static void
542 TOOLBAR_DrawArrow (HDC hdc, INT left, INT top, INT colorRef)
544 INT x, y;
545 HPEN hPen, hOldPen;
547 if (!(hPen = CreatePen( PS_SOLID, 1, GetSysColor( colorRef )))) return;
548 hOldPen = SelectObject ( hdc, hPen );
549 x = left + 2;
550 y = top;
551 MoveToEx (hdc, x, y, NULL);
552 LineTo (hdc, x+5, y++); x++;
553 MoveToEx (hdc, x, y, NULL);
554 LineTo (hdc, x+3, y++); x++;
555 MoveToEx (hdc, x, y, NULL);
556 LineTo (hdc, x+1, y++);
557 SelectObject( hdc, hOldPen );
558 DeleteObject( hPen );
562 * Draw the text string for this button.
563 * note: infoPtr->himlDis *SHOULD* be non-zero when infoPtr->himlDef
564 * is non-zero, so we can simply check himlDef to see if we have
565 * an image list
567 static void
568 TOOLBAR_DrawString (TOOLBAR_INFO *infoPtr, TBUTTON_INFO *btnPtr,
569 HDC hdc, DWORD dwStyle,
570 RECT *rcText, LPWSTR lpText, NMTBCUSTOMDRAW *tbcd)
572 HFONT hOldFont = 0;
573 COLORREF clrOld = 0;
574 UINT state = tbcd->nmcd.uItemState;
576 /* draw text */
577 if (lpText) {
578 TRACE("string=%s rect=(%ld,%ld)-(%ld,%ld)\n", debugstr_w(lpText),
579 rcText->left, rcText->top, rcText->right, rcText->bottom);
581 hOldFont = SelectObject (hdc, infoPtr->hFont);
582 if ((state & CDIS_HOT) && (infoPtr->dwItemCDFlag & TBCDRF_HILITEHOTTRACK )) {
583 clrOld = SetTextColor (hdc, tbcd->clrTextHighlight);
585 else if (state & CDIS_DISABLED) {
586 clrOld = SetTextColor (hdc, tbcd->clrBtnHighlight);
587 OffsetRect (rcText, 1, 1);
588 DrawTextW (hdc, lpText, -1, rcText, infoPtr->dwDTFlags);
589 SetTextColor (hdc, comctl32_color.clr3dShadow);
590 OffsetRect (rcText, -1, -1);
592 else if (state & CDIS_INDETERMINATE) {
593 clrOld = SetTextColor (hdc, comctl32_color.clr3dShadow);
595 else {
596 clrOld = SetTextColor (hdc, tbcd->clrText);
599 DrawTextW (hdc, lpText, -1, rcText, infoPtr->dwDTFlags);
600 SetTextColor (hdc, clrOld);
601 SelectObject (hdc, hOldFont);
606 static void
607 TOOLBAR_DrawPattern (HDC hdc, LPRECT lpRect)
609 HBRUSH hbr = SelectObject (hdc, COMCTL32_hPattern55AABrush);
610 INT cx = lpRect->right - lpRect->left;
611 INT cy = lpRect->bottom - lpRect->top;
612 PatBlt (hdc, lpRect->left, lpRect->top, cx, cy, 0x00FA0089);
613 SelectObject (hdc, hbr);
617 static void
618 TOOLBAR_DrawMasked (TOOLBAR_INFO *infoPtr, TBUTTON_INFO *btnPtr,
619 HDC hdc, INT x, INT y)
621 HIMAGELIST himl = GETDEFIMAGELIST(infoPtr, 0);
622 INT cx, cy;
623 HBITMAP hbmMask;
624 HDC hdcMask;
626 if (!himl)
627 return;
629 ImageList_GetIconSize(himl, &cx, &cy);
631 /* create new dc's */
632 hdcMask = CreateCompatibleDC (0);
634 /* create new bitmap */
635 hbmMask = CreateBitmap (cx, cy, 1, 1, NULL);
636 SelectObject (hdcMask, hbmMask);
638 /* copy the mask bitmap */
639 ImageList_DrawEx(himl, btnPtr->iBitmap, hdcMask, 0, 0, 0, 0, RGB(255, 255, 255), RGB(0, 0, 0), ILD_MASK);
641 /* draw the new mask */
642 SelectObject (hdc, GetSysColorBrush (COLOR_3DHILIGHT));
643 BitBlt (hdc, x+1, y+1, cx, cy, hdcMask, 0, 0, 0xB8074A);
645 SelectObject (hdc, GetSysColorBrush (COLOR_3DSHADOW));
646 BitBlt (hdc, x, y, cx, cy, hdcMask, 0, 0, 0xB8074A);
648 DeleteObject (hbmMask);
649 DeleteDC (hdcMask);
653 static UINT
654 TOOLBAR_TranslateState(TBUTTON_INFO *btnPtr)
656 UINT retstate = 0;
658 retstate |= (btnPtr->fsState & TBSTATE_CHECKED) ? CDIS_CHECKED : 0;
659 retstate |= (btnPtr->fsState & TBSTATE_PRESSED) ? CDIS_SELECTED : 0;
660 retstate |= (btnPtr->fsState & TBSTATE_ENABLED) ? 0 : CDIS_DISABLED;
661 retstate |= (btnPtr->fsState & TBSTATE_MARKED ) ? CDIS_MARKED : 0;
662 retstate |= (btnPtr->bHot ) ? CDIS_HOT : 0;
663 retstate |= (btnPtr->fsState & TBSTATE_INDETERMINATE) ? CDIS_INDETERMINATE : 0;
664 /* FIXME: don't set CDIS_GRAYED, CDIS_FOCUS, CDIS_DEFAULT */
665 /* don't test TBSTATE_HIDDEN */
666 return retstate;
670 static void
671 TOOLBAR_DrawButton (HWND hwnd, TBUTTON_INFO *btnPtr, HDC hdc)
673 TOOLBAR_INFO *infoPtr = TOOLBAR_GetInfoPtr (hwnd);
674 DWORD dwStyle = GetWindowLongA (hwnd, GWL_STYLE);
675 BOOL hasDropDownArrow = TOOLBAR_HasDropDownArrows(infoPtr->dwExStyle) &&
676 (btnPtr->fsStyle & TBSTYLE_DROPDOWN);
677 RECT rc, rcArrow, rcBitmap, rcText, rcFill;
678 LPWSTR lpText = NULL;
679 NMTBCUSTOMDRAW tbcd;
680 DWORD ntfret;
681 INT offset;
683 if (btnPtr->fsState & TBSTATE_HIDDEN)
684 return;
686 rc = btnPtr->rect;
687 CopyRect (&rcFill, &rc);
688 CopyRect (&rcArrow, &rc);
689 CopyRect(&rcBitmap, &rc);
691 /* get a pointer to the text */
692 lpText = TOOLBAR_GetText(infoPtr, btnPtr);
694 if (hasDropDownArrow)
696 if (dwStyle & TBSTYLE_FLAT)
697 rc.right = max(rc.left, rc.right - DDARROW_WIDTH);
698 else
699 rc.right = max(rc.left, rc.right - DDARROW_WIDTH - 2);
700 rcArrow.left = rc.right;
703 /* copy text rect after adjusting for drop-down arrow
704 * so that text is centred in the rectangle not containing
705 * the arrow */
706 CopyRect(&rcText, &rc);
708 /* Center the bitmap horizontally and vertically */
709 if (dwStyle & TBSTYLE_LIST)
710 rcBitmap.left += LIST_IMAGE_OFFSET;
711 else
712 rcBitmap.left+=(infoPtr->nButtonWidth - infoPtr->nBitmapWidth) / 2;
714 if(lpText)
715 rcBitmap.top+=2; /* this looks to be the correct value from vmware comparison - cmm */
716 else
717 rcBitmap.top+=(infoPtr->nButtonHeight - infoPtr->nBitmapHeight) / 2;
719 TRACE("iBitmap: %d, start=(%ld,%ld) w=%d, h=%d\n",
720 btnPtr->iBitmap, rcBitmap.left, rcBitmap.top,
721 infoPtr->nBitmapWidth, infoPtr->nBitmapHeight);
722 TRACE ("iString: %x\n", btnPtr->iString);
723 TRACE ("Stringtext: %s\n", debugstr_w(lpText));
725 /* draw text */
726 if (lpText) {
728 InflateRect (&rcText, -3, -3);
730 if (GETDEFIMAGELIST(infoPtr, 0) &&
731 TOOLBAR_IsValidBitmapIndex(infoPtr,btnPtr->iBitmap)) {
732 /* The following test looked like this before
733 * I changed it. IE4 "Links" toolbar would not
734 * draw correctly with the original code. - GA 8/01
735 * ((dwStyle & TBSTYLE_LIST) &&
736 * ((btnPtr->fsStyle & TBSTYLE_AUTOSIZE) == 0) &&
737 * (btnPtr->iBitmap != I_IMAGENONE))
739 if (dwStyle & TBSTYLE_LIST) {
740 /* LIST style w/ ICON offset is by matching native. */
741 /* Matches IE4 "Links" bar. - GA 8/01 */
742 rcText.left += (infoPtr->nBitmapWidth + LIST_TEXT_OFFSET);
744 else {
745 rcText.top += infoPtr->nBitmapHeight + 1;
748 else {
749 if (dwStyle & TBSTYLE_LIST) {
750 /* LIST style w/o ICON offset is by matching native. */
751 /* Matches IE4 "menu" bar. - GA 8/01 */
752 rcText.left += LIST_IMAGE_ABSENT_WIDTH + LIST_TEXT_OFFSET;
756 if (btnPtr->fsState & (TBSTATE_PRESSED | TBSTATE_CHECKED))
757 OffsetRect (&rcText, 1, 1);
760 /* Initialize fields in all cases, because we use these later */
761 ZeroMemory (&tbcd, sizeof(NMTBCUSTOMDRAW));
762 tbcd.clrText = comctl32_color.clrBtnText;
763 tbcd.clrTextHighlight = comctl32_color.clrHighlightText;
764 tbcd.clrBtnFace = comctl32_color.clrBtnFace;
765 tbcd.clrBtnHighlight = comctl32_color.clrBtnHighlight;
766 tbcd.clrMark = comctl32_color.clrHighlight;
767 tbcd.clrHighlightHotTrack = 0;
768 tbcd.nStringBkMode = (infoPtr->bBtnTranspnt) ? TRANSPARENT : OPAQUE;
769 tbcd.nHLStringBkMode = (infoPtr->bBtnTranspnt) ? TRANSPARENT : OPAQUE;
770 /* MSDN says that this is the text rectangle. */
771 /* But (why always a but) tracing of v5.7 of native shows */
772 /* that this is really a *relative* rectangle based on the */
773 /* the nmcd.rc. Also the left and top are always 0 ignoring*/
774 /* any bitmap that might be present. */
775 tbcd.rcText.left = 0;
776 tbcd.rcText.top = 0;
777 tbcd.rcText.right = rcText.right - rc.left;
778 tbcd.rcText.bottom = rcText.bottom - rc.top;
779 /* we use this state later on to decide how to draw the buttons */
780 /* NOTE: applications can and do alter this to customize their */
781 /* toolbars */
782 tbcd.nmcd.uItemState = TOOLBAR_TranslateState(btnPtr);
784 /* FIXME: what should these be set to ????? */
785 tbcd.hbrMonoDither = 0;
786 tbcd.hbrLines = 0;
787 tbcd.hpenLines = 0;
789 /* Issue Item Prepaint notify */
790 infoPtr->dwItemCustDraw = 0;
791 infoPtr->dwItemCDFlag = 0;
792 if (infoPtr->dwBaseCustDraw & CDRF_NOTIFYITEMDRAW)
794 tbcd.nmcd.dwDrawStage = CDDS_ITEMPREPAINT;
795 tbcd.nmcd.hdc = hdc;
796 tbcd.nmcd.rc = rc;
797 tbcd.nmcd.dwItemSpec = btnPtr->idCommand;
798 tbcd.nmcd.lItemlParam = btnPtr->dwData;
799 ntfret = TOOLBAR_SendNotify ((NMHDR *)&tbcd, infoPtr, NM_CUSTOMDRAW);
800 infoPtr->dwItemCustDraw = ntfret & 0xffff;
801 infoPtr->dwItemCDFlag = ntfret & 0xffff0000;
802 if (infoPtr->dwItemCustDraw & CDRF_SKIPDEFAULT)
803 return;
804 /* save the only part of the rect that the user can change */
805 rcText.right = tbcd.rcText.right + rc.left;
806 rcText.bottom = tbcd.rcText.bottom + rc.top;
809 if (!infoPtr->bBtnTranspnt)
810 FillRect( hdc, &rcFill, GetSysColorBrush(COLOR_BTNFACE));
812 /* separator */
813 if (btnPtr->fsStyle & TBSTYLE_SEP) {
814 /* with the FLAT style, iBitmap is the width and has already */
815 /* been taken into consideration in calculating the width */
816 /* so now we need to draw the vertical separator */
817 /* empirical tests show that iBitmap can/will be non-zero */
818 /* when drawing the vertical bar... */
819 if ((dwStyle & TBSTYLE_FLAT) /* && (btnPtr->iBitmap == 0) */) {
820 if (btnPtr->fsStyle & TBSTYLE_DROPDOWN)
821 TOOLBAR_DrawDDFlatSeparator (&rc, hdc, btnPtr, infoPtr);
822 else
823 TOOLBAR_DrawFlatSeparator (&rc, hdc, infoPtr);
825 else if (btnPtr->fsStyle != TBSTYLE_SEP) {
826 FIXME("Draw some kind of separator: fsStyle=%x\n",
827 btnPtr->fsStyle);
829 goto FINALNOTIFY;
832 if ((dwStyle & TBSTYLE_FLAT) && (tbcd.nmcd.uItemState & CDIS_HOT))
834 if ( infoPtr->dwItemCDFlag & TBCDRF_HILITEHOTTRACK )
836 COLORREF oldclr;
838 oldclr = SetBkColor(hdc, tbcd.clrHighlightHotTrack);
839 ExtTextOutA(hdc, 0, 0, ETO_OPAQUE, &rc, NULL, 0, 0);
840 if (hasDropDownArrow)
841 ExtTextOutA(hdc, 0, 0, ETO_OPAQUE, &rcArrow, NULL, 0, 0);
842 SetBkColor(hdc, oldclr);
844 else
846 if (!(tbcd.nmcd.uItemState & CDIS_DISABLED) && !(infoPtr->dwItemCDFlag & TBCDRF_NOEDGES))
848 DrawEdge (hdc, &rc, BDR_RAISEDINNER, BF_RECT);
849 if (hasDropDownArrow)
850 DrawEdge (hdc, &rcArrow, BDR_RAISEDINNER, BF_RECT);
855 /* disabled */
856 if (tbcd.nmcd.uItemState & CDIS_DISABLED) {
857 if (!(dwStyle & TBSTYLE_FLAT) && !(infoPtr->dwItemCDFlag & TBCDRF_NOEDGES))
859 DrawEdge (hdc, &rc, EDGE_RAISED,
860 BF_SOFT | BF_RECT | BF_MIDDLE | BF_ADJUST);
861 if (hasDropDownArrow)
862 DrawEdge (hdc, &rcArrow, EDGE_RAISED,
863 BF_SOFT | BF_RECT | BF_MIDDLE | BF_ADJUST);
866 if (hasDropDownArrow)
868 TOOLBAR_DrawArrow(hdc, rcArrow.left+1, rcArrow.top+1 + (rcArrow.bottom - rcArrow.top - ARROW_HEIGHT) / 2, COLOR_3DHIGHLIGHT);
869 TOOLBAR_DrawArrow(hdc, rcArrow.left, rcArrow.top + (rcArrow.bottom - rcArrow.top - ARROW_HEIGHT) / 2, COLOR_3DSHADOW);
872 if (!TOOLBAR_DrawImageList (infoPtr, btnPtr, IMAGE_LIST_DISABLED,
873 hdc, rcBitmap.left, rcBitmap.top,
874 ILD_NORMAL))
875 TOOLBAR_DrawMasked (infoPtr, btnPtr, hdc, rcBitmap.left, rcBitmap.top);
877 if (!(infoPtr->dwExStyle & TBSTYLE_EX_MIXEDBUTTONS) || (btnPtr->fsStyle & BTNS_SHOWTEXT))
878 TOOLBAR_DrawString (infoPtr, btnPtr, hdc, dwStyle, &rcText, lpText, &tbcd);
879 goto FINALNOTIFY;
882 /* pressed TBSTYLE_BUTTON */
883 if (tbcd.nmcd.uItemState & CDIS_SELECTED) {
884 offset = (infoPtr->dwItemCDFlag & TBCDRF_NOOFFSET) ? 0 : 1;
885 if (!(infoPtr->dwItemCDFlag & TBCDRF_NOEDGES))
887 if (dwStyle & TBSTYLE_FLAT)
889 DrawEdge (hdc, &rc, BDR_SUNKENOUTER, BF_RECT | BF_ADJUST);
890 if (hasDropDownArrow)
891 DrawEdge (hdc, &rcArrow, BDR_SUNKENOUTER, BF_RECT | BF_ADJUST);
893 else
895 DrawEdge (hdc, &rc, EDGE_SUNKEN, BF_RECT | BF_MIDDLE | BF_ADJUST);
896 if (hasDropDownArrow)
897 DrawEdge (hdc, &rcArrow, EDGE_SUNKEN, BF_RECT | BF_MIDDLE | BF_ADJUST);
901 if (hasDropDownArrow)
902 TOOLBAR_DrawArrow(hdc, rcArrow.left + offset, rcArrow.top + offset + (rcArrow.bottom - rcArrow.top - ARROW_HEIGHT) / 2, COLOR_WINDOWFRAME);
904 TOOLBAR_DrawImageList (infoPtr, btnPtr, IMAGE_LIST_DEFAULT,
905 hdc, rcBitmap.left+offset, rcBitmap.top+offset,
906 ILD_NORMAL);
908 if (!(infoPtr->dwExStyle & TBSTYLE_EX_MIXEDBUTTONS) || (btnPtr->fsStyle & BTNS_SHOWTEXT))
909 TOOLBAR_DrawString (infoPtr, btnPtr, hdc, dwStyle, &rcText, lpText, &tbcd);
910 goto FINALNOTIFY;
913 /* checked TBSTYLE_CHECK */
914 if ((tbcd.nmcd.uItemState & CDIS_CHECKED) &&
915 (btnPtr->fsStyle & TBSTYLE_CHECK)) {
916 if (!(infoPtr->dwItemCDFlag & TBCDRF_NOEDGES))
918 if (dwStyle & TBSTYLE_FLAT)
919 DrawEdge (hdc, &rc, BDR_SUNKENOUTER,
920 BF_RECT | BF_ADJUST);
921 else
922 DrawEdge (hdc, &rc, EDGE_SUNKEN,
923 BF_RECT | BF_MIDDLE | BF_ADJUST);
926 TOOLBAR_DrawPattern (hdc, &rc);
928 TOOLBAR_DrawImageList (infoPtr, btnPtr, IMAGE_LIST_DEFAULT,
929 hdc, rcBitmap.left+1, rcBitmap.top+1,
930 ILD_NORMAL);
932 if (!(infoPtr->dwExStyle & TBSTYLE_EX_MIXEDBUTTONS) || (btnPtr->fsStyle & BTNS_SHOWTEXT))
933 TOOLBAR_DrawString (infoPtr, btnPtr, hdc, dwStyle, &rcText, lpText, &tbcd);
934 goto FINALNOTIFY;
937 /* indeterminate */
938 if (tbcd.nmcd.uItemState & CDIS_INDETERMINATE) {
939 if (!(infoPtr->dwItemCDFlag & TBCDRF_NOEDGES))
940 DrawEdge (hdc, &rc, EDGE_RAISED,
941 BF_SOFT | BF_RECT | BF_MIDDLE | BF_ADJUST);
943 TOOLBAR_DrawPattern (hdc, &rc);
944 TOOLBAR_DrawMasked (infoPtr, btnPtr, hdc, rcBitmap.left, rcBitmap.top);
945 if (!(infoPtr->dwExStyle & TBSTYLE_EX_MIXEDBUTTONS) || (btnPtr->fsStyle & BTNS_SHOWTEXT))
946 TOOLBAR_DrawString (infoPtr, btnPtr, hdc, dwStyle, &rcText, lpText, &tbcd);
947 goto FINALNOTIFY;
950 /* normal state */
951 if (dwStyle & TBSTYLE_FLAT)
953 if (hasDropDownArrow)
954 TOOLBAR_DrawArrow(hdc, rcArrow.left, rcArrow.top + (rcArrow.bottom - rcArrow.top - ARROW_HEIGHT) / 2, COLOR_WINDOWFRAME);
956 if (tbcd.nmcd.uItemState & CDIS_HOT) {
957 /* if hot, attempt to draw with hot image list, if fails,
958 use default image list */
959 if (!TOOLBAR_DrawImageList (infoPtr, btnPtr,
960 IMAGE_LIST_HOT,
961 hdc, rcBitmap.left,
962 rcBitmap.top, ILD_NORMAL))
963 TOOLBAR_DrawImageList (infoPtr, btnPtr, IMAGE_LIST_DEFAULT,
964 hdc, rcBitmap.left, rcBitmap.top,
965 ILD_NORMAL);
967 else
968 TOOLBAR_DrawImageList (infoPtr, btnPtr, IMAGE_LIST_DEFAULT,
969 hdc, rcBitmap.left, rcBitmap.top,
970 ILD_NORMAL);
972 else
974 if (!(infoPtr->dwItemCDFlag & TBCDRF_NOEDGES))
975 DrawEdge (hdc, &rc, EDGE_RAISED,
976 BF_SOFT | BF_RECT | BF_MIDDLE | BF_ADJUST);
978 if (hasDropDownArrow)
980 if (!(infoPtr->dwItemCDFlag & TBCDRF_NOEDGES))
981 DrawEdge (hdc, &rcArrow, EDGE_RAISED,
982 BF_SOFT | BF_RECT | BF_MIDDLE | BF_ADJUST);
983 TOOLBAR_DrawArrow(hdc, rcArrow.left, rcArrow.top + (rcArrow.bottom - rcArrow.top - ARROW_HEIGHT) / 2, COLOR_WINDOWFRAME);
986 TOOLBAR_DrawImageList (infoPtr, btnPtr, IMAGE_LIST_DEFAULT,
987 hdc, rcBitmap.left, rcBitmap.top,
988 ILD_NORMAL);
992 if (!(infoPtr->dwExStyle & TBSTYLE_EX_MIXEDBUTTONS) || (btnPtr->fsStyle & BTNS_SHOWTEXT))
993 TOOLBAR_DrawString (infoPtr, btnPtr, hdc, dwStyle, &rcText, lpText, &tbcd);
995 FINALNOTIFY:
996 if (infoPtr->dwItemCustDraw & CDRF_NOTIFYPOSTPAINT)
998 tbcd.nmcd.dwDrawStage = CDDS_ITEMPOSTPAINT;
999 tbcd.nmcd.hdc = hdc;
1000 tbcd.nmcd.rc = rc;
1001 tbcd.nmcd.dwItemSpec = btnPtr->idCommand;
1002 tbcd.nmcd.uItemState = TOOLBAR_TranslateState(btnPtr);
1003 tbcd.nmcd.lItemlParam = btnPtr->dwData;
1004 tbcd.rcText = rcText;
1005 tbcd.nStringBkMode = (infoPtr->bBtnTranspnt) ? TRANSPARENT : OPAQUE;
1006 tbcd.nHLStringBkMode = (infoPtr->bBtnTranspnt) ? TRANSPARENT : OPAQUE;
1007 ntfret = TOOLBAR_SendNotify ((NMHDR *)&tbcd, infoPtr, NM_CUSTOMDRAW);
1013 static void
1014 TOOLBAR_Refresh (HWND hwnd, HDC hdc, PAINTSTRUCT* ps)
1016 TOOLBAR_INFO *infoPtr = TOOLBAR_GetInfoPtr (hwnd);
1017 TBUTTON_INFO *btnPtr;
1018 INT i, oldBKmode = 0;
1019 RECT rcTemp, rcClient;
1020 NMTBCUSTOMDRAW tbcd;
1021 DWORD ntfret;
1023 /* if imagelist belongs to the app, it can be changed
1024 by the app after setting it */
1025 if (GETDEFIMAGELIST(infoPtr, 0) != infoPtr->himlInt)
1027 infoPtr->nNumBitmaps = 0;
1028 for (i = 0; i < infoPtr->cimlDef; i++)
1029 infoPtr->nNumBitmaps += ImageList_GetImageCount(infoPtr->himlDef[i]->himl);
1032 TOOLBAR_DumpToolbar (infoPtr, __LINE__);
1034 /* Send initial notify */
1035 ZeroMemory (&tbcd, sizeof(NMTBCUSTOMDRAW));
1036 tbcd.nmcd.dwDrawStage = CDDS_PREPAINT;
1037 tbcd.nmcd.hdc = hdc;
1038 tbcd.nmcd.rc = ps->rcPaint;
1039 ntfret = TOOLBAR_SendNotify ((NMHDR *)&tbcd, infoPtr, NM_CUSTOMDRAW);
1040 infoPtr->dwBaseCustDraw = ntfret & 0xffff;
1042 if (infoPtr->bBtnTranspnt)
1043 oldBKmode = SetBkMode (hdc, TRANSPARENT);
1045 GetClientRect(hwnd, &rcClient);
1047 /* redraw necessary buttons */
1048 btnPtr = infoPtr->buttons;
1049 for (i = 0; i < infoPtr->nNumButtons; i++, btnPtr++)
1051 BOOL bDraw;
1052 if (infoPtr->dwExStyle & TBSTYLE_EX_HIDECLIPPEDBUTTONS)
1054 IntersectRect(&rcTemp, &rcClient, &btnPtr->rect);
1055 bDraw = EqualRect(&rcTemp, &btnPtr->rect);
1057 else
1058 bDraw = TRUE;
1059 bDraw &= IntersectRect(&rcTemp, &(ps->rcPaint), &(btnPtr->rect));
1060 if (bDraw)
1061 TOOLBAR_DrawButton (hwnd, btnPtr, hdc);
1064 if (infoPtr->bBtnTranspnt && (oldBKmode != TRANSPARENT))
1065 SetBkMode (hdc, oldBKmode);
1067 if (infoPtr->dwBaseCustDraw & CDRF_NOTIFYPOSTPAINT)
1069 ZeroMemory (&tbcd, sizeof(NMTBCUSTOMDRAW));
1070 tbcd.nmcd.dwDrawStage = CDDS_POSTPAINT;
1071 tbcd.nmcd.hdc = hdc;
1072 tbcd.nmcd.rc = ps->rcPaint;
1073 ntfret = TOOLBAR_SendNotify ((NMHDR *)&tbcd, infoPtr, NM_CUSTOMDRAW);
1077 /***********************************************************************
1078 * TOOLBAR_MeasureString
1080 * This function gets the width and height of a string in pixels. This
1081 * is done first by using GetTextExtentPoint to get the basic width
1082 * and height. The DrawText is called with DT_CALCRECT to get the exact
1083 * width. The reason is because the text may have more than one "&" (or
1084 * prefix characters as M$ likes to call them). The prefix character
1085 * indicates where the underline goes, except for the string "&&" which
1086 * is reduced to a single "&". GetTextExtentPoint does not process these
1087 * only DrawText does. Note that the TBSTYLE_NOPREFIX is handled here.
1089 static void
1090 TOOLBAR_MeasureString(TOOLBAR_INFO *infoPtr, TBUTTON_INFO *btnPtr,
1091 HDC hdc, LPSIZE lpSize)
1093 RECT myrect;
1095 lpSize->cx = 0;
1096 lpSize->cy = 0;
1098 if (!(btnPtr->fsState & TBSTATE_HIDDEN) &&
1099 (!(infoPtr->dwExStyle & TBSTYLE_EX_MIXEDBUTTONS) ||
1100 (btnPtr->fsStyle & BTNS_SHOWTEXT)) )
1102 LPWSTR lpText = TOOLBAR_GetText(infoPtr, btnPtr);
1104 if(lpText != NULL) {
1105 /* first get size of all the text */
1106 GetTextExtentPoint32W (hdc, lpText, strlenW (lpText), lpSize);
1108 /* feed above size into the rectangle for DrawText */
1109 myrect.left = myrect.top = 0;
1110 myrect.right = lpSize->cx;
1111 myrect.bottom = lpSize->cy;
1113 /* Use DrawText to get true size as drawn (less pesky "&") */
1114 DrawTextW (hdc, lpText, -1, &myrect, DT_VCENTER | DT_SINGLELINE |
1115 DT_CALCRECT | ((btnPtr->fsStyle & TBSTYLE_NOPREFIX) ?
1116 DT_NOPREFIX : 0));
1118 /* feed back to caller */
1119 lpSize->cx = myrect.right;
1120 lpSize->cy = myrect.bottom;
1124 TRACE("string size %ld x %ld!\n", lpSize->cx, lpSize->cy);
1127 /***********************************************************************
1128 * TOOLBAR_CalcStrings
1130 * This function walks through each string and measures it and returns
1131 * the largest height and width to caller.
1133 static void
1134 TOOLBAR_CalcStrings (HWND hwnd, LPSIZE lpSize)
1136 TOOLBAR_INFO *infoPtr = TOOLBAR_GetInfoPtr (hwnd);
1137 TBUTTON_INFO *btnPtr;
1138 INT i;
1139 SIZE sz;
1140 HDC hdc;
1141 HFONT hOldFont;
1143 lpSize->cx = 0;
1144 lpSize->cy = 0;
1146 hdc = GetDC (hwnd);
1147 hOldFont = SelectObject (hdc, infoPtr->hFont);
1149 btnPtr = infoPtr->buttons;
1150 for (i = 0; i < infoPtr->nNumButtons; i++, btnPtr++) {
1151 if(TOOLBAR_HasText(infoPtr, btnPtr))
1153 TOOLBAR_MeasureString(infoPtr, btnPtr, hdc, &sz);
1154 if (sz.cx > lpSize->cx)
1155 lpSize->cx = sz.cx;
1156 if (sz.cy > lpSize->cy)
1157 lpSize->cy = sz.cy;
1161 SelectObject (hdc, hOldFont);
1162 ReleaseDC (hwnd, hdc);
1164 TRACE("max string size %ld x %ld!\n", lpSize->cx, lpSize->cy);
1167 /***********************************************************************
1168 * TOOLBAR_WrapToolbar
1170 * This function walks through the buttons and separators in the
1171 * toolbar, and sets the TBSTATE_WRAP flag only on those items where
1172 * wrapping should occur based on the width of the toolbar window.
1173 * It does *not* calculate button placement itself. That task
1174 * takes place in TOOLBAR_CalcToolbar. If the program wants to manage
1175 * the toolbar wrapping on its own, it can use the TBSTYLE_WRAPABLE
1176 * flag, and set the TBSTATE_WRAP flags manually on the appropriate items.
1178 * Note: TBSTYLE_WRAPABLE or TBSTYLE_EX_UNDOC1 can be used also to allow
1179 * vertical toolbar lists.
1182 static void
1183 TOOLBAR_WrapToolbar( HWND hwnd, DWORD dwStyle )
1185 TOOLBAR_INFO *infoPtr = TOOLBAR_GetInfoPtr (hwnd);
1186 TBUTTON_INFO *btnPtr;
1187 INT x, cx, i, j;
1188 RECT rc;
1189 BOOL bWrap, bButtonWrap;
1191 /* When the toolbar window style is not TBSTYLE_WRAPABLE, */
1192 /* no layout is necessary. Applications may use this style */
1193 /* to perform their own layout on the toolbar. */
1194 if( !(dwStyle & TBSTYLE_WRAPABLE) &&
1195 !(infoPtr->dwExStyle & TBSTYLE_EX_UNDOC1) ) return;
1197 btnPtr = infoPtr->buttons;
1198 x = infoPtr->nIndent;
1200 /* this can get the parents width, to know how far we can extend
1201 * this toolbar. We cannot use its height, as there may be multiple
1202 * toolbars in a rebar control
1204 GetClientRect( GetParent(hwnd), &rc );
1205 infoPtr->nWidth = rc.right - rc.left;
1206 bButtonWrap = FALSE;
1208 TRACE("start ButtonWidth=%d, BitmapWidth=%d, nWidth=%d, nIndent=%d\n",
1209 infoPtr->nButtonWidth, infoPtr->nBitmapWidth, infoPtr->nWidth,
1210 infoPtr->nIndent);
1212 for (i = 0; i < infoPtr->nNumButtons; i++ )
1214 bWrap = FALSE;
1215 btnPtr[i].fsState &= ~TBSTATE_WRAP;
1217 if (btnPtr[i].fsState & TBSTATE_HIDDEN)
1218 continue;
1220 /* UNDOCUMENTED: If a separator has a non zero bitmap index, */
1221 /* it is the actual width of the separator. This is used for */
1222 /* custom controls in toolbars. */
1223 /* */
1224 /* TBSTYLE_DROPDOWN separators are treated as buttons for */
1225 /* width. - GA 8/01 */
1226 if ((btnPtr[i].fsStyle & TBSTYLE_SEP) &&
1227 !(btnPtr[i].fsStyle & TBSTYLE_DROPDOWN))
1228 cx = (btnPtr[i].iBitmap > 0) ?
1229 btnPtr[i].iBitmap : SEPARATOR_WIDTH;
1230 else
1231 cx = infoPtr->nButtonWidth;
1233 /* Two or more adjacent separators form a separator group. */
1234 /* The first separator in a group should be wrapped to the */
1235 /* next row if the previous wrapping is on a button. */
1236 if( bButtonWrap &&
1237 (btnPtr[i].fsStyle & TBSTYLE_SEP) &&
1238 (i + 1 < infoPtr->nNumButtons ) &&
1239 (btnPtr[i + 1].fsStyle & TBSTYLE_SEP) )
1241 TRACE("wrap point 1 btn %d style %02x\n", i, btnPtr[i].fsStyle);
1242 btnPtr[i].fsState |= TBSTATE_WRAP;
1243 x = infoPtr->nIndent;
1244 i++;
1245 bButtonWrap = FALSE;
1246 continue;
1249 /* The layout makes sure the bitmap is visible, but not the button. */
1250 /* Test added to also wrap after a button that starts a row but */
1251 /* is bigger than the area. - GA 8/01 */
1252 if (( x + cx - (infoPtr->nButtonWidth - infoPtr->nBitmapWidth) / 2
1253 > infoPtr->nWidth ) ||
1254 ((x == infoPtr->nIndent) && (cx > infoPtr->nWidth)))
1256 BOOL bFound = FALSE;
1258 /* If the current button is a separator and not hidden, */
1259 /* go to the next until it reaches a non separator. */
1260 /* Wrap the last separator if it is before a button. */
1261 while( ( ((btnPtr[i].fsStyle & TBSTYLE_SEP) &&
1262 !(btnPtr[i].fsStyle & TBSTYLE_DROPDOWN)) ||
1263 (btnPtr[i].fsState & TBSTATE_HIDDEN) ) &&
1264 i < infoPtr->nNumButtons )
1266 i++;
1267 bFound = TRUE;
1270 if( bFound && i < infoPtr->nNumButtons )
1272 i--;
1273 TRACE("wrap point 2 btn %d style %02x, x=%d, cx=%d\n",
1274 i, btnPtr[i].fsStyle, x, cx);
1275 btnPtr[i].fsState |= TBSTATE_WRAP;
1276 x = infoPtr->nIndent;
1277 bButtonWrap = FALSE;
1278 continue;
1280 else if ( i >= infoPtr->nNumButtons)
1281 break;
1283 /* If the current button is not a separator, find the last */
1284 /* separator and wrap it. */
1285 for ( j = i - 1; j >= 0 && !(btnPtr[j].fsState & TBSTATE_WRAP); j--)
1287 if ((btnPtr[j].fsStyle & TBSTYLE_SEP) &&
1288 !(btnPtr[j].fsState & TBSTATE_HIDDEN))
1290 bFound = TRUE;
1291 i = j;
1292 TRACE("wrap point 3 btn %d style %02x, x=%d, cx=%d\n",
1293 i, btnPtr[i].fsStyle, x, cx);
1294 x = infoPtr->nIndent;
1295 btnPtr[j].fsState |= TBSTATE_WRAP;
1296 bButtonWrap = FALSE;
1297 break;
1301 /* If no separator available for wrapping, wrap one of */
1302 /* non-hidden previous button. */
1303 if (!bFound)
1305 for ( j = i - 1;
1306 j >= 0 && !(btnPtr[j].fsState & TBSTATE_WRAP); j--)
1308 if (btnPtr[j].fsState & TBSTATE_HIDDEN)
1309 continue;
1311 bFound = TRUE;
1312 i = j;
1313 TRACE("wrap point 4 btn %d style %02x, x=%d, cx=%d\n",
1314 i, btnPtr[i].fsStyle, x, cx);
1315 x = infoPtr->nIndent;
1316 btnPtr[j].fsState |= TBSTATE_WRAP;
1317 bButtonWrap = TRUE;
1318 break;
1322 /* If all above failed, wrap the current button. */
1323 if (!bFound)
1325 TRACE("wrap point 5 btn %d style %02x, x=%d, cx=%d\n",
1326 i, btnPtr[i].fsStyle, x, cx);
1327 btnPtr[i].fsState |= TBSTATE_WRAP;
1328 bFound = TRUE;
1329 x = infoPtr->nIndent;
1330 if (btnPtr[i].fsStyle & TBSTYLE_SEP )
1331 bButtonWrap = FALSE;
1332 else
1333 bButtonWrap = TRUE;
1336 else {
1337 TRACE("wrap point 6 btn %d style %02x, x=%d, cx=%d\n",
1338 i, btnPtr[i].fsStyle, x, cx);
1339 x += cx;
1345 /***********************************************************************
1346 * TOOLBAR_CalcToolbar
1348 * This function calculates button and separator placement. It first
1349 * calculates the button sizes, gets the toolbar window width and then
1350 * calls TOOLBAR_WrapToolbar to determine which buttons we need to wrap
1351 * on. It assigns a new location to each item and sends this location to
1352 * the tooltip window if appropriate. Finally, it updates the rcBound
1353 * rect and calculates the new required toolbar window height.
1356 static void
1357 TOOLBAR_CalcToolbar (HWND hwnd)
1359 TOOLBAR_INFO *infoPtr = TOOLBAR_GetInfoPtr(hwnd);
1360 DWORD dwStyle = GetWindowLongA (hwnd, GWL_STYLE);
1361 TBUTTON_INFO *btnPtr;
1362 INT i, nRows, nSepRows;
1363 INT x, y, cx, cy;
1364 SIZE sizeString;
1365 BOOL bWrap;
1366 BOOL usesBitmaps = FALSE;
1367 BOOL hasDropDownArrows = TOOLBAR_HasDropDownArrows(infoPtr->dwExStyle);
1369 TOOLBAR_CalcStrings (hwnd, &sizeString);
1371 for (i = 0; i < infoPtr->nNumButtons && !usesBitmaps; i++)
1373 if (TOOLBAR_IsValidBitmapIndex(infoPtr,infoPtr->buttons[i].iBitmap))
1374 usesBitmaps = TRUE;
1376 if (dwStyle & TBSTYLE_LIST)
1378 infoPtr->nButtonHeight = max((usesBitmaps) ? infoPtr->nBitmapHeight :
1379 0, sizeString.cy) + infoPtr->szPadding.cy;
1380 infoPtr->nButtonWidth = ((usesBitmaps) ? infoPtr->nBitmapWidth :
1381 0) + sizeString.cx + 6;
1382 TRACE("LIST style, But w=%d h=%d, useBitmaps=%d, Bit w=%d h=%d\n",
1383 infoPtr->nButtonWidth, infoPtr->nButtonHeight, usesBitmaps,
1384 infoPtr->nBitmapWidth, infoPtr->nBitmapHeight);
1385 TOOLBAR_DumpToolbar (infoPtr, __LINE__);
1387 else {
1388 if (sizeString.cy > 0)
1390 if (usesBitmaps)
1391 infoPtr->nButtonHeight = sizeString.cy +
1392 2 + /* this is the space to separate text from bitmap */
1393 infoPtr->nBitmapHeight + 6;
1394 else
1395 infoPtr->nButtonHeight = sizeString.cy + 6;
1397 else if (infoPtr->nButtonHeight < infoPtr->nBitmapHeight + 6)
1398 infoPtr->nButtonHeight = infoPtr->nBitmapHeight + 6;
1400 if (sizeString.cx > infoPtr->nBitmapWidth)
1401 infoPtr->nButtonWidth = sizeString.cx + 6;
1402 else if (infoPtr->nButtonWidth < infoPtr->nBitmapWidth + 6)
1403 infoPtr->nButtonWidth = infoPtr->nBitmapWidth + 6;
1406 if ( infoPtr->cxMin >= 0 && infoPtr->nButtonWidth < infoPtr->cxMin )
1407 infoPtr->nButtonWidth = infoPtr->cxMin;
1408 if ( infoPtr->cxMax > 0 && infoPtr->nButtonWidth > infoPtr->cxMax )
1409 infoPtr->nButtonWidth = infoPtr->cxMax;
1411 TOOLBAR_WrapToolbar( hwnd, dwStyle );
1413 x = infoPtr->nIndent;
1414 y = 0;
1417 * We will set the height below, and we set the width on entry
1418 * so we do not reset them here..
1420 #if 0
1421 GetClientRect( hwnd, &rc );
1422 /* get initial values for toolbar */
1423 infoPtr->nWidth = rc.right - rc.left;
1424 infoPtr->nHeight = rc.bottom - rc.top;
1425 #endif
1427 /* from above, minimum is a button, and possible text */
1428 cx = infoPtr->nButtonWidth;
1430 /* cannot use just ButtonHeight, we may have no buttons! */
1431 if (infoPtr->nNumButtons > 0)
1432 infoPtr->nHeight = infoPtr->nButtonHeight;
1434 cy = infoPtr->nHeight;
1436 nRows = nSepRows = 0;
1438 infoPtr->rcBound.top = y;
1439 infoPtr->rcBound.left = x;
1440 infoPtr->rcBound.bottom = y + cy;
1441 infoPtr->rcBound.right = x;
1443 btnPtr = infoPtr->buttons;
1445 /* do not base height/width on parent, if the parent is a */
1446 /* rebar control it could have multiple rows of toolbars */
1447 /* GetClientRect( GetParent(hwnd), &rc ); */
1448 /* cx = rc.right - rc.left; */
1449 /* cy = rc.bottom - rc.top; */
1451 TRACE("cy=%d\n", cy);
1453 for (i = 0; i < infoPtr->nNumButtons; i++, btnPtr++ )
1455 bWrap = FALSE;
1456 if (btnPtr->fsState & TBSTATE_HIDDEN)
1458 SetRectEmpty (&btnPtr->rect);
1459 continue;
1462 cy = infoPtr->nHeight;
1464 /* UNDOCUMENTED: If a separator has a non zero bitmap index, */
1465 /* it is the actual width of the separator. This is used for */
1466 /* custom controls in toolbars. */
1467 if (btnPtr->fsStyle & TBSTYLE_SEP) {
1468 if (btnPtr->fsStyle & TBSTYLE_DROPDOWN) {
1469 cy = (btnPtr->iBitmap > 0) ?
1470 btnPtr->iBitmap : SEPARATOR_WIDTH;
1471 cx = infoPtr->nButtonWidth;
1473 else
1474 cx = (btnPtr->iBitmap > 0) ?
1475 btnPtr->iBitmap : SEPARATOR_WIDTH;
1477 else
1479 if ((infoPtr->dwExStyle & TBSTYLE_EX_MIXEDBUTTONS) ||
1480 (btnPtr->fsStyle & TBSTYLE_AUTOSIZE))
1482 SIZE sz;
1483 HDC hdc;
1484 HFONT hOldFont;
1486 hdc = GetDC (hwnd);
1487 hOldFont = SelectObject (hdc, infoPtr->hFont);
1489 TOOLBAR_MeasureString(infoPtr, btnPtr, hdc, &sz);
1491 SelectObject (hdc, hOldFont);
1492 ReleaseDC (hwnd, hdc);
1494 if (sz.cx > 0)
1495 sz.cx += 2*LIST_TEXT_OFFSET;
1496 cx = sz.cx + 2*LIST_IMAGE_OFFSET;
1497 if (TOOLBAR_TestImageExist (infoPtr, btnPtr, GETDEFIMAGELIST(infoPtr,0)))
1499 if (dwStyle & TBSTYLE_LIST)
1500 cx += infoPtr->nBitmapWidth;
1501 else if (cx < (infoPtr->nBitmapWidth+7))
1502 cx = infoPtr->nBitmapWidth+7;
1504 else if (dwStyle & TBSTYLE_LIST)
1505 cx += LIST_IMAGE_ABSENT_WIDTH;
1507 else
1508 cx = infoPtr->nButtonWidth;
1510 if (hasDropDownArrows && (btnPtr->fsStyle & TBSTYLE_DROPDOWN))
1511 cx += DDARROW_WIDTH;
1513 if (btnPtr->fsState & TBSTATE_WRAP )
1514 bWrap = TRUE;
1516 SetRect (&btnPtr->rect, x, y, x + cx, y + cy);
1518 if (infoPtr->rcBound.left > x)
1519 infoPtr->rcBound.left = x;
1520 if (infoPtr->rcBound.right < x + cx)
1521 infoPtr->rcBound.right = x + cx;
1522 if (infoPtr->rcBound.bottom < y + cy)
1523 infoPtr->rcBound.bottom = y + cy;
1525 /* Set the toolTip only for non-hidden, non-separator button */
1526 if (infoPtr->hwndToolTip && !(btnPtr->fsStyle & TBSTYLE_SEP ))
1528 TTTOOLINFOA ti;
1530 ZeroMemory (&ti, sizeof(TTTOOLINFOA));
1531 ti.cbSize = sizeof(TTTOOLINFOA);
1532 ti.hwnd = hwnd;
1533 ti.uId = btnPtr->idCommand;
1534 ti.rect = btnPtr->rect;
1535 SendMessageA (infoPtr->hwndToolTip, TTM_NEWTOOLRECTA,
1536 0, (LPARAM)&ti);
1539 /* btnPtr->nRow is zero based. The space between the rows is */
1540 /* also considered as a row. */
1541 btnPtr->nRow = nRows + nSepRows;
1543 TRACE("button %d style=%x, bWrap=%d, nRows=%d, nSepRows=%d, btnrow=%d, (%d,%d)-(%d,%d)\n",
1544 i, btnPtr->fsStyle, bWrap, nRows, nSepRows, btnPtr->nRow,
1545 x, y, x+cx, y+cy);
1547 if( bWrap )
1549 if ( !(btnPtr->fsStyle & TBSTYLE_SEP) )
1550 y += cy;
1551 else
1553 /* UNDOCUMENTED: If a separator has a non zero bitmap index, */
1554 /* it is the actual width of the separator. This is used for */
1555 /* custom controls in toolbars. */
1556 if ( !(btnPtr->fsStyle & TBSTYLE_DROPDOWN))
1557 y += cy + ( (btnPtr->iBitmap > 0 ) ?
1558 btnPtr->iBitmap : SEPARATOR_WIDTH) * 2 /3;
1559 else
1560 y += cy;
1562 /* nSepRows is used to calculate the extra height follwoing */
1563 /* the last row. */
1564 nSepRows++;
1566 x = infoPtr->nIndent;
1568 /* Increment row number unless this is the last button */
1569 /* and it has Wrap set. */
1570 if (i != infoPtr->nNumButtons-1)
1571 nRows++;
1573 else
1574 x += cx;
1577 /* infoPtr->nRows is the number of rows on the toolbar */
1578 infoPtr->nRows = nRows + nSepRows + 1;
1580 #if 0
1581 /********************************************************************
1582 * The following while interesting, does not match the values *
1583 * created above for the button rectangles, nor the rcBound rect. *
1584 * We will comment it out and remove it later. *
1586 * The problem showed up as heights in the pager control that was *
1587 * wrong. *
1588 ********************************************************************/
1590 /* nSepRows * (infoPtr->nBitmapHeight + 1) is the space following */
1591 /* the last row. */
1592 infoPtr->nHeight = TOP_BORDER + (nRows + 1) * infoPtr->nButtonHeight +
1593 nSepRows * (SEPARATOR_WIDTH * 2 / 3) +
1594 nSepRows * (infoPtr->nBitmapHeight + 1) +
1595 BOTTOM_BORDER;
1596 #endif
1598 infoPtr->nHeight = infoPtr->rcBound.bottom - infoPtr->rcBound.top;
1600 TRACE("toolbar height %d, button width %d\n", infoPtr->nHeight, infoPtr->nButtonWidth);
1604 static INT
1605 TOOLBAR_InternalHitTest (HWND hwnd, LPPOINT lpPt)
1607 TOOLBAR_INFO *infoPtr = TOOLBAR_GetInfoPtr (hwnd);
1608 TBUTTON_INFO *btnPtr;
1609 INT i;
1611 btnPtr = infoPtr->buttons;
1612 for (i = 0; i < infoPtr->nNumButtons; i++, btnPtr++) {
1613 if (btnPtr->fsState & TBSTATE_HIDDEN)
1614 continue;
1616 if (btnPtr->fsStyle & TBSTYLE_SEP) {
1617 if (PtInRect (&btnPtr->rect, *lpPt)) {
1618 TRACE(" ON SEPARATOR %d!\n", i);
1619 return -i;
1622 else {
1623 if (PtInRect (&btnPtr->rect, *lpPt)) {
1624 TRACE(" ON BUTTON %d!\n", i);
1625 return i;
1630 TRACE(" NOWHERE!\n");
1631 return -1;
1635 static INT
1636 TOOLBAR_GetButtonIndex (TOOLBAR_INFO *infoPtr, INT idCommand, BOOL CommandIsIndex)
1638 TBUTTON_INFO *btnPtr;
1639 INT i;
1641 if (CommandIsIndex) {
1642 TRACE("command is really index command=%d\n", idCommand);
1643 if (idCommand >= infoPtr->nNumButtons) return -1;
1644 return idCommand;
1646 btnPtr = infoPtr->buttons;
1647 for (i = 0; i < infoPtr->nNumButtons; i++, btnPtr++) {
1648 if (btnPtr->idCommand == idCommand) {
1649 TRACE("command=%d index=%d\n", idCommand, i);
1650 return i;
1653 TRACE("no index found for command=%d\n", idCommand);
1654 return -1;
1658 static INT
1659 TOOLBAR_GetCheckedGroupButtonIndex (TOOLBAR_INFO *infoPtr, INT nIndex)
1661 TBUTTON_INFO *btnPtr;
1662 INT nRunIndex;
1664 if ((nIndex < 0) || (nIndex > infoPtr->nNumButtons))
1665 return -1;
1667 /* check index button */
1668 btnPtr = &infoPtr->buttons[nIndex];
1669 if ((btnPtr->fsStyle & TBSTYLE_CHECKGROUP) == TBSTYLE_CHECKGROUP) {
1670 if (btnPtr->fsState & TBSTATE_CHECKED)
1671 return nIndex;
1674 /* check previous buttons */
1675 nRunIndex = nIndex - 1;
1676 while (nRunIndex >= 0) {
1677 btnPtr = &infoPtr->buttons[nRunIndex];
1678 if ((btnPtr->fsStyle & TBSTYLE_CHECKGROUP) == TBSTYLE_CHECKGROUP) {
1679 if (btnPtr->fsState & TBSTATE_CHECKED)
1680 return nRunIndex;
1682 else
1683 break;
1684 nRunIndex--;
1687 /* check next buttons */
1688 nRunIndex = nIndex + 1;
1689 while (nRunIndex < infoPtr->nNumButtons) {
1690 btnPtr = &infoPtr->buttons[nRunIndex];
1691 if ((btnPtr->fsStyle & TBSTYLE_CHECKGROUP) == TBSTYLE_CHECKGROUP) {
1692 if (btnPtr->fsState & TBSTATE_CHECKED)
1693 return nRunIndex;
1695 else
1696 break;
1697 nRunIndex++;
1700 return -1;
1704 static VOID
1705 TOOLBAR_RelayEvent (HWND hwndTip, HWND hwndMsg, UINT uMsg,
1706 WPARAM wParam, LPARAM lParam)
1708 MSG msg;
1710 msg.hwnd = hwndMsg;
1711 msg.message = uMsg;
1712 msg.wParam = wParam;
1713 msg.lParam = lParam;
1714 msg.time = GetMessageTime ();
1715 msg.pt.x = LOWORD(GetMessagePos ());
1716 msg.pt.y = HIWORD(GetMessagePos ());
1718 SendMessageA (hwndTip, TTM_RELAYEVENT, 0, (LPARAM)&msg);
1722 /***********************************************************************
1723 * TOOLBAR_CustomizeDialogProc
1724 * This function implements the toolbar customization dialog.
1726 static INT_PTR CALLBACK
1727 TOOLBAR_CustomizeDialogProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
1729 PCUSTDLG_INFO custInfo = (PCUSTDLG_INFO)GetWindowLongA (hwnd, DWL_USER);
1730 PCUSTOMBUTTON btnInfo;
1731 NMTOOLBARA nmtb;
1732 TOOLBAR_INFO *infoPtr = custInfo ? custInfo->tbInfo : NULL;
1734 switch (uMsg)
1736 case WM_INITDIALOG:
1737 custInfo = (PCUSTDLG_INFO)lParam;
1738 SetWindowLongA (hwnd, DWL_USER, (DWORD)custInfo);
1740 if (custInfo)
1742 WCHAR Buffer[256];
1743 int i = 0;
1744 int index;
1746 infoPtr = custInfo->tbInfo;
1748 /* send TBN_QUERYINSERT notification */
1749 nmtb.iItem = custInfo->tbInfo->nNumButtons;
1751 if (!TOOLBAR_SendNotify ((NMHDR *) &nmtb, infoPtr, TBN_QUERYINSERT))
1752 return FALSE;
1754 /* UNDOCUMENTED: dialog hwnd immediately follows NMHDR */
1755 nmtb.iItem = (int)hwnd;
1756 /* Send TBN_INITCUSTOMIZE notification */
1757 if (TOOLBAR_SendNotify ((NMHDR *) &nmtb, infoPtr, TBN_INITCUSTOMIZE) ==
1758 TBNRF_HIDEHELP)
1760 TRACE("TBNRF_HIDEHELP requested\n");
1761 ShowWindow(GetDlgItem(hwnd, IDC_HELP_BTN), SW_HIDE);
1764 /* add items to 'toolbar buttons' list and check if removable */
1765 for (i = 0; i < custInfo->tbInfo->nNumButtons; i++)
1767 btnInfo = (PCUSTOMBUTTON)Alloc(sizeof(CUSTOMBUTTON));
1768 memset (&btnInfo->btn, 0, sizeof(TBBUTTON));
1769 btnInfo->btn.fsStyle = TBSTYLE_SEP;
1770 btnInfo->bVirtual = FALSE;
1771 LoadStringW (COMCTL32_hModule, IDS_SEPARATOR, btnInfo->text, 64);
1773 /* send TBN_QUERYDELETE notification */
1774 btnInfo->bRemovable = TOOLBAR_IsButtonRemovable(infoPtr, i, btnInfo);
1776 index = (int)SendDlgItemMessageA (hwnd, IDC_TOOLBARBTN_LBOX, LB_ADDSTRING, 0, 0);
1777 SendDlgItemMessageA (hwnd, IDC_TOOLBARBTN_LBOX, LB_SETITEMDATA, index, (LPARAM)btnInfo);
1780 /* insert separator button into 'available buttons' list */
1781 btnInfo = (PCUSTOMBUTTON)Alloc(sizeof(CUSTOMBUTTON));
1782 memset (&btnInfo->btn, 0, sizeof(TBBUTTON));
1783 btnInfo->btn.fsStyle = TBSTYLE_SEP;
1784 btnInfo->bVirtual = FALSE;
1785 btnInfo->bRemovable = TRUE;
1786 LoadStringW (COMCTL32_hModule, IDS_SEPARATOR, btnInfo->text, 64);
1787 index = (int)SendDlgItemMessageA (hwnd, IDC_AVAILBTN_LBOX, LB_ADDSTRING, 0, (LPARAM)btnInfo);
1788 SendDlgItemMessageA (hwnd, IDC_AVAILBTN_LBOX, LB_SETITEMDATA, index, (LPARAM)btnInfo);
1790 /* insert all buttons into dsa */
1791 for (i = 0;; i++)
1793 /* send TBN_GETBUTTONINFO notification */
1794 NMTOOLBARW nmtb;
1795 nmtb.iItem = i;
1796 nmtb.pszText = Buffer;
1797 nmtb.cchText = 256;
1799 /* Clear previous button's text */
1800 ZeroMemory(nmtb.pszText, nmtb.cchText * sizeof(WCHAR));
1802 if (!TOOLBAR_GetButtonInfo(infoPtr, &nmtb))
1803 break;
1805 TRACE("WM_INITDIALOG style: %x iItem(%d) idCommand(%d) iString(%d) %s\n",
1806 nmtb.tbButton.fsStyle, i,
1807 nmtb.tbButton.idCommand,
1808 nmtb.tbButton.iString,
1809 nmtb.tbButton.iString >= 0 ? debugstr_w(infoPtr->strings[nmtb.tbButton.iString])
1810 : "");
1812 /* insert button into the apropriate list */
1813 index = TOOLBAR_GetButtonIndex (custInfo->tbInfo, nmtb.tbButton.idCommand, FALSE);
1814 if (index == -1)
1816 btnInfo = (PCUSTOMBUTTON)Alloc(sizeof(CUSTOMBUTTON));
1817 btnInfo->bVirtual = FALSE;
1818 btnInfo->bRemovable = TRUE;
1820 index = SendDlgItemMessageA (hwnd, IDC_AVAILBTN_LBOX, LB_ADDSTRING, 0, 0);
1821 SendDlgItemMessageA (hwnd, IDC_AVAILBTN_LBOX,
1822 LB_SETITEMDATA, index, (LPARAM)btnInfo);
1824 else
1826 btnInfo = (PCUSTOMBUTTON)SendDlgItemMessageA (hwnd,
1827 IDC_TOOLBARBTN_LBOX, LB_GETITEMDATA, index, 0);
1830 memcpy (&btnInfo->btn, &nmtb.tbButton, sizeof(TBBUTTON));
1831 if (!(nmtb.tbButton.fsStyle & TBSTYLE_SEP))
1833 if (lstrlenW(nmtb.pszText))
1834 lstrcpyW(btnInfo->text, nmtb.pszText);
1835 else if (nmtb.tbButton.iString >= 0 &&
1836 nmtb.tbButton.iString < infoPtr->nNumStrings)
1838 lstrcpyW(btnInfo->text,
1839 infoPtr->strings[nmtb.tbButton.iString]);
1844 /* select first item in the 'available' list */
1845 SendDlgItemMessageA (hwnd, IDC_AVAILBTN_LBOX, LB_SETCURSEL, 0, 0);
1847 /* append 'virtual' separator button to the 'toolbar buttons' list */
1848 btnInfo = (PCUSTOMBUTTON)Alloc(sizeof(CUSTOMBUTTON));
1849 memset (&btnInfo->btn, 0, sizeof(TBBUTTON));
1850 btnInfo->btn.fsStyle = TBSTYLE_SEP;
1851 btnInfo->bVirtual = TRUE;
1852 btnInfo->bRemovable = FALSE;
1853 LoadStringW (COMCTL32_hModule, IDS_SEPARATOR, btnInfo->text, 64);
1854 index = (int)SendDlgItemMessageA (hwnd, IDC_TOOLBARBTN_LBOX, LB_ADDSTRING, 0, (LPARAM)btnInfo);
1855 SendDlgItemMessageA (hwnd, IDC_TOOLBARBTN_LBOX, LB_SETITEMDATA, index, (LPARAM)btnInfo);
1857 /* select last item in the 'toolbar' list */
1858 SendDlgItemMessageA (hwnd, IDC_TOOLBARBTN_LBOX, LB_SETCURSEL, index, 0);
1859 SendDlgItemMessageA (hwnd, IDC_TOOLBARBTN_LBOX, LB_SETTOPINDEX, index, 0);
1861 /* set focus and disable buttons */
1862 PostMessageA (hwnd, WM_USER, 0, 0);
1864 return TRUE;
1866 case WM_USER:
1867 EnableWindow (GetDlgItem (hwnd,IDC_MOVEUP_BTN), FALSE);
1868 EnableWindow (GetDlgItem (hwnd,IDC_MOVEDN_BTN), FALSE);
1869 EnableWindow (GetDlgItem (hwnd,IDC_REMOVE_BTN), FALSE);
1870 SetFocus (GetDlgItem (hwnd, IDC_TOOLBARBTN_LBOX));
1871 return TRUE;
1873 case WM_CLOSE:
1874 EndDialog(hwnd, FALSE);
1875 return TRUE;
1877 case WM_COMMAND:
1878 switch (LOWORD(wParam))
1880 case IDC_TOOLBARBTN_LBOX:
1881 if (HIWORD(wParam) == LBN_SELCHANGE)
1883 PCUSTOMBUTTON btnInfo;
1884 NMTOOLBARA nmtb;
1885 int count;
1886 int index;
1888 count = SendDlgItemMessageA (hwnd, IDC_TOOLBARBTN_LBOX, LB_GETCOUNT, 0, 0);
1889 index = SendDlgItemMessageA (hwnd, IDC_TOOLBARBTN_LBOX, LB_GETCURSEL, 0, 0);
1891 /* send TBN_QUERYINSERT notification */
1892 nmtb.iItem = index;
1893 TOOLBAR_SendNotify ((NMHDR *) &nmtb, infoPtr,
1894 TBN_QUERYINSERT);
1896 /* get list box item */
1897 btnInfo = (PCUSTOMBUTTON)SendDlgItemMessageA (hwnd, IDC_TOOLBARBTN_LBOX, LB_GETITEMDATA, index, 0);
1899 if (index == (count - 1))
1901 /* last item (virtual separator) */
1902 EnableWindow (GetDlgItem (hwnd,IDC_MOVEUP_BTN), FALSE);
1903 EnableWindow (GetDlgItem (hwnd,IDC_MOVEDN_BTN), FALSE);
1905 else if (index == (count - 2))
1907 /* second last item (last non-virtual item) */
1908 EnableWindow (GetDlgItem (hwnd,IDC_MOVEUP_BTN), TRUE);
1909 EnableWindow (GetDlgItem (hwnd,IDC_MOVEDN_BTN), FALSE);
1911 else if (index == 0)
1913 /* first item */
1914 EnableWindow (GetDlgItem (hwnd,IDC_MOVEUP_BTN), FALSE);
1915 EnableWindow (GetDlgItem (hwnd,IDC_MOVEDN_BTN), TRUE);
1917 else
1919 EnableWindow (GetDlgItem (hwnd,IDC_MOVEUP_BTN), TRUE);
1920 EnableWindow (GetDlgItem (hwnd,IDC_MOVEDN_BTN), TRUE);
1923 EnableWindow (GetDlgItem (hwnd,IDC_REMOVE_BTN), btnInfo->bRemovable);
1925 break;
1927 case IDC_MOVEUP_BTN:
1929 PCUSTOMBUTTON btnInfo;
1930 int index;
1931 int count;
1933 count = SendDlgItemMessageA (hwnd, IDC_TOOLBARBTN_LBOX, LB_GETCOUNT, 0, 0);
1934 index = SendDlgItemMessageA (hwnd, IDC_TOOLBARBTN_LBOX, LB_GETCURSEL, 0, 0);
1935 TRACE("Move up: index %d\n", index);
1937 /* send TBN_QUERYINSERT notification */
1938 nmtb.iItem = index;
1940 if (TOOLBAR_SendNotify ((NMHDR *) &nmtb, infoPtr,
1941 TBN_QUERYINSERT))
1943 btnInfo = (PCUSTOMBUTTON)SendDlgItemMessageA (hwnd, IDC_TOOLBARBTN_LBOX, LB_GETITEMDATA, index, 0);
1945 SendDlgItemMessageA (hwnd, IDC_TOOLBARBTN_LBOX, LB_DELETESTRING, index, 0);
1946 SendDlgItemMessageA (hwnd, IDC_TOOLBARBTN_LBOX, LB_INSERTSTRING, index-1, 0);
1947 SendDlgItemMessageA (hwnd, IDC_TOOLBARBTN_LBOX, LB_SETITEMDATA, index-1, (LPARAM)btnInfo);
1948 SendDlgItemMessageA (hwnd, IDC_TOOLBARBTN_LBOX, LB_SETCURSEL, index-1 , 0);
1950 if (index <= 1)
1951 EnableWindow (GetDlgItem (hwnd,IDC_MOVEUP_BTN), FALSE);
1952 else if (index >= (count - 3))
1953 EnableWindow (GetDlgItem (hwnd,IDC_MOVEDN_BTN), TRUE);
1955 SendMessageA (custInfo->tbHwnd, TB_DELETEBUTTON, index, 0);
1956 SendMessageA (custInfo->tbHwnd, TB_INSERTBUTTONA, index-1, (LPARAM)&(btnInfo->btn));
1959 break;
1961 case IDC_MOVEDN_BTN: /* move down */
1963 PCUSTOMBUTTON btnInfo;
1964 int index;
1965 int count;
1967 count = SendDlgItemMessageA (hwnd, IDC_TOOLBARBTN_LBOX, LB_GETCOUNT, 0, 0);
1968 index = SendDlgItemMessageA (hwnd, IDC_TOOLBARBTN_LBOX, LB_GETCURSEL, 0, 0);
1969 TRACE("Move up: index %d\n", index);
1971 /* send TBN_QUERYINSERT notification */
1972 nmtb.iItem = index;
1973 if (TOOLBAR_SendNotify ((NMHDR *) &nmtb, infoPtr,
1974 TBN_QUERYINSERT))
1976 btnInfo = (PCUSTOMBUTTON)SendDlgItemMessageA (hwnd, IDC_TOOLBARBTN_LBOX, LB_GETITEMDATA, index, 0);
1978 /* move button down */
1979 SendDlgItemMessageA (hwnd, IDC_TOOLBARBTN_LBOX, LB_DELETESTRING, index, 0);
1980 SendDlgItemMessageA (hwnd, IDC_TOOLBARBTN_LBOX, LB_INSERTSTRING, index+1, 0);
1981 SendDlgItemMessageA (hwnd, IDC_TOOLBARBTN_LBOX, LB_SETITEMDATA, index+1, (LPARAM)btnInfo);
1982 SendDlgItemMessageA (hwnd, IDC_TOOLBARBTN_LBOX, LB_SETCURSEL, index+1 , 0);
1984 if (index == 0)
1985 EnableWindow (GetDlgItem (hwnd,IDC_MOVEUP_BTN), TRUE);
1986 else if (index >= (count - 3))
1987 EnableWindow (GetDlgItem (hwnd,IDC_MOVEDN_BTN), FALSE);
1989 SendMessageA (custInfo->tbHwnd, TB_DELETEBUTTON, index, 0);
1990 SendMessageA (custInfo->tbHwnd, TB_INSERTBUTTONA, index+1, (LPARAM)&(btnInfo->btn));
1993 break;
1995 case IDC_REMOVE_BTN: /* remove button */
1997 PCUSTOMBUTTON btnInfo;
1998 int index;
2000 index = SendDlgItemMessageA (hwnd, IDC_TOOLBARBTN_LBOX, LB_GETCURSEL, 0, 0);
2002 if (LB_ERR == index)
2003 break;
2005 TRACE("Remove: index %d\n", index);
2007 btnInfo = (PCUSTOMBUTTON)SendDlgItemMessageA (hwnd, IDC_TOOLBARBTN_LBOX,
2008 LB_GETITEMDATA, index, 0);
2010 /* send TBN_QUERYDELETE notification */
2011 if (TOOLBAR_IsButtonRemovable(infoPtr, index, btnInfo))
2013 btnInfo = (PCUSTOMBUTTON)SendDlgItemMessageA (hwnd, IDC_TOOLBARBTN_LBOX, LB_GETITEMDATA, index, 0);
2014 SendDlgItemMessageA (hwnd, IDC_TOOLBARBTN_LBOX, LB_DELETESTRING, index, 0);
2015 SendDlgItemMessageA (hwnd, IDC_TOOLBARBTN_LBOX, LB_SETCURSEL, index , 0);
2017 SendMessageA (custInfo->tbHwnd, TB_DELETEBUTTON, index, 0);
2019 /* insert into 'available button' list */
2020 if (!(btnInfo->btn.fsStyle & TBSTYLE_SEP))
2022 index = (int)SendDlgItemMessageA (hwnd, IDC_AVAILBTN_LBOX, LB_ADDSTRING, 0, 0);
2023 SendDlgItemMessageA (hwnd, IDC_AVAILBTN_LBOX, LB_SETITEMDATA, index, (LPARAM)btnInfo);
2025 else
2026 Free (btnInfo);
2029 break;
2030 case IDC_HELP_BTN:
2031 TOOLBAR_SendNotify(&nmtb.hdr, infoPtr, TBN_CUSTHELP);
2032 break;
2033 case IDC_RESET_BTN:
2034 TOOLBAR_SendNotify(&nmtb.hdr, infoPtr, TBN_RESET);
2035 break;
2037 case IDOK: /* Add button */
2039 int index;
2040 int count;
2042 count = SendDlgItemMessageA (hwnd, IDC_AVAILBTN_LBOX, LB_GETCOUNT, 0, 0);
2043 index = SendDlgItemMessageA (hwnd, IDC_AVAILBTN_LBOX, LB_GETCURSEL, 0, 0);
2044 TRACE("Add: index %d\n", index);
2046 /* send TBN_QUERYINSERT notification */
2047 nmtb.iItem = index;
2048 if (TOOLBAR_SendNotify ((NMHDR *) &nmtb, infoPtr,
2049 TBN_QUERYINSERT))
2051 btnInfo = (PCUSTOMBUTTON)SendDlgItemMessageA (hwnd, IDC_AVAILBTN_LBOX, LB_GETITEMDATA, index, 0);
2053 if (index != 0)
2055 /* remove from 'available buttons' list */
2056 SendDlgItemMessageA (hwnd, IDC_AVAILBTN_LBOX, LB_DELETESTRING, index, 0);
2057 if (index == count-1)
2058 SendDlgItemMessageA (hwnd, IDC_AVAILBTN_LBOX, LB_SETCURSEL, index-1 , 0);
2059 else
2060 SendDlgItemMessageA (hwnd, IDC_AVAILBTN_LBOX, LB_SETCURSEL, index , 0);
2062 else
2064 PCUSTOMBUTTON btnNew;
2066 /* duplicate 'separator' button */
2067 btnNew = (PCUSTOMBUTTON)Alloc (sizeof(CUSTOMBUTTON));
2068 memcpy (btnNew, btnInfo, sizeof(CUSTOMBUTTON));
2069 btnInfo = btnNew;
2072 /* insert into 'toolbar button' list */
2073 index = SendDlgItemMessageA (hwnd, IDC_TOOLBARBTN_LBOX, LB_GETCURSEL, 0, 0);
2074 SendDlgItemMessageA (hwnd, IDC_TOOLBARBTN_LBOX, LB_INSERTSTRING, index, 0);
2075 SendDlgItemMessageA (hwnd, IDC_TOOLBARBTN_LBOX, LB_SETITEMDATA, index, (LPARAM)btnInfo);
2077 SendMessageA (custInfo->tbHwnd, TB_INSERTBUTTONA, index, (LPARAM)&(btnInfo->btn));
2080 break;
2082 case IDCANCEL:
2083 EndDialog(hwnd, FALSE);
2084 break;
2086 return TRUE;
2088 case WM_DESTROY:
2090 int count;
2091 int i;
2093 /* delete items from 'toolbar buttons' listbox*/
2094 count = SendDlgItemMessageA (hwnd, IDC_TOOLBARBTN_LBOX, LB_GETCOUNT, 0, 0);
2095 for (i = 0; i < count; i++)
2097 btnInfo = (PCUSTOMBUTTON)SendDlgItemMessageA (hwnd, IDC_TOOLBARBTN_LBOX, LB_GETITEMDATA, i, 0);
2098 Free(btnInfo);
2099 SendDlgItemMessageA (hwnd, IDC_TOOLBARBTN_LBOX, LB_SETITEMDATA, 0, 0);
2101 SendDlgItemMessageA (hwnd, IDC_TOOLBARBTN_LBOX, LB_RESETCONTENT, 0, 0);
2104 /* delete items from 'available buttons' listbox*/
2105 count = SendDlgItemMessageA (hwnd, IDC_AVAILBTN_LBOX, LB_GETCOUNT, 0, 0);
2106 for (i = 0; i < count; i++)
2108 btnInfo = (PCUSTOMBUTTON)SendDlgItemMessageA (hwnd, IDC_AVAILBTN_LBOX, LB_GETITEMDATA, i, 0);
2109 Free(btnInfo);
2110 SendDlgItemMessageA (hwnd, IDC_AVAILBTN_LBOX, LB_SETITEMDATA, i, 0);
2112 SendDlgItemMessageA (hwnd, IDC_AVAILBTN_LBOX, LB_RESETCONTENT, 0, 0);
2114 return TRUE;
2116 case WM_DRAWITEM:
2117 if (wParam == IDC_AVAILBTN_LBOX || wParam == IDC_TOOLBARBTN_LBOX)
2119 LPDRAWITEMSTRUCT lpdis = (LPDRAWITEMSTRUCT)lParam;
2120 DWORD dwStyle = GetWindowLongA (infoPtr->hwndSelf, GWL_STYLE);
2121 RECT rcButton;
2122 RECT rcText;
2123 HPEN hPen, hOldPen;
2124 HBRUSH hOldBrush;
2125 COLORREF oldText = 0;
2126 COLORREF oldBk = 0;
2128 /* get item data */
2129 btnInfo = (PCUSTOMBUTTON)SendDlgItemMessageA (hwnd, wParam, LB_GETITEMDATA, (WPARAM)lpdis->itemID, 0);
2130 if (btnInfo == NULL)
2132 FIXME("btnInfo invalid!\n");
2133 return TRUE;
2136 /* set colors and select objects */
2137 oldBk = SetBkColor (lpdis->hDC, (lpdis->itemState & ODS_FOCUS)?comctl32_color.clrHighlight:comctl32_color.clrWindow);
2138 if (btnInfo->bVirtual)
2139 oldText = SetTextColor (lpdis->hDC, comctl32_color.clrGrayText);
2140 else
2141 oldText = SetTextColor (lpdis->hDC, (lpdis->itemState & ODS_FOCUS)?comctl32_color.clrHighlightText:comctl32_color.clrWindowText);
2142 hPen = CreatePen( PS_SOLID, 1,
2143 GetSysColor( (lpdis->itemState & ODS_SELECTED)?COLOR_HIGHLIGHT:COLOR_WINDOW));
2144 hOldPen = SelectObject (lpdis->hDC, hPen );
2145 hOldBrush = SelectObject (lpdis->hDC, GetSysColorBrush ((lpdis->itemState & ODS_FOCUS)?COLOR_HIGHLIGHT:COLOR_WINDOW));
2147 /* fill background rectangle */
2148 Rectangle (lpdis->hDC, lpdis->rcItem.left, lpdis->rcItem.top,
2149 lpdis->rcItem.right, lpdis->rcItem.bottom);
2151 /* calculate button and text rectangles */
2152 CopyRect (&rcButton, &lpdis->rcItem);
2153 InflateRect (&rcButton, -1, -1);
2154 CopyRect (&rcText, &rcButton);
2155 rcButton.right = rcButton.left + custInfo->tbInfo->nBitmapWidth + 6;
2156 rcText.left = rcButton.right + 2;
2158 /* draw focus rectangle */
2159 if (lpdis->itemState & ODS_FOCUS)
2160 DrawFocusRect (lpdis->hDC, &lpdis->rcItem);
2162 /* draw button */
2163 if (!(dwStyle & TBSTYLE_FLAT))
2164 DrawEdge (lpdis->hDC, &rcButton, EDGE_RAISED, BF_RECT|BF_MIDDLE|BF_SOFT);
2166 /* draw image and text */
2167 if ((btnInfo->btn.fsStyle & TBSTYLE_SEP) == 0) {
2168 HIMAGELIST himl = GETDEFIMAGELIST(infoPtr, GETHIMLID(infoPtr,
2169 btnInfo->btn.iBitmap));
2170 ImageList_Draw (himl, GETIBITMAP(infoPtr, btnInfo->btn.iBitmap),
2171 lpdis->hDC, rcButton.left+3, rcButton.top+3, ILD_NORMAL);
2173 DrawTextW (lpdis->hDC, btnInfo->text, -1, &rcText,
2174 DT_LEFT | DT_VCENTER | DT_SINGLELINE);
2176 /* delete objects and reset colors */
2177 SelectObject (lpdis->hDC, hOldBrush);
2178 SelectObject (lpdis->hDC, hOldPen);
2179 SetBkColor (lpdis->hDC, oldBk);
2180 SetTextColor (lpdis->hDC, oldText);
2181 DeleteObject( hPen );
2182 return TRUE;
2184 return FALSE;
2186 case WM_MEASUREITEM:
2187 if (wParam == IDC_AVAILBTN_LBOX || wParam == IDC_TOOLBARBTN_LBOX)
2189 MEASUREITEMSTRUCT *lpmis = (MEASUREITEMSTRUCT*)lParam;
2191 if (custInfo && custInfo->tbInfo)
2192 lpmis->itemHeight = custInfo->tbInfo->nBitmapHeight + 8;
2193 else
2194 lpmis->itemHeight = 15 + 8; /* default height */
2196 return TRUE;
2198 return FALSE;
2200 default:
2201 return FALSE;
2206 /***********************************************************************
2207 * TOOLBAR_AddBitmap: Add the bitmaps to the default image list.
2210 static LRESULT
2211 TOOLBAR_AddBitmap (HWND hwnd, WPARAM wParam, LPARAM lParam)
2213 TOOLBAR_INFO *infoPtr = TOOLBAR_GetInfoPtr (hwnd);
2214 LPTBADDBITMAP lpAddBmp = (LPTBADDBITMAP)lParam;
2215 INT nIndex = 0, nButtons, nCount;
2216 HBITMAP hbmLoad;
2217 HIMAGELIST himlDef;
2219 TRACE("hwnd=%p wParam=%x lParam=%lx\n", hwnd, wParam, lParam);
2220 if (!lpAddBmp)
2221 return -1;
2223 if (lpAddBmp->hInst == HINST_COMMCTRL)
2225 if ((lpAddBmp->nID & ~1) == IDB_STD_SMALL_COLOR)
2226 nButtons = 15;
2227 else if ((lpAddBmp->nID & ~1) == IDB_VIEW_SMALL_COLOR)
2228 nButtons = 13;
2229 else if ((lpAddBmp->nID & ~1) == IDB_HIST_SMALL_COLOR)
2230 nButtons = 5;
2231 else
2232 return -1;
2234 TRACE ("adding %d internal bitmaps!\n", nButtons);
2236 /* Windows resize all the buttons to the size of a newly added standard image */
2237 if (lpAddBmp->nID & 1)
2239 /* large icons */
2240 /* FIXME: on windows the size of the images is 25x24 but the size of the bitmap
2241 * in rsrc is only 24x24. Fix the bitmap (how?) and then fix this
2243 SendMessageA (hwnd, TB_SETBITMAPSIZE, 0,
2244 MAKELPARAM((WORD)24, (WORD)24));
2245 SendMessageA (hwnd, TB_SETBUTTONSIZE, 0,
2246 MAKELPARAM((WORD)31, (WORD)30));
2248 else
2250 /* small icons */
2251 SendMessageA (hwnd, TB_SETBITMAPSIZE, 0,
2252 MAKELPARAM((WORD)16, (WORD)16));
2253 SendMessageA (hwnd, TB_SETBUTTONSIZE, 0,
2254 MAKELPARAM((WORD)22, (WORD)22));
2257 TOOLBAR_CalcToolbar (hwnd);
2259 else
2261 nButtons = (INT)wParam;
2262 if (nButtons <= 0)
2263 return -1;
2265 TRACE ("adding %d bitmaps!\n", nButtons);
2268 if (!infoPtr->cimlDef) {
2269 /* create new default image list */
2270 TRACE ("creating default image list!\n");
2272 himlDef = ImageList_Create (infoPtr->nBitmapWidth, infoPtr->nBitmapHeight,
2273 ILC_COLOR | ILC_MASK, nButtons, 2);
2274 TOOLBAR_InsertImageList(&infoPtr->himlDef, &infoPtr->cimlDef, himlDef, 0);
2275 infoPtr->himlInt = himlDef;
2277 else {
2278 himlDef = GETDEFIMAGELIST(infoPtr, 0);
2281 if (!himlDef) {
2282 WARN("No default image list available\n");
2283 return -1;
2286 nCount = ImageList_GetImageCount(himlDef);
2288 /* Add bitmaps to the default image list */
2289 if (lpAddBmp->hInst == NULL)
2291 BITMAP bmp;
2292 HBITMAP hOldBitmapBitmap, hOldBitmapLoad;
2293 HDC hdcImage, hdcBitmap;
2295 /* copy the bitmap before adding it so that the user's bitmap
2296 * doesn't get modified.
2298 GetObjectA ((HBITMAP)lpAddBmp->nID, sizeof(BITMAP), (LPVOID)&bmp);
2300 hdcImage = CreateCompatibleDC(0);
2301 hdcBitmap = CreateCompatibleDC(0);
2303 /* create new bitmap */
2304 hbmLoad = CreateBitmap (bmp.bmWidth, bmp.bmHeight, bmp.bmPlanes, bmp.bmBitsPixel, NULL);
2305 hOldBitmapBitmap = SelectObject(hdcBitmap, (HBITMAP)lpAddBmp->nID);
2306 hOldBitmapLoad = SelectObject(hdcImage, hbmLoad);
2308 /* Copy the user's image */
2309 BitBlt (hdcImage, 0, 0, bmp.bmWidth, bmp.bmHeight,
2310 hdcBitmap, 0, 0, SRCCOPY);
2312 SelectObject (hdcImage, hOldBitmapLoad);
2313 SelectObject (hdcBitmap, hOldBitmapBitmap);
2314 DeleteDC (hdcImage);
2315 DeleteDC (hdcBitmap);
2317 nIndex = ImageList_AddMasked (himlDef, hbmLoad, comctl32_color.clrBtnFace);
2318 DeleteObject (hbmLoad);
2320 else if (lpAddBmp->hInst == HINST_COMMCTRL)
2322 /* Add system bitmaps */
2323 switch (lpAddBmp->nID)
2325 case IDB_STD_SMALL_COLOR:
2326 hbmLoad = LoadBitmapA (COMCTL32_hModule,
2327 MAKEINTRESOURCEA(IDB_STD_SMALL));
2328 nIndex = ImageList_AddMasked (himlDef,
2329 hbmLoad, comctl32_color.clrBtnFace);
2330 DeleteObject (hbmLoad);
2331 break;
2333 case IDB_STD_LARGE_COLOR:
2334 hbmLoad = LoadBitmapA (COMCTL32_hModule,
2335 MAKEINTRESOURCEA(IDB_STD_LARGE));
2336 nIndex = ImageList_AddMasked (himlDef,
2337 hbmLoad, comctl32_color.clrBtnFace);
2338 DeleteObject (hbmLoad);
2339 break;
2341 case IDB_VIEW_SMALL_COLOR:
2342 hbmLoad = LoadBitmapA (COMCTL32_hModule,
2343 MAKEINTRESOURCEA(IDB_VIEW_SMALL));
2344 nIndex = ImageList_AddMasked (himlDef,
2345 hbmLoad, comctl32_color.clrBtnFace);
2346 DeleteObject (hbmLoad);
2347 break;
2349 case IDB_VIEW_LARGE_COLOR:
2350 hbmLoad = LoadBitmapA (COMCTL32_hModule,
2351 MAKEINTRESOURCEA(IDB_VIEW_LARGE));
2352 nIndex = ImageList_AddMasked (himlDef,
2353 hbmLoad, comctl32_color.clrBtnFace);
2354 DeleteObject (hbmLoad);
2355 break;
2357 case IDB_HIST_SMALL_COLOR:
2358 hbmLoad = LoadBitmapA (COMCTL32_hModule,
2359 MAKEINTRESOURCEA(IDB_HIST_SMALL));
2360 nIndex = ImageList_AddMasked (himlDef,
2361 hbmLoad, comctl32_color.clrBtnFace);
2362 DeleteObject (hbmLoad);
2363 break;
2365 case IDB_HIST_LARGE_COLOR:
2366 hbmLoad = LoadBitmapA (COMCTL32_hModule,
2367 MAKEINTRESOURCEA(IDB_HIST_LARGE));
2368 nIndex = ImageList_AddMasked (himlDef,
2369 hbmLoad, comctl32_color.clrBtnFace);
2370 DeleteObject (hbmLoad);
2371 break;
2373 default:
2374 nIndex = ImageList_GetImageCount (himlDef);
2375 ERR ("invalid imagelist!\n");
2376 break;
2379 else
2381 hbmLoad = LoadBitmapA (lpAddBmp->hInst, (LPSTR)lpAddBmp->nID);
2382 nIndex = ImageList_AddMasked (himlDef, hbmLoad, comctl32_color.clrBtnFace);
2383 DeleteObject (hbmLoad);
2386 TRACE("Number of bitmap infos: %d\n", infoPtr->nNumBitmapInfos);
2388 if (infoPtr->nNumBitmapInfos == 0)
2390 infoPtr->bitmaps = Alloc(sizeof(TBITMAP_INFO));
2392 else
2394 TBITMAP_INFO *oldBitmaps = infoPtr->bitmaps;
2395 infoPtr->bitmaps = Alloc((infoPtr->nNumBitmapInfos + 1) * sizeof(TBITMAP_INFO));
2396 memcpy(&infoPtr->bitmaps[0], &oldBitmaps[0], infoPtr->nNumBitmapInfos);
2399 infoPtr->bitmaps[infoPtr->nNumBitmapInfos].nButtons = nButtons;
2400 infoPtr->bitmaps[infoPtr->nNumBitmapInfos].hInst = lpAddBmp->hInst;
2401 infoPtr->bitmaps[infoPtr->nNumBitmapInfos].nID = lpAddBmp->nID;
2403 infoPtr->nNumBitmapInfos++;
2404 TRACE("Number of bitmap infos: %d\n", infoPtr->nNumBitmapInfos);
2406 if (nIndex != -1)
2408 INT imagecount = ImageList_GetImageCount(himlDef);
2410 if (infoPtr->nNumBitmaps + nButtons != imagecount)
2412 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",
2413 infoPtr->nNumBitmaps, nCount, imagecount - nCount,
2414 infoPtr->nNumBitmaps+nButtons,imagecount);
2416 infoPtr->nNumBitmaps = imagecount;
2418 else
2419 infoPtr->nNumBitmaps += nButtons;
2422 InvalidateRect(hwnd, NULL, FALSE);
2424 return nIndex;
2428 static LRESULT
2429 TOOLBAR_AddButtonsA (HWND hwnd, WPARAM wParam, LPARAM lParam)
2431 TOOLBAR_INFO *infoPtr = TOOLBAR_GetInfoPtr (hwnd);
2432 LPTBBUTTON lpTbb = (LPTBBUTTON)lParam;
2433 INT nOldButtons, nNewButtons, nAddButtons, nCount;
2435 TRACE("adding %d buttons!\n", wParam);
2437 nAddButtons = (UINT)wParam;
2438 nOldButtons = infoPtr->nNumButtons;
2439 nNewButtons = nOldButtons + nAddButtons;
2441 if (infoPtr->nNumButtons == 0) {
2442 infoPtr->buttons =
2443 Alloc (sizeof(TBUTTON_INFO) * nNewButtons);
2445 else {
2446 TBUTTON_INFO *oldButtons = infoPtr->buttons;
2447 infoPtr->buttons =
2448 Alloc (sizeof(TBUTTON_INFO) * nNewButtons);
2449 memcpy (&infoPtr->buttons[0], &oldButtons[0],
2450 nOldButtons * sizeof(TBUTTON_INFO));
2451 Free (oldButtons);
2454 infoPtr->nNumButtons = nNewButtons;
2456 /* insert new button data */
2457 for (nCount = 0; nCount < nAddButtons; nCount++) {
2458 TBUTTON_INFO *btnPtr = &infoPtr->buttons[nOldButtons+nCount];
2459 btnPtr->iBitmap = lpTbb[nCount].iBitmap;
2460 btnPtr->idCommand = lpTbb[nCount].idCommand;
2461 btnPtr->fsState = lpTbb[nCount].fsState;
2462 btnPtr->fsStyle = lpTbb[nCount].fsStyle;
2463 btnPtr->dwData = lpTbb[nCount].dwData;
2464 btnPtr->iString = lpTbb[nCount].iString;
2465 btnPtr->bHot = FALSE;
2467 if ((infoPtr->hwndToolTip) && !(btnPtr->fsStyle & TBSTYLE_SEP)) {
2468 TTTOOLINFOA ti;
2470 ZeroMemory (&ti, sizeof(TTTOOLINFOA));
2471 ti.cbSize = sizeof (TTTOOLINFOA);
2472 ti.hwnd = hwnd;
2473 ti.uId = btnPtr->idCommand;
2474 ti.hinst = 0;
2475 ti.lpszText = LPSTR_TEXTCALLBACKA;
2477 SendMessageA (infoPtr->hwndToolTip, TTM_ADDTOOLA,
2478 0, (LPARAM)&ti);
2482 TOOLBAR_CalcToolbar (hwnd);
2484 TOOLBAR_DumpToolbar (infoPtr, __LINE__);
2486 InvalidateRect(hwnd, NULL, FALSE);
2488 return TRUE;
2492 static LRESULT
2493 TOOLBAR_AddButtonsW (HWND hwnd, WPARAM wParam, LPARAM lParam)
2495 TOOLBAR_INFO *infoPtr = TOOLBAR_GetInfoPtr (hwnd);
2496 LPTBBUTTON lpTbb = (LPTBBUTTON)lParam;
2497 INT nOldButtons, nNewButtons, nAddButtons, nCount;
2499 TRACE("adding %d buttons!\n", wParam);
2501 nAddButtons = (UINT)wParam;
2502 nOldButtons = infoPtr->nNumButtons;
2503 nNewButtons = nOldButtons + nAddButtons;
2505 if (infoPtr->nNumButtons == 0) {
2506 infoPtr->buttons =
2507 Alloc (sizeof(TBUTTON_INFO) * nNewButtons);
2509 else {
2510 TBUTTON_INFO *oldButtons = infoPtr->buttons;
2511 infoPtr->buttons =
2512 Alloc (sizeof(TBUTTON_INFO) * nNewButtons);
2513 memcpy (&infoPtr->buttons[0], &oldButtons[0],
2514 nOldButtons * sizeof(TBUTTON_INFO));
2515 Free (oldButtons);
2518 infoPtr->nNumButtons = nNewButtons;
2520 /* insert new button data */
2521 for (nCount = 0; nCount < nAddButtons; nCount++) {
2522 TBUTTON_INFO *btnPtr = &infoPtr->buttons[nOldButtons+nCount];
2523 btnPtr->iBitmap = lpTbb[nCount].iBitmap;
2524 btnPtr->idCommand = lpTbb[nCount].idCommand;
2525 btnPtr->fsState = lpTbb[nCount].fsState;
2526 btnPtr->fsStyle = lpTbb[nCount].fsStyle;
2527 btnPtr->dwData = lpTbb[nCount].dwData;
2528 btnPtr->iString = lpTbb[nCount].iString;
2529 btnPtr->bHot = FALSE;
2531 if ((infoPtr->hwndToolTip) && !(btnPtr->fsStyle & TBSTYLE_SEP)) {
2532 TTTOOLINFOW ti;
2534 ZeroMemory (&ti, sizeof(TTTOOLINFOW));
2535 ti.cbSize = sizeof (TTTOOLINFOW);
2536 ti.hwnd = hwnd;
2537 ti.uId = btnPtr->idCommand;
2538 ti.hinst = 0;
2539 ti.lpszText = LPSTR_TEXTCALLBACKW;
2540 ti.lParam = lParam;
2542 SendMessageW (infoPtr->hwndToolTip, TTM_ADDTOOLW,
2543 0, (LPARAM)&ti);
2547 TOOLBAR_CalcToolbar (hwnd);
2549 TOOLBAR_DumpToolbar (infoPtr, __LINE__);
2551 InvalidateRect(hwnd, NULL, FALSE);
2553 return TRUE;
2557 static LRESULT
2558 TOOLBAR_AddStringA (HWND hwnd, WPARAM wParam, LPARAM lParam)
2560 TOOLBAR_INFO *infoPtr = TOOLBAR_GetInfoPtr (hwnd);
2561 INT nIndex;
2563 if ((wParam) && (HIWORD(lParam) == 0)) {
2564 char szString[256];
2565 INT len;
2566 TRACE("adding string from resource!\n");
2568 len = LoadStringA ((HINSTANCE)wParam, (UINT)lParam,
2569 szString, 256);
2571 TRACE("len=%d \"%s\"\n", len, szString);
2572 nIndex = infoPtr->nNumStrings;
2573 if (infoPtr->nNumStrings == 0) {
2574 infoPtr->strings =
2575 Alloc (sizeof(LPWSTR));
2577 else {
2578 LPWSTR *oldStrings = infoPtr->strings;
2579 infoPtr->strings =
2580 Alloc (sizeof(LPWSTR) * (infoPtr->nNumStrings + 1));
2581 memcpy (&infoPtr->strings[0], &oldStrings[0],
2582 sizeof(LPWSTR) * infoPtr->nNumStrings);
2583 Free (oldStrings);
2586 /*Alloc zeros out the allocated memory*/
2587 Str_SetPtrAtoW (&infoPtr->strings[infoPtr->nNumStrings], szString );
2588 infoPtr->nNumStrings++;
2590 else {
2591 LPSTR p = (LPSTR)lParam;
2592 INT len;
2594 if (p == NULL)
2595 return -1;
2596 TRACE("adding string(s) from array!\n");
2598 nIndex = infoPtr->nNumStrings;
2599 while (*p) {
2600 len = strlen (p);
2601 TRACE("len=%d \"%s\"\n", len, p);
2603 if (infoPtr->nNumStrings == 0) {
2604 infoPtr->strings =
2605 Alloc (sizeof(LPWSTR));
2607 else {
2608 LPWSTR *oldStrings = infoPtr->strings;
2609 infoPtr->strings =
2610 Alloc (sizeof(LPWSTR) * (infoPtr->nNumStrings + 1));
2611 memcpy (&infoPtr->strings[0], &oldStrings[0],
2612 sizeof(LPWSTR) * infoPtr->nNumStrings);
2613 Free (oldStrings);
2616 Str_SetPtrAtoW (&infoPtr->strings[infoPtr->nNumStrings], p );
2617 infoPtr->nNumStrings++;
2619 p += (len+1);
2623 return nIndex;
2627 static LRESULT
2628 TOOLBAR_AddStringW (HWND hwnd, WPARAM wParam, LPARAM lParam)
2630 #define MAX_RESOURCE_STRING_LENGTH 512
2631 TOOLBAR_INFO *infoPtr = TOOLBAR_GetInfoPtr (hwnd);
2632 INT nIndex;
2634 if ((wParam) && (HIWORD(lParam) == 0)) {
2635 WCHAR szString[MAX_RESOURCE_STRING_LENGTH];
2636 INT len;
2637 TRACE("adding string from resource!\n");
2639 len = LoadStringW ((HINSTANCE)wParam, (UINT)lParam,
2640 szString, MAX_RESOURCE_STRING_LENGTH);
2642 TRACE("len=%d %s\n", len, debugstr_w(szString));
2643 TRACE("First char: 0x%x\n", *szString);
2644 if (szString[0] == L'|')
2646 PWSTR p = szString + 1;
2648 nIndex = infoPtr->nNumStrings;
2649 while (*p != L'|' && *p != L'\0') {
2650 PWSTR np;
2652 if (infoPtr->nNumStrings == 0) {
2653 infoPtr->strings = Alloc (sizeof(LPWSTR));
2655 else
2657 LPWSTR *oldStrings = infoPtr->strings;
2658 infoPtr->strings = Alloc(sizeof(LPWSTR) * (infoPtr->nNumStrings + 1));
2659 memcpy(&infoPtr->strings[0], &oldStrings[0],
2660 sizeof(LPWSTR) * infoPtr->nNumStrings);
2661 Free(oldStrings);
2664 np=strchrW (p, '|');
2665 if (np!=NULL) {
2666 len = np - p;
2667 np++;
2668 } else {
2669 len = strlenW(p);
2670 np = p + len;
2672 TRACE("len=%d %s\n", len, debugstr_w(p));
2673 infoPtr->strings[infoPtr->nNumStrings] =
2674 Alloc (sizeof(WCHAR)*(len+1));
2675 lstrcpynW (infoPtr->strings[infoPtr->nNumStrings], p, len+1);
2676 infoPtr->nNumStrings++;
2678 p = np;
2681 else
2683 nIndex = infoPtr->nNumStrings;
2684 if (infoPtr->nNumStrings == 0) {
2685 infoPtr->strings =
2686 Alloc (sizeof(LPWSTR));
2688 else {
2689 LPWSTR *oldStrings = infoPtr->strings;
2690 infoPtr->strings =
2691 Alloc (sizeof(LPWSTR) * (infoPtr->nNumStrings + 1));
2692 memcpy (&infoPtr->strings[0], &oldStrings[0],
2693 sizeof(LPWSTR) * infoPtr->nNumStrings);
2694 Free (oldStrings);
2697 Str_SetPtrW (&infoPtr->strings[infoPtr->nNumStrings], szString);
2698 infoPtr->nNumStrings++;
2701 else {
2702 LPWSTR p = (LPWSTR)lParam;
2703 INT len;
2705 if (p == NULL)
2706 return -1;
2707 TRACE("adding string(s) from array!\n");
2708 nIndex = infoPtr->nNumStrings;
2709 while (*p) {
2710 len = strlenW (p);
2712 TRACE("len=%d %s\n", len, debugstr_w(p));
2713 if (infoPtr->nNumStrings == 0) {
2714 infoPtr->strings =
2715 Alloc (sizeof(LPWSTR));
2717 else {
2718 LPWSTR *oldStrings = infoPtr->strings;
2719 infoPtr->strings =
2720 Alloc (sizeof(LPWSTR) * (infoPtr->nNumStrings + 1));
2721 memcpy (&infoPtr->strings[0], &oldStrings[0],
2722 sizeof(LPWSTR) * infoPtr->nNumStrings);
2723 Free (oldStrings);
2726 Str_SetPtrW (&infoPtr->strings[infoPtr->nNumStrings], p);
2727 infoPtr->nNumStrings++;
2729 p += (len+1);
2733 return nIndex;
2737 static LRESULT
2738 TOOLBAR_AutoSize (HWND hwnd)
2740 TOOLBAR_INFO *infoPtr = TOOLBAR_GetInfoPtr (hwnd);
2741 DWORD dwStyle = GetWindowLongA (hwnd, GWL_STYLE);
2742 RECT parent_rect;
2743 RECT window_rect;
2744 HWND parent;
2745 INT x, y;
2746 INT cx, cy;
2747 UINT uPosFlags = SWP_NOZORDER;
2749 TRACE("resize forced, style=%lx!\n", dwStyle);
2751 parent = GetParent (hwnd);
2752 GetClientRect(parent, &parent_rect);
2754 x = parent_rect.left;
2755 y = parent_rect.top;
2757 /* FIXME: we should be able to early out if nothing */
2758 /* has changed with nWidth != parent_rect width */
2760 if (dwStyle & CCS_NORESIZE) {
2761 uPosFlags |= (SWP_NOSIZE | SWP_NOMOVE);
2762 cx = 0;
2763 cy = 0;
2764 TOOLBAR_CalcToolbar (hwnd);
2766 else {
2767 infoPtr->nWidth = parent_rect.right - parent_rect.left;
2768 TOOLBAR_CalcToolbar (hwnd);
2769 InvalidateRect( hwnd, NULL, TRUE );
2770 cy = infoPtr->nHeight;
2771 cx = infoPtr->nWidth;
2773 if ((dwStyle & CCS_BOTTOM) == CCS_NOMOVEY) {
2774 GetWindowRect(hwnd, &window_rect);
2775 ScreenToClient(parent, (LPPOINT)&window_rect.left);
2776 y = window_rect.top;
2778 if ((dwStyle & CCS_BOTTOM) == CCS_BOTTOM) {
2779 GetWindowRect(hwnd, &window_rect);
2780 y = parent_rect.bottom - ( window_rect.bottom - window_rect.top);
2784 if (dwStyle & CCS_NOPARENTALIGN)
2785 uPosFlags |= SWP_NOMOVE;
2787 if (!(dwStyle & CCS_NODIVIDER))
2788 cy += GetSystemMetrics(SM_CYEDGE);
2790 if (dwStyle & WS_BORDER)
2792 x = y = 1;
2793 cy += GetSystemMetrics(SM_CYEDGE);
2794 cx += GetSystemMetrics(SM_CYEDGE);
2797 infoPtr->bAutoSize = TRUE;
2798 SetWindowPos (hwnd, HWND_TOP, x, y, cx, cy, uPosFlags);
2799 /* The following line makes sure that the infoPtr->bAutoSize is turned off
2800 * after the setwindowpos calls */
2801 infoPtr->bAutoSize = FALSE;
2803 return 0;
2807 static LRESULT
2808 TOOLBAR_ButtonCount (HWND hwnd, WPARAM wParam, LPARAM lParam)
2810 TOOLBAR_INFO *infoPtr = TOOLBAR_GetInfoPtr (hwnd);
2812 return infoPtr->nNumButtons;
2816 static LRESULT
2817 TOOLBAR_ButtonStructSize (HWND hwnd, WPARAM wParam, LPARAM lParam)
2819 TOOLBAR_INFO *infoPtr = TOOLBAR_GetInfoPtr (hwnd);
2821 if (infoPtr == NULL) {
2822 ERR("(%p, 0x%x, 0x%lx)\n", hwnd, wParam, lParam);
2823 ERR("infoPtr == NULL!\n");
2824 return 0;
2827 infoPtr->dwStructSize = (DWORD)wParam;
2829 return 0;
2833 static LRESULT
2834 TOOLBAR_ChangeBitmap (HWND hwnd, WPARAM wParam, LPARAM lParam)
2836 TOOLBAR_INFO *infoPtr = TOOLBAR_GetInfoPtr (hwnd);
2837 TBUTTON_INFO *btnPtr;
2838 INT nIndex;
2840 TRACE("button %d, iBitmap now %d\n", wParam, LOWORD(lParam));
2842 nIndex = TOOLBAR_GetButtonIndex (infoPtr, (INT)wParam, FALSE);
2843 if (nIndex == -1)
2844 return FALSE;
2846 btnPtr = &infoPtr->buttons[nIndex];
2847 btnPtr->iBitmap = LOWORD(lParam);
2849 /* we HAVE to erase the background, the new bitmap could be */
2850 /* transparent */
2851 InvalidateRect(hwnd, &btnPtr->rect, TRUE);
2853 return TRUE;
2857 static LRESULT
2858 TOOLBAR_CheckButton (HWND hwnd, WPARAM wParam, LPARAM lParam)
2860 TOOLBAR_INFO *infoPtr = TOOLBAR_GetInfoPtr (hwnd);
2861 TBUTTON_INFO *btnPtr;
2862 INT nIndex;
2863 INT nOldIndex = -1;
2864 BOOL bChecked = FALSE;
2866 nIndex = TOOLBAR_GetButtonIndex (infoPtr, (INT)wParam, FALSE);
2867 if (nIndex == -1)
2868 return FALSE;
2870 btnPtr = &infoPtr->buttons[nIndex];
2872 if (!(btnPtr->fsStyle & TBSTYLE_CHECK))
2873 return FALSE;
2875 bChecked = (btnPtr->fsState & TBSTATE_CHECKED) ? TRUE : FALSE;
2877 if (LOWORD(lParam) == FALSE)
2878 btnPtr->fsState &= ~TBSTATE_CHECKED;
2879 else {
2880 if (btnPtr->fsStyle & TBSTYLE_GROUP) {
2881 nOldIndex =
2882 TOOLBAR_GetCheckedGroupButtonIndex (infoPtr, nIndex);
2883 if (nOldIndex == nIndex)
2884 return 0;
2885 if (nOldIndex != -1)
2886 infoPtr->buttons[nOldIndex].fsState &= ~TBSTATE_CHECKED;
2888 btnPtr->fsState |= TBSTATE_CHECKED;
2891 if( bChecked != LOWORD(lParam) )
2893 if (nOldIndex != -1)
2895 InvalidateRect(hwnd, &infoPtr->buttons[nOldIndex].rect,
2896 TOOLBAR_HasText(infoPtr, &infoPtr->buttons[nOldIndex]));
2898 InvalidateRect(hwnd, &btnPtr->rect, TRUE);
2901 /* FIXME: Send a WM_NOTIFY?? */
2903 return TRUE;
2907 static LRESULT
2908 TOOLBAR_CommandToIndex (HWND hwnd, WPARAM wParam, LPARAM lParam)
2910 TOOLBAR_INFO *infoPtr = TOOLBAR_GetInfoPtr (hwnd);
2912 return TOOLBAR_GetButtonIndex (infoPtr, (INT)wParam, FALSE);
2916 static LRESULT
2917 TOOLBAR_Customize (HWND hwnd)
2919 TOOLBAR_INFO *infoPtr = TOOLBAR_GetInfoPtr (hwnd);
2920 CUSTDLG_INFO custInfo;
2921 LRESULT ret;
2922 LPCVOID template;
2923 HRSRC hRes;
2924 NMHDR nmhdr;
2926 custInfo.tbInfo = infoPtr;
2927 custInfo.tbHwnd = hwnd;
2929 /* send TBN_BEGINADJUST notification */
2930 TOOLBAR_SendNotify ((NMHDR *) &nmhdr, infoPtr,
2931 TBN_BEGINADJUST);
2933 if (!(hRes = FindResourceA (COMCTL32_hModule,
2934 MAKEINTRESOURCEA(IDD_TBCUSTOMIZE),
2935 (LPSTR)RT_DIALOG)))
2936 return FALSE;
2938 if(!(template = (LPVOID)LoadResource (COMCTL32_hModule, hRes)))
2939 return FALSE;
2941 ret = DialogBoxIndirectParamA ((HINSTANCE)GetWindowLongA(hwnd, GWL_HINSTANCE),
2942 (LPDLGTEMPLATEA)template,
2943 hwnd,
2944 TOOLBAR_CustomizeDialogProc,
2945 (LPARAM)&custInfo);
2947 /* send TBN_ENDADJUST notification */
2948 TOOLBAR_SendNotify ((NMHDR *) &nmhdr, infoPtr,
2949 TBN_ENDADJUST);
2951 return ret;
2955 static LRESULT
2956 TOOLBAR_DeleteButton (HWND hwnd, WPARAM wParam, LPARAM lParam)
2958 TOOLBAR_INFO *infoPtr = TOOLBAR_GetInfoPtr (hwnd);
2959 INT nIndex = (INT)wParam;
2961 if ((nIndex < 0) || (nIndex >= infoPtr->nNumButtons))
2962 return FALSE;
2964 if ((infoPtr->hwndToolTip) &&
2965 !(infoPtr->buttons[nIndex].fsStyle & TBSTYLE_SEP)) {
2966 TTTOOLINFOA ti;
2968 ZeroMemory (&ti, sizeof(TTTOOLINFOA));
2969 ti.cbSize = sizeof (TTTOOLINFOA);
2970 ti.hwnd = hwnd;
2971 ti.uId = infoPtr->buttons[nIndex].idCommand;
2973 SendMessageA (infoPtr->hwndToolTip, TTM_DELTOOLA, 0, (LPARAM)&ti);
2976 if (infoPtr->nNumButtons == 1) {
2977 TRACE(" simple delete!\n");
2978 Free (infoPtr->buttons);
2979 infoPtr->buttons = NULL;
2980 infoPtr->nNumButtons = 0;
2982 else {
2983 TBUTTON_INFO *oldButtons = infoPtr->buttons;
2984 TRACE("complex delete! [nIndex=%d]\n", nIndex);
2986 infoPtr->nNumButtons--;
2987 infoPtr->buttons = Alloc (sizeof (TBUTTON_INFO) * infoPtr->nNumButtons);
2988 if (nIndex > 0) {
2989 memcpy (&infoPtr->buttons[0], &oldButtons[0],
2990 nIndex * sizeof(TBUTTON_INFO));
2993 if (nIndex < infoPtr->nNumButtons) {
2994 memcpy (&infoPtr->buttons[nIndex], &oldButtons[nIndex+1],
2995 (infoPtr->nNumButtons - nIndex) * sizeof(TBUTTON_INFO));
2998 Free (oldButtons);
3001 TOOLBAR_CalcToolbar (hwnd);
3003 InvalidateRect (hwnd, NULL, TRUE);
3005 return TRUE;
3009 static LRESULT
3010 TOOLBAR_EnableButton (HWND hwnd, WPARAM wParam, LPARAM lParam)
3012 TOOLBAR_INFO *infoPtr = TOOLBAR_GetInfoPtr (hwnd);
3013 TBUTTON_INFO *btnPtr;
3014 INT nIndex;
3015 DWORD bState;
3017 nIndex = TOOLBAR_GetButtonIndex (infoPtr, (INT)wParam, FALSE);
3018 if (nIndex == -1)
3019 return FALSE;
3021 btnPtr = &infoPtr->buttons[nIndex];
3023 bState = btnPtr->fsState & TBSTATE_ENABLED;
3025 /* update the toolbar button state */
3026 if(LOWORD(lParam) == FALSE) {
3027 btnPtr->fsState &= ~(TBSTATE_ENABLED | TBSTATE_PRESSED);
3028 } else {
3029 btnPtr->fsState |= TBSTATE_ENABLED;
3032 /* redraw the button only if the state of the button changed */
3033 if(bState != (btnPtr->fsState & TBSTATE_ENABLED))
3035 InvalidateRect(hwnd, &btnPtr->rect,
3036 TOOLBAR_HasText(infoPtr, btnPtr));
3039 return TRUE;
3043 static inline LRESULT
3044 TOOLBAR_GetAnchorHighlight (HWND hwnd)
3046 TOOLBAR_INFO *infoPtr = TOOLBAR_GetInfoPtr (hwnd);
3048 return infoPtr->bAnchor;
3052 static LRESULT
3053 TOOLBAR_GetBitmap (HWND hwnd, WPARAM wParam, LPARAM lParam)
3055 TOOLBAR_INFO *infoPtr = TOOLBAR_GetInfoPtr (hwnd);
3056 INT nIndex;
3058 nIndex = TOOLBAR_GetButtonIndex (infoPtr, (INT)wParam, FALSE);
3059 if (nIndex == -1)
3060 return -1;
3062 return infoPtr->buttons[nIndex].iBitmap;
3066 static inline LRESULT
3067 TOOLBAR_GetBitmapFlags (HWND hwnd, WPARAM wParam, LPARAM lParam)
3069 return (GetDeviceCaps (0, LOGPIXELSX) >= 120) ? TBBF_LARGE : 0;
3073 static LRESULT
3074 TOOLBAR_GetButton (HWND hwnd, WPARAM wParam, LPARAM lParam)
3076 TOOLBAR_INFO *infoPtr = TOOLBAR_GetInfoPtr (hwnd);
3077 LPTBBUTTON lpTbb = (LPTBBUTTON)lParam;
3078 INT nIndex = (INT)wParam;
3079 TBUTTON_INFO *btnPtr;
3081 if (infoPtr == NULL)
3082 return FALSE;
3084 if (lpTbb == NULL)
3085 return FALSE;
3087 if ((nIndex < 0) || (nIndex >= infoPtr->nNumButtons))
3088 return FALSE;
3090 btnPtr = &infoPtr->buttons[nIndex];
3091 lpTbb->iBitmap = btnPtr->iBitmap;
3092 lpTbb->idCommand = btnPtr->idCommand;
3093 lpTbb->fsState = btnPtr->fsState;
3094 lpTbb->fsStyle = btnPtr->fsStyle;
3095 lpTbb->bReserved[0] = 0;
3096 lpTbb->bReserved[1] = 0;
3097 lpTbb->dwData = btnPtr->dwData;
3098 lpTbb->iString = btnPtr->iString;
3100 return TRUE;
3104 static LRESULT
3105 TOOLBAR_GetButtonInfoA (HWND hwnd, WPARAM wParam, LPARAM lParam)
3107 TOOLBAR_INFO *infoPtr = TOOLBAR_GetInfoPtr (hwnd);
3108 LPTBBUTTONINFOA lpTbInfo = (LPTBBUTTONINFOA)lParam;
3109 TBUTTON_INFO *btnPtr;
3110 INT nIndex;
3112 if (infoPtr == NULL)
3113 return -1;
3114 if (lpTbInfo == NULL)
3115 return -1;
3116 if (lpTbInfo->cbSize < sizeof(TBBUTTONINFOA))
3117 return -1;
3119 nIndex = TOOLBAR_GetButtonIndex (infoPtr, (INT)wParam,
3120 lpTbInfo->dwMask & 0x80000000);
3121 if (nIndex == -1)
3122 return -1;
3124 if (!(btnPtr = &infoPtr->buttons[nIndex])) return -1;
3126 if (lpTbInfo->dwMask & TBIF_COMMAND)
3127 lpTbInfo->idCommand = btnPtr->idCommand;
3128 if (lpTbInfo->dwMask & TBIF_IMAGE)
3129 lpTbInfo->iImage = btnPtr->iBitmap;
3130 if (lpTbInfo->dwMask & TBIF_LPARAM)
3131 lpTbInfo->lParam = btnPtr->dwData;
3132 if (lpTbInfo->dwMask & TBIF_SIZE)
3133 lpTbInfo->cx = (WORD)(btnPtr->rect.right - btnPtr->rect.left);
3134 if (lpTbInfo->dwMask & TBIF_STATE)
3135 lpTbInfo->fsState = btnPtr->fsState;
3136 if (lpTbInfo->dwMask & TBIF_STYLE)
3137 lpTbInfo->fsStyle = btnPtr->fsStyle;
3138 if (lpTbInfo->dwMask & TBIF_TEXT) {
3139 LPWSTR lpText = TOOLBAR_GetText(infoPtr,btnPtr);
3140 Str_GetPtrWtoA (lpText, lpTbInfo->pszText,lpTbInfo->cchText);
3142 return nIndex;
3146 static LRESULT
3147 TOOLBAR_GetButtonInfoW (HWND hwnd, WPARAM wParam, LPARAM lParam)
3149 TOOLBAR_INFO *infoPtr = TOOLBAR_GetInfoPtr (hwnd);
3150 LPTBBUTTONINFOW lpTbInfo = (LPTBBUTTONINFOW)lParam;
3151 TBUTTON_INFO *btnPtr;
3152 INT nIndex;
3154 if (infoPtr == NULL)
3155 return -1;
3156 if (lpTbInfo == NULL)
3157 return -1;
3158 if (lpTbInfo->cbSize < sizeof(TBBUTTONINFOW))
3159 return -1;
3161 nIndex = TOOLBAR_GetButtonIndex (infoPtr, (INT)wParam,
3162 lpTbInfo->dwMask & 0x80000000);
3163 if (nIndex == -1)
3164 return -1;
3166 btnPtr = &infoPtr->buttons[nIndex];
3168 if(!btnPtr)
3169 return -1;
3171 if (lpTbInfo->dwMask & TBIF_COMMAND)
3172 lpTbInfo->idCommand = btnPtr->idCommand;
3173 if (lpTbInfo->dwMask & TBIF_IMAGE)
3174 lpTbInfo->iImage = btnPtr->iBitmap;
3175 if (lpTbInfo->dwMask & TBIF_LPARAM)
3176 lpTbInfo->lParam = btnPtr->dwData;
3177 if (lpTbInfo->dwMask & TBIF_SIZE)
3178 lpTbInfo->cx = (WORD)(btnPtr->rect.right - btnPtr->rect.left);
3179 if (lpTbInfo->dwMask & TBIF_STATE)
3180 lpTbInfo->fsState = btnPtr->fsState;
3181 if (lpTbInfo->dwMask & TBIF_STYLE)
3182 lpTbInfo->fsStyle = btnPtr->fsStyle;
3183 if (lpTbInfo->dwMask & TBIF_TEXT) {
3184 LPWSTR lpText = TOOLBAR_GetText(infoPtr,btnPtr);
3185 Str_GetPtrW (lpText,lpTbInfo->pszText,lpTbInfo->cchText);
3188 return nIndex;
3192 static LRESULT
3193 TOOLBAR_GetButtonSize (HWND hwnd)
3195 TOOLBAR_INFO *infoPtr = TOOLBAR_GetInfoPtr (hwnd);
3197 if (infoPtr->nNumButtons > 0)
3198 return MAKELONG((WORD)infoPtr->nButtonWidth,
3199 (WORD)infoPtr->nButtonHeight);
3200 else
3201 return MAKELONG(8,7);
3205 static LRESULT
3206 TOOLBAR_GetButtonTextA (HWND hwnd, WPARAM wParam, LPARAM lParam)
3208 TOOLBAR_INFO *infoPtr = TOOLBAR_GetInfoPtr (hwnd);
3209 INT nIndex;
3210 LPWSTR lpText;
3212 if (lParam == 0)
3213 return -1;
3215 nIndex = TOOLBAR_GetButtonIndex (infoPtr, (INT)wParam, FALSE);
3216 if (nIndex == -1)
3217 return -1;
3219 lpText = TOOLBAR_GetText(infoPtr,&infoPtr->buttons[nIndex]);
3221 return WideCharToMultiByte( CP_ACP, 0, lpText, -1,
3222 (LPSTR)lParam, 0x7fffffff, NULL, NULL ) - 1;
3226 static LRESULT
3227 TOOLBAR_GetButtonTextW (HWND hwnd, WPARAM wParam, LPARAM lParam)
3229 TOOLBAR_INFO *infoPtr = TOOLBAR_GetInfoPtr (hwnd);
3230 INT nIndex;
3231 LPWSTR lpText;
3233 if (lParam == 0)
3234 return -1;
3236 nIndex = TOOLBAR_GetButtonIndex (infoPtr, (INT)wParam, FALSE);
3237 if (nIndex == -1)
3238 return -1;
3240 lpText = TOOLBAR_GetText(infoPtr,&infoPtr->buttons[nIndex]);
3242 strcpyW ((LPWSTR)lParam, lpText);
3244 return strlenW (lpText);
3248 static LRESULT
3249 TOOLBAR_GetDisabledImageList (HWND hwnd, WPARAM wParam, LPARAM lParam)
3251 return (LRESULT)GETDISIMAGELIST(TOOLBAR_GetInfoPtr (hwnd), 0);
3255 inline static LRESULT
3256 TOOLBAR_GetExtendedStyle (HWND hwnd)
3258 TOOLBAR_INFO *infoPtr = TOOLBAR_GetInfoPtr (hwnd);
3260 TRACE("\n");
3262 return infoPtr->dwExStyle;
3266 static LRESULT
3267 TOOLBAR_GetHotImageList (HWND hwnd, WPARAM wParam, LPARAM lParam)
3269 return (LRESULT)GETHOTIMAGELIST(TOOLBAR_GetInfoPtr (hwnd), 0);
3273 static LRESULT
3274 TOOLBAR_GetHotItem (HWND hwnd)
3276 TOOLBAR_INFO *infoPtr = TOOLBAR_GetInfoPtr (hwnd);
3278 if (!(GetWindowLongA (hwnd, GWL_STYLE) & TBSTYLE_FLAT))
3279 return -1;
3281 if (infoPtr->nHotItem < 0)
3282 return -1;
3284 return (LRESULT)infoPtr->nHotItem;
3288 static LRESULT
3289 TOOLBAR_GetDefImageList (HWND hwnd, WPARAM wParam, LPARAM lParam)
3291 return (LRESULT) GETDEFIMAGELIST(TOOLBAR_GetInfoPtr(hwnd), 0);
3295 /* << TOOLBAR_GetInsertMark >> */
3296 /* << TOOLBAR_GetInsertMarkColor >> */
3299 static LRESULT
3300 TOOLBAR_GetItemRect (HWND hwnd, WPARAM wParam, LPARAM lParam)
3302 TOOLBAR_INFO *infoPtr = TOOLBAR_GetInfoPtr (hwnd);
3303 TBUTTON_INFO *btnPtr;
3304 LPRECT lpRect;
3305 INT nIndex;
3307 if (infoPtr == NULL)
3308 return FALSE;
3309 nIndex = (INT)wParam;
3310 btnPtr = &infoPtr->buttons[nIndex];
3311 if ((nIndex < 0) || (nIndex >= infoPtr->nNumButtons))
3312 return FALSE;
3313 lpRect = (LPRECT)lParam;
3314 if (lpRect == NULL)
3315 return FALSE;
3316 if (btnPtr->fsState & TBSTATE_HIDDEN)
3317 return FALSE;
3319 lpRect->left = btnPtr->rect.left;
3320 lpRect->right = btnPtr->rect.right;
3321 lpRect->bottom = btnPtr->rect.bottom;
3322 lpRect->top = btnPtr->rect.top;
3324 return TRUE;
3328 static LRESULT
3329 TOOLBAR_GetMaxSize (HWND hwnd, WPARAM wParam, LPARAM lParam)
3331 TOOLBAR_INFO *infoPtr = TOOLBAR_GetInfoPtr (hwnd);
3332 LPSIZE lpSize = (LPSIZE)lParam;
3334 if (lpSize == NULL)
3335 return FALSE;
3337 lpSize->cx = infoPtr->rcBound.right - infoPtr->rcBound.left;
3338 lpSize->cy = infoPtr->rcBound.bottom - infoPtr->rcBound.top;
3340 TRACE("maximum size %ld x %ld\n",
3341 infoPtr->rcBound.right - infoPtr->rcBound.left,
3342 infoPtr->rcBound.bottom - infoPtr->rcBound.top);
3344 return TRUE;
3348 /* << TOOLBAR_GetObject >> */
3351 static LRESULT
3352 TOOLBAR_GetPadding (HWND hwnd)
3354 TOOLBAR_INFO *infoPtr = TOOLBAR_GetInfoPtr (hwnd);
3355 DWORD oldPad;
3357 oldPad = MAKELONG(infoPtr->szPadding.cx, infoPtr->szPadding.cy);
3358 return (LRESULT) oldPad;
3362 static LRESULT
3363 TOOLBAR_GetRect (HWND hwnd, WPARAM wParam, LPARAM lParam)
3365 TOOLBAR_INFO *infoPtr = TOOLBAR_GetInfoPtr (hwnd);
3366 TBUTTON_INFO *btnPtr;
3367 LPRECT lpRect;
3368 INT nIndex;
3370 if (infoPtr == NULL)
3371 return FALSE;
3372 nIndex = TOOLBAR_GetButtonIndex (infoPtr, (INT)wParam, FALSE);
3373 btnPtr = &infoPtr->buttons[nIndex];
3374 if ((nIndex < 0) || (nIndex >= infoPtr->nNumButtons))
3375 return FALSE;
3376 lpRect = (LPRECT)lParam;
3377 if (lpRect == NULL)
3378 return FALSE;
3380 lpRect->left = btnPtr->rect.left;
3381 lpRect->right = btnPtr->rect.right;
3382 lpRect->bottom = btnPtr->rect.bottom;
3383 lpRect->top = btnPtr->rect.top;
3385 return TRUE;
3389 static LRESULT
3390 TOOLBAR_GetRows (HWND hwnd, WPARAM wParam, LPARAM lParam)
3392 TOOLBAR_INFO *infoPtr = TOOLBAR_GetInfoPtr (hwnd);
3394 if (GetWindowLongA (hwnd, GWL_STYLE) & TBSTYLE_WRAPABLE)
3395 return infoPtr->nRows;
3396 else
3397 return 1;
3401 static LRESULT
3402 TOOLBAR_GetState (HWND hwnd, WPARAM wParam, LPARAM lParam)
3404 TOOLBAR_INFO *infoPtr = TOOLBAR_GetInfoPtr (hwnd);
3405 INT nIndex;
3407 nIndex = TOOLBAR_GetButtonIndex (infoPtr, (INT)wParam, FALSE);
3408 if (nIndex == -1)
3409 return -1;
3411 return infoPtr->buttons[nIndex].fsState;
3415 static LRESULT
3416 TOOLBAR_GetStyle (HWND hwnd, WPARAM wParam, LPARAM lParam)
3418 TOOLBAR_INFO *infoPtr = TOOLBAR_GetInfoPtr (hwnd);
3419 INT nIndex;
3421 nIndex = TOOLBAR_GetButtonIndex (infoPtr, (INT)wParam, FALSE);
3422 if (nIndex == -1)
3423 return -1;
3425 return infoPtr->buttons[nIndex].fsStyle;
3429 static LRESULT
3430 TOOLBAR_GetTextRows (HWND hwnd, WPARAM wParam, LPARAM lParam)
3432 TOOLBAR_INFO *infoPtr = TOOLBAR_GetInfoPtr (hwnd);
3434 if (infoPtr == NULL)
3435 return 0;
3437 return infoPtr->nMaxTextRows;
3441 static LRESULT
3442 TOOLBAR_GetToolTips (HWND hwnd, WPARAM wParam, LPARAM lParam)
3444 TOOLBAR_INFO *infoPtr = TOOLBAR_GetInfoPtr (hwnd);
3446 if (infoPtr == NULL)
3447 return 0;
3448 return (LRESULT)infoPtr->hwndToolTip;
3452 static LRESULT
3453 TOOLBAR_GetUnicodeFormat (HWND hwnd, WPARAM wParam, LPARAM lParam)
3455 TOOLBAR_INFO *infoPtr = TOOLBAR_GetInfoPtr (hwnd);
3457 TRACE("%s hwnd=%p stub!\n",
3458 infoPtr->bUnicode ? "TRUE" : "FALSE", hwnd);
3460 return infoPtr->bUnicode;
3464 inline static LRESULT
3465 TOOLBAR_GetVersion (HWND hwnd)
3467 TOOLBAR_INFO *infoPtr = TOOLBAR_GetInfoPtr (hwnd);
3468 return infoPtr->iVersion;
3472 static LRESULT
3473 TOOLBAR_HideButton (HWND hwnd, WPARAM wParam, LPARAM lParam)
3475 TOOLBAR_INFO *infoPtr = TOOLBAR_GetInfoPtr (hwnd);
3476 TBUTTON_INFO *btnPtr;
3477 INT nIndex;
3479 TRACE("\n");
3481 nIndex = TOOLBAR_GetButtonIndex (infoPtr, (INT)wParam, FALSE);
3482 if (nIndex == -1)
3483 return FALSE;
3485 btnPtr = &infoPtr->buttons[nIndex];
3486 if (LOWORD(lParam) == FALSE)
3487 btnPtr->fsState &= ~TBSTATE_HIDDEN;
3488 else
3489 btnPtr->fsState |= TBSTATE_HIDDEN;
3491 TOOLBAR_CalcToolbar (hwnd);
3493 InvalidateRect (hwnd, NULL, TRUE);
3495 return TRUE;
3499 inline static LRESULT
3500 TOOLBAR_HitTest (HWND hwnd, WPARAM wParam, LPARAM lParam)
3502 return TOOLBAR_InternalHitTest (hwnd, (LPPOINT)lParam);
3506 static LRESULT
3507 TOOLBAR_Indeterminate (HWND hwnd, WPARAM wParam, LPARAM lParam)
3509 TOOLBAR_INFO *infoPtr = TOOLBAR_GetInfoPtr (hwnd);
3510 TBUTTON_INFO *btnPtr;
3511 INT nIndex;
3513 nIndex = TOOLBAR_GetButtonIndex (infoPtr, (INT)wParam, FALSE);
3514 if (nIndex == -1)
3515 return FALSE;
3517 btnPtr = &infoPtr->buttons[nIndex];
3518 if (LOWORD(lParam) == FALSE)
3519 btnPtr->fsState &= ~TBSTATE_INDETERMINATE;
3520 else
3521 btnPtr->fsState |= TBSTATE_INDETERMINATE;
3523 InvalidateRect(hwnd, &btnPtr->rect, TOOLBAR_HasText(infoPtr, btnPtr));
3525 return TRUE;
3529 static LRESULT
3530 TOOLBAR_InsertButtonA (HWND hwnd, WPARAM wParam, LPARAM lParam)
3532 TOOLBAR_INFO *infoPtr = TOOLBAR_GetInfoPtr (hwnd);
3533 LPTBBUTTON lpTbb = (LPTBBUTTON)lParam;
3534 INT nIndex = (INT)wParam;
3535 TBUTTON_INFO *oldButtons;
3537 if (lpTbb == NULL)
3538 return FALSE;
3540 TOOLBAR_DumpButton(infoPtr, (TBUTTON_INFO *)lpTbb, nIndex, FALSE);
3542 if (nIndex == -1) {
3543 /* EPP: this seems to be an undocumented call (from my IE4)
3544 * I assume in that case that:
3545 * - lpTbb->iString is a string pointer (not a string index in strings[] table
3546 * - index of insertion is at the end of existing buttons
3547 * I only see this happen with nIndex == -1, but it could have a special
3548 * meaning (like -nIndex (or ~nIndex) to get the real position of insertion).
3550 nIndex = infoPtr->nNumButtons;
3552 } else if (nIndex < 0)
3553 return FALSE;
3555 /* If the string passed is not an index, assume address of string
3556 and do our own AddString */
3557 if ((HIWORD(lpTbb->iString) != 0) && (lpTbb->iString != -1)) {
3558 LPSTR ptr;
3559 INT len;
3561 TRACE("string %s passed instead of index, adding string\n",
3562 debugstr_a((LPSTR)lpTbb->iString));
3563 len = strlen((LPSTR)lpTbb->iString) + 2;
3564 ptr = Alloc(len);
3565 strcpy(ptr, (LPSTR)lpTbb->iString);
3566 ptr[len - 1] = 0; /* ended by two '\0' */
3567 lpTbb->iString = TOOLBAR_AddStringA(hwnd, 0, (LPARAM)ptr);
3568 Free(ptr);
3571 TRACE("inserting button index=%d\n", nIndex);
3572 if (nIndex > infoPtr->nNumButtons) {
3573 nIndex = infoPtr->nNumButtons;
3574 TRACE("adjust index=%d\n", nIndex);
3577 oldButtons = infoPtr->buttons;
3578 infoPtr->nNumButtons++;
3579 infoPtr->buttons = Alloc (sizeof (TBUTTON_INFO) * infoPtr->nNumButtons);
3580 /* pre insert copy */
3581 if (nIndex > 0) {
3582 memcpy (&infoPtr->buttons[0], &oldButtons[0],
3583 nIndex * sizeof(TBUTTON_INFO));
3586 /* insert new button */
3587 infoPtr->buttons[nIndex].iBitmap = lpTbb->iBitmap;
3588 infoPtr->buttons[nIndex].idCommand = lpTbb->idCommand;
3589 infoPtr->buttons[nIndex].fsState = lpTbb->fsState;
3590 infoPtr->buttons[nIndex].fsStyle = lpTbb->fsStyle;
3591 infoPtr->buttons[nIndex].dwData = lpTbb->dwData;
3592 /* if passed string and not index, then add string */
3593 if(HIWORD(lpTbb->iString) && lpTbb->iString!=-1) {
3594 Str_SetPtrAtoW ((LPWSTR *)&infoPtr->buttons[nIndex].iString, (LPCSTR )lpTbb->iString);
3596 else
3597 infoPtr->buttons[nIndex].iString = lpTbb->iString;
3599 if ((infoPtr->hwndToolTip) && !(lpTbb->fsStyle & TBSTYLE_SEP)) {
3600 TTTOOLINFOA ti;
3602 ZeroMemory (&ti, sizeof(TTTOOLINFOA));
3603 ti.cbSize = sizeof (TTTOOLINFOA);
3604 ti.hwnd = hwnd;
3605 ti.uId = lpTbb->idCommand;
3606 ti.hinst = 0;
3607 ti.lpszText = LPSTR_TEXTCALLBACKA;
3609 SendMessageA (infoPtr->hwndToolTip, TTM_ADDTOOLA,
3610 0, (LPARAM)&ti);
3613 /* post insert copy */
3614 if (nIndex < infoPtr->nNumButtons - 1) {
3615 memcpy (&infoPtr->buttons[nIndex+1], &oldButtons[nIndex],
3616 (infoPtr->nNumButtons - nIndex - 1) * sizeof(TBUTTON_INFO));
3619 Free (oldButtons);
3621 TOOLBAR_CalcToolbar (hwnd);
3623 InvalidateRect (hwnd, NULL, TRUE);
3625 return TRUE;
3629 static LRESULT
3630 TOOLBAR_InsertButtonW (HWND hwnd, WPARAM wParam, LPARAM lParam)
3632 TOOLBAR_INFO *infoPtr = TOOLBAR_GetInfoPtr (hwnd);
3633 LPTBBUTTON lpTbb = (LPTBBUTTON)lParam;
3634 INT nIndex = (INT)wParam;
3635 TBUTTON_INFO *oldButtons;
3637 if (lpTbb == NULL)
3638 return FALSE;
3640 TOOLBAR_DumpButton(infoPtr, (TBUTTON_INFO *)lpTbb, nIndex, FALSE);
3642 if (nIndex == -1) {
3643 /* EPP: this seems to be an undocumented call (from my IE4)
3644 * I assume in that case that:
3645 * - lpTbb->iString is a string pointer (not a string index in strings[] table
3646 * - index of insertion is at the end of existing buttons
3647 * I only see this happen with nIndex == -1, but it could have a special
3648 * meaning (like -nIndex (or ~nIndex) to get the real position of insertion).
3650 nIndex = infoPtr->nNumButtons;
3652 } else if (nIndex < 0)
3653 return FALSE;
3655 /* If the string passed is not an index, assume address of string
3656 and do our own AddString */
3657 if ((HIWORD(lpTbb->iString) != 0) && (lpTbb->iString != -1)) {
3658 LPWSTR ptr;
3659 INT len;
3661 TRACE("string %s passed instead of index, adding string\n",
3662 debugstr_w((LPWSTR)lpTbb->iString));
3663 len = strlenW((LPWSTR)lpTbb->iString) + 2;
3664 ptr = Alloc(len*sizeof(WCHAR));
3665 strcpyW(ptr, (LPWSTR)lpTbb->iString);
3666 ptr[len - 1] = 0; /* ended by two '\0' */
3667 lpTbb->iString = TOOLBAR_AddStringW(hwnd, 0, (LPARAM)ptr);
3668 Free(ptr);
3671 TRACE("inserting button index=%d\n", nIndex);
3672 if (nIndex > infoPtr->nNumButtons) {
3673 nIndex = infoPtr->nNumButtons;
3674 TRACE("adjust index=%d\n", nIndex);
3677 oldButtons = infoPtr->buttons;
3678 infoPtr->nNumButtons++;
3679 infoPtr->buttons = Alloc (sizeof (TBUTTON_INFO) * infoPtr->nNumButtons);
3680 /* pre insert copy */
3681 if (nIndex > 0) {
3682 memcpy (&infoPtr->buttons[0], &oldButtons[0],
3683 nIndex * sizeof(TBUTTON_INFO));
3686 /* insert new button */
3687 infoPtr->buttons[nIndex].iBitmap = lpTbb->iBitmap;
3688 infoPtr->buttons[nIndex].idCommand = lpTbb->idCommand;
3689 infoPtr->buttons[nIndex].fsState = lpTbb->fsState;
3690 infoPtr->buttons[nIndex].fsStyle = lpTbb->fsStyle;
3691 infoPtr->buttons[nIndex].dwData = lpTbb->dwData;
3692 /* if passed string and not index, then add string */
3693 if(HIWORD(lpTbb->iString) && lpTbb->iString!=-1) {
3694 Str_SetPtrW ((LPWSTR *)&infoPtr->buttons[nIndex].iString, (LPWSTR)lpTbb->iString);
3696 else
3697 infoPtr->buttons[nIndex].iString = lpTbb->iString;
3699 if ((infoPtr->hwndToolTip) && !(lpTbb->fsStyle & TBSTYLE_SEP)) {
3700 TTTOOLINFOW ti;
3702 ZeroMemory (&ti, sizeof(TTTOOLINFOW));
3703 ti.cbSize = sizeof (TTTOOLINFOW);
3704 ti.hwnd = hwnd;
3705 ti.uId = lpTbb->idCommand;
3706 ti.hinst = 0;
3707 ti.lpszText = LPSTR_TEXTCALLBACKW;
3709 SendMessageW (infoPtr->hwndToolTip, TTM_ADDTOOLW,
3710 0, (LPARAM)&ti);
3713 /* post insert copy */
3714 if (nIndex < infoPtr->nNumButtons - 1) {
3715 memcpy (&infoPtr->buttons[nIndex+1], &oldButtons[nIndex],
3716 (infoPtr->nNumButtons - nIndex - 1) * sizeof(TBUTTON_INFO));
3719 Free (oldButtons);
3721 TOOLBAR_CalcToolbar (hwnd);
3723 InvalidateRect (hwnd, NULL, TRUE);
3725 return TRUE;
3729 /* << TOOLBAR_InsertMarkHitTest >> */
3732 static LRESULT
3733 TOOLBAR_IsButtonChecked (HWND hwnd, WPARAM wParam, LPARAM lParam)
3735 TOOLBAR_INFO *infoPtr = TOOLBAR_GetInfoPtr (hwnd);
3736 INT nIndex;
3738 nIndex = TOOLBAR_GetButtonIndex (infoPtr, (INT)wParam, FALSE);
3739 if (nIndex == -1)
3740 return FALSE;
3742 return (infoPtr->buttons[nIndex].fsState & TBSTATE_CHECKED);
3746 static LRESULT
3747 TOOLBAR_IsButtonEnabled (HWND hwnd, WPARAM wParam, LPARAM lParam)
3749 TOOLBAR_INFO *infoPtr = TOOLBAR_GetInfoPtr (hwnd);
3750 INT nIndex;
3752 nIndex = TOOLBAR_GetButtonIndex (infoPtr, (INT)wParam, FALSE);
3753 if (nIndex == -1)
3754 return FALSE;
3756 return (infoPtr->buttons[nIndex].fsState & TBSTATE_ENABLED);
3760 static LRESULT
3761 TOOLBAR_IsButtonHidden (HWND hwnd, WPARAM wParam, LPARAM lParam)
3763 TOOLBAR_INFO *infoPtr = TOOLBAR_GetInfoPtr (hwnd);
3764 INT nIndex;
3766 nIndex = TOOLBAR_GetButtonIndex (infoPtr, (INT)wParam, FALSE);
3767 if (nIndex == -1)
3768 return TRUE;
3770 return (infoPtr->buttons[nIndex].fsState & TBSTATE_HIDDEN);
3774 static LRESULT
3775 TOOLBAR_IsButtonHighlighted (HWND hwnd, WPARAM wParam, LPARAM lParam)
3777 TOOLBAR_INFO *infoPtr = TOOLBAR_GetInfoPtr (hwnd);
3778 INT nIndex;
3780 nIndex = TOOLBAR_GetButtonIndex (infoPtr, (INT)wParam, FALSE);
3781 if (nIndex == -1)
3782 return FALSE;
3784 return (infoPtr->buttons[nIndex].fsState & TBSTATE_MARKED);
3788 static LRESULT
3789 TOOLBAR_IsButtonIndeterminate (HWND hwnd, WPARAM wParam, LPARAM lParam)
3791 TOOLBAR_INFO *infoPtr = TOOLBAR_GetInfoPtr (hwnd);
3792 INT nIndex;
3794 nIndex = TOOLBAR_GetButtonIndex (infoPtr, (INT)wParam, FALSE);
3795 if (nIndex == -1)
3796 return FALSE;
3798 return (infoPtr->buttons[nIndex].fsState & TBSTATE_INDETERMINATE);
3802 static LRESULT
3803 TOOLBAR_IsButtonPressed (HWND hwnd, WPARAM wParam, LPARAM lParam)
3805 TOOLBAR_INFO *infoPtr = TOOLBAR_GetInfoPtr (hwnd);
3806 INT nIndex;
3808 nIndex = TOOLBAR_GetButtonIndex (infoPtr, (INT)wParam, FALSE);
3809 if (nIndex == -1)
3810 return FALSE;
3812 return (infoPtr->buttons[nIndex].fsState & TBSTATE_PRESSED);
3816 /* << TOOLBAR_LoadImages >> */
3817 /* << TOOLBAR_MapAccelerator >> */
3818 /* << TOOLBAR_MarkButton >> */
3819 /* << TOOLBAR_MoveButton >> */
3822 static LRESULT
3823 TOOLBAR_PressButton (HWND hwnd, WPARAM wParam, LPARAM lParam)
3825 TOOLBAR_INFO *infoPtr = TOOLBAR_GetInfoPtr (hwnd);
3826 TBUTTON_INFO *btnPtr;
3827 INT nIndex;
3829 nIndex = TOOLBAR_GetButtonIndex (infoPtr, (INT)wParam, FALSE);
3830 if (nIndex == -1)
3831 return FALSE;
3833 btnPtr = &infoPtr->buttons[nIndex];
3834 if (LOWORD(lParam) == FALSE)
3835 btnPtr->fsState &= ~TBSTATE_PRESSED;
3836 else
3837 btnPtr->fsState |= TBSTATE_PRESSED;
3839 InvalidateRect(hwnd, &btnPtr->rect, TOOLBAR_HasText(infoPtr, btnPtr));
3841 return TRUE;
3844 /* FIXME: there might still be some confusion her between number of buttons
3845 * and number of bitmaps */
3846 static LRESULT
3847 TOOLBAR_ReplaceBitmap (HWND hwnd, WPARAM wParam, LPARAM lParam)
3849 TOOLBAR_INFO *infoPtr = TOOLBAR_GetInfoPtr (hwnd);
3850 LPTBREPLACEBITMAP lpReplace = (LPTBREPLACEBITMAP) lParam;
3851 HBITMAP hBitmap;
3852 int i = 0, nOldButtons = 0, pos = 0;
3853 int nOldBitmaps, nNewBitmaps;
3854 HIMAGELIST himlDef = 0;
3856 TRACE("hInstOld %p nIDOld %x hInstNew %p nIDNew %x nButtons %x\n",
3857 lpReplace->hInstOld, lpReplace->nIDOld, lpReplace->hInstNew, lpReplace->nIDNew,
3858 lpReplace->nButtons);
3860 if (lpReplace->hInstOld == HINST_COMMCTRL)
3862 FIXME("changing standard bitmaps not implemented\n");
3863 return FALSE;
3865 else if (lpReplace->hInstOld != 0)
3867 FIXME("resources not in the current module not implemented\n");
3868 return FALSE;
3870 else
3872 hBitmap = (HBITMAP) lpReplace->nIDNew;
3875 TRACE("To be replaced hInstOld %p nIDOld %x\n", lpReplace->hInstOld, lpReplace->nIDOld);
3876 for (i = 0; i < infoPtr->nNumBitmapInfos; i++) {
3877 TBITMAP_INFO *tbi = &infoPtr->bitmaps[i];
3878 TRACE("tbimapinfo %d hInstOld %p nIDOld %x\n", i, tbi->hInst, tbi->nID);
3879 if (tbi->hInst == lpReplace->hInstOld && tbi->nID == lpReplace->nIDOld)
3881 TRACE("Found: nButtons %d hInst %p nID %x\n", tbi->nButtons, tbi->hInst, tbi->nID);
3882 nOldButtons = tbi->nButtons;
3883 tbi->nButtons = lpReplace->nButtons;
3884 tbi->hInst = lpReplace->hInstNew;
3885 tbi->nID = lpReplace->nIDNew;
3886 TRACE("tbimapinfo changed %d hInstOld %p nIDOld %x\n", i, tbi->hInst, tbi->nID);
3887 break;
3889 pos += tbi->nButtons;
3892 if (nOldButtons == 0)
3894 WARN("No hinst/bitmap found! hInst %p nID %x\n", lpReplace->hInstOld, lpReplace->nIDOld);
3895 return FALSE;
3898 himlDef = GETDEFIMAGELIST(infoPtr, 0); /* fixme: correct? */
3899 nOldBitmaps = ImageList_GetImageCount(himlDef);
3901 /* ImageList_Replace(GETDEFIMAGELIST(), pos, hBitmap, NULL); */
3903 for (i = pos + nOldBitmaps - 1; i >= pos; i--)
3904 ImageList_Remove(himlDef, i);
3907 BITMAP bmp;
3908 HBITMAP hOldBitmapBitmap, hOldBitmapLoad, hbmLoad;
3909 HDC hdcImage, hdcBitmap;
3911 /* copy the bitmap before adding it so that the user's bitmap
3912 * doesn't get modified.
3914 GetObjectA (hBitmap, sizeof(BITMAP), (LPVOID)&bmp);
3916 hdcImage = CreateCompatibleDC(0);
3917 hdcBitmap = CreateCompatibleDC(0);
3919 /* create new bitmap */
3920 hbmLoad = CreateBitmap (bmp.bmWidth, bmp.bmHeight, bmp.bmPlanes, bmp.bmBitsPixel, NULL);
3921 hOldBitmapBitmap = SelectObject(hdcBitmap, hBitmap);
3922 hOldBitmapLoad = SelectObject(hdcImage, hbmLoad);
3924 /* Copy the user's image */
3925 BitBlt (hdcImage, 0, 0, bmp.bmWidth, bmp.bmHeight,
3926 hdcBitmap, 0, 0, SRCCOPY);
3928 SelectObject (hdcImage, hOldBitmapLoad);
3929 SelectObject (hdcBitmap, hOldBitmapBitmap);
3930 DeleteDC (hdcImage);
3931 DeleteDC (hdcBitmap);
3933 ImageList_AddMasked (himlDef, hbmLoad, comctl32_color.clrBtnFace);
3934 nNewBitmaps = ImageList_GetImageCount(himlDef);
3935 DeleteObject (hbmLoad);
3938 infoPtr->nNumBitmaps = infoPtr->nNumBitmaps - nOldBitmaps + nNewBitmaps;
3940 TRACE(" pos %d %d old bitmaps replaced by %d new ones.\n",
3941 pos, nOldBitmaps, nNewBitmaps);
3943 InvalidateRect(hwnd, NULL, FALSE);
3945 return TRUE;
3948 static LRESULT
3949 TOOLBAR_SaveRestoreA (HWND hwnd, WPARAM wParam, LPARAM lParam)
3951 #if 0
3952 TOOLBAR_INFO *infoPtr = TOOLBAR_GetInfoPtr (hwnd);
3953 LPTBSAVEPARAMSA lpSave = (LPTBSAVEPARAMSA)lParam;
3955 if (lpSave == NULL) return 0;
3957 if ((BOOL)wParam) {
3958 /* save toolbar information */
3959 FIXME("save to \"%s\" \"%s\"\n",
3960 lpSave->pszSubKey, lpSave->pszValueName);
3964 else {
3965 /* restore toolbar information */
3967 FIXME("restore from \"%s\" \"%s\"\n",
3968 lpSave->pszSubKey, lpSave->pszValueName);
3972 #endif
3974 return 0;
3978 static LRESULT
3979 TOOLBAR_SaveRestoreW (HWND hwnd, WPARAM wParam, LPARAM lParam)
3981 #if 0
3982 TOOLBAR_INFO *infoPtr = TOOLBAR_GetInfoPtr (hwnd);
3983 LPTBSAVEPARAMSW lpSave = (LPTBSAVEPARAMSW)lParam;
3985 if (lpSave == NULL)
3986 return 0;
3988 if ((BOOL)wParam) {
3989 /* save toolbar information */
3990 FIXME("save to \"%s\" \"%s\"\n",
3991 lpSave->pszSubKey, lpSave->pszValueName);
3995 else {
3996 /* restore toolbar information */
3998 FIXME("restore from \"%s\" \"%s\"\n",
3999 lpSave->pszSubKey, lpSave->pszValueName);
4003 #endif
4005 return 0;
4009 static LRESULT
4010 TOOLBAR_SetAnchorHighlight (HWND hwnd, WPARAM wParam)
4012 TOOLBAR_INFO *infoPtr = TOOLBAR_GetInfoPtr (hwnd);
4013 BOOL bOldAnchor = infoPtr->bAnchor;
4015 infoPtr->bAnchor = (BOOL)wParam;
4017 return (LRESULT)bOldAnchor;
4021 static LRESULT
4022 TOOLBAR_SetBitmapSize (HWND hwnd, WPARAM wParam, LPARAM lParam)
4024 TOOLBAR_INFO *infoPtr = TOOLBAR_GetInfoPtr (hwnd);
4025 HIMAGELIST himlDef = GETDEFIMAGELIST(infoPtr, 0);
4027 if ((LOWORD(lParam) <= 0) || (HIWORD(lParam)<=0))
4028 return FALSE;
4030 if (infoPtr->nNumButtons > 0)
4031 WARN("%d buttons, undoc increase to bitmap size : %d-%d -> %d-%d\n",
4032 infoPtr->nNumButtons,
4033 infoPtr->nBitmapWidth, infoPtr->nBitmapHeight,
4034 LOWORD(lParam), HIWORD(lParam));
4036 infoPtr->nBitmapWidth = (INT)LOWORD(lParam);
4037 infoPtr->nBitmapHeight = (INT)HIWORD(lParam);
4040 /* uses image list internals directly */
4041 if (himlDef) {
4042 himlDef->cx = infoPtr->nBitmapWidth;
4043 himlDef->cy = infoPtr->nBitmapHeight;
4046 return TRUE;
4050 static LRESULT
4051 TOOLBAR_SetButtonInfoA (HWND hwnd, WPARAM wParam, LPARAM lParam)
4053 TOOLBAR_INFO *infoPtr = TOOLBAR_GetInfoPtr (hwnd);
4054 LPTBBUTTONINFOA lptbbi = (LPTBBUTTONINFOA)lParam;
4055 TBUTTON_INFO *btnPtr;
4056 INT nIndex;
4058 if (lptbbi == NULL)
4059 return FALSE;
4060 if (lptbbi->cbSize < sizeof(TBBUTTONINFOA))
4061 return FALSE;
4063 nIndex = TOOLBAR_GetButtonIndex (infoPtr, (INT)wParam,
4064 lptbbi->dwMask & 0x80000000);
4065 if (nIndex == -1)
4066 return FALSE;
4068 btnPtr = &infoPtr->buttons[nIndex];
4069 if (lptbbi->dwMask & TBIF_COMMAND)
4070 btnPtr->idCommand = lptbbi->idCommand;
4071 if (lptbbi->dwMask & TBIF_IMAGE)
4072 btnPtr->iBitmap = lptbbi->iImage;
4073 if (lptbbi->dwMask & TBIF_LPARAM)
4074 btnPtr->dwData = lptbbi->lParam;
4075 /* if (lptbbi->dwMask & TBIF_SIZE) */
4076 /* btnPtr->cx = lptbbi->cx; */
4077 if (lptbbi->dwMask & TBIF_STATE)
4078 btnPtr->fsState = lptbbi->fsState;
4079 if (lptbbi->dwMask & TBIF_STYLE)
4080 btnPtr->fsStyle = lptbbi->fsStyle;
4082 if ((lptbbi->dwMask & TBIF_TEXT) && ((INT)lptbbi->pszText != -1)) {
4083 if ((HIWORD(btnPtr->iString) == 0) || (btnPtr->iString == -1))
4084 /* iString is index, zero it to make Str_SetPtr succeed */
4085 btnPtr->iString=0;
4087 Str_SetPtrAtoW ((LPWSTR *)&btnPtr->iString, lptbbi->pszText);
4089 return TRUE;
4093 static LRESULT
4094 TOOLBAR_SetButtonInfoW (HWND hwnd, WPARAM wParam, LPARAM lParam)
4096 TOOLBAR_INFO *infoPtr = TOOLBAR_GetInfoPtr (hwnd);
4097 LPTBBUTTONINFOW lptbbi = (LPTBBUTTONINFOW)lParam;
4098 TBUTTON_INFO *btnPtr;
4099 INT nIndex;
4101 if (lptbbi == NULL)
4102 return FALSE;
4103 if (lptbbi->cbSize < sizeof(TBBUTTONINFOW))
4104 return FALSE;
4106 nIndex = TOOLBAR_GetButtonIndex (infoPtr, (INT)wParam,
4107 lptbbi->dwMask & 0x80000000);
4108 if (nIndex == -1)
4109 return FALSE;
4111 btnPtr = &infoPtr->buttons[nIndex];
4112 if (lptbbi->dwMask & TBIF_COMMAND)
4113 btnPtr->idCommand = lptbbi->idCommand;
4114 if (lptbbi->dwMask & TBIF_IMAGE)
4115 btnPtr->iBitmap = lptbbi->iImage;
4116 if (lptbbi->dwMask & TBIF_LPARAM)
4117 btnPtr->dwData = lptbbi->lParam;
4118 /* if (lptbbi->dwMask & TBIF_SIZE) */
4119 /* btnPtr->cx = lptbbi->cx; */
4120 if (lptbbi->dwMask & TBIF_STATE)
4121 btnPtr->fsState = lptbbi->fsState;
4122 if (lptbbi->dwMask & TBIF_STYLE)
4123 btnPtr->fsStyle = lptbbi->fsStyle;
4125 if ((lptbbi->dwMask & TBIF_TEXT) && ((INT)lptbbi->pszText != -1)) {
4126 if ((HIWORD(btnPtr->iString) == 0) || (btnPtr->iString == -1))
4127 /* iString is index, zero it to make Str_SetPtr succeed */
4128 btnPtr->iString=0;
4129 Str_SetPtrW ((LPWSTR *)&btnPtr->iString, lptbbi->pszText);
4131 return TRUE;
4135 static LRESULT
4136 TOOLBAR_SetButtonSize (HWND hwnd, WPARAM wParam, LPARAM lParam)
4138 TOOLBAR_INFO *infoPtr = TOOLBAR_GetInfoPtr (hwnd);
4139 INT cx = LOWORD(lParam), cy = HIWORD(lParam);
4141 if ((cx < 0) || (cy < 0))
4143 ERR("invalid parameter 0x%08lx\n", (DWORD)lParam);
4144 return FALSE;
4147 /* The documentation claims you can only change the button size before
4148 * any button has been added. But this is wrong.
4149 * WINZIP32.EXE (ver 8) calls this on one of its buttons after adding
4150 * it to the toolbar, and it checks that the return value is nonzero - mjm
4151 * Further testing shows that we must actually perform the change too.
4154 * The documentation also does not mention that if 0 is supplied for
4155 * either size, the system changes it to the default of 24 wide and
4156 * 22 high. Demonstarted in ControlSpy Toolbar. GLA 3/02
4158 infoPtr->nButtonWidth = (cx) ? cx : 24;
4159 infoPtr->nButtonHeight = (cy) ? cy : 22;
4160 return TRUE;
4164 static LRESULT
4165 TOOLBAR_SetButtonWidth (HWND hwnd, WPARAM wParam, LPARAM lParam)
4167 TOOLBAR_INFO *infoPtr = TOOLBAR_GetInfoPtr (hwnd);
4169 if (infoPtr == NULL) {
4170 TRACE("Toolbar not initialized yet?????\n");
4171 return FALSE;
4174 /* if setting to current values, ignore */
4175 if ((infoPtr->cxMin == (INT)LOWORD(lParam)) &&
4176 (infoPtr->cxMax == (INT)HIWORD(lParam))) {
4177 TRACE("matches current width, min=%d, max=%d, no recalc\n",
4178 infoPtr->cxMin, infoPtr->cxMax);
4179 return TRUE;
4182 /* save new values */
4183 infoPtr->cxMin = (INT)LOWORD(lParam);
4184 infoPtr->cxMax = (INT)HIWORD(lParam);
4186 /* if both values are 0 then we are done */
4187 if (lParam == 0) {
4188 TRACE("setting both min and max to 0, norecalc\n");
4189 return TRUE;
4192 /* otherwise we need to recalc the toolbar and in some cases
4193 recalc the bounding rectangle (does DrawText w/ DT_CALCRECT
4194 which doesn't actually draw - GA). */
4195 TRACE("number of buttons %d, cx=%d, cy=%d, recalcing\n",
4196 infoPtr->nNumButtons, infoPtr->cxMin, infoPtr->cxMax);
4198 TOOLBAR_CalcToolbar (hwnd);
4200 InvalidateRect (hwnd, NULL, TRUE);
4202 return TRUE;
4206 static LRESULT
4207 TOOLBAR_SetCmdId (HWND hwnd, WPARAM wParam, LPARAM lParam)
4209 TOOLBAR_INFO *infoPtr = TOOLBAR_GetInfoPtr (hwnd);
4210 INT nIndex = (INT)wParam;
4212 if ((nIndex < 0) || (nIndex >= infoPtr->nNumButtons))
4213 return FALSE;
4215 infoPtr->buttons[nIndex].idCommand = (INT)lParam;
4217 if (infoPtr->hwndToolTip) {
4219 FIXME("change tool tip!\n");
4223 return TRUE;
4227 static LRESULT
4228 TOOLBAR_SetDisabledImageList (HWND hwnd, WPARAM wParam, LPARAM lParam)
4230 TOOLBAR_INFO *infoPtr = TOOLBAR_GetInfoPtr (hwnd);
4231 HIMAGELIST himl = (HIMAGELIST)lParam;
4232 HIMAGELIST himlTemp;
4233 INT id = 0;
4235 if (infoPtr->iVersion >= 5)
4236 id = wParam;
4238 himlTemp = TOOLBAR_InsertImageList(&infoPtr->himlDis,
4239 &infoPtr->cimlDis, himl, id);
4241 /* FIXME: redraw ? */
4243 return (LRESULT)himlTemp;
4247 static LRESULT
4248 TOOLBAR_SetDrawTextFlags (HWND hwnd, WPARAM wParam, LPARAM lParam)
4250 TOOLBAR_INFO *infoPtr = TOOLBAR_GetInfoPtr (hwnd);
4251 DWORD dwTemp;
4253 dwTemp = infoPtr->dwDTFlags;
4254 infoPtr->dwDTFlags =
4255 (infoPtr->dwDTFlags & (DWORD)wParam) | (DWORD)lParam;
4257 return (LRESULT)dwTemp;
4260 static LRESULT
4261 TOOLBAR_SetExtendedStyle (HWND hwnd, WPARAM wParam, LPARAM lParam)
4263 TOOLBAR_INFO *infoPtr = TOOLBAR_GetInfoPtr (hwnd);
4264 DWORD dwTemp;
4266 dwTemp = infoPtr->dwExStyle;
4267 infoPtr->dwExStyle |= (DWORD)lParam;
4269 TRACE("new style 0x%08lx\n", infoPtr->dwExStyle);
4271 if (infoPtr->dwExStyle & ~TBSTYLE_EX_ALL)
4272 FIXME("Unknown Toolbar Extended Style 0x%08lx. Please report.\n",
4273 (infoPtr->dwExStyle & ~TBSTYLE_EX_ALL));
4275 TOOLBAR_CalcToolbar (hwnd);
4277 TOOLBAR_AutoSize(hwnd);
4279 InvalidateRect(hwnd, NULL, FALSE);
4281 return (LRESULT)dwTemp;
4285 static LRESULT
4286 TOOLBAR_SetHotImageList (HWND hwnd, WPARAM wParam, LPARAM lParam)
4288 TOOLBAR_INFO *infoPtr = TOOLBAR_GetInfoPtr(hwnd);
4289 HIMAGELIST himlTemp;
4290 HIMAGELIST himl = (HIMAGELIST)lParam;
4291 INT id = 0;
4293 if (infoPtr->iVersion >= 5)
4294 id = wParam;
4296 TRACE("hwnd = %p, himl = %p, id = %d\n", hwnd, himl, id);
4298 himlTemp = TOOLBAR_InsertImageList(&infoPtr->himlHot,
4299 &infoPtr->cimlHot, himl, id);
4301 /* FIXME: redraw ? */
4303 return (LRESULT)himlTemp;
4307 static LRESULT
4308 TOOLBAR_SetHotItem (HWND hwnd, WPARAM wParam)
4310 TOOLBAR_INFO *infoPtr = TOOLBAR_GetInfoPtr(hwnd);
4311 INT nOldHotItem = infoPtr->nHotItem;
4312 TBUTTON_INFO *btnPtr;
4314 if ((INT) wParam < 0 || (INT)wParam > infoPtr->nNumButtons)
4315 wParam = -2;
4317 if (GetWindowLongA (hwnd, GWL_STYLE) & TBSTYLE_FLAT)
4320 infoPtr->nHotItem = (INT)wParam;
4321 if ((INT)wParam >=0)
4323 btnPtr = &infoPtr->buttons[(INT)wParam];
4324 btnPtr->bHot = TRUE;
4325 InvalidateRect (hwnd, &btnPtr->rect,
4326 TOOLBAR_HasText(infoPtr, btnPtr));
4328 if (nOldHotItem>=0)
4330 btnPtr = &infoPtr->buttons[nOldHotItem];
4331 btnPtr->bHot = FALSE;
4332 InvalidateRect (hwnd, &btnPtr->rect,
4333 TOOLBAR_HasText(infoPtr, btnPtr));
4337 if (nOldHotItem < 0)
4338 return -1;
4340 return (LRESULT)nOldHotItem;
4344 static LRESULT
4345 TOOLBAR_SetImageList (HWND hwnd, WPARAM wParam, LPARAM lParam)
4347 TOOLBAR_INFO *infoPtr = TOOLBAR_GetInfoPtr (hwnd);
4348 HIMAGELIST himlTemp;
4349 HIMAGELIST himl = (HIMAGELIST)lParam;
4350 INT i, id = 0;
4352 if (infoPtr->iVersion >= 5)
4353 id = wParam;
4355 himlTemp = TOOLBAR_InsertImageList(&infoPtr->himlDef,
4356 &infoPtr->cimlDef, himl, id);
4358 infoPtr->nNumBitmaps = 0;
4359 for (i = 0; i < infoPtr->cimlDef; i++)
4360 infoPtr->nNumBitmaps += ImageList_GetImageCount(infoPtr->himlDef[i]->himl);
4362 ImageList_GetIconSize(himl, &infoPtr->nBitmapWidth,
4363 &infoPtr->nBitmapHeight);
4364 TRACE("hwnd %p, new himl=%08x, count=%d, bitmap w=%d, h=%d\n",
4365 hwnd, (INT)infoPtr->himlDef, infoPtr->nNumBitmaps,
4366 infoPtr->nBitmapWidth, infoPtr->nBitmapHeight);
4368 /* FIXME: redraw ? */
4369 InvalidateRect(hwnd, NULL, TRUE);
4371 return (LRESULT)himlTemp;
4375 static LRESULT
4376 TOOLBAR_SetIndent (HWND hwnd, WPARAM wParam, LPARAM lParam)
4378 TOOLBAR_INFO *infoPtr = TOOLBAR_GetInfoPtr (hwnd);
4380 infoPtr->nIndent = (INT)wParam;
4382 TRACE("\n");
4384 /* process only on indent changing */
4385 if(infoPtr->nIndent != (INT)wParam)
4387 infoPtr->nIndent = (INT)wParam;
4388 TOOLBAR_CalcToolbar (hwnd);
4389 InvalidateRect(hwnd, NULL, FALSE);
4392 return TRUE;
4396 /* << TOOLBAR_SetInsertMark >> */
4399 static LRESULT
4400 TOOLBAR_SetInsertMarkColor (HWND hwnd, WPARAM wParam, LPARAM lParam)
4402 TOOLBAR_INFO *infoPtr = TOOLBAR_GetInfoPtr (hwnd);
4404 infoPtr->clrInsertMark = (COLORREF)lParam;
4406 /* FIXME : redraw ??*/
4408 return 0;
4412 static LRESULT
4413 TOOLBAR_SetMaxTextRows (HWND hwnd, WPARAM wParam, LPARAM lParam)
4415 TOOLBAR_INFO *infoPtr = TOOLBAR_GetInfoPtr (hwnd);
4417 if (infoPtr == NULL)
4418 return FALSE;
4420 infoPtr->nMaxTextRows = (INT)wParam;
4422 return TRUE;
4426 static LRESULT
4427 TOOLBAR_SetPadding (HWND hwnd, WPARAM wParam, LPARAM lParam)
4429 TOOLBAR_INFO *infoPtr = TOOLBAR_GetInfoPtr (hwnd);
4430 DWORD oldPad;
4432 oldPad = MAKELONG(infoPtr->szPadding.cx, infoPtr->szPadding.cy);
4433 infoPtr->szPadding.cx = LOWORD((DWORD)lParam);
4434 infoPtr->szPadding.cy = HIWORD((DWORD)lParam);
4435 FIXME("stub - nothing done with values, cx=%ld, cy=%ld\n",
4436 infoPtr->szPadding.cx, infoPtr->szPadding.cy);
4437 return (LRESULT) oldPad;
4441 static LRESULT
4442 TOOLBAR_SetParent (HWND hwnd, WPARAM wParam, LPARAM lParam)
4444 TOOLBAR_INFO *infoPtr = TOOLBAR_GetInfoPtr (hwnd);
4445 HWND hwndOldNotify;
4447 TRACE("\n");
4449 if (infoPtr == NULL)
4450 return 0;
4451 hwndOldNotify = infoPtr->hwndNotify;
4452 infoPtr->hwndNotify = (HWND)wParam;
4454 return (LRESULT)hwndOldNotify;
4458 static LRESULT
4459 TOOLBAR_SetRows (HWND hwnd, WPARAM wParam, LPARAM lParam)
4461 TOOLBAR_INFO *infoPtr = TOOLBAR_GetInfoPtr (hwnd);
4462 LPRECT lprc = (LPRECT)lParam;
4464 TRACE("\n");
4466 if (LOWORD(wParam) > 1) {
4467 FIXME("multiple rows not supported!\n");
4470 if(infoPtr->nRows != LOWORD(wParam))
4472 infoPtr->nRows = LOWORD(wParam);
4474 /* recalculate toolbar */
4475 TOOLBAR_CalcToolbar (hwnd);
4477 /* repaint toolbar */
4478 InvalidateRect(hwnd, NULL, FALSE);
4481 /* return bounding rectangle */
4482 if (lprc) {
4483 lprc->left = infoPtr->rcBound.left;
4484 lprc->right = infoPtr->rcBound.right;
4485 lprc->top = infoPtr->rcBound.top;
4486 lprc->bottom = infoPtr->rcBound.bottom;
4489 return 0;
4493 static LRESULT
4494 TOOLBAR_SetState (HWND hwnd, WPARAM wParam, LPARAM lParam)
4496 TOOLBAR_INFO *infoPtr = TOOLBAR_GetInfoPtr (hwnd);
4497 TBUTTON_INFO *btnPtr;
4498 INT nIndex;
4500 nIndex = TOOLBAR_GetButtonIndex (infoPtr, (INT)wParam, FALSE);
4501 if (nIndex == -1)
4502 return FALSE;
4504 btnPtr = &infoPtr->buttons[nIndex];
4506 /* if hidden state has changed the invalidate entire window and recalc */
4507 if ((btnPtr->fsState & TBSTATE_HIDDEN) != (LOWORD(lParam) & TBSTATE_HIDDEN)) {
4508 btnPtr->fsState = LOWORD(lParam);
4509 TOOLBAR_CalcToolbar (hwnd);
4510 InvalidateRect(hwnd, 0, TOOLBAR_HasText(infoPtr, btnPtr));
4511 return TRUE;
4514 /* process state changing if current state doesn't match new state */
4515 if(btnPtr->fsState != LOWORD(lParam))
4517 btnPtr->fsState = LOWORD(lParam);
4518 InvalidateRect(hwnd, &btnPtr->rect, TOOLBAR_HasText(infoPtr,
4519 btnPtr));
4522 return TRUE;
4526 static LRESULT
4527 TOOLBAR_SetStyle (HWND hwnd, WPARAM wParam, LPARAM lParam)
4529 SetWindowLongW(hwnd, GWL_STYLE, lParam);
4531 return TRUE;
4535 inline static LRESULT
4536 TOOLBAR_SetToolTips (HWND hwnd, WPARAM wParam, LPARAM lParam)
4538 TOOLBAR_INFO *infoPtr = TOOLBAR_GetInfoPtr (hwnd);
4540 if (infoPtr == NULL)
4541 return 0;
4542 infoPtr->hwndToolTip = (HWND)wParam;
4543 return 0;
4547 static LRESULT
4548 TOOLBAR_SetUnicodeFormat (HWND hwnd, WPARAM wParam, LPARAM lParam)
4550 TOOLBAR_INFO *infoPtr = TOOLBAR_GetInfoPtr (hwnd);
4551 BOOL bTemp;
4553 TRACE("%s hwnd=%p stub!\n",
4554 ((BOOL)wParam) ? "TRUE" : "FALSE", hwnd);
4556 bTemp = infoPtr->bUnicode;
4557 infoPtr->bUnicode = (BOOL)wParam;
4559 return bTemp;
4563 static LRESULT
4564 TOOLBAR_GetColorScheme (HWND hwnd, LPCOLORSCHEME lParam)
4566 TOOLBAR_INFO *infoPtr = TOOLBAR_GetInfoPtr (hwnd);
4568 lParam->clrBtnHighlight = (infoPtr->clrBtnHighlight == CLR_DEFAULT) ?
4569 comctl32_color.clrBtnHighlight :
4570 infoPtr->clrBtnHighlight;
4571 lParam->clrBtnShadow = (infoPtr->clrBtnShadow == CLR_DEFAULT) ?
4572 comctl32_color.clrBtnShadow : infoPtr->clrBtnShadow;
4573 return 1;
4577 static LRESULT
4578 TOOLBAR_SetColorScheme (HWND hwnd, LPCOLORSCHEME lParam)
4580 TOOLBAR_INFO *infoPtr = TOOLBAR_GetInfoPtr (hwnd);
4582 TRACE("new colors Hl=%lx Shd=%lx, old colors Hl=%lx Shd=%lx\n",
4583 lParam->clrBtnHighlight, lParam->clrBtnShadow,
4584 infoPtr->clrBtnHighlight, infoPtr->clrBtnShadow);
4586 infoPtr->clrBtnHighlight = lParam->clrBtnHighlight;
4587 infoPtr->clrBtnShadow = lParam->clrBtnShadow;
4588 InvalidateRect(hwnd, 0, 0);
4589 return 0;
4593 static LRESULT
4594 TOOLBAR_SetVersion (HWND hwnd, INT iVersion)
4596 TOOLBAR_INFO *infoPtr = TOOLBAR_GetInfoPtr (hwnd);
4597 INT iOldVersion = infoPtr->iVersion;
4599 infoPtr->iVersion = iVersion;
4601 if (infoPtr->iVersion >= 5)
4602 TOOLBAR_SetUnicodeFormat(hwnd, (WPARAM)TRUE, (LPARAM)0);
4604 return iOldVersion;
4608 /*********************************************************************/
4609 /* */
4610 /* This is undocumented and appears to be a "Super" TB_SETHOTITEM */
4611 /* without the restriction of TBSTYLE_FLAT. This implementation is */
4612 /* based on relay traces of the native control and IE 5.5 */
4613 /* */
4614 /*********************************************************************/
4615 static LRESULT
4616 TOOLBAR_Unkwn45E (HWND hwnd, WPARAM wParam, LPARAM lParam)
4618 TOOLBAR_INFO *infoPtr = TOOLBAR_GetInfoPtr(hwnd);
4619 INT nOldHotItem = infoPtr->nHotItem;
4620 TBUTTON_INFO *btnPtr;
4621 INT no_hi = 0;
4622 NMTBHOTITEM nmhotitem;
4624 if ((INT) wParam < 0 || (INT)wParam > infoPtr->nNumButtons)
4625 wParam = -2;
4627 infoPtr->nHotItem = (INT)wParam;
4628 if (nOldHotItem != infoPtr->nHotItem) {
4629 nmhotitem.dwFlags = (DWORD)lParam;
4630 if ( !(nmhotitem.dwFlags & HICF_ENTERING) )
4631 nmhotitem.idOld = (nOldHotItem >= 0) ?
4632 infoPtr->buttons[nOldHotItem].idCommand : 0;
4633 if ( !(nmhotitem.dwFlags & HICF_LEAVING) )
4634 nmhotitem.idNew = (infoPtr->nHotItem >= 0) ?
4635 infoPtr->buttons[infoPtr->nHotItem].idCommand : 0;
4636 no_hi = TOOLBAR_SendNotify((NMHDR*)&nmhotitem, infoPtr, TBN_HOTITEMCHANGE);
4638 if ((INT)wParam >=0) {
4639 btnPtr = &infoPtr->buttons[(INT)wParam];
4640 btnPtr->bHot = (no_hi) ? FALSE : TRUE;
4641 InvalidateRect (hwnd, &btnPtr->rect,
4642 TOOLBAR_HasText(infoPtr, btnPtr));
4644 if (nOldHotItem>=0) {
4645 btnPtr = &infoPtr->buttons[nOldHotItem];
4646 btnPtr->bHot = FALSE;
4647 InvalidateRect (hwnd, &btnPtr->rect,
4648 TOOLBAR_HasText(infoPtr, btnPtr));
4650 GetFocus();
4651 TRACE("old item=%d, new item=%d, flags=%08lx, notify=%d\n",
4652 nOldHotItem, infoPtr->nHotItem, (DWORD)lParam, no_hi);
4654 if (nOldHotItem < 0)
4655 return -1;
4657 return (LRESULT)nOldHotItem;
4661 static LRESULT
4662 TOOLBAR_Unkwn463 (HWND hwnd, WPARAM wParam, LPARAM lParam)
4664 TOOLBAR_INFO *infoPtr = TOOLBAR_GetInfoPtr (hwnd);
4665 LPSIZE lpsize = (LPSIZE)lParam;
4667 if (lpsize == NULL)
4668 return FALSE;
4671 * Testing shows the following:
4672 * wParam = 0 adjust cx value
4673 * = 1 set cy value to max size.
4674 * lParam pointer to SIZE structure
4677 TRACE("[0463] wParam %d, lParam 0x%08lx -> 0x%08lx 0x%08lx\n",
4678 wParam, lParam, lpsize->cx, lpsize->cy);
4680 switch(wParam) {
4681 case 0:
4682 if (lpsize->cx == -1) {
4683 /* **** this is wrong, native measures each button and sets it */
4684 lpsize->cx = infoPtr->rcBound.right - infoPtr->rcBound.left;
4686 else if(HIWORD(lpsize->cx)) {
4687 RECT rc;
4688 HWND hwndParent = GetParent(hwnd);
4690 InvalidateRect(hwnd, 0, 1);
4691 GetWindowRect(hwnd, &rc);
4692 MapWindowPoints(0, hwndParent, (LPPOINT)&rc, 2);
4693 TRACE("mapped to (%ld,%ld)-(%ld,%ld)\n",
4694 rc.left, rc.top, rc.right, rc.bottom);
4695 lpsize->cx = max(rc.right-rc.left,
4696 infoPtr->rcBound.right - infoPtr->rcBound.left);
4698 else {
4699 lpsize->cx = infoPtr->rcBound.right - infoPtr->rcBound.left;
4701 break;
4702 case 1:
4703 lpsize->cy = infoPtr->rcBound.bottom - infoPtr->rcBound.top;
4704 /* lpsize->cy = infoPtr->nHeight; */
4705 break;
4706 default:
4707 ERR("Unknown wParam %d for Toolbar message [0463]. Please report\n",
4708 wParam);
4709 return 0;
4711 TRACE("[0463] set to -> 0x%08lx 0x%08lx\n",
4712 lpsize->cx, lpsize->cy);
4713 return 1;
4717 static LRESULT
4718 TOOLBAR_Create (HWND hwnd, WPARAM wParam, LPARAM lParam)
4720 TOOLBAR_INFO *infoPtr = TOOLBAR_GetInfoPtr (hwnd);
4721 DWORD dwStyle = GetWindowLongA (hwnd, GWL_STYLE);
4722 LOGFONTA logFont;
4724 /* initialize info structure */
4725 infoPtr->nButtonHeight = 22;
4726 infoPtr->nButtonWidth = 24;
4727 infoPtr->nBitmapHeight = 15;
4728 infoPtr->nBitmapWidth = 16;
4730 infoPtr->nHeight = infoPtr->nButtonHeight + TOP_BORDER + BOTTOM_BORDER;
4731 infoPtr->nMaxTextRows = 1;
4732 infoPtr->cxMin = -1;
4733 infoPtr->cxMax = -1;
4734 infoPtr->nNumBitmaps = 0;
4735 infoPtr->nNumStrings = 0;
4737 infoPtr->bCaptured = FALSE;
4738 infoPtr->bUnicode = IsWindowUnicode (hwnd);
4739 infoPtr->nButtonDown = -1;
4740 infoPtr->nOldHit = -1;
4741 infoPtr->nHotItem = -2; /* It has to be initially different from nOldHit */
4742 infoPtr->hwndNotify = ((LPCREATESTRUCTW)lParam)->hwndParent;
4743 infoPtr->bTransparent = (dwStyle & TBSTYLE_TRANSPARENT);
4744 infoPtr->bBtnTranspnt = (dwStyle & (TBSTYLE_FLAT | TBSTYLE_LIST));
4745 infoPtr->dwDTFlags = (dwStyle & TBSTYLE_LIST) ? DT_LEFT | DT_VCENTER | DT_SINGLELINE : DT_CENTER;
4746 infoPtr->bAnchor = FALSE; /* no anchor highlighting */
4747 infoPtr->iVersion = 0;
4748 infoPtr->hwndSelf = hwnd;
4749 infoPtr->bDoRedraw = TRUE;
4750 infoPtr->clrBtnHighlight = CLR_DEFAULT;
4751 infoPtr->clrBtnShadow = CLR_DEFAULT;
4752 infoPtr->szPadding.cx = 7;
4753 infoPtr->szPadding.cy = 6;
4754 TOOLBAR_NotifyFormat(infoPtr, (WPARAM)hwnd, (LPARAM)NF_REQUERY);
4756 SystemParametersInfoA (SPI_GETICONTITLELOGFONT, 0, &logFont, 0);
4757 infoPtr->hFont = infoPtr->hDefaultFont = CreateFontIndirectA (&logFont);
4759 if (dwStyle & TBSTYLE_TOOLTIPS) {
4760 /* Create tooltip control */
4761 infoPtr->hwndToolTip =
4762 CreateWindowExA (0, TOOLTIPS_CLASSA, NULL, 0,
4763 CW_USEDEFAULT, CW_USEDEFAULT,
4764 CW_USEDEFAULT, CW_USEDEFAULT,
4765 hwnd, 0, 0, 0);
4767 /* Send NM_TOOLTIPSCREATED notification */
4768 if (infoPtr->hwndToolTip) {
4769 NMTOOLTIPSCREATED nmttc;
4771 nmttc.hwndToolTips = infoPtr->hwndToolTip;
4773 TOOLBAR_SendNotify ((NMHDR *) &nmttc, infoPtr,
4774 NM_TOOLTIPSCREATED);
4778 TOOLBAR_CheckStyle (hwnd, dwStyle);
4780 TOOLBAR_CalcToolbar(hwnd);
4782 return 0;
4786 static LRESULT
4787 TOOLBAR_Destroy (HWND hwnd, WPARAM wParam, LPARAM lParam)
4789 TOOLBAR_INFO *infoPtr = TOOLBAR_GetInfoPtr (hwnd);
4791 /* delete tooltip control */
4792 if (infoPtr->hwndToolTip)
4793 DestroyWindow (infoPtr->hwndToolTip);
4795 /* delete button data */
4796 if (infoPtr->buttons)
4797 Free (infoPtr->buttons);
4799 /* delete strings */
4800 if (infoPtr->strings) {
4801 INT i;
4802 for (i = 0; i < infoPtr->nNumStrings; i++)
4803 if (infoPtr->strings[i])
4804 Free (infoPtr->strings[i]);
4806 Free (infoPtr->strings);
4809 /* destroy internal image list */
4810 if (infoPtr->himlInt)
4811 ImageList_Destroy (infoPtr->himlInt);
4813 TOOLBAR_DeleteImageList(&infoPtr->himlDef, &infoPtr->cimlDef);
4814 TOOLBAR_DeleteImageList(&infoPtr->himlDis, &infoPtr->cimlDis);
4815 TOOLBAR_DeleteImageList(&infoPtr->himlHot, &infoPtr->cimlHot);
4817 /* delete default font */
4818 if (infoPtr->hFont)
4819 DeleteObject (infoPtr->hDefaultFont);
4821 /* free toolbar info data */
4822 Free (infoPtr);
4823 SetWindowLongA (hwnd, 0, 0);
4825 return 0;
4829 static LRESULT
4830 TOOLBAR_EraseBackground (HWND hwnd, WPARAM wParam, LPARAM lParam)
4832 TOOLBAR_INFO *infoPtr = TOOLBAR_GetInfoPtr (hwnd);
4833 DWORD dwStyle = GetWindowLongA (hwnd, GWL_STYLE);
4834 NMTBCUSTOMDRAW tbcd;
4835 INT ret = FALSE;
4836 DWORD ntfret;
4838 if (dwStyle & TBSTYLE_CUSTOMERASE) {
4839 ZeroMemory (&tbcd, sizeof(NMTBCUSTOMDRAW));
4840 tbcd.nmcd.dwDrawStage = CDDS_PREERASE;
4841 tbcd.nmcd.hdc = (HDC)wParam;
4842 ntfret = TOOLBAR_SendNotify ((NMHDR *)&tbcd, infoPtr, NM_CUSTOMDRAW);
4843 infoPtr->dwBaseCustDraw = ntfret & 0xffff;
4845 /* FIXME: in general the return flags *can* be or'ed together */
4846 switch (infoPtr->dwBaseCustDraw)
4848 case CDRF_DODEFAULT:
4849 break;
4850 case CDRF_SKIPDEFAULT:
4851 return TRUE;
4852 default:
4853 FIXME("[%p] response %ld not handled to NM_CUSTOMDRAW (CDDS_PREERASE)\n",
4854 hwnd, ntfret);
4858 /* If the toolbar is "transparent" then pass the WM_ERASEBKGND up
4859 * to my parent for processing.
4861 if (infoPtr->bTransparent) {
4862 POINT pt, ptorig;
4863 HDC hdc = (HDC)wParam;
4864 HWND parent;
4866 pt.x = 0;
4867 pt.y = 0;
4868 parent = GetParent(hwnd);
4869 MapWindowPoints(hwnd, parent, &pt, 1);
4870 OffsetWindowOrgEx (hdc, pt.x, pt.y, &ptorig);
4871 ret = SendMessageA (parent, WM_ERASEBKGND, wParam, lParam);
4872 SetWindowOrgEx (hdc, ptorig.x, ptorig.y, 0);
4874 if (!ret)
4875 ret = DefWindowProcA (hwnd, WM_ERASEBKGND, wParam, lParam);
4877 if ((dwStyle & TBSTYLE_CUSTOMERASE) &&
4878 (infoPtr->dwBaseCustDraw & CDRF_NOTIFYPOSTERASE)) {
4879 ZeroMemory (&tbcd, sizeof(NMTBCUSTOMDRAW));
4880 tbcd.nmcd.dwDrawStage = CDDS_POSTERASE;
4881 tbcd.nmcd.hdc = (HDC)wParam;
4882 ntfret = TOOLBAR_SendNotify ((NMHDR *)&tbcd, infoPtr, NM_CUSTOMDRAW);
4883 infoPtr->dwBaseCustDraw = ntfret & 0xffff;
4884 switch (infoPtr->dwBaseCustDraw)
4886 case CDRF_DODEFAULT:
4887 break;
4888 case CDRF_SKIPDEFAULT:
4889 return TRUE;
4890 default:
4891 FIXME("[%p] response %ld not handled to NM_CUSTOMDRAW (CDDS_PREERASE)\n",
4892 hwnd, ntfret);
4895 return ret;
4899 static LRESULT
4900 TOOLBAR_GetFont (HWND hwnd, WPARAM wParam, LPARAM lParam)
4902 TOOLBAR_INFO *infoPtr = TOOLBAR_GetInfoPtr (hwnd);
4904 return (LRESULT)infoPtr->hFont;
4908 static LRESULT
4909 TOOLBAR_LButtonDblClk (HWND hwnd, WPARAM wParam, LPARAM lParam)
4911 TOOLBAR_INFO *infoPtr = TOOLBAR_GetInfoPtr (hwnd);
4912 TBUTTON_INFO *btnPtr;
4913 POINT pt;
4914 INT nHit;
4916 pt.x = (INT)LOWORD(lParam);
4917 pt.y = (INT)HIWORD(lParam);
4918 nHit = TOOLBAR_InternalHitTest (hwnd, &pt);
4920 if (nHit >= 0) {
4921 btnPtr = &infoPtr->buttons[nHit];
4922 if (!(btnPtr->fsState & TBSTATE_ENABLED))
4923 return 0;
4924 SetCapture (hwnd);
4925 infoPtr->bCaptured = TRUE;
4926 infoPtr->nButtonDown = nHit;
4928 btnPtr->fsState |= TBSTATE_PRESSED;
4930 InvalidateRect(hwnd, &btnPtr->rect, TOOLBAR_HasText(infoPtr,
4931 btnPtr));
4933 else if (GetWindowLongA (hwnd, GWL_STYLE) & CCS_ADJUSTABLE)
4934 TOOLBAR_Customize (hwnd);
4936 return 0;
4940 static LRESULT
4941 TOOLBAR_LButtonDown (HWND hwnd, WPARAM wParam, LPARAM lParam)
4943 TOOLBAR_INFO *infoPtr = TOOLBAR_GetInfoPtr (hwnd);
4944 TBUTTON_INFO *btnPtr;
4945 POINT pt;
4946 INT nHit;
4947 NMTOOLBARA nmtb;
4949 if (infoPtr->hwndToolTip)
4950 TOOLBAR_RelayEvent (infoPtr->hwndToolTip, hwnd,
4951 WM_LBUTTONDOWN, wParam, lParam);
4953 pt.x = (INT)LOWORD(lParam);
4954 pt.y = (INT)HIWORD(lParam);
4955 nHit = TOOLBAR_InternalHitTest (hwnd, &pt);
4957 if (nHit >= 0) {
4958 RECT arrowRect;
4959 btnPtr = &infoPtr->buttons[nHit];
4960 infoPtr->nOldHit = nHit;
4962 CopyRect(&arrowRect, &btnPtr->rect);
4963 arrowRect.left = max(btnPtr->rect.left, btnPtr->rect.right - DDARROW_WIDTH);
4965 /* for EX_DRAWDDARROWS style, click must be in the drop-down arrow rect */
4966 if ((btnPtr->fsState & TBSTATE_ENABLED) && (btnPtr->fsStyle & TBSTYLE_DROPDOWN) &&
4967 ((TOOLBAR_HasDropDownArrows(infoPtr->dwExStyle) && PtInRect(&arrowRect, pt)) ||
4968 (!TOOLBAR_HasDropDownArrows(infoPtr->dwExStyle))))
4970 LRESULT res;
4972 * this time we must force a Redraw, so the btn is
4973 * painted down before CaptureChanged repaints it up
4975 RedrawWindow(hwnd,&btnPtr->rect,0,
4976 RDW_ERASE|RDW_INVALIDATE|RDW_UPDATENOW);
4978 nmtb.iItem = btnPtr->idCommand;
4979 memset(&nmtb.tbButton, 0, sizeof(TBBUTTON));
4980 nmtb.cchText = 0;
4981 nmtb.pszText = 0;
4982 memset(&nmtb.rcButton, 0, sizeof(RECT));
4983 res = TOOLBAR_SendNotify ((NMHDR *) &nmtb, infoPtr,
4984 TBN_DROPDOWN);
4985 if (res != TBDDRET_TREATPRESSED)
4986 /* ??? guess (GA) */
4987 return 0;
4988 /* otherwise drop through and process as pushed */
4990 /* SetCapture (hwnd); */
4991 infoPtr->bCaptured = TRUE;
4992 infoPtr->nButtonDown = nHit;
4994 btnPtr->fsState |= TBSTATE_PRESSED;
4995 btnPtr->bHot = FALSE;
4997 if (btnPtr->fsState & TBSTATE_ENABLED)
4998 InvalidateRect(hwnd, &btnPtr->rect, TOOLBAR_HasText(infoPtr, btnPtr));
4999 UpdateWindow(hwnd);
5000 SetCapture (hwnd);
5002 /* native issues the TBN_BEGINDRAG here */
5003 nmtb.iItem = btnPtr->idCommand;
5004 nmtb.tbButton.iBitmap = btnPtr->iBitmap;
5005 nmtb.tbButton.idCommand = btnPtr->idCommand;
5006 nmtb.tbButton.fsState = btnPtr->fsState;
5007 nmtb.tbButton.fsStyle = btnPtr->fsStyle;
5008 nmtb.tbButton.dwData = btnPtr->dwData;
5009 nmtb.tbButton.iString = btnPtr->iString;
5010 nmtb.cchText = 0; /* !!! not correct */
5011 nmtb.pszText = 0; /* !!! not correct */
5012 TOOLBAR_SendNotify ((NMHDR *) &nmtb, infoPtr,
5013 TBN_BEGINDRAG);
5016 return 0;
5019 static LRESULT
5020 TOOLBAR_LButtonUp (HWND hwnd, WPARAM wParam, LPARAM lParam)
5022 TOOLBAR_INFO *infoPtr = TOOLBAR_GetInfoPtr (hwnd);
5023 TBUTTON_INFO *btnPtr;
5024 POINT pt;
5025 INT nHit;
5026 INT nOldIndex = -1;
5027 BOOL bSendMessage = TRUE;
5028 NMHDR hdr;
5029 NMMOUSE nmmouse;
5030 NMTOOLBARA nmtb;
5032 if (infoPtr->hwndToolTip)
5033 TOOLBAR_RelayEvent (infoPtr->hwndToolTip, hwnd,
5034 WM_LBUTTONUP, wParam, lParam);
5036 pt.x = (INT)LOWORD(lParam);
5037 pt.y = (INT)HIWORD(lParam);
5038 nHit = TOOLBAR_InternalHitTest (hwnd, &pt);
5040 /* restore hot effect to hot button disabled by TOOLBAR_LButtonDown() */
5041 /* if the cursor is still inside of the toolbar */
5042 if((infoPtr->nHotItem >= 0) && (nHit != -1))
5043 infoPtr->buttons[infoPtr->nHotItem].bHot = TRUE;
5045 if (0 <= infoPtr->nButtonDown) {
5046 btnPtr = &infoPtr->buttons[infoPtr->nButtonDown];
5047 btnPtr->fsState &= ~TBSTATE_PRESSED;
5049 if (btnPtr->fsStyle & TBSTYLE_CHECK) {
5050 if (btnPtr->fsStyle & TBSTYLE_GROUP) {
5051 nOldIndex = TOOLBAR_GetCheckedGroupButtonIndex (infoPtr,
5052 nHit);
5053 if (nOldIndex == nHit)
5054 bSendMessage = FALSE;
5055 if ((nOldIndex != nHit) &&
5056 (nOldIndex != -1))
5057 infoPtr->buttons[nOldIndex].fsState &= ~TBSTATE_CHECKED;
5058 btnPtr->fsState |= TBSTATE_CHECKED;
5060 else {
5061 if (btnPtr->fsState & TBSTATE_CHECKED)
5062 btnPtr->fsState &= ~TBSTATE_CHECKED;
5063 else
5064 btnPtr->fsState |= TBSTATE_CHECKED;
5068 if (nOldIndex != -1)
5070 InvalidateRect(hwnd, &infoPtr->buttons[nOldIndex].rect,
5071 TOOLBAR_HasText(infoPtr, &infoPtr->buttons[nOldIndex]));
5075 * now we can ReleaseCapture, which triggers CAPTURECHANGED msg,
5076 * that resets bCaptured and btn TBSTATE_PRESSED flags,
5077 * and obliterates nButtonDown and nOldHit (see TOOLBAR_CaptureChanged)
5079 if ((infoPtr->bCaptured) && (infoPtr->nButtonDown >= 0))
5080 ReleaseCapture ();
5081 infoPtr->nButtonDown = -1;
5083 /* Issue NM_RELEASEDCAPTURE to parent to let him know it is released */
5084 TOOLBAR_SendNotify ((NMHDR *) &hdr, infoPtr,
5085 NM_RELEASEDCAPTURE);
5087 /* native issues TBN_ENDDRAG here, if _LBUTTONDOWN issued the
5088 * TBN_BEGINDRAG
5090 nmtb.iItem = btnPtr->idCommand;
5091 nmtb.tbButton.iBitmap = btnPtr->iBitmap;
5092 nmtb.tbButton.idCommand = btnPtr->idCommand;
5093 nmtb.tbButton.fsState = btnPtr->fsState;
5094 nmtb.tbButton.fsStyle = btnPtr->fsStyle;
5095 nmtb.tbButton.dwData = btnPtr->dwData;
5096 nmtb.tbButton.iString = btnPtr->iString;
5097 nmtb.cchText = 0; /* !!! not correct */
5098 nmtb.pszText = 0; /* !!! not correct */
5099 TOOLBAR_SendNotify ((NMHDR *) &nmtb, infoPtr,
5100 TBN_ENDDRAG);
5102 if (btnPtr->fsState & TBSTATE_ENABLED)
5104 SendMessageA (infoPtr->hwndNotify, WM_COMMAND,
5105 MAKEWPARAM(infoPtr->buttons[nHit].idCommand, 0), (LPARAM)hwnd);
5107 /* !!! Undocumented - toolbar at 4.71 level and above sends
5108 * either NMRCLICK or NM_CLICK with the NMMOUSE structure.
5109 * Only NM_RCLICK is documented.
5111 nmmouse.dwItemSpec = btnPtr->idCommand;
5112 nmmouse.dwItemData = btnPtr->dwData;
5113 TOOLBAR_SendNotify ((NMHDR *) &nmmouse, infoPtr, NM_CLICK);
5116 return 0;
5119 static LRESULT
5120 TOOLBAR_CaptureChanged(HWND hwnd)
5122 TOOLBAR_INFO *infoPtr = TOOLBAR_GetInfoPtr (hwnd);
5123 TBUTTON_INFO *btnPtr;
5125 infoPtr->bCaptured = FALSE;
5127 if (infoPtr->nButtonDown >= 0)
5129 btnPtr = &infoPtr->buttons[infoPtr->nButtonDown];
5130 btnPtr->fsState &= ~TBSTATE_PRESSED;
5132 infoPtr->nOldHit = -1;
5134 if (btnPtr->fsState & TBSTATE_ENABLED)
5135 InvalidateRect(hwnd, &btnPtr->rect, TOOLBAR_HasText(infoPtr,
5136 btnPtr));
5138 return 0;
5141 static LRESULT
5142 TOOLBAR_MouseLeave (HWND hwnd, WPARAM wParam, LPARAM lParam)
5144 TOOLBAR_INFO *infoPtr = TOOLBAR_GetInfoPtr (hwnd);
5145 TBUTTON_INFO *hotBtnPtr, *btnPtr;
5146 RECT rc1;
5148 if (infoPtr->nOldHit < 0)
5149 return TRUE;
5151 hotBtnPtr = &infoPtr->buttons[infoPtr->nOldHit];
5153 /* Redraw the button if the last button we were over is the hot button and it
5154 is enabled */
5155 if((infoPtr->nOldHit == infoPtr->nHotItem) && (hotBtnPtr->fsState & TBSTATE_ENABLED))
5157 hotBtnPtr->bHot = FALSE;
5158 rc1 = hotBtnPtr->rect;
5159 InflateRect (&rc1, 1, 1);
5160 InvalidateRect (hwnd, &rc1, TOOLBAR_HasText(infoPtr,
5161 hotBtnPtr));
5164 /* If the last button we were over is depressed then make it not */
5165 /* depressed and redraw it */
5166 if(infoPtr->nOldHit == infoPtr->nButtonDown)
5168 btnPtr = &infoPtr->buttons[infoPtr->nButtonDown];
5170 btnPtr->fsState &= ~TBSTATE_PRESSED;
5172 rc1 = hotBtnPtr->rect;
5173 InflateRect (&rc1, 1, 1);
5174 InvalidateRect (hwnd, &rc1, TRUE);
5177 infoPtr->nOldHit = -1; /* reset the old hit index as we've left the toolbar */
5178 infoPtr->nHotItem = -2; /* It has to be initially different from nOldHit */
5180 return TRUE;
5183 static LRESULT
5184 TOOLBAR_MouseMove (HWND hwnd, WPARAM wParam, LPARAM lParam)
5186 TBUTTON_INFO *btnPtr = NULL, *oldBtnPtr = NULL;
5187 TOOLBAR_INFO *infoPtr = TOOLBAR_GetInfoPtr (hwnd);
5188 POINT pt;
5189 INT nHit;
5190 TRACKMOUSEEVENT trackinfo;
5191 NMTBHOTITEM nmhotitem;
5193 /* fill in the TRACKMOUSEEVENT struct */
5194 trackinfo.cbSize = sizeof(TRACKMOUSEEVENT);
5195 trackinfo.dwFlags = TME_QUERY;
5196 trackinfo.hwndTrack = hwnd;
5197 trackinfo.dwHoverTime = HOVER_DEFAULT;
5199 /* call _TrackMouseEvent to see if we are currently tracking for this hwnd */
5200 _TrackMouseEvent(&trackinfo);
5202 /* Make sure tracking is enabled so we receive a WM_MOUSELEAVE message */
5203 if(!(trackinfo.dwFlags & TME_LEAVE)) {
5204 trackinfo.dwFlags = TME_LEAVE; /* notify upon leaving */
5206 /* call TRACKMOUSEEVENT so we receive a WM_MOUSELEAVE message */
5207 /* and can properly deactivate the hot toolbar button */
5208 _TrackMouseEvent(&trackinfo);
5211 if (infoPtr->hwndToolTip)
5212 TOOLBAR_RelayEvent (infoPtr->hwndToolTip, hwnd,
5213 WM_MOUSEMOVE, wParam, lParam);
5215 pt.x = (INT)LOWORD(lParam);
5216 pt.y = (INT)HIWORD(lParam);
5218 nHit = TOOLBAR_InternalHitTest (hwnd, &pt);
5220 if (infoPtr->nOldHit != nHit)
5222 /* Remove the effect of an old hot button if the button was
5223 drawn with the hot button effect */
5224 if(infoPtr->nOldHit >= 0 && infoPtr->nOldHit == infoPtr->nHotItem)
5226 oldBtnPtr = &infoPtr->buttons[infoPtr->nOldHit];
5227 oldBtnPtr->bHot = FALSE;
5230 /* It's not a separator or in nowhere. It's a hot button. */
5231 if (nHit >= 0)
5233 btnPtr = &infoPtr->buttons[nHit];
5235 infoPtr->nHotItem = nHit;
5237 btnPtr->bHot = TRUE;
5240 nmhotitem.dwFlags = HICF_MOUSE;
5241 if (oldBtnPtr)
5242 nmhotitem.idOld = oldBtnPtr->idCommand;
5243 else
5244 nmhotitem.dwFlags |= HICF_ENTERING;
5245 if (btnPtr)
5246 nmhotitem.idNew = btnPtr->idCommand;
5247 else
5248 nmhotitem.dwFlags |= HICF_LEAVING;
5249 TOOLBAR_SendNotify((NMHDR*)&nmhotitem, infoPtr, TBN_HOTITEMCHANGE);
5251 /* now invalidate the old and new buttons so they will be painted */
5252 if (oldBtnPtr)
5253 InvalidateRect (hwnd, &oldBtnPtr->rect,
5254 TOOLBAR_HasText(infoPtr, oldBtnPtr));
5255 if (btnPtr)
5256 InvalidateRect(hwnd, &btnPtr->rect,
5257 TOOLBAR_HasText(infoPtr, btnPtr));
5259 if (infoPtr->bCaptured) {
5260 btnPtr = &infoPtr->buttons[infoPtr->nButtonDown];
5261 if (infoPtr->nOldHit == infoPtr->nButtonDown) {
5262 btnPtr->fsState &= ~TBSTATE_PRESSED;
5263 InvalidateRect(hwnd, &btnPtr->rect, TRUE);
5265 else if (nHit == infoPtr->nButtonDown) {
5266 btnPtr->fsState |= TBSTATE_PRESSED;
5267 InvalidateRect(hwnd, &btnPtr->rect, TRUE);
5270 infoPtr->nOldHit = nHit;
5272 return 0;
5276 inline static LRESULT
5277 TOOLBAR_NCActivate (HWND hwnd, WPARAM wParam, LPARAM lParam)
5279 /* if (wndPtr->dwStyle & CCS_NODIVIDER) */
5280 return DefWindowProcA (hwnd, WM_NCACTIVATE, wParam, lParam);
5281 /* else */
5282 /* return TOOLBAR_NCPaint (wndPtr, wParam, lParam); */
5286 inline static LRESULT
5287 TOOLBAR_NCCalcSize (HWND hwnd, WPARAM wParam, LPARAM lParam)
5289 if (!(GetWindowLongA (hwnd, GWL_STYLE) & CCS_NODIVIDER))
5290 ((LPRECT)lParam)->top += GetSystemMetrics(SM_CYEDGE);
5292 return DefWindowProcA (hwnd, WM_NCCALCSIZE, wParam, lParam);
5296 static LRESULT
5297 TOOLBAR_NCCreate (HWND hwnd, WPARAM wParam, LPARAM lParam)
5299 TOOLBAR_INFO *infoPtr;
5300 LPCREATESTRUCTA cs = (LPCREATESTRUCTA)lParam;
5301 DWORD styleadd = 0;
5303 /* allocate memory for info structure */
5304 infoPtr = (TOOLBAR_INFO *)Alloc (sizeof(TOOLBAR_INFO));
5305 SetWindowLongA (hwnd, 0, (DWORD)infoPtr);
5307 /* paranoid!! */
5308 infoPtr->dwStructSize = sizeof(TBBUTTON);
5309 infoPtr->nRows = 1;
5311 /* fix instance handle, if the toolbar was created by CreateToolbarEx() */
5312 if (!GetWindowLongA (hwnd, GWL_HINSTANCE)) {
5313 HINSTANCE hInst = (HINSTANCE)GetWindowLongA (GetParent (hwnd), GWL_HINSTANCE);
5314 SetWindowLongA (hwnd, GWL_HINSTANCE, (DWORD)hInst);
5317 /* native control does:
5318 * Get a lot of colors and brushes
5319 * WM_NOTIFYFORMAT
5320 * SystemParametersInfoA(0x1f, 0x3c, adr1, 0)
5321 * CreateFontIndirectA(adr1)
5322 * CreateBitmap(0x27, 0x24, 1, 1, 0)
5323 * hdc = GetDC(toolbar)
5324 * GetSystemMetrics(0x48)
5325 * fnt2=CreateFontA(0xe, 0, 0, 0, 0x190, 0, 0, 0, 0, 2,
5326 * 0, 0, 0, 0, "MARLETT")
5327 * oldfnt = SelectObject(hdc, fnt2)
5328 * GetCharWidthA(hdc, 0x36, 0x36, adr2)
5329 * GetTextMetricsA(hdc, adr3)
5330 * SelectObject(hdc, oldfnt)
5331 * DeleteObject(fnt2)
5332 * ReleaseDC(hdc)
5333 * InvalidateRect(toolbar, 0, 1)
5334 * SetWindowLongA(toolbar, 0, addr)
5335 * SetWindowLongA(toolbar, -16, xxx) **sometimes**
5336 * WM_STYLECHANGING
5337 * CallWinEx old new
5338 * ie 1 0x56000a4c 0x46000a4c 0x56008a4d
5339 * ie 2 0x4600094c 0x4600094c 0x4600894d
5340 * ie 3 0x56000b4c 0x46000b4c 0x56008b4d
5341 * rebar 0x50008844 0x40008844 0x50008845
5342 * pager 0x50000844 0x40000844 0x50008845
5343 * IC35mgr 0x5400084e **nochange**
5344 * on entry to _NCCREATE 0x5400084e
5345 * rowlist 0x5400004e **nochange**
5346 * on entry to _NCCREATE 0x5400004e
5350 /* I think the code below is a bug, but it is the way that the native
5351 * controls seem to work. The effect is that if the user of TBSTYLE_FLAT
5352 * forgets to specify TBSTYLE_TRANSPARENT but does specify either
5353 * CCS_TOP or CCS_BOTTOM (_NOMOVEY and _TOP), then the control
5354 * does *not* set TBSTYLE_TRANSPARENT even though it should!!!!
5355 * Some how, the only cases of this seem to be MFC programs.
5357 * Note also that the addition of _TRANSPARENT occurs *only* here. It
5358 * does not occur in the WM_STYLECHANGING routine.
5359 * (Guy Albertelli 9/2001)
5362 if ((cs->style & TBSTYLE_FLAT) && !(cs->style & TBSTYLE_TRANSPARENT))
5363 styleadd |= TBSTYLE_TRANSPARENT;
5364 if (!(cs->style & (CCS_TOP | CCS_NOMOVEY))) {
5365 styleadd |= CCS_TOP; /* default to top */
5366 SetWindowLongA (hwnd, GWL_STYLE, cs->style | styleadd);
5369 return DefWindowProcA (hwnd, WM_NCCREATE, wParam, lParam);
5373 static LRESULT
5374 TOOLBAR_NCPaint (HWND hwnd, WPARAM wParam, LPARAM lParam)
5376 DWORD dwStyle = GetWindowLongA (hwnd, GWL_STYLE);
5377 RECT rcWindow;
5378 HDC hdc;
5380 if (dwStyle & WS_MINIMIZE)
5381 return 0; /* Nothing to do */
5383 DefWindowProcA (hwnd, WM_NCPAINT, wParam, lParam);
5385 if (!(hdc = GetDCEx (hwnd, 0, DCX_USESTYLE | DCX_WINDOW)))
5386 return 0;
5388 if (!(dwStyle & CCS_NODIVIDER))
5390 GetWindowRect (hwnd, &rcWindow);
5391 OffsetRect (&rcWindow, -rcWindow.left, -rcWindow.top);
5392 if( dwStyle & WS_BORDER )
5393 OffsetRect (&rcWindow, 1, 1);
5394 DrawEdge (hdc, &rcWindow, EDGE_ETCHED, BF_TOP);
5397 ReleaseDC( hwnd, hdc );
5399 return 0;
5403 inline static LRESULT
5404 TOOLBAR_Notify (HWND hwnd, WPARAM wParam, LPARAM lParam)
5406 TOOLBAR_INFO *infoPtr = TOOLBAR_GetInfoPtr (hwnd);
5407 LPNMHDR lpnmh = (LPNMHDR)lParam;
5409 if (lpnmh->code == PGN_CALCSIZE) {
5410 LPNMPGCALCSIZE lppgc = (LPNMPGCALCSIZE)lParam;
5412 if (lppgc->dwFlag == PGF_CALCWIDTH) {
5413 lppgc->iWidth = infoPtr->rcBound.right - infoPtr->rcBound.left;
5414 TRACE("processed PGN_CALCSIZE, returning horz size = %d\n",
5415 lppgc->iWidth);
5417 else {
5418 lppgc->iHeight = infoPtr->rcBound.bottom - infoPtr->rcBound.top;
5419 TRACE("processed PGN_CALCSIZE, returning vert size = %d\n",
5420 lppgc->iHeight);
5422 return 0;
5425 if (lpnmh->code == PGN_SCROLL) {
5426 LPNMPGSCROLL lppgs = (LPNMPGSCROLL)lParam;
5428 lppgs->iScroll = (lppgs->iDir & (PGF_SCROLLLEFT | PGF_SCROLLRIGHT)) ?
5429 infoPtr->nButtonWidth : infoPtr->nButtonHeight;
5430 TRACE("processed PGN_SCROLL, returning scroll=%d, dir=%d\n",
5431 lppgs->iScroll, lppgs->iDir);
5432 return 0;
5436 TRACE("passing WM_NOTIFY!\n");
5438 if ((infoPtr->hwndToolTip) && (lpnmh->hwndFrom == infoPtr->hwndToolTip)) {
5439 if (infoPtr->bNtfUnicode)
5440 return SendMessageW (infoPtr->hwndNotify, WM_NOTIFY,
5441 wParam, lParam);
5442 else
5443 return SendMessageA (infoPtr->hwndNotify, WM_NOTIFY,
5444 wParam, lParam);
5446 #if 0
5447 if (lpnmh->code == TTN_GETDISPINFOA) {
5448 LPNMTTDISPINFOA lpdi = (LPNMTTDISPINFOA)lParam;
5450 FIXME("retrieving ASCII string\n");
5453 else if (lpnmh->code == TTN_GETDISPINFOW) {
5454 LPNMTTDISPINFOW lpdi = (LPNMTTDISPINFOW)lParam;
5456 FIXME("retrieving UNICODE string\n");
5459 #endif
5462 return 0;
5466 static LRESULT
5467 TOOLBAR_NotifyFormatFake(HWND hwnd, WPARAM wParam, LPARAM lParam)
5469 /* remove this routine when Toolbar is improved to pass infoPtr
5470 * around instead of hwnd.
5472 TOOLBAR_INFO *infoPtr = TOOLBAR_GetInfoPtr(hwnd);
5473 return TOOLBAR_NotifyFormat(infoPtr, wParam, lParam);
5477 static LRESULT
5478 TOOLBAR_NotifyFormat(TOOLBAR_INFO *infoPtr, WPARAM wParam, LPARAM lParam)
5480 INT i;
5482 if (lParam == NF_REQUERY) {
5483 i = SendMessageA(infoPtr->hwndNotify,
5484 WM_NOTIFYFORMAT, (WPARAM)infoPtr->hwndSelf, NF_QUERY);
5485 if ((i < NFR_ANSI) || (i > NFR_UNICODE)) {
5486 ERR("wrong response to WM_NOTIFYFORMAT (%d), assuming ANSI\n",
5488 i = NFR_ANSI;
5490 infoPtr->bNtfUnicode = (i == NFR_UNICODE) ? 1 : 0;
5491 return (LRESULT)i;
5493 return (LRESULT)((infoPtr->bUnicode) ? NFR_UNICODE : NFR_ANSI);
5497 static LRESULT
5498 TOOLBAR_Paint (HWND hwnd, WPARAM wParam)
5500 TOOLBAR_INFO *infoPtr = TOOLBAR_GetInfoPtr(hwnd);
5501 HDC hdc;
5502 PAINTSTRUCT ps;
5504 /* fill ps.rcPaint with a default rect */
5505 memcpy(&(ps.rcPaint), &(infoPtr->rcBound), sizeof(infoPtr->rcBound));
5507 hdc = wParam==0 ? BeginPaint(hwnd, &ps) : (HDC)wParam;
5509 TRACE("psrect=(%ld,%ld)-(%ld,%ld)\n",
5510 ps.rcPaint.left, ps.rcPaint.top,
5511 ps.rcPaint.right, ps.rcPaint.bottom);
5513 TOOLBAR_Refresh (hwnd, hdc, &ps);
5514 if (!wParam) EndPaint (hwnd, &ps);
5516 return 0;
5520 static LRESULT
5521 TOOLBAR_SetRedraw (HWND hwnd, WPARAM wParam, LPARAM lParam)
5522 /*****************************************************
5524 * Function;
5525 * Handles the WM_SETREDRAW message.
5527 * Documentation:
5528 * According to testing V4.71 of COMCTL32 returns the
5529 * *previous* status of the redraw flag (either 0 or 1)
5530 * instead of the MSDN documented value of 0 if handled.
5531 * (For laughs see the "consistency" with same function
5532 * in rebar.)
5534 *****************************************************/
5536 TOOLBAR_INFO *infoPtr = TOOLBAR_GetInfoPtr (hwnd);
5537 BOOL oldredraw = infoPtr->bDoRedraw;
5539 TRACE("set to %s\n",
5540 (wParam) ? "TRUE" : "FALSE");
5541 infoPtr->bDoRedraw = (BOOL) wParam;
5542 if (wParam) {
5543 InvalidateRect (infoPtr->hwndSelf, 0, TRUE);
5545 return (oldredraw) ? 1 : 0;
5549 static LRESULT
5550 TOOLBAR_Size (HWND hwnd, WPARAM wParam, LPARAM lParam)
5552 TOOLBAR_INFO *infoPtr = TOOLBAR_GetInfoPtr (hwnd);
5553 DWORD dwStyle = GetWindowLongA (hwnd, GWL_STYLE);
5554 RECT parent_rect;
5555 RECT window_rect;
5556 HWND parent;
5557 INT x, y;
5558 INT cx, cy;
5559 INT flags;
5560 UINT uPosFlags = 0;
5562 /* Resize deadlock check */
5563 if (infoPtr->bAutoSize) {
5564 infoPtr->bAutoSize = FALSE;
5565 return 0;
5568 /* FIXME: optimize to only update size if the new size doesn't */
5569 /* match the current size */
5571 flags = (INT) wParam;
5573 /* FIXME for flags =
5574 * SIZE_MAXIMIZED, SIZE_MAXSHOW, SIZE_MINIMIZED
5577 TRACE("sizing toolbar!\n");
5579 if (flags == SIZE_RESTORED) {
5580 /* width and height don't apply */
5581 parent = GetParent (hwnd);
5582 GetClientRect(parent, &parent_rect);
5583 x = parent_rect.left;
5584 y = parent_rect.top;
5586 if (dwStyle & CCS_NORESIZE) {
5587 uPosFlags |= (SWP_NOSIZE | SWP_NOMOVE);
5590 * this sets the working width of the toolbar, and
5591 * Calc Toolbar will not adjust it, only the height
5593 infoPtr->nWidth = parent_rect.right - parent_rect.left;
5594 cy = infoPtr->nHeight;
5595 cx = infoPtr->nWidth;
5596 TOOLBAR_CalcToolbar (hwnd);
5597 infoPtr->nWidth = cx;
5598 infoPtr->nHeight = cy;
5600 else {
5601 infoPtr->nWidth = parent_rect.right - parent_rect.left;
5602 TOOLBAR_CalcToolbar (hwnd);
5603 cy = infoPtr->nHeight;
5604 cx = infoPtr->nWidth;
5606 if ((dwStyle & CCS_BOTTOM) == CCS_NOMOVEY) {
5607 GetWindowRect(hwnd, &window_rect);
5608 ScreenToClient(parent, (LPPOINT)&window_rect.left);
5609 y = window_rect.top;
5611 if ((dwStyle & CCS_BOTTOM) == CCS_BOTTOM) {
5612 GetWindowRect(hwnd, &window_rect);
5613 y = parent_rect.bottom -
5614 ( window_rect.bottom - window_rect.top);
5618 if (dwStyle & CCS_NOPARENTALIGN) {
5619 uPosFlags |= SWP_NOMOVE;
5620 cy = infoPtr->nHeight;
5621 cx = infoPtr->nWidth;
5624 if (!(dwStyle & CCS_NODIVIDER))
5625 cy += GetSystemMetrics(SM_CYEDGE);
5627 if (dwStyle & WS_BORDER)
5629 x = y = 1;
5630 cy += GetSystemMetrics(SM_CYEDGE);
5631 cx += GetSystemMetrics(SM_CYEDGE);
5634 SetWindowPos (hwnd, 0, x, y, cx, cy, uPosFlags | SWP_NOZORDER);
5636 return 0;
5640 static LRESULT
5641 TOOLBAR_StyleChanged (HWND hwnd, INT nType, LPSTYLESTRUCT lpStyle)
5643 TOOLBAR_INFO *infoPtr = TOOLBAR_GetInfoPtr (hwnd);
5645 if (nType == GWL_STYLE) {
5646 if (lpStyle->styleNew & TBSTYLE_LIST) {
5647 infoPtr->dwDTFlags = DT_LEFT | DT_VCENTER | DT_SINGLELINE;
5649 else {
5650 infoPtr->dwDTFlags = DT_CENTER;
5652 infoPtr->bTransparent = (lpStyle->styleNew & TBSTYLE_TRANSPARENT);
5653 infoPtr->bBtnTranspnt = (lpStyle->styleNew &
5654 (TBSTYLE_FLAT | TBSTYLE_LIST));
5655 TOOLBAR_CheckStyle (hwnd, lpStyle->styleNew);
5657 TRACE("new style 0x%08lx\n", lpStyle->styleNew);
5660 TOOLBAR_CalcToolbar(hwnd);
5662 TOOLBAR_AutoSize (hwnd);
5664 InvalidateRect(hwnd, NULL, FALSE);
5666 return 0;
5670 static LRESULT
5671 TOOLBAR_SysColorChange (HWND hwnd)
5673 COMCTL32_RefreshSysColors();
5675 return 0;
5680 static LRESULT WINAPI
5681 ToolbarWindowProc (HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
5683 TOOLBAR_INFO *infoPtr = TOOLBAR_GetInfoPtr (hwnd);
5685 TRACE("hwnd=%p msg=%x wparam=%x lparam=%lx\n",
5686 hwnd, uMsg, /* SPY_GetMsgName(uMsg), */ wParam, lParam);
5688 if (!TOOLBAR_GetInfoPtr(hwnd) && (uMsg != WM_NCCREATE))
5689 return DefWindowProcA( hwnd, uMsg, wParam, lParam );
5691 switch (uMsg)
5693 case TB_ADDBITMAP:
5694 return TOOLBAR_AddBitmap (hwnd, wParam, lParam);
5696 case TB_ADDBUTTONSA:
5697 return TOOLBAR_AddButtonsA (hwnd, wParam, lParam);
5699 case TB_ADDBUTTONSW:
5700 return TOOLBAR_AddButtonsW (hwnd, wParam, lParam);
5702 case TB_ADDSTRINGA:
5703 return TOOLBAR_AddStringA (hwnd, wParam, lParam);
5705 case TB_ADDSTRINGW:
5706 return TOOLBAR_AddStringW (hwnd, wParam, lParam);
5708 case TB_AUTOSIZE:
5709 return TOOLBAR_AutoSize (hwnd);
5711 case TB_BUTTONCOUNT:
5712 return TOOLBAR_ButtonCount (hwnd, wParam, lParam);
5714 case TB_BUTTONSTRUCTSIZE:
5715 return TOOLBAR_ButtonStructSize (hwnd, wParam, lParam);
5717 case TB_CHANGEBITMAP:
5718 return TOOLBAR_ChangeBitmap (hwnd, wParam, lParam);
5720 case TB_CHECKBUTTON:
5721 return TOOLBAR_CheckButton (hwnd, wParam, lParam);
5723 case TB_COMMANDTOINDEX:
5724 return TOOLBAR_CommandToIndex (hwnd, wParam, lParam);
5726 case TB_CUSTOMIZE:
5727 return TOOLBAR_Customize (hwnd);
5729 case TB_DELETEBUTTON:
5730 return TOOLBAR_DeleteButton (hwnd, wParam, lParam);
5732 case TB_ENABLEBUTTON:
5733 return TOOLBAR_EnableButton (hwnd, wParam, lParam);
5735 case TB_GETANCHORHIGHLIGHT:
5736 return TOOLBAR_GetAnchorHighlight (hwnd);
5738 case TB_GETBITMAP:
5739 return TOOLBAR_GetBitmap (hwnd, wParam, lParam);
5741 case TB_GETBITMAPFLAGS:
5742 return TOOLBAR_GetBitmapFlags (hwnd, wParam, lParam);
5744 case TB_GETBUTTON:
5745 return TOOLBAR_GetButton (hwnd, wParam, lParam);
5747 case TB_GETBUTTONINFOA:
5748 return TOOLBAR_GetButtonInfoA (hwnd, wParam, lParam);
5750 case TB_GETBUTTONINFOW:
5751 return TOOLBAR_GetButtonInfoW (hwnd, wParam, lParam);
5753 case TB_GETBUTTONSIZE:
5754 return TOOLBAR_GetButtonSize (hwnd);
5756 case TB_GETBUTTONTEXTA:
5757 return TOOLBAR_GetButtonTextA (hwnd, wParam, lParam);
5759 case TB_GETBUTTONTEXTW:
5760 return TOOLBAR_GetButtonTextW (hwnd, wParam, lParam);
5762 case TB_GETDISABLEDIMAGELIST:
5763 return TOOLBAR_GetDisabledImageList (hwnd, wParam, lParam);
5765 case TB_GETEXTENDEDSTYLE:
5766 return TOOLBAR_GetExtendedStyle (hwnd);
5768 case TB_GETHOTIMAGELIST:
5769 return TOOLBAR_GetHotImageList (hwnd, wParam, lParam);
5771 case TB_GETHOTITEM:
5772 return TOOLBAR_GetHotItem (hwnd);
5774 case TB_GETIMAGELIST:
5775 return TOOLBAR_GetDefImageList (hwnd, wParam, lParam);
5777 /* case TB_GETINSERTMARK: */ /* 4.71 */
5778 /* case TB_GETINSERTMARKCOLOR: */ /* 4.71 */
5780 case TB_GETITEMRECT:
5781 return TOOLBAR_GetItemRect (hwnd, wParam, lParam);
5783 case TB_GETMAXSIZE:
5784 return TOOLBAR_GetMaxSize (hwnd, wParam, lParam);
5786 /* case TB_GETOBJECT: */ /* 4.71 */
5788 case TB_GETPADDING:
5789 return TOOLBAR_GetPadding (hwnd);
5791 case TB_GETRECT:
5792 return TOOLBAR_GetRect (hwnd, wParam, lParam);
5794 case TB_GETROWS:
5795 return TOOLBAR_GetRows (hwnd, wParam, lParam);
5797 case TB_GETSTATE:
5798 return TOOLBAR_GetState (hwnd, wParam, lParam);
5800 case TB_GETSTYLE:
5801 return TOOLBAR_GetStyle (hwnd, wParam, lParam);
5803 case TB_GETTEXTROWS:
5804 return TOOLBAR_GetTextRows (hwnd, wParam, lParam);
5806 case TB_GETTOOLTIPS:
5807 return TOOLBAR_GetToolTips (hwnd, wParam, lParam);
5809 case TB_GETUNICODEFORMAT:
5810 return TOOLBAR_GetUnicodeFormat (hwnd, wParam, lParam);
5812 case TB_HIDEBUTTON:
5813 return TOOLBAR_HideButton (hwnd, wParam, lParam);
5815 case TB_HITTEST:
5816 return TOOLBAR_HitTest (hwnd, wParam, lParam);
5818 case TB_INDETERMINATE:
5819 return TOOLBAR_Indeterminate (hwnd, wParam, lParam);
5821 case TB_INSERTBUTTONA:
5822 return TOOLBAR_InsertButtonA (hwnd, wParam, lParam);
5824 case TB_INSERTBUTTONW:
5825 return TOOLBAR_InsertButtonW (hwnd, wParam, lParam);
5827 /* case TB_INSERTMARKHITTEST: */ /* 4.71 */
5829 case TB_ISBUTTONCHECKED:
5830 return TOOLBAR_IsButtonChecked (hwnd, wParam, lParam);
5832 case TB_ISBUTTONENABLED:
5833 return TOOLBAR_IsButtonEnabled (hwnd, wParam, lParam);
5835 case TB_ISBUTTONHIDDEN:
5836 return TOOLBAR_IsButtonHidden (hwnd, wParam, lParam);
5838 case TB_ISBUTTONHIGHLIGHTED:
5839 return TOOLBAR_IsButtonHighlighted (hwnd, wParam, lParam);
5841 case TB_ISBUTTONINDETERMINATE:
5842 return TOOLBAR_IsButtonIndeterminate (hwnd, wParam, lParam);
5844 case TB_ISBUTTONPRESSED:
5845 return TOOLBAR_IsButtonPressed (hwnd, wParam, lParam);
5847 case TB_LOADIMAGES: /* 4.70 */
5848 FIXME("missing standard imagelists\n");
5849 return 0;
5851 /* case TB_MAPACCELERATORA: */ /* 4.71 */
5852 /* case TB_MAPACCELERATORW: */ /* 4.71 */
5853 /* case TB_MARKBUTTON: */ /* 4.71 */
5854 /* case TB_MOVEBUTTON: */ /* 4.71 */
5856 case TB_PRESSBUTTON:
5857 return TOOLBAR_PressButton (hwnd, wParam, lParam);
5859 case TB_REPLACEBITMAP:
5860 return TOOLBAR_ReplaceBitmap (hwnd, wParam, lParam);
5862 case TB_SAVERESTOREA:
5863 return TOOLBAR_SaveRestoreA (hwnd, wParam, lParam);
5865 case TB_SAVERESTOREW:
5866 return TOOLBAR_SaveRestoreW (hwnd, wParam, lParam);
5868 case TB_SETANCHORHIGHLIGHT:
5869 return TOOLBAR_SetAnchorHighlight (hwnd, wParam);
5871 case TB_SETBITMAPSIZE:
5872 return TOOLBAR_SetBitmapSize (hwnd, wParam, lParam);
5874 case TB_SETBUTTONINFOA:
5875 return TOOLBAR_SetButtonInfoA (hwnd, wParam, lParam);
5877 case TB_SETBUTTONINFOW:
5878 return TOOLBAR_SetButtonInfoW (hwnd, wParam, lParam);
5880 case TB_SETBUTTONSIZE:
5881 return TOOLBAR_SetButtonSize (hwnd, wParam, lParam);
5883 case TB_SETBUTTONWIDTH:
5884 return TOOLBAR_SetButtonWidth (hwnd, wParam, lParam);
5886 case TB_SETCMDID:
5887 return TOOLBAR_SetCmdId (hwnd, wParam, lParam);
5889 case TB_SETDISABLEDIMAGELIST:
5890 return TOOLBAR_SetDisabledImageList (hwnd, wParam, lParam);
5892 case TB_SETDRAWTEXTFLAGS:
5893 return TOOLBAR_SetDrawTextFlags (hwnd, wParam, lParam);
5895 case TB_SETEXTENDEDSTYLE:
5896 return TOOLBAR_SetExtendedStyle (hwnd, wParam, lParam);
5898 case TB_SETHOTIMAGELIST:
5899 return TOOLBAR_SetHotImageList (hwnd, wParam, lParam);
5901 case TB_SETHOTITEM:
5902 return TOOLBAR_SetHotItem (hwnd, wParam);
5904 case TB_SETIMAGELIST:
5905 return TOOLBAR_SetImageList (hwnd, wParam, lParam);
5907 case TB_SETINDENT:
5908 return TOOLBAR_SetIndent (hwnd, wParam, lParam);
5910 /* case TB_SETINSERTMARK: */ /* 4.71 */
5912 case TB_SETINSERTMARKCOLOR:
5913 return TOOLBAR_SetInsertMarkColor (hwnd, wParam, lParam);
5915 case TB_SETMAXTEXTROWS:
5916 return TOOLBAR_SetMaxTextRows (hwnd, wParam, lParam);
5918 case TB_SETPADDING:
5919 return TOOLBAR_SetPadding (hwnd, wParam, lParam);
5921 case TB_SETPARENT:
5922 return TOOLBAR_SetParent (hwnd, wParam, lParam);
5924 case TB_SETROWS:
5925 return TOOLBAR_SetRows (hwnd, wParam, lParam);
5927 case TB_SETSTATE:
5928 return TOOLBAR_SetState (hwnd, wParam, lParam);
5930 case TB_SETSTYLE:
5931 return TOOLBAR_SetStyle (hwnd, wParam, lParam);
5933 case TB_SETTOOLTIPS:
5934 return TOOLBAR_SetToolTips (hwnd, wParam, lParam);
5936 case TB_SETUNICODEFORMAT:
5937 return TOOLBAR_SetUnicodeFormat (hwnd, wParam, lParam);
5939 case TB_UNKWN45E:
5940 return TOOLBAR_Unkwn45E (hwnd, wParam, lParam);
5942 case TB_UNKWN463:
5943 return TOOLBAR_Unkwn463 (hwnd, wParam, lParam);
5946 /* Common Control Messages */
5948 /* case TB_GETCOLORSCHEME: */ /* identical to CCM_ */
5949 case CCM_GETCOLORSCHEME:
5950 return TOOLBAR_GetColorScheme (hwnd, (LPCOLORSCHEME)lParam);
5952 /* case TB_SETCOLORSCHEME: */ /* identical to CCM_ */
5953 case CCM_SETCOLORSCHEME:
5954 return TOOLBAR_SetColorScheme (hwnd, (LPCOLORSCHEME)lParam);
5956 case CCM_GETVERSION:
5957 return TOOLBAR_GetVersion (hwnd);
5959 case CCM_SETVERSION:
5960 return TOOLBAR_SetVersion (hwnd, (INT)wParam);
5963 /* case WM_CHAR: */
5965 case WM_CREATE:
5966 return TOOLBAR_Create (hwnd, wParam, lParam);
5968 case WM_DESTROY:
5969 return TOOLBAR_Destroy (hwnd, wParam, lParam);
5971 case WM_ERASEBKGND:
5972 return TOOLBAR_EraseBackground (hwnd, wParam, lParam);
5974 case WM_GETFONT:
5975 return TOOLBAR_GetFont (hwnd, wParam, lParam);
5977 /* case WM_KEYDOWN: */
5978 /* case WM_KILLFOCUS: */
5980 case WM_LBUTTONDBLCLK:
5981 return TOOLBAR_LButtonDblClk (hwnd, wParam, lParam);
5983 case WM_LBUTTONDOWN:
5984 return TOOLBAR_LButtonDown (hwnd, wParam, lParam);
5986 case WM_LBUTTONUP:
5987 return TOOLBAR_LButtonUp (hwnd, wParam, lParam);
5989 case WM_MOUSEMOVE:
5990 return TOOLBAR_MouseMove (hwnd, wParam, lParam);
5992 case WM_MOUSELEAVE:
5993 return TOOLBAR_MouseLeave (hwnd, wParam, lParam);
5995 case WM_CAPTURECHANGED:
5996 return TOOLBAR_CaptureChanged(hwnd);
5998 case WM_NCACTIVATE:
5999 return TOOLBAR_NCActivate (hwnd, wParam, lParam);
6001 case WM_NCCALCSIZE:
6002 return TOOLBAR_NCCalcSize (hwnd, wParam, lParam);
6004 case WM_NCCREATE:
6005 return TOOLBAR_NCCreate (hwnd, wParam, lParam);
6007 case WM_NCPAINT:
6008 return TOOLBAR_NCPaint (hwnd, wParam, lParam);
6010 case WM_NOTIFY:
6011 return TOOLBAR_Notify (hwnd, wParam, lParam);
6013 case WM_NOTIFYFORMAT:
6014 TOOLBAR_NotifyFormatFake (hwnd, wParam, lParam);
6016 case WM_PAINT:
6017 return TOOLBAR_Paint (hwnd, wParam);
6019 case WM_SETREDRAW:
6020 return TOOLBAR_SetRedraw (hwnd, wParam, lParam);
6022 case WM_SIZE:
6023 return TOOLBAR_Size (hwnd, wParam, lParam);
6025 case WM_STYLECHANGED:
6026 return TOOLBAR_StyleChanged (hwnd, (INT)wParam, (LPSTYLESTRUCT)lParam);
6028 case WM_SYSCOLORCHANGE:
6029 return TOOLBAR_SysColorChange (hwnd);
6031 /* case WM_WININICHANGE: */
6033 case WM_CHARTOITEM:
6034 case WM_COMMAND:
6035 case WM_DRAWITEM:
6036 case WM_MEASUREITEM:
6037 case WM_VKEYTOITEM:
6038 return SendMessageA (infoPtr->hwndNotify, uMsg, wParam, lParam);
6040 /* We see this in Outlook Express 5.x and just does DefWindowProc */
6041 case PGM_FORWARDMOUSE:
6042 return DefWindowProcA (hwnd, uMsg, wParam, lParam);
6044 default:
6045 if ((uMsg >= WM_USER) && (uMsg < WM_APP))
6046 ERR("unknown msg %04x wp=%08x lp=%08lx\n",
6047 uMsg, wParam, lParam);
6048 return DefWindowProcA (hwnd, uMsg, wParam, lParam);
6050 return 0;
6054 VOID
6055 TOOLBAR_Register (void)
6057 WNDCLASSA wndClass;
6059 ZeroMemory (&wndClass, sizeof(WNDCLASSA));
6060 wndClass.style = CS_GLOBALCLASS | CS_DBLCLKS;
6061 wndClass.lpfnWndProc = (WNDPROC)ToolbarWindowProc;
6062 wndClass.cbClsExtra = 0;
6063 wndClass.cbWndExtra = sizeof(TOOLBAR_INFO *);
6064 wndClass.hCursor = LoadCursorA (0, (LPSTR)IDC_ARROW);
6065 wndClass.hbrBackground = (HBRUSH)(COLOR_3DFACE + 1);
6066 wndClass.lpszClassName = TOOLBARCLASSNAMEA;
6068 RegisterClassA (&wndClass);
6072 VOID
6073 TOOLBAR_Unregister (void)
6075 UnregisterClassA (TOOLBARCLASSNAMEA, NULL);
6078 static HIMAGELIST TOOLBAR_InsertImageList(PIMLENTRY **pies, INT *cies, HIMAGELIST himl, INT id)
6080 HIMAGELIST himlold;
6081 PIMLENTRY c = NULL;
6083 /* Check if the entry already exists */
6084 c = TOOLBAR_GetImageListEntry(*pies, *cies, id);
6086 /* If this is a new entry we must create it and insert into the array */
6087 if (!c)
6089 PIMLENTRY *pnies;
6091 c = (PIMLENTRY) Alloc(sizeof(IMLENTRY));
6092 c->id = id;
6094 pnies = Alloc((*cies + 1) * sizeof(PIMLENTRY));
6095 memcpy(pnies, *pies, ((*cies) * sizeof(PIMLENTRY)));
6096 pnies[*cies] = c;
6097 (*cies)++;
6099 Free(*pies);
6100 *pies = pnies;
6103 himlold = c->himl;
6104 c->himl = himl;
6106 return himlold;
6110 static VOID TOOLBAR_DeleteImageList(PIMLENTRY **pies, INT *cies)
6112 int i;
6114 for (i = 0; i < *cies; i++)
6115 Free((*pies)[i]);
6117 Free(*pies);
6119 *cies = 0;
6120 *pies = NULL;
6124 static PIMLENTRY TOOLBAR_GetImageListEntry(PIMLENTRY *pies, INT cies, INT id)
6126 PIMLENTRY c = NULL;
6128 if (pies != NULL)
6130 int i;
6132 for (i = 0; i < cies; i++)
6134 if (pies[i]->id == id)
6136 c = pies[i];
6137 break;
6142 return c;
6146 static HIMAGELIST TOOLBAR_GetImageList(PIMLENTRY *pies, INT cies, INT id)
6148 HIMAGELIST himlDef = 0;
6149 PIMLENTRY pie = TOOLBAR_GetImageListEntry(pies, cies, id);
6151 if (pie)
6152 himlDef = pie->himl;
6154 return himlDef;
6158 static BOOL TOOLBAR_GetButtonInfo(TOOLBAR_INFO *infoPtr, NMTOOLBARW *nmtb)
6160 if (infoPtr->bUnicode)
6161 return TOOLBAR_SendNotify ((NMHDR *) nmtb, infoPtr, TBN_GETBUTTONINFOW);
6162 else
6164 CHAR Buffer[256];
6165 NMTOOLBARA nmtba;
6166 BOOL bRet = FALSE;
6168 nmtba.iItem = nmtb->iItem;
6169 nmtba.pszText = Buffer;
6170 nmtba.cchText = 256;
6171 ZeroMemory(nmtba.pszText, nmtba.cchText);
6173 if (TOOLBAR_SendNotify ((NMHDR *) &nmtba, infoPtr, TBN_GETBUTTONINFOA))
6175 int ccht = strlen(nmtba.pszText);
6176 if (ccht)
6177 MultiByteToWideChar(CP_ACP, 0, (LPCSTR)nmtba.pszText, -1,
6178 nmtb->pszText, nmtb->cchText);
6180 memcpy(&nmtb->tbButton, &nmtba.tbButton, sizeof(TBBUTTON));
6181 bRet = TRUE;
6184 return bRet;
6189 static BOOL TOOLBAR_IsButtonRemovable(TOOLBAR_INFO *infoPtr,
6190 int iItem, PCUSTOMBUTTON btnInfo)
6192 NMTOOLBARA nmtb;
6194 nmtb.iItem = iItem;
6195 memcpy(&nmtb.tbButton, &btnInfo->btn, sizeof(TBBUTTON));
6197 return TOOLBAR_SendNotify ((NMHDR *) &nmtb, infoPtr, TBN_QUERYDELETE);