TB_ADDBUTTONS can pass a string ptr instead of an index.
[wine.git] / dlls / comctl32 / toolbar.c
blob6e2fc318e3cb2cee23e8dfc955b968c79b6fa222
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 BTNS_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 TOOLBAR_DrawMasked(TOOLBAR_INFO *infoPtr, TBUTTON_INFO *btnPtr,
618 HDC hdc, INT x, INT y)
620 HIMAGELIST himl = GETDEFIMAGELIST(infoPtr, 0);
622 if (himl)
624 INT cx, cy;
625 HBITMAP hbmMask, hbmImage;
626 HDC hdcMask, hdcImage;
628 ImageList_GetIconSize(himl, &cx, &cy);
630 /* Create src image */
631 hdcImage = CreateCompatibleDC(hdc);
632 hbmImage = CreateBitmap(cx, cy, GetDeviceCaps(hdc,PLANES),
633 GetDeviceCaps(hdc,BITSPIXEL), NULL);
634 SelectObject(hdcImage, hbmImage);
635 ImageList_DrawEx(himl, btnPtr->iBitmap, hdcImage, 0, 0, cx, cy,
636 RGB(0xff, 0xff, 0xff), RGB(0,0,0), ILD_NORMAL);
638 /* Create Mask */
639 hdcMask = CreateCompatibleDC(0);
640 hbmMask = CreateBitmap(cx, cy, 1, 1, NULL);
641 SelectObject(hdcMask, hbmMask);
643 /* Remove the background and all white pixels */
644 SetBkColor(hdcImage, ImageList_GetBkColor(himl));
645 BitBlt(hdcMask, 0, 0, cx, cy, hdcImage, 0, 0, SRCCOPY);
646 SetBkColor(hdcImage, RGB(0xff, 0xff, 0xff));
647 BitBlt(hdcMask, 0, 0, cx, cy, hdcImage, 0, 0, NOTSRCERASE);
649 /* draw the new mask 'etched' to hdc */
650 SetBkColor(hdc, RGB(255, 255, 255));
651 SelectObject(hdc, GetSysColorBrush(COLOR_3DHILIGHT));
652 BitBlt(hdc, x + 1, y + 1, cx, cy, hdcMask, 0, 0, 0xE20746);
653 SelectObject(hdc, GetSysColorBrush(COLOR_3DSHADOW));
654 BitBlt(hdc, x, y, cx, cy, hdcMask, 0, 0, 0xE20746);
656 /* Cleanup */
657 DeleteObject(hbmImage);
658 DeleteDC(hdcImage);
659 DeleteObject (hbmMask);
660 DeleteDC(hdcMask);
665 static UINT
666 TOOLBAR_TranslateState(TBUTTON_INFO *btnPtr)
668 UINT retstate = 0;
670 retstate |= (btnPtr->fsState & TBSTATE_CHECKED) ? CDIS_CHECKED : 0;
671 retstate |= (btnPtr->fsState & TBSTATE_PRESSED) ? CDIS_SELECTED : 0;
672 retstate |= (btnPtr->fsState & TBSTATE_ENABLED) ? 0 : CDIS_DISABLED;
673 retstate |= (btnPtr->fsState & TBSTATE_MARKED ) ? CDIS_MARKED : 0;
674 retstate |= (btnPtr->bHot ) ? CDIS_HOT : 0;
675 retstate |= (btnPtr->fsState & TBSTATE_INDETERMINATE) ? CDIS_INDETERMINATE : 0;
676 /* FIXME: don't set CDIS_GRAYED, CDIS_FOCUS, CDIS_DEFAULT */
677 /* don't test TBSTATE_HIDDEN */
678 return retstate;
682 static void
683 TOOLBAR_DrawButton (HWND hwnd, TBUTTON_INFO *btnPtr, HDC hdc)
685 TOOLBAR_INFO *infoPtr = TOOLBAR_GetInfoPtr (hwnd);
686 DWORD dwStyle = GetWindowLongA (hwnd, GWL_STYLE);
687 BOOL hasDropDownArrow = TOOLBAR_HasDropDownArrows(infoPtr->dwExStyle) &&
688 (btnPtr->fsStyle & BTNS_DROPDOWN);
689 RECT rc, rcArrow, rcBitmap, rcText, rcFill;
690 LPWSTR lpText = NULL;
691 NMTBCUSTOMDRAW tbcd;
692 DWORD ntfret;
693 INT offset;
695 if (btnPtr->fsState & TBSTATE_HIDDEN)
696 return;
698 rc = btnPtr->rect;
699 CopyRect (&rcFill, &rc);
700 CopyRect (&rcArrow, &rc);
701 CopyRect(&rcBitmap, &rc);
703 /* get a pointer to the text */
704 lpText = TOOLBAR_GetText(infoPtr, btnPtr);
706 if (hasDropDownArrow)
708 if (dwStyle & TBSTYLE_FLAT)
709 rc.right = max(rc.left, rc.right - DDARROW_WIDTH);
710 else
711 rc.right = max(rc.left, rc.right - DDARROW_WIDTH - 2);
712 rcArrow.left = rc.right;
715 /* copy text rect after adjusting for drop-down arrow
716 * so that text is centred in the rectangle not containing
717 * the arrow */
718 CopyRect(&rcText, &rc);
720 /* Center the bitmap horizontally and vertically */
721 if (dwStyle & TBSTYLE_LIST)
722 rcBitmap.left += LIST_IMAGE_OFFSET;
723 else
724 rcBitmap.left+=(infoPtr->nButtonWidth - infoPtr->nBitmapWidth) / 2;
726 if(lpText)
727 rcBitmap.top+=2; /* this looks to be the correct value from vmware comparison - cmm */
728 else
729 rcBitmap.top+=(infoPtr->nButtonHeight - infoPtr->nBitmapHeight) / 2;
731 TRACE("iBitmap: %d, start=(%ld,%ld) w=%d, h=%d\n",
732 btnPtr->iBitmap, rcBitmap.left, rcBitmap.top,
733 infoPtr->nBitmapWidth, infoPtr->nBitmapHeight);
734 TRACE ("iString: %x\n", btnPtr->iString);
735 TRACE ("Stringtext: %s\n", debugstr_w(lpText));
737 /* draw text */
738 if (lpText) {
740 InflateRect (&rcText, -3, -3);
742 if (GETDEFIMAGELIST(infoPtr, 0) &&
743 TOOLBAR_IsValidBitmapIndex(infoPtr,btnPtr->iBitmap)) {
744 /* The following test looked like this before
745 * I changed it. IE4 "Links" toolbar would not
746 * draw correctly with the original code. - GA 8/01
747 * ((dwStyle & TBSTYLE_LIST) &&
748 * ((btnPtr->fsStyle & BTNS_AUTOSIZE) == 0) &&
749 * (btnPtr->iBitmap != I_IMAGENONE))
751 if (dwStyle & TBSTYLE_LIST) {
752 /* LIST style w/ ICON offset is by matching native. */
753 /* Matches IE4 "Links" bar. - GA 8/01 */
754 rcText.left += (infoPtr->nBitmapWidth + LIST_TEXT_OFFSET);
756 else {
757 rcText.top += infoPtr->nBitmapHeight + 1;
760 else {
761 if (dwStyle & TBSTYLE_LIST) {
762 /* LIST style w/o ICON offset is by matching native. */
763 /* Matches IE4 "menu" bar. - GA 8/01 */
764 rcText.left += LIST_IMAGE_ABSENT_WIDTH + LIST_TEXT_OFFSET;
768 if (btnPtr->fsState & (TBSTATE_PRESSED | TBSTATE_CHECKED))
769 OffsetRect (&rcText, 1, 1);
772 /* Initialize fields in all cases, because we use these later */
773 ZeroMemory (&tbcd, sizeof(NMTBCUSTOMDRAW));
774 tbcd.clrText = comctl32_color.clrBtnText;
775 tbcd.clrTextHighlight = comctl32_color.clrHighlightText;
776 tbcd.clrBtnFace = comctl32_color.clrBtnFace;
777 tbcd.clrBtnHighlight = comctl32_color.clrBtnHighlight;
778 tbcd.clrMark = comctl32_color.clrHighlight;
779 tbcd.clrHighlightHotTrack = 0;
780 tbcd.nStringBkMode = (infoPtr->bBtnTranspnt) ? TRANSPARENT : OPAQUE;
781 tbcd.nHLStringBkMode = (infoPtr->bBtnTranspnt) ? TRANSPARENT : OPAQUE;
782 /* MSDN says that this is the text rectangle. */
783 /* But (why always a but) tracing of v5.7 of native shows */
784 /* that this is really a *relative* rectangle based on the */
785 /* the nmcd.rc. Also the left and top are always 0 ignoring*/
786 /* any bitmap that might be present. */
787 tbcd.rcText.left = 0;
788 tbcd.rcText.top = 0;
789 tbcd.rcText.right = rcText.right - rc.left;
790 tbcd.rcText.bottom = rcText.bottom - rc.top;
791 /* we use this state later on to decide how to draw the buttons */
792 /* NOTE: applications can and do alter this to customize their */
793 /* toolbars */
794 tbcd.nmcd.uItemState = TOOLBAR_TranslateState(btnPtr);
796 /* FIXME: what should these be set to ????? */
797 tbcd.hbrMonoDither = 0;
798 tbcd.hbrLines = 0;
799 tbcd.hpenLines = 0;
801 /* Issue Item Prepaint notify */
802 infoPtr->dwItemCustDraw = 0;
803 infoPtr->dwItemCDFlag = 0;
804 if (infoPtr->dwBaseCustDraw & CDRF_NOTIFYITEMDRAW)
806 tbcd.nmcd.dwDrawStage = CDDS_ITEMPREPAINT;
807 tbcd.nmcd.hdc = hdc;
808 tbcd.nmcd.rc = rc;
809 tbcd.nmcd.dwItemSpec = btnPtr->idCommand;
810 tbcd.nmcd.lItemlParam = btnPtr->dwData;
811 ntfret = TOOLBAR_SendNotify ((NMHDR *)&tbcd, infoPtr, NM_CUSTOMDRAW);
812 infoPtr->dwItemCustDraw = ntfret & 0xffff;
813 infoPtr->dwItemCDFlag = ntfret & 0xffff0000;
814 if (infoPtr->dwItemCustDraw & CDRF_SKIPDEFAULT)
815 return;
816 /* save the only part of the rect that the user can change */
817 rcText.right = tbcd.rcText.right + rc.left;
818 rcText.bottom = tbcd.rcText.bottom + rc.top;
821 if (!infoPtr->bBtnTranspnt)
822 FillRect( hdc, &rcFill, GetSysColorBrush(COLOR_BTNFACE));
824 /* separator */
825 if (btnPtr->fsStyle & BTNS_SEP) {
826 /* with the FLAT style, iBitmap is the width and has already */
827 /* been taken into consideration in calculating the width */
828 /* so now we need to draw the vertical separator */
829 /* empirical tests show that iBitmap can/will be non-zero */
830 /* when drawing the vertical bar... */
831 if ((dwStyle & TBSTYLE_FLAT) /* && (btnPtr->iBitmap == 0) */) {
832 if (btnPtr->fsStyle & BTNS_DROPDOWN)
833 TOOLBAR_DrawDDFlatSeparator (&rc, hdc, btnPtr, infoPtr);
834 else
835 TOOLBAR_DrawFlatSeparator (&rc, hdc, infoPtr);
837 else if (btnPtr->fsStyle != BTNS_SEP) {
838 FIXME("Draw some kind of separator: fsStyle=%x\n",
839 btnPtr->fsStyle);
841 goto FINALNOTIFY;
844 if ((dwStyle & TBSTYLE_FLAT) && (tbcd.nmcd.uItemState & CDIS_HOT))
846 if ( infoPtr->dwItemCDFlag & TBCDRF_HILITEHOTTRACK )
848 COLORREF oldclr;
850 oldclr = SetBkColor(hdc, tbcd.clrHighlightHotTrack);
851 ExtTextOutA(hdc, 0, 0, ETO_OPAQUE, &rc, NULL, 0, 0);
852 if (hasDropDownArrow)
853 ExtTextOutA(hdc, 0, 0, ETO_OPAQUE, &rcArrow, NULL, 0, 0);
854 SetBkColor(hdc, oldclr);
856 else
858 if (!(tbcd.nmcd.uItemState & CDIS_DISABLED) && !(infoPtr->dwItemCDFlag & TBCDRF_NOEDGES))
860 DrawEdge (hdc, &rc, BDR_RAISEDINNER, BF_RECT);
861 if (hasDropDownArrow)
862 DrawEdge (hdc, &rcArrow, BDR_RAISEDINNER, BF_RECT);
867 /* disabled */
868 if (tbcd.nmcd.uItemState & CDIS_DISABLED) {
869 if (!(dwStyle & TBSTYLE_FLAT) && !(infoPtr->dwItemCDFlag & TBCDRF_NOEDGES))
871 DrawEdge (hdc, &rc, EDGE_RAISED,
872 BF_SOFT | BF_RECT | BF_MIDDLE | BF_ADJUST);
873 if (hasDropDownArrow)
874 DrawEdge (hdc, &rcArrow, EDGE_RAISED,
875 BF_SOFT | BF_RECT | BF_MIDDLE | BF_ADJUST);
878 if (hasDropDownArrow)
880 TOOLBAR_DrawArrow(hdc, rcArrow.left+1, rcArrow.top+1 + (rcArrow.bottom - rcArrow.top - ARROW_HEIGHT) / 2, COLOR_3DHIGHLIGHT);
881 TOOLBAR_DrawArrow(hdc, rcArrow.left, rcArrow.top + (rcArrow.bottom - rcArrow.top - ARROW_HEIGHT) / 2, COLOR_3DSHADOW);
884 if (!TOOLBAR_DrawImageList (infoPtr, btnPtr, IMAGE_LIST_DISABLED,
885 hdc, rcBitmap.left, rcBitmap.top,
886 ILD_NORMAL))
887 TOOLBAR_DrawMasked (infoPtr, btnPtr, hdc, rcBitmap.left, rcBitmap.top);
889 if (!(infoPtr->dwExStyle & TBSTYLE_EX_MIXEDBUTTONS) || (btnPtr->fsStyle & BTNS_SHOWTEXT))
890 TOOLBAR_DrawString (infoPtr, btnPtr, hdc, dwStyle, &rcText, lpText, &tbcd);
891 goto FINALNOTIFY;
894 /* pressed BTNS_BUTTON */
895 if (tbcd.nmcd.uItemState & CDIS_SELECTED) {
896 offset = (infoPtr->dwItemCDFlag & TBCDRF_NOOFFSET) ? 0 : 1;
897 if (!(infoPtr->dwItemCDFlag & TBCDRF_NOEDGES))
899 if (dwStyle & TBSTYLE_FLAT)
901 DrawEdge (hdc, &rc, BDR_SUNKENOUTER, BF_RECT | BF_ADJUST);
902 if (hasDropDownArrow)
903 DrawEdge (hdc, &rcArrow, BDR_SUNKENOUTER, BF_RECT | BF_ADJUST);
905 else
907 DrawEdge (hdc, &rc, EDGE_SUNKEN, BF_RECT | BF_MIDDLE | BF_ADJUST);
908 if (hasDropDownArrow)
909 DrawEdge (hdc, &rcArrow, EDGE_SUNKEN, BF_RECT | BF_MIDDLE | BF_ADJUST);
913 if (hasDropDownArrow)
914 TOOLBAR_DrawArrow(hdc, rcArrow.left + offset, rcArrow.top + offset + (rcArrow.bottom - rcArrow.top - ARROW_HEIGHT) / 2, COLOR_WINDOWFRAME);
916 TOOLBAR_DrawImageList (infoPtr, btnPtr, IMAGE_LIST_DEFAULT,
917 hdc, rcBitmap.left+offset, rcBitmap.top+offset,
918 ILD_NORMAL);
920 if (!(infoPtr->dwExStyle & TBSTYLE_EX_MIXEDBUTTONS) || (btnPtr->fsStyle & BTNS_SHOWTEXT))
921 TOOLBAR_DrawString (infoPtr, btnPtr, hdc, dwStyle, &rcText, lpText, &tbcd);
922 goto FINALNOTIFY;
925 /* checked BTNS_CHECK */
926 if ((tbcd.nmcd.uItemState & CDIS_CHECKED) &&
927 (btnPtr->fsStyle & BTNS_CHECK)) {
928 if (!(infoPtr->dwItemCDFlag & TBCDRF_NOEDGES))
930 if (dwStyle & TBSTYLE_FLAT)
931 DrawEdge (hdc, &rc, BDR_SUNKENOUTER,
932 BF_RECT | BF_ADJUST);
933 else
934 DrawEdge (hdc, &rc, EDGE_SUNKEN,
935 BF_RECT | BF_MIDDLE | BF_ADJUST);
938 TOOLBAR_DrawPattern (hdc, &rc);
940 TOOLBAR_DrawImageList (infoPtr, btnPtr, IMAGE_LIST_DEFAULT,
941 hdc, rcBitmap.left+1, rcBitmap.top+1,
942 ILD_NORMAL);
944 if (!(infoPtr->dwExStyle & TBSTYLE_EX_MIXEDBUTTONS) || (btnPtr->fsStyle & BTNS_SHOWTEXT))
945 TOOLBAR_DrawString (infoPtr, btnPtr, hdc, dwStyle, &rcText, lpText, &tbcd);
946 goto FINALNOTIFY;
949 /* indeterminate */
950 if (tbcd.nmcd.uItemState & CDIS_INDETERMINATE) {
951 if (!(infoPtr->dwItemCDFlag & TBCDRF_NOEDGES))
952 DrawEdge (hdc, &rc, EDGE_RAISED,
953 BF_SOFT | BF_RECT | BF_MIDDLE | BF_ADJUST);
955 TOOLBAR_DrawPattern (hdc, &rc);
956 TOOLBAR_DrawMasked (infoPtr, btnPtr, hdc, rcBitmap.left, rcBitmap.top);
957 if (!(infoPtr->dwExStyle & TBSTYLE_EX_MIXEDBUTTONS) || (btnPtr->fsStyle & BTNS_SHOWTEXT))
958 TOOLBAR_DrawString (infoPtr, btnPtr, hdc, dwStyle, &rcText, lpText, &tbcd);
959 goto FINALNOTIFY;
962 /* normal state */
963 if (dwStyle & TBSTYLE_FLAT)
965 if (hasDropDownArrow)
966 TOOLBAR_DrawArrow(hdc, rcArrow.left, rcArrow.top + (rcArrow.bottom - rcArrow.top - ARROW_HEIGHT) / 2, COLOR_WINDOWFRAME);
968 if (tbcd.nmcd.uItemState & CDIS_HOT) {
969 /* if hot, attempt to draw with hot image list, if fails,
970 use default image list */
971 if (!TOOLBAR_DrawImageList (infoPtr, btnPtr,
972 IMAGE_LIST_HOT,
973 hdc, rcBitmap.left,
974 rcBitmap.top, ILD_NORMAL))
975 TOOLBAR_DrawImageList (infoPtr, btnPtr, IMAGE_LIST_DEFAULT,
976 hdc, rcBitmap.left, rcBitmap.top,
977 ILD_NORMAL);
979 else
980 TOOLBAR_DrawImageList (infoPtr, btnPtr, IMAGE_LIST_DEFAULT,
981 hdc, rcBitmap.left, rcBitmap.top,
982 ILD_NORMAL);
984 else
986 if (!(infoPtr->dwItemCDFlag & TBCDRF_NOEDGES))
987 DrawEdge (hdc, &rc, EDGE_RAISED,
988 BF_SOFT | BF_RECT | BF_MIDDLE | BF_ADJUST);
990 if (hasDropDownArrow)
992 if (!(infoPtr->dwItemCDFlag & TBCDRF_NOEDGES))
993 DrawEdge (hdc, &rcArrow, EDGE_RAISED,
994 BF_SOFT | BF_RECT | BF_MIDDLE | BF_ADJUST);
995 TOOLBAR_DrawArrow(hdc, rcArrow.left, rcArrow.top + (rcArrow.bottom - rcArrow.top - ARROW_HEIGHT) / 2, COLOR_WINDOWFRAME);
998 TOOLBAR_DrawImageList (infoPtr, btnPtr, IMAGE_LIST_DEFAULT,
999 hdc, rcBitmap.left, rcBitmap.top,
1000 ILD_NORMAL);
1004 if (!(infoPtr->dwExStyle & TBSTYLE_EX_MIXEDBUTTONS) || (btnPtr->fsStyle & BTNS_SHOWTEXT))
1005 TOOLBAR_DrawString (infoPtr, btnPtr, hdc, dwStyle, &rcText, lpText, &tbcd);
1007 FINALNOTIFY:
1008 if (infoPtr->dwItemCustDraw & CDRF_NOTIFYPOSTPAINT)
1010 tbcd.nmcd.dwDrawStage = CDDS_ITEMPOSTPAINT;
1011 tbcd.nmcd.hdc = hdc;
1012 tbcd.nmcd.rc = rc;
1013 tbcd.nmcd.dwItemSpec = btnPtr->idCommand;
1014 tbcd.nmcd.uItemState = TOOLBAR_TranslateState(btnPtr);
1015 tbcd.nmcd.lItemlParam = btnPtr->dwData;
1016 tbcd.rcText = rcText;
1017 tbcd.nStringBkMode = (infoPtr->bBtnTranspnt) ? TRANSPARENT : OPAQUE;
1018 tbcd.nHLStringBkMode = (infoPtr->bBtnTranspnt) ? TRANSPARENT : OPAQUE;
1019 ntfret = TOOLBAR_SendNotify ((NMHDR *)&tbcd, infoPtr, NM_CUSTOMDRAW);
1025 static void
1026 TOOLBAR_Refresh (HWND hwnd, HDC hdc, PAINTSTRUCT* ps)
1028 TOOLBAR_INFO *infoPtr = TOOLBAR_GetInfoPtr (hwnd);
1029 TBUTTON_INFO *btnPtr;
1030 INT i, oldBKmode = 0;
1031 RECT rcTemp, rcClient;
1032 NMTBCUSTOMDRAW tbcd;
1033 DWORD ntfret;
1035 /* if imagelist belongs to the app, it can be changed
1036 by the app after setting it */
1037 if (GETDEFIMAGELIST(infoPtr, 0) != infoPtr->himlInt)
1039 infoPtr->nNumBitmaps = 0;
1040 for (i = 0; i < infoPtr->cimlDef; i++)
1041 infoPtr->nNumBitmaps += ImageList_GetImageCount(infoPtr->himlDef[i]->himl);
1044 TOOLBAR_DumpToolbar (infoPtr, __LINE__);
1046 /* Send initial notify */
1047 ZeroMemory (&tbcd, sizeof(NMTBCUSTOMDRAW));
1048 tbcd.nmcd.dwDrawStage = CDDS_PREPAINT;
1049 tbcd.nmcd.hdc = hdc;
1050 tbcd.nmcd.rc = ps->rcPaint;
1051 ntfret = TOOLBAR_SendNotify ((NMHDR *)&tbcd, infoPtr, NM_CUSTOMDRAW);
1052 infoPtr->dwBaseCustDraw = ntfret & 0xffff;
1054 if (infoPtr->bBtnTranspnt)
1055 oldBKmode = SetBkMode (hdc, TRANSPARENT);
1057 GetClientRect(hwnd, &rcClient);
1059 /* redraw necessary buttons */
1060 btnPtr = infoPtr->buttons;
1061 for (i = 0; i < infoPtr->nNumButtons; i++, btnPtr++)
1063 BOOL bDraw;
1064 if (infoPtr->dwExStyle & TBSTYLE_EX_HIDECLIPPEDBUTTONS)
1066 IntersectRect(&rcTemp, &rcClient, &btnPtr->rect);
1067 bDraw = EqualRect(&rcTemp, &btnPtr->rect);
1069 else
1070 bDraw = TRUE;
1071 bDraw &= IntersectRect(&rcTemp, &(ps->rcPaint), &(btnPtr->rect));
1072 if (bDraw)
1073 TOOLBAR_DrawButton (hwnd, btnPtr, hdc);
1076 if (infoPtr->bBtnTranspnt && (oldBKmode != TRANSPARENT))
1077 SetBkMode (hdc, oldBKmode);
1079 if (infoPtr->dwBaseCustDraw & CDRF_NOTIFYPOSTPAINT)
1081 ZeroMemory (&tbcd, sizeof(NMTBCUSTOMDRAW));
1082 tbcd.nmcd.dwDrawStage = CDDS_POSTPAINT;
1083 tbcd.nmcd.hdc = hdc;
1084 tbcd.nmcd.rc = ps->rcPaint;
1085 ntfret = TOOLBAR_SendNotify ((NMHDR *)&tbcd, infoPtr, NM_CUSTOMDRAW);
1089 /***********************************************************************
1090 * TOOLBAR_MeasureString
1092 * This function gets the width and height of a string in pixels. This
1093 * is done first by using GetTextExtentPoint to get the basic width
1094 * and height. The DrawText is called with DT_CALCRECT to get the exact
1095 * width. The reason is because the text may have more than one "&" (or
1096 * prefix characters as M$ likes to call them). The prefix character
1097 * indicates where the underline goes, except for the string "&&" which
1098 * is reduced to a single "&". GetTextExtentPoint does not process these
1099 * only DrawText does. Note that the BTNS_NOPREFIX is handled here.
1101 static void
1102 TOOLBAR_MeasureString(TOOLBAR_INFO *infoPtr, TBUTTON_INFO *btnPtr,
1103 HDC hdc, LPSIZE lpSize)
1105 RECT myrect;
1107 lpSize->cx = 0;
1108 lpSize->cy = 0;
1110 if (!(btnPtr->fsState & TBSTATE_HIDDEN) &&
1111 (!(infoPtr->dwExStyle & TBSTYLE_EX_MIXEDBUTTONS) ||
1112 (btnPtr->fsStyle & BTNS_SHOWTEXT)) )
1114 LPWSTR lpText = TOOLBAR_GetText(infoPtr, btnPtr);
1116 if(lpText != NULL) {
1117 /* first get size of all the text */
1118 GetTextExtentPoint32W (hdc, lpText, strlenW (lpText), lpSize);
1120 /* feed above size into the rectangle for DrawText */
1121 myrect.left = myrect.top = 0;
1122 myrect.right = lpSize->cx;
1123 myrect.bottom = lpSize->cy;
1125 /* Use DrawText to get true size as drawn (less pesky "&") */
1126 DrawTextW (hdc, lpText, -1, &myrect, DT_VCENTER | DT_SINGLELINE |
1127 DT_CALCRECT | ((btnPtr->fsStyle & BTNS_NOPREFIX) ?
1128 DT_NOPREFIX : 0));
1130 /* feed back to caller */
1131 lpSize->cx = myrect.right;
1132 lpSize->cy = myrect.bottom;
1136 TRACE("string size %ld x %ld!\n", lpSize->cx, lpSize->cy);
1139 /***********************************************************************
1140 * TOOLBAR_CalcStrings
1142 * This function walks through each string and measures it and returns
1143 * the largest height and width to caller.
1145 static void
1146 TOOLBAR_CalcStrings (HWND hwnd, LPSIZE lpSize)
1148 TOOLBAR_INFO *infoPtr = TOOLBAR_GetInfoPtr (hwnd);
1149 TBUTTON_INFO *btnPtr;
1150 INT i;
1151 SIZE sz;
1152 HDC hdc;
1153 HFONT hOldFont;
1155 lpSize->cx = 0;
1156 lpSize->cy = 0;
1158 hdc = GetDC (hwnd);
1159 hOldFont = SelectObject (hdc, infoPtr->hFont);
1161 btnPtr = infoPtr->buttons;
1162 for (i = 0; i < infoPtr->nNumButtons; i++, btnPtr++) {
1163 if(TOOLBAR_HasText(infoPtr, btnPtr))
1165 TOOLBAR_MeasureString(infoPtr, btnPtr, hdc, &sz);
1166 if (sz.cx > lpSize->cx)
1167 lpSize->cx = sz.cx;
1168 if (sz.cy > lpSize->cy)
1169 lpSize->cy = sz.cy;
1173 SelectObject (hdc, hOldFont);
1174 ReleaseDC (hwnd, hdc);
1176 TRACE("max string size %ld x %ld!\n", lpSize->cx, lpSize->cy);
1179 /***********************************************************************
1180 * TOOLBAR_WrapToolbar
1182 * This function walks through the buttons and separators in the
1183 * toolbar, and sets the TBSTATE_WRAP flag only on those items where
1184 * wrapping should occur based on the width of the toolbar window.
1185 * It does *not* calculate button placement itself. That task
1186 * takes place in TOOLBAR_CalcToolbar. If the program wants to manage
1187 * the toolbar wrapping on its own, it can use the TBSTYLE_WRAPABLE
1188 * flag, and set the TBSTATE_WRAP flags manually on the appropriate items.
1190 * Note: TBSTYLE_WRAPABLE or TBSTYLE_EX_UNDOC1 can be used also to allow
1191 * vertical toolbar lists.
1194 static void
1195 TOOLBAR_WrapToolbar( HWND hwnd, DWORD dwStyle )
1197 TOOLBAR_INFO *infoPtr = TOOLBAR_GetInfoPtr (hwnd);
1198 TBUTTON_INFO *btnPtr;
1199 INT x, cx, i, j;
1200 RECT rc;
1201 BOOL bWrap, bButtonWrap;
1203 /* When the toolbar window style is not TBSTYLE_WRAPABLE, */
1204 /* no layout is necessary. Applications may use this style */
1205 /* to perform their own layout on the toolbar. */
1206 if( !(dwStyle & TBSTYLE_WRAPABLE) &&
1207 !(infoPtr->dwExStyle & TBSTYLE_EX_UNDOC1) ) return;
1209 btnPtr = infoPtr->buttons;
1210 x = infoPtr->nIndent;
1212 /* this can get the parents width, to know how far we can extend
1213 * this toolbar. We cannot use its height, as there may be multiple
1214 * toolbars in a rebar control
1216 GetClientRect( GetParent(hwnd), &rc );
1217 infoPtr->nWidth = rc.right - rc.left;
1218 bButtonWrap = FALSE;
1220 TRACE("start ButtonWidth=%d, BitmapWidth=%d, nWidth=%d, nIndent=%d\n",
1221 infoPtr->nButtonWidth, infoPtr->nBitmapWidth, infoPtr->nWidth,
1222 infoPtr->nIndent);
1224 for (i = 0; i < infoPtr->nNumButtons; i++ )
1226 bWrap = FALSE;
1227 btnPtr[i].fsState &= ~TBSTATE_WRAP;
1229 if (btnPtr[i].fsState & TBSTATE_HIDDEN)
1230 continue;
1232 /* UNDOCUMENTED: If a separator has a non zero bitmap index, */
1233 /* it is the actual width of the separator. This is used for */
1234 /* custom controls in toolbars. */
1235 /* */
1236 /* BTNS_DROPDOWN separators are treated as buttons for */
1237 /* width. - GA 8/01 */
1238 if ((btnPtr[i].fsStyle & BTNS_SEP) &&
1239 !(btnPtr[i].fsStyle & BTNS_DROPDOWN))
1240 cx = (btnPtr[i].iBitmap > 0) ?
1241 btnPtr[i].iBitmap : SEPARATOR_WIDTH;
1242 else
1243 cx = infoPtr->nButtonWidth;
1245 /* Two or more adjacent separators form a separator group. */
1246 /* The first separator in a group should be wrapped to the */
1247 /* next row if the previous wrapping is on a button. */
1248 if( bButtonWrap &&
1249 (btnPtr[i].fsStyle & BTNS_SEP) &&
1250 (i + 1 < infoPtr->nNumButtons ) &&
1251 (btnPtr[i + 1].fsStyle & BTNS_SEP) )
1253 TRACE("wrap point 1 btn %d style %02x\n", i, btnPtr[i].fsStyle);
1254 btnPtr[i].fsState |= TBSTATE_WRAP;
1255 x = infoPtr->nIndent;
1256 i++;
1257 bButtonWrap = FALSE;
1258 continue;
1261 /* The layout makes sure the bitmap is visible, but not the button. */
1262 /* Test added to also wrap after a button that starts a row but */
1263 /* is bigger than the area. - GA 8/01 */
1264 if (( x + cx - (infoPtr->nButtonWidth - infoPtr->nBitmapWidth) / 2
1265 > infoPtr->nWidth ) ||
1266 ((x == infoPtr->nIndent) && (cx > infoPtr->nWidth)))
1268 BOOL bFound = FALSE;
1270 /* If the current button is a separator and not hidden, */
1271 /* go to the next until it reaches a non separator. */
1272 /* Wrap the last separator if it is before a button. */
1273 while( ( ((btnPtr[i].fsStyle & BTNS_SEP) &&
1274 !(btnPtr[i].fsStyle & BTNS_DROPDOWN)) ||
1275 (btnPtr[i].fsState & TBSTATE_HIDDEN) ) &&
1276 i < infoPtr->nNumButtons )
1278 i++;
1279 bFound = TRUE;
1282 if( bFound && i < infoPtr->nNumButtons )
1284 i--;
1285 TRACE("wrap point 2 btn %d style %02x, x=%d, cx=%d\n",
1286 i, btnPtr[i].fsStyle, x, cx);
1287 btnPtr[i].fsState |= TBSTATE_WRAP;
1288 x = infoPtr->nIndent;
1289 bButtonWrap = FALSE;
1290 continue;
1292 else if ( i >= infoPtr->nNumButtons)
1293 break;
1295 /* If the current button is not a separator, find the last */
1296 /* separator and wrap it. */
1297 for ( j = i - 1; j >= 0 && !(btnPtr[j].fsState & TBSTATE_WRAP); j--)
1299 if ((btnPtr[j].fsStyle & BTNS_SEP) &&
1300 !(btnPtr[j].fsState & TBSTATE_HIDDEN))
1302 bFound = TRUE;
1303 i = j;
1304 TRACE("wrap point 3 btn %d style %02x, x=%d, cx=%d\n",
1305 i, btnPtr[i].fsStyle, x, cx);
1306 x = infoPtr->nIndent;
1307 btnPtr[j].fsState |= TBSTATE_WRAP;
1308 bButtonWrap = FALSE;
1309 break;
1313 /* If no separator available for wrapping, wrap one of */
1314 /* non-hidden previous button. */
1315 if (!bFound)
1317 for ( j = i - 1;
1318 j >= 0 && !(btnPtr[j].fsState & TBSTATE_WRAP); j--)
1320 if (btnPtr[j].fsState & TBSTATE_HIDDEN)
1321 continue;
1323 bFound = TRUE;
1324 i = j;
1325 TRACE("wrap point 4 btn %d style %02x, x=%d, cx=%d\n",
1326 i, btnPtr[i].fsStyle, x, cx);
1327 x = infoPtr->nIndent;
1328 btnPtr[j].fsState |= TBSTATE_WRAP;
1329 bButtonWrap = TRUE;
1330 break;
1334 /* If all above failed, wrap the current button. */
1335 if (!bFound)
1337 TRACE("wrap point 5 btn %d style %02x, x=%d, cx=%d\n",
1338 i, btnPtr[i].fsStyle, x, cx);
1339 btnPtr[i].fsState |= TBSTATE_WRAP;
1340 bFound = TRUE;
1341 x = infoPtr->nIndent;
1342 if (btnPtr[i].fsStyle & BTNS_SEP )
1343 bButtonWrap = FALSE;
1344 else
1345 bButtonWrap = TRUE;
1348 else {
1349 TRACE("wrap point 6 btn %d style %02x, x=%d, cx=%d\n",
1350 i, btnPtr[i].fsStyle, x, cx);
1351 x += cx;
1357 /***********************************************************************
1358 * TOOLBAR_CalcToolbar
1360 * This function calculates button and separator placement. It first
1361 * calculates the button sizes, gets the toolbar window width and then
1362 * calls TOOLBAR_WrapToolbar to determine which buttons we need to wrap
1363 * on. It assigns a new location to each item and sends this location to
1364 * the tooltip window if appropriate. Finally, it updates the rcBound
1365 * rect and calculates the new required toolbar window height.
1368 static void
1369 TOOLBAR_CalcToolbar (HWND hwnd)
1371 TOOLBAR_INFO *infoPtr = TOOLBAR_GetInfoPtr(hwnd);
1372 DWORD dwStyle = GetWindowLongA (hwnd, GWL_STYLE);
1373 TBUTTON_INFO *btnPtr;
1374 INT i, nRows, nSepRows;
1375 INT x, y, cx, cy;
1376 SIZE sizeString;
1377 BOOL bWrap;
1378 BOOL usesBitmaps = FALSE;
1379 BOOL hasDropDownArrows = TOOLBAR_HasDropDownArrows(infoPtr->dwExStyle);
1381 TOOLBAR_CalcStrings (hwnd, &sizeString);
1383 for (i = 0; i < infoPtr->nNumButtons && !usesBitmaps; i++)
1385 if (TOOLBAR_IsValidBitmapIndex(infoPtr,infoPtr->buttons[i].iBitmap))
1386 usesBitmaps = TRUE;
1388 if (dwStyle & TBSTYLE_LIST)
1390 infoPtr->nButtonHeight = max((usesBitmaps) ? infoPtr->nBitmapHeight :
1391 0, sizeString.cy) + infoPtr->szPadding.cy;
1392 infoPtr->nButtonWidth = ((usesBitmaps) ? infoPtr->nBitmapWidth :
1393 0) + sizeString.cx + 6;
1394 TRACE("LIST style, But w=%d h=%d, useBitmaps=%d, Bit w=%d h=%d\n",
1395 infoPtr->nButtonWidth, infoPtr->nButtonHeight, usesBitmaps,
1396 infoPtr->nBitmapWidth, infoPtr->nBitmapHeight);
1397 TOOLBAR_DumpToolbar (infoPtr, __LINE__);
1399 else {
1400 if (sizeString.cy > 0)
1402 if (usesBitmaps)
1403 infoPtr->nButtonHeight = sizeString.cy +
1404 2 + /* this is the space to separate text from bitmap */
1405 infoPtr->nBitmapHeight + 6;
1406 else
1407 infoPtr->nButtonHeight = sizeString.cy + 6;
1409 else if (infoPtr->nButtonHeight < infoPtr->nBitmapHeight + 6)
1410 infoPtr->nButtonHeight = infoPtr->nBitmapHeight + 6;
1412 if (sizeString.cx > infoPtr->nBitmapWidth)
1413 infoPtr->nButtonWidth = sizeString.cx + 6;
1414 else if (infoPtr->nButtonWidth < infoPtr->nBitmapWidth + 6)
1415 infoPtr->nButtonWidth = infoPtr->nBitmapWidth + 6;
1418 if ( infoPtr->cxMin >= 0 && infoPtr->nButtonWidth < infoPtr->cxMin )
1419 infoPtr->nButtonWidth = infoPtr->cxMin;
1420 if ( infoPtr->cxMax > 0 && infoPtr->nButtonWidth > infoPtr->cxMax )
1421 infoPtr->nButtonWidth = infoPtr->cxMax;
1423 TOOLBAR_WrapToolbar( hwnd, dwStyle );
1425 x = infoPtr->nIndent;
1426 y = 0;
1429 * We will set the height below, and we set the width on entry
1430 * so we do not reset them here..
1432 #if 0
1433 GetClientRect( hwnd, &rc );
1434 /* get initial values for toolbar */
1435 infoPtr->nWidth = rc.right - rc.left;
1436 infoPtr->nHeight = rc.bottom - rc.top;
1437 #endif
1439 /* from above, minimum is a button, and possible text */
1440 cx = infoPtr->nButtonWidth;
1442 /* cannot use just ButtonHeight, we may have no buttons! */
1443 if (infoPtr->nNumButtons > 0)
1444 infoPtr->nHeight = infoPtr->nButtonHeight;
1446 cy = infoPtr->nHeight;
1448 nRows = nSepRows = 0;
1450 infoPtr->rcBound.top = y;
1451 infoPtr->rcBound.left = x;
1452 infoPtr->rcBound.bottom = y + cy;
1453 infoPtr->rcBound.right = x;
1455 btnPtr = infoPtr->buttons;
1457 /* do not base height/width on parent, if the parent is a */
1458 /* rebar control it could have multiple rows of toolbars */
1459 /* GetClientRect( GetParent(hwnd), &rc ); */
1460 /* cx = rc.right - rc.left; */
1461 /* cy = rc.bottom - rc.top; */
1463 TRACE("cy=%d\n", cy);
1465 for (i = 0; i < infoPtr->nNumButtons; i++, btnPtr++ )
1467 bWrap = FALSE;
1468 if (btnPtr->fsState & TBSTATE_HIDDEN)
1470 SetRectEmpty (&btnPtr->rect);
1471 continue;
1474 cy = infoPtr->nHeight;
1476 /* UNDOCUMENTED: If a separator has a non zero bitmap index, */
1477 /* it is the actual width of the separator. This is used for */
1478 /* custom controls in toolbars. */
1479 if (btnPtr->fsStyle & BTNS_SEP) {
1480 if (btnPtr->fsStyle & BTNS_DROPDOWN) {
1481 cy = (btnPtr->iBitmap > 0) ?
1482 btnPtr->iBitmap : SEPARATOR_WIDTH;
1483 cx = infoPtr->nButtonWidth;
1485 else
1486 cx = (btnPtr->iBitmap > 0) ?
1487 btnPtr->iBitmap : SEPARATOR_WIDTH;
1489 else
1491 if ((infoPtr->dwExStyle & TBSTYLE_EX_MIXEDBUTTONS) ||
1492 (btnPtr->fsStyle & BTNS_AUTOSIZE))
1494 SIZE sz;
1495 HDC hdc;
1496 HFONT hOldFont;
1498 hdc = GetDC (hwnd);
1499 hOldFont = SelectObject (hdc, infoPtr->hFont);
1501 TOOLBAR_MeasureString(infoPtr, btnPtr, hdc, &sz);
1503 SelectObject (hdc, hOldFont);
1504 ReleaseDC (hwnd, hdc);
1506 if (sz.cx > 0)
1507 sz.cx += 2*LIST_TEXT_OFFSET;
1508 cx = sz.cx + 2*LIST_IMAGE_OFFSET;
1509 if (TOOLBAR_TestImageExist (infoPtr, btnPtr, GETDEFIMAGELIST(infoPtr,0)))
1511 if (dwStyle & TBSTYLE_LIST)
1512 cx += infoPtr->nBitmapWidth;
1513 else if (cx < (infoPtr->nBitmapWidth+7))
1514 cx = infoPtr->nBitmapWidth+7;
1516 else if (dwStyle & TBSTYLE_LIST)
1517 cx += LIST_IMAGE_ABSENT_WIDTH;
1519 else
1520 cx = infoPtr->nButtonWidth;
1522 if (hasDropDownArrows && (btnPtr->fsStyle & BTNS_DROPDOWN))
1523 cx += DDARROW_WIDTH;
1525 if (btnPtr->fsState & TBSTATE_WRAP )
1526 bWrap = TRUE;
1528 SetRect (&btnPtr->rect, x, y, x + cx, y + cy);
1530 if (infoPtr->rcBound.left > x)
1531 infoPtr->rcBound.left = x;
1532 if (infoPtr->rcBound.right < x + cx)
1533 infoPtr->rcBound.right = x + cx;
1534 if (infoPtr->rcBound.bottom < y + cy)
1535 infoPtr->rcBound.bottom = y + cy;
1537 /* Set the toolTip only for non-hidden, non-separator button */
1538 if (infoPtr->hwndToolTip && !(btnPtr->fsStyle & BTNS_SEP ))
1540 TTTOOLINFOA ti;
1542 ZeroMemory (&ti, sizeof(TTTOOLINFOA));
1543 ti.cbSize = sizeof(TTTOOLINFOA);
1544 ti.hwnd = hwnd;
1545 ti.uId = btnPtr->idCommand;
1546 ti.rect = btnPtr->rect;
1547 SendMessageA (infoPtr->hwndToolTip, TTM_NEWTOOLRECTA,
1548 0, (LPARAM)&ti);
1551 /* btnPtr->nRow is zero based. The space between the rows is */
1552 /* also considered as a row. */
1553 btnPtr->nRow = nRows + nSepRows;
1555 TRACE("button %d style=%x, bWrap=%d, nRows=%d, nSepRows=%d, btnrow=%d, (%d,%d)-(%d,%d)\n",
1556 i, btnPtr->fsStyle, bWrap, nRows, nSepRows, btnPtr->nRow,
1557 x, y, x+cx, y+cy);
1559 if( bWrap )
1561 if ( !(btnPtr->fsStyle & BTNS_SEP) )
1562 y += cy;
1563 else
1565 /* UNDOCUMENTED: If a separator has a non zero bitmap index, */
1566 /* it is the actual width of the separator. This is used for */
1567 /* custom controls in toolbars. */
1568 if ( !(btnPtr->fsStyle & BTNS_DROPDOWN))
1569 y += cy + ( (btnPtr->iBitmap > 0 ) ?
1570 btnPtr->iBitmap : SEPARATOR_WIDTH) * 2 /3;
1571 else
1572 y += cy;
1574 /* nSepRows is used to calculate the extra height follwoing */
1575 /* the last row. */
1576 nSepRows++;
1578 x = infoPtr->nIndent;
1580 /* Increment row number unless this is the last button */
1581 /* and it has Wrap set. */
1582 if (i != infoPtr->nNumButtons-1)
1583 nRows++;
1585 else
1586 x += cx;
1589 /* infoPtr->nRows is the number of rows on the toolbar */
1590 infoPtr->nRows = nRows + nSepRows + 1;
1592 #if 0
1593 /********************************************************************
1594 * The following while interesting, does not match the values *
1595 * created above for the button rectangles, nor the rcBound rect. *
1596 * We will comment it out and remove it later. *
1598 * The problem showed up as heights in the pager control that was *
1599 * wrong. *
1600 ********************************************************************/
1602 /* nSepRows * (infoPtr->nBitmapHeight + 1) is the space following */
1603 /* the last row. */
1604 infoPtr->nHeight = TOP_BORDER + (nRows + 1) * infoPtr->nButtonHeight +
1605 nSepRows * (SEPARATOR_WIDTH * 2 / 3) +
1606 nSepRows * (infoPtr->nBitmapHeight + 1) +
1607 BOTTOM_BORDER;
1608 #endif
1610 infoPtr->nHeight = infoPtr->rcBound.bottom - infoPtr->rcBound.top;
1612 TRACE("toolbar height %d, button width %d\n", infoPtr->nHeight, infoPtr->nButtonWidth);
1616 static INT
1617 TOOLBAR_InternalHitTest (HWND hwnd, LPPOINT lpPt)
1619 TOOLBAR_INFO *infoPtr = TOOLBAR_GetInfoPtr (hwnd);
1620 TBUTTON_INFO *btnPtr;
1621 INT i;
1623 btnPtr = infoPtr->buttons;
1624 for (i = 0; i < infoPtr->nNumButtons; i++, btnPtr++) {
1625 if (btnPtr->fsState & TBSTATE_HIDDEN)
1626 continue;
1628 if (btnPtr->fsStyle & BTNS_SEP) {
1629 if (PtInRect (&btnPtr->rect, *lpPt)) {
1630 TRACE(" ON SEPARATOR %d!\n", i);
1631 return -i;
1634 else {
1635 if (PtInRect (&btnPtr->rect, *lpPt)) {
1636 TRACE(" ON BUTTON %d!\n", i);
1637 return i;
1642 TRACE(" NOWHERE!\n");
1643 return -1;
1647 static INT
1648 TOOLBAR_GetButtonIndex (TOOLBAR_INFO *infoPtr, INT idCommand, BOOL CommandIsIndex)
1650 TBUTTON_INFO *btnPtr;
1651 INT i;
1653 if (CommandIsIndex) {
1654 TRACE("command is really index command=%d\n", idCommand);
1655 if (idCommand >= infoPtr->nNumButtons) return -1;
1656 return idCommand;
1658 btnPtr = infoPtr->buttons;
1659 for (i = 0; i < infoPtr->nNumButtons; i++, btnPtr++) {
1660 if (btnPtr->idCommand == idCommand) {
1661 TRACE("command=%d index=%d\n", idCommand, i);
1662 return i;
1665 TRACE("no index found for command=%d\n", idCommand);
1666 return -1;
1670 static INT
1671 TOOLBAR_GetCheckedGroupButtonIndex (TOOLBAR_INFO *infoPtr, INT nIndex)
1673 TBUTTON_INFO *btnPtr;
1674 INT nRunIndex;
1676 if ((nIndex < 0) || (nIndex > infoPtr->nNumButtons))
1677 return -1;
1679 /* check index button */
1680 btnPtr = &infoPtr->buttons[nIndex];
1681 if ((btnPtr->fsStyle & BTNS_CHECKGROUP) == BTNS_CHECKGROUP) {
1682 if (btnPtr->fsState & TBSTATE_CHECKED)
1683 return nIndex;
1686 /* check previous buttons */
1687 nRunIndex = nIndex - 1;
1688 while (nRunIndex >= 0) {
1689 btnPtr = &infoPtr->buttons[nRunIndex];
1690 if ((btnPtr->fsStyle & BTNS_CHECKGROUP) == BTNS_CHECKGROUP) {
1691 if (btnPtr->fsState & TBSTATE_CHECKED)
1692 return nRunIndex;
1694 else
1695 break;
1696 nRunIndex--;
1699 /* check next buttons */
1700 nRunIndex = nIndex + 1;
1701 while (nRunIndex < infoPtr->nNumButtons) {
1702 btnPtr = &infoPtr->buttons[nRunIndex];
1703 if ((btnPtr->fsStyle & BTNS_CHECKGROUP) == BTNS_CHECKGROUP) {
1704 if (btnPtr->fsState & TBSTATE_CHECKED)
1705 return nRunIndex;
1707 else
1708 break;
1709 nRunIndex++;
1712 return -1;
1716 static VOID
1717 TOOLBAR_RelayEvent (HWND hwndTip, HWND hwndMsg, UINT uMsg,
1718 WPARAM wParam, LPARAM lParam)
1720 MSG msg;
1722 msg.hwnd = hwndMsg;
1723 msg.message = uMsg;
1724 msg.wParam = wParam;
1725 msg.lParam = lParam;
1726 msg.time = GetMessageTime ();
1727 msg.pt.x = LOWORD(GetMessagePos ());
1728 msg.pt.y = HIWORD(GetMessagePos ());
1730 SendMessageA (hwndTip, TTM_RELAYEVENT, 0, (LPARAM)&msg);
1734 /***********************************************************************
1735 * TOOLBAR_CustomizeDialogProc
1736 * This function implements the toolbar customization dialog.
1738 static INT_PTR CALLBACK
1739 TOOLBAR_CustomizeDialogProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
1741 PCUSTDLG_INFO custInfo = (PCUSTDLG_INFO)GetWindowLongA (hwnd, DWL_USER);
1742 PCUSTOMBUTTON btnInfo;
1743 NMTOOLBARA nmtb;
1744 TOOLBAR_INFO *infoPtr = custInfo ? custInfo->tbInfo : NULL;
1746 switch (uMsg)
1748 case WM_INITDIALOG:
1749 custInfo = (PCUSTDLG_INFO)lParam;
1750 SetWindowLongA (hwnd, DWL_USER, (DWORD)custInfo);
1752 if (custInfo)
1754 WCHAR Buffer[256];
1755 int i = 0;
1756 int index;
1758 infoPtr = custInfo->tbInfo;
1760 /* send TBN_QUERYINSERT notification */
1761 nmtb.iItem = custInfo->tbInfo->nNumButtons;
1763 if (!TOOLBAR_SendNotify ((NMHDR *) &nmtb, infoPtr, TBN_QUERYINSERT))
1764 return FALSE;
1766 /* UNDOCUMENTED: dialog hwnd immediately follows NMHDR */
1767 nmtb.iItem = (int)hwnd;
1768 /* Send TBN_INITCUSTOMIZE notification */
1769 if (TOOLBAR_SendNotify ((NMHDR *) &nmtb, infoPtr, TBN_INITCUSTOMIZE) ==
1770 TBNRF_HIDEHELP)
1772 TRACE("TBNRF_HIDEHELP requested\n");
1773 ShowWindow(GetDlgItem(hwnd, IDC_HELP_BTN), SW_HIDE);
1776 /* add items to 'toolbar buttons' list and check if removable */
1777 for (i = 0; i < custInfo->tbInfo->nNumButtons; i++)
1779 btnInfo = (PCUSTOMBUTTON)Alloc(sizeof(CUSTOMBUTTON));
1780 memset (&btnInfo->btn, 0, sizeof(TBBUTTON));
1781 btnInfo->btn.fsStyle = BTNS_SEP;
1782 btnInfo->bVirtual = FALSE;
1783 LoadStringW (COMCTL32_hModule, IDS_SEPARATOR, btnInfo->text, 64);
1785 /* send TBN_QUERYDELETE notification */
1786 btnInfo->bRemovable = TOOLBAR_IsButtonRemovable(infoPtr, i, btnInfo);
1788 index = (int)SendDlgItemMessageA (hwnd, IDC_TOOLBARBTN_LBOX, LB_ADDSTRING, 0, 0);
1789 SendDlgItemMessageA (hwnd, IDC_TOOLBARBTN_LBOX, LB_SETITEMDATA, index, (LPARAM)btnInfo);
1792 /* insert separator button into 'available buttons' list */
1793 btnInfo = (PCUSTOMBUTTON)Alloc(sizeof(CUSTOMBUTTON));
1794 memset (&btnInfo->btn, 0, sizeof(TBBUTTON));
1795 btnInfo->btn.fsStyle = BTNS_SEP;
1796 btnInfo->bVirtual = FALSE;
1797 btnInfo->bRemovable = TRUE;
1798 LoadStringW (COMCTL32_hModule, IDS_SEPARATOR, btnInfo->text, 64);
1799 index = (int)SendDlgItemMessageA (hwnd, IDC_AVAILBTN_LBOX, LB_ADDSTRING, 0, (LPARAM)btnInfo);
1800 SendDlgItemMessageA (hwnd, IDC_AVAILBTN_LBOX, LB_SETITEMDATA, index, (LPARAM)btnInfo);
1802 /* insert all buttons into dsa */
1803 for (i = 0;; i++)
1805 /* send TBN_GETBUTTONINFO notification */
1806 NMTOOLBARW nmtb;
1807 nmtb.iItem = i;
1808 nmtb.pszText = Buffer;
1809 nmtb.cchText = 256;
1811 /* Clear previous button's text */
1812 ZeroMemory(nmtb.pszText, nmtb.cchText * sizeof(WCHAR));
1814 if (!TOOLBAR_GetButtonInfo(infoPtr, &nmtb))
1815 break;
1817 TRACE("WM_INITDIALOG style: %x iItem(%d) idCommand(%d) iString(%d) %s\n",
1818 nmtb.tbButton.fsStyle, i,
1819 nmtb.tbButton.idCommand,
1820 nmtb.tbButton.iString,
1821 nmtb.tbButton.iString >= 0 ? debugstr_w(infoPtr->strings[nmtb.tbButton.iString])
1822 : "");
1824 /* insert button into the apropriate list */
1825 index = TOOLBAR_GetButtonIndex (custInfo->tbInfo, nmtb.tbButton.idCommand, FALSE);
1826 if (index == -1)
1828 btnInfo = (PCUSTOMBUTTON)Alloc(sizeof(CUSTOMBUTTON));
1829 btnInfo->bVirtual = FALSE;
1830 btnInfo->bRemovable = TRUE;
1832 index = SendDlgItemMessageA (hwnd, IDC_AVAILBTN_LBOX, LB_ADDSTRING, 0, 0);
1833 SendDlgItemMessageA (hwnd, IDC_AVAILBTN_LBOX,
1834 LB_SETITEMDATA, index, (LPARAM)btnInfo);
1836 else
1838 btnInfo = (PCUSTOMBUTTON)SendDlgItemMessageA (hwnd,
1839 IDC_TOOLBARBTN_LBOX, LB_GETITEMDATA, index, 0);
1842 memcpy (&btnInfo->btn, &nmtb.tbButton, sizeof(TBBUTTON));
1843 if (!(nmtb.tbButton.fsStyle & BTNS_SEP))
1845 if (lstrlenW(nmtb.pszText))
1846 lstrcpyW(btnInfo->text, nmtb.pszText);
1847 else if (nmtb.tbButton.iString >= 0 &&
1848 nmtb.tbButton.iString < infoPtr->nNumStrings)
1850 lstrcpyW(btnInfo->text,
1851 infoPtr->strings[nmtb.tbButton.iString]);
1856 /* select first item in the 'available' list */
1857 SendDlgItemMessageA (hwnd, IDC_AVAILBTN_LBOX, LB_SETCURSEL, 0, 0);
1859 /* append 'virtual' separator button to the 'toolbar buttons' list */
1860 btnInfo = (PCUSTOMBUTTON)Alloc(sizeof(CUSTOMBUTTON));
1861 memset (&btnInfo->btn, 0, sizeof(TBBUTTON));
1862 btnInfo->btn.fsStyle = BTNS_SEP;
1863 btnInfo->bVirtual = TRUE;
1864 btnInfo->bRemovable = FALSE;
1865 LoadStringW (COMCTL32_hModule, IDS_SEPARATOR, btnInfo->text, 64);
1866 index = (int)SendDlgItemMessageA (hwnd, IDC_TOOLBARBTN_LBOX, LB_ADDSTRING, 0, (LPARAM)btnInfo);
1867 SendDlgItemMessageA (hwnd, IDC_TOOLBARBTN_LBOX, LB_SETITEMDATA, index, (LPARAM)btnInfo);
1869 /* select last item in the 'toolbar' list */
1870 SendDlgItemMessageA (hwnd, IDC_TOOLBARBTN_LBOX, LB_SETCURSEL, index, 0);
1871 SendDlgItemMessageA (hwnd, IDC_TOOLBARBTN_LBOX, LB_SETTOPINDEX, index, 0);
1873 /* set focus and disable buttons */
1874 PostMessageA (hwnd, WM_USER, 0, 0);
1876 return TRUE;
1878 case WM_USER:
1879 EnableWindow (GetDlgItem (hwnd,IDC_MOVEUP_BTN), FALSE);
1880 EnableWindow (GetDlgItem (hwnd,IDC_MOVEDN_BTN), FALSE);
1881 EnableWindow (GetDlgItem (hwnd,IDC_REMOVE_BTN), FALSE);
1882 SetFocus (GetDlgItem (hwnd, IDC_TOOLBARBTN_LBOX));
1883 return TRUE;
1885 case WM_CLOSE:
1886 EndDialog(hwnd, FALSE);
1887 return TRUE;
1889 case WM_COMMAND:
1890 switch (LOWORD(wParam))
1892 case IDC_TOOLBARBTN_LBOX:
1893 if (HIWORD(wParam) == LBN_SELCHANGE)
1895 PCUSTOMBUTTON btnInfo;
1896 NMTOOLBARA nmtb;
1897 int count;
1898 int index;
1900 count = SendDlgItemMessageA (hwnd, IDC_TOOLBARBTN_LBOX, LB_GETCOUNT, 0, 0);
1901 index = SendDlgItemMessageA (hwnd, IDC_TOOLBARBTN_LBOX, LB_GETCURSEL, 0, 0);
1903 /* send TBN_QUERYINSERT notification */
1904 nmtb.iItem = index;
1905 TOOLBAR_SendNotify ((NMHDR *) &nmtb, infoPtr,
1906 TBN_QUERYINSERT);
1908 /* get list box item */
1909 btnInfo = (PCUSTOMBUTTON)SendDlgItemMessageA (hwnd, IDC_TOOLBARBTN_LBOX, LB_GETITEMDATA, index, 0);
1911 if (index == (count - 1))
1913 /* last item (virtual separator) */
1914 EnableWindow (GetDlgItem (hwnd,IDC_MOVEUP_BTN), FALSE);
1915 EnableWindow (GetDlgItem (hwnd,IDC_MOVEDN_BTN), FALSE);
1917 else if (index == (count - 2))
1919 /* second last item (last non-virtual item) */
1920 EnableWindow (GetDlgItem (hwnd,IDC_MOVEUP_BTN), TRUE);
1921 EnableWindow (GetDlgItem (hwnd,IDC_MOVEDN_BTN), FALSE);
1923 else if (index == 0)
1925 /* first item */
1926 EnableWindow (GetDlgItem (hwnd,IDC_MOVEUP_BTN), FALSE);
1927 EnableWindow (GetDlgItem (hwnd,IDC_MOVEDN_BTN), TRUE);
1929 else
1931 EnableWindow (GetDlgItem (hwnd,IDC_MOVEUP_BTN), TRUE);
1932 EnableWindow (GetDlgItem (hwnd,IDC_MOVEDN_BTN), TRUE);
1935 EnableWindow (GetDlgItem (hwnd,IDC_REMOVE_BTN), btnInfo->bRemovable);
1937 break;
1939 case IDC_MOVEUP_BTN:
1941 PCUSTOMBUTTON btnInfo;
1942 int index;
1943 int count;
1945 count = SendDlgItemMessageA (hwnd, IDC_TOOLBARBTN_LBOX, LB_GETCOUNT, 0, 0);
1946 index = SendDlgItemMessageA (hwnd, IDC_TOOLBARBTN_LBOX, LB_GETCURSEL, 0, 0);
1947 TRACE("Move up: index %d\n", index);
1949 /* send TBN_QUERYINSERT notification */
1950 nmtb.iItem = index;
1952 if (TOOLBAR_SendNotify ((NMHDR *) &nmtb, infoPtr,
1953 TBN_QUERYINSERT))
1955 btnInfo = (PCUSTOMBUTTON)SendDlgItemMessageA (hwnd, IDC_TOOLBARBTN_LBOX, LB_GETITEMDATA, index, 0);
1957 SendDlgItemMessageA (hwnd, IDC_TOOLBARBTN_LBOX, LB_DELETESTRING, index, 0);
1958 SendDlgItemMessageA (hwnd, IDC_TOOLBARBTN_LBOX, LB_INSERTSTRING, index-1, 0);
1959 SendDlgItemMessageA (hwnd, IDC_TOOLBARBTN_LBOX, LB_SETITEMDATA, index-1, (LPARAM)btnInfo);
1960 SendDlgItemMessageA (hwnd, IDC_TOOLBARBTN_LBOX, LB_SETCURSEL, index-1 , 0);
1962 if (index <= 1)
1963 EnableWindow (GetDlgItem (hwnd,IDC_MOVEUP_BTN), FALSE);
1964 else if (index >= (count - 3))
1965 EnableWindow (GetDlgItem (hwnd,IDC_MOVEDN_BTN), TRUE);
1967 SendMessageA (custInfo->tbHwnd, TB_DELETEBUTTON, index, 0);
1968 SendMessageA (custInfo->tbHwnd, TB_INSERTBUTTONA, index-1, (LPARAM)&(btnInfo->btn));
1971 break;
1973 case IDC_MOVEDN_BTN: /* move down */
1975 PCUSTOMBUTTON btnInfo;
1976 int index;
1977 int count;
1979 count = SendDlgItemMessageA (hwnd, IDC_TOOLBARBTN_LBOX, LB_GETCOUNT, 0, 0);
1980 index = SendDlgItemMessageA (hwnd, IDC_TOOLBARBTN_LBOX, LB_GETCURSEL, 0, 0);
1981 TRACE("Move up: index %d\n", index);
1983 /* send TBN_QUERYINSERT notification */
1984 nmtb.iItem = index;
1985 if (TOOLBAR_SendNotify ((NMHDR *) &nmtb, infoPtr,
1986 TBN_QUERYINSERT))
1988 btnInfo = (PCUSTOMBUTTON)SendDlgItemMessageA (hwnd, IDC_TOOLBARBTN_LBOX, LB_GETITEMDATA, index, 0);
1990 /* move button down */
1991 SendDlgItemMessageA (hwnd, IDC_TOOLBARBTN_LBOX, LB_DELETESTRING, index, 0);
1992 SendDlgItemMessageA (hwnd, IDC_TOOLBARBTN_LBOX, LB_INSERTSTRING, index+1, 0);
1993 SendDlgItemMessageA (hwnd, IDC_TOOLBARBTN_LBOX, LB_SETITEMDATA, index+1, (LPARAM)btnInfo);
1994 SendDlgItemMessageA (hwnd, IDC_TOOLBARBTN_LBOX, LB_SETCURSEL, index+1 , 0);
1996 if (index == 0)
1997 EnableWindow (GetDlgItem (hwnd,IDC_MOVEUP_BTN), TRUE);
1998 else if (index >= (count - 3))
1999 EnableWindow (GetDlgItem (hwnd,IDC_MOVEDN_BTN), FALSE);
2001 SendMessageA (custInfo->tbHwnd, TB_DELETEBUTTON, index, 0);
2002 SendMessageA (custInfo->tbHwnd, TB_INSERTBUTTONA, index+1, (LPARAM)&(btnInfo->btn));
2005 break;
2007 case IDC_REMOVE_BTN: /* remove button */
2009 PCUSTOMBUTTON btnInfo;
2010 int index;
2012 index = SendDlgItemMessageA (hwnd, IDC_TOOLBARBTN_LBOX, LB_GETCURSEL, 0, 0);
2014 if (LB_ERR == index)
2015 break;
2017 TRACE("Remove: index %d\n", index);
2019 btnInfo = (PCUSTOMBUTTON)SendDlgItemMessageA (hwnd, IDC_TOOLBARBTN_LBOX,
2020 LB_GETITEMDATA, index, 0);
2022 /* send TBN_QUERYDELETE notification */
2023 if (TOOLBAR_IsButtonRemovable(infoPtr, index, btnInfo))
2025 btnInfo = (PCUSTOMBUTTON)SendDlgItemMessageA (hwnd, IDC_TOOLBARBTN_LBOX, LB_GETITEMDATA, index, 0);
2026 SendDlgItemMessageA (hwnd, IDC_TOOLBARBTN_LBOX, LB_DELETESTRING, index, 0);
2027 SendDlgItemMessageA (hwnd, IDC_TOOLBARBTN_LBOX, LB_SETCURSEL, index , 0);
2029 SendMessageA (custInfo->tbHwnd, TB_DELETEBUTTON, index, 0);
2031 /* insert into 'available button' list */
2032 if (!(btnInfo->btn.fsStyle & BTNS_SEP))
2034 index = (int)SendDlgItemMessageA (hwnd, IDC_AVAILBTN_LBOX, LB_ADDSTRING, 0, 0);
2035 SendDlgItemMessageA (hwnd, IDC_AVAILBTN_LBOX, LB_SETITEMDATA, index, (LPARAM)btnInfo);
2037 else
2038 Free (btnInfo);
2041 break;
2042 case IDC_HELP_BTN:
2043 TOOLBAR_SendNotify(&nmtb.hdr, infoPtr, TBN_CUSTHELP);
2044 break;
2045 case IDC_RESET_BTN:
2046 TOOLBAR_SendNotify(&nmtb.hdr, infoPtr, TBN_RESET);
2047 break;
2049 case IDOK: /* Add button */
2051 int index;
2052 int count;
2054 count = SendDlgItemMessageA (hwnd, IDC_AVAILBTN_LBOX, LB_GETCOUNT, 0, 0);
2055 index = SendDlgItemMessageA (hwnd, IDC_AVAILBTN_LBOX, LB_GETCURSEL, 0, 0);
2056 TRACE("Add: index %d\n", index);
2058 /* send TBN_QUERYINSERT notification */
2059 nmtb.iItem = index;
2060 if (TOOLBAR_SendNotify ((NMHDR *) &nmtb, infoPtr,
2061 TBN_QUERYINSERT))
2063 btnInfo = (PCUSTOMBUTTON)SendDlgItemMessageA (hwnd, IDC_AVAILBTN_LBOX, LB_GETITEMDATA, index, 0);
2065 if (index != 0)
2067 /* remove from 'available buttons' list */
2068 SendDlgItemMessageA (hwnd, IDC_AVAILBTN_LBOX, LB_DELETESTRING, index, 0);
2069 if (index == count-1)
2070 SendDlgItemMessageA (hwnd, IDC_AVAILBTN_LBOX, LB_SETCURSEL, index-1 , 0);
2071 else
2072 SendDlgItemMessageA (hwnd, IDC_AVAILBTN_LBOX, LB_SETCURSEL, index , 0);
2074 else
2076 PCUSTOMBUTTON btnNew;
2078 /* duplicate 'separator' button */
2079 btnNew = (PCUSTOMBUTTON)Alloc (sizeof(CUSTOMBUTTON));
2080 memcpy (btnNew, btnInfo, sizeof(CUSTOMBUTTON));
2081 btnInfo = btnNew;
2084 /* insert into 'toolbar button' list */
2085 index = SendDlgItemMessageA (hwnd, IDC_TOOLBARBTN_LBOX, LB_GETCURSEL, 0, 0);
2086 SendDlgItemMessageA (hwnd, IDC_TOOLBARBTN_LBOX, LB_INSERTSTRING, index, 0);
2087 SendDlgItemMessageA (hwnd, IDC_TOOLBARBTN_LBOX, LB_SETITEMDATA, index, (LPARAM)btnInfo);
2089 SendMessageA (custInfo->tbHwnd, TB_INSERTBUTTONA, index, (LPARAM)&(btnInfo->btn));
2092 break;
2094 case IDCANCEL:
2095 EndDialog(hwnd, FALSE);
2096 break;
2098 return TRUE;
2100 case WM_DESTROY:
2102 int count;
2103 int i;
2105 /* delete items from 'toolbar buttons' listbox*/
2106 count = SendDlgItemMessageA (hwnd, IDC_TOOLBARBTN_LBOX, LB_GETCOUNT, 0, 0);
2107 for (i = 0; i < count; i++)
2109 btnInfo = (PCUSTOMBUTTON)SendDlgItemMessageA (hwnd, IDC_TOOLBARBTN_LBOX, LB_GETITEMDATA, i, 0);
2110 Free(btnInfo);
2111 SendDlgItemMessageA (hwnd, IDC_TOOLBARBTN_LBOX, LB_SETITEMDATA, 0, 0);
2113 SendDlgItemMessageA (hwnd, IDC_TOOLBARBTN_LBOX, LB_RESETCONTENT, 0, 0);
2116 /* delete items from 'available buttons' listbox*/
2117 count = SendDlgItemMessageA (hwnd, IDC_AVAILBTN_LBOX, LB_GETCOUNT, 0, 0);
2118 for (i = 0; i < count; i++)
2120 btnInfo = (PCUSTOMBUTTON)SendDlgItemMessageA (hwnd, IDC_AVAILBTN_LBOX, LB_GETITEMDATA, i, 0);
2121 Free(btnInfo);
2122 SendDlgItemMessageA (hwnd, IDC_AVAILBTN_LBOX, LB_SETITEMDATA, i, 0);
2124 SendDlgItemMessageA (hwnd, IDC_AVAILBTN_LBOX, LB_RESETCONTENT, 0, 0);
2126 return TRUE;
2128 case WM_DRAWITEM:
2129 if (wParam == IDC_AVAILBTN_LBOX || wParam == IDC_TOOLBARBTN_LBOX)
2131 LPDRAWITEMSTRUCT lpdis = (LPDRAWITEMSTRUCT)lParam;
2132 DWORD dwStyle = GetWindowLongA (infoPtr->hwndSelf, GWL_STYLE);
2133 RECT rcButton;
2134 RECT rcText;
2135 HPEN hPen, hOldPen;
2136 HBRUSH hOldBrush;
2137 COLORREF oldText = 0;
2138 COLORREF oldBk = 0;
2140 /* get item data */
2141 btnInfo = (PCUSTOMBUTTON)SendDlgItemMessageA (hwnd, wParam, LB_GETITEMDATA, (WPARAM)lpdis->itemID, 0);
2142 if (btnInfo == NULL)
2144 FIXME("btnInfo invalid!\n");
2145 return TRUE;
2148 /* set colors and select objects */
2149 oldBk = SetBkColor (lpdis->hDC, (lpdis->itemState & ODS_FOCUS)?comctl32_color.clrHighlight:comctl32_color.clrWindow);
2150 if (btnInfo->bVirtual)
2151 oldText = SetTextColor (lpdis->hDC, comctl32_color.clrGrayText);
2152 else
2153 oldText = SetTextColor (lpdis->hDC, (lpdis->itemState & ODS_FOCUS)?comctl32_color.clrHighlightText:comctl32_color.clrWindowText);
2154 hPen = CreatePen( PS_SOLID, 1,
2155 GetSysColor( (lpdis->itemState & ODS_SELECTED)?COLOR_HIGHLIGHT:COLOR_WINDOW));
2156 hOldPen = SelectObject (lpdis->hDC, hPen );
2157 hOldBrush = SelectObject (lpdis->hDC, GetSysColorBrush ((lpdis->itemState & ODS_FOCUS)?COLOR_HIGHLIGHT:COLOR_WINDOW));
2159 /* fill background rectangle */
2160 Rectangle (lpdis->hDC, lpdis->rcItem.left, lpdis->rcItem.top,
2161 lpdis->rcItem.right, lpdis->rcItem.bottom);
2163 /* calculate button and text rectangles */
2164 CopyRect (&rcButton, &lpdis->rcItem);
2165 InflateRect (&rcButton, -1, -1);
2166 CopyRect (&rcText, &rcButton);
2167 rcButton.right = rcButton.left + custInfo->tbInfo->nBitmapWidth + 6;
2168 rcText.left = rcButton.right + 2;
2170 /* draw focus rectangle */
2171 if (lpdis->itemState & ODS_FOCUS)
2172 DrawFocusRect (lpdis->hDC, &lpdis->rcItem);
2174 /* draw button */
2175 if (!(dwStyle & TBSTYLE_FLAT))
2176 DrawEdge (lpdis->hDC, &rcButton, EDGE_RAISED, BF_RECT|BF_MIDDLE|BF_SOFT);
2178 /* draw image and text */
2179 if ((btnInfo->btn.fsStyle & BTNS_SEP) == 0) {
2180 HIMAGELIST himl = GETDEFIMAGELIST(infoPtr, GETHIMLID(infoPtr,
2181 btnInfo->btn.iBitmap));
2182 ImageList_Draw (himl, GETIBITMAP(infoPtr, btnInfo->btn.iBitmap),
2183 lpdis->hDC, rcButton.left+3, rcButton.top+3, ILD_NORMAL);
2185 DrawTextW (lpdis->hDC, btnInfo->text, -1, &rcText,
2186 DT_LEFT | DT_VCENTER | DT_SINGLELINE);
2188 /* delete objects and reset colors */
2189 SelectObject (lpdis->hDC, hOldBrush);
2190 SelectObject (lpdis->hDC, hOldPen);
2191 SetBkColor (lpdis->hDC, oldBk);
2192 SetTextColor (lpdis->hDC, oldText);
2193 DeleteObject( hPen );
2194 return TRUE;
2196 return FALSE;
2198 case WM_MEASUREITEM:
2199 if (wParam == IDC_AVAILBTN_LBOX || wParam == IDC_TOOLBARBTN_LBOX)
2201 MEASUREITEMSTRUCT *lpmis = (MEASUREITEMSTRUCT*)lParam;
2203 if (custInfo && custInfo->tbInfo)
2204 lpmis->itemHeight = custInfo->tbInfo->nBitmapHeight + 8;
2205 else
2206 lpmis->itemHeight = 15 + 8; /* default height */
2208 return TRUE;
2210 return FALSE;
2212 default:
2213 return FALSE;
2218 /***********************************************************************
2219 * TOOLBAR_AddBitmap: Add the bitmaps to the default image list.
2222 static LRESULT
2223 TOOLBAR_AddBitmap (HWND hwnd, WPARAM wParam, LPARAM lParam)
2225 TOOLBAR_INFO *infoPtr = TOOLBAR_GetInfoPtr (hwnd);
2226 LPTBADDBITMAP lpAddBmp = (LPTBADDBITMAP)lParam;
2227 INT nIndex = 0, nButtons, nCount;
2228 HBITMAP hbmLoad;
2229 HIMAGELIST himlDef;
2231 TRACE("hwnd=%p wParam=%x lParam=%lx\n", hwnd, wParam, lParam);
2232 if (!lpAddBmp)
2233 return -1;
2235 if (lpAddBmp->hInst == HINST_COMMCTRL)
2237 if ((lpAddBmp->nID & ~1) == IDB_STD_SMALL_COLOR)
2238 nButtons = 15;
2239 else if ((lpAddBmp->nID & ~1) == IDB_VIEW_SMALL_COLOR)
2240 nButtons = 13;
2241 else if ((lpAddBmp->nID & ~1) == IDB_HIST_SMALL_COLOR)
2242 nButtons = 5;
2243 else
2244 return -1;
2246 TRACE ("adding %d internal bitmaps!\n", nButtons);
2248 /* Windows resize all the buttons to the size of a newly added standard image */
2249 if (lpAddBmp->nID & 1)
2251 /* large icons */
2252 /* FIXME: on windows the size of the images is 25x24 but the size of the bitmap
2253 * in rsrc is only 24x24. Fix the bitmap (how?) and then fix this
2255 SendMessageA (hwnd, TB_SETBITMAPSIZE, 0,
2256 MAKELPARAM((WORD)24, (WORD)24));
2257 SendMessageA (hwnd, TB_SETBUTTONSIZE, 0,
2258 MAKELPARAM((WORD)31, (WORD)30));
2260 else
2262 /* small icons */
2263 SendMessageA (hwnd, TB_SETBITMAPSIZE, 0,
2264 MAKELPARAM((WORD)16, (WORD)16));
2265 SendMessageA (hwnd, TB_SETBUTTONSIZE, 0,
2266 MAKELPARAM((WORD)22, (WORD)22));
2269 TOOLBAR_CalcToolbar (hwnd);
2271 else
2273 nButtons = (INT)wParam;
2274 if (nButtons <= 0)
2275 return -1;
2277 TRACE ("adding %d bitmaps!\n", nButtons);
2280 if (!infoPtr->cimlDef) {
2281 /* create new default image list */
2282 TRACE ("creating default image list!\n");
2284 himlDef = ImageList_Create (infoPtr->nBitmapWidth, infoPtr->nBitmapHeight,
2285 ILC_COLOR | ILC_MASK, nButtons, 2);
2286 TOOLBAR_InsertImageList(&infoPtr->himlDef, &infoPtr->cimlDef, himlDef, 0);
2287 infoPtr->himlInt = himlDef;
2289 else {
2290 himlDef = GETDEFIMAGELIST(infoPtr, 0);
2293 if (!himlDef) {
2294 WARN("No default image list available\n");
2295 return -1;
2298 nCount = ImageList_GetImageCount(himlDef);
2300 /* Add bitmaps to the default image list */
2301 if (lpAddBmp->hInst == NULL)
2303 BITMAP bmp;
2304 HBITMAP hOldBitmapBitmap, hOldBitmapLoad;
2305 HDC hdcImage, hdcBitmap;
2307 /* copy the bitmap before adding it so that the user's bitmap
2308 * doesn't get modified.
2310 GetObjectA ((HBITMAP)lpAddBmp->nID, sizeof(BITMAP), (LPVOID)&bmp);
2312 hdcImage = CreateCompatibleDC(0);
2313 hdcBitmap = CreateCompatibleDC(0);
2315 /* create new bitmap */
2316 hbmLoad = CreateBitmap (bmp.bmWidth, bmp.bmHeight, bmp.bmPlanes, bmp.bmBitsPixel, NULL);
2317 hOldBitmapBitmap = SelectObject(hdcBitmap, (HBITMAP)lpAddBmp->nID);
2318 hOldBitmapLoad = SelectObject(hdcImage, hbmLoad);
2320 /* Copy the user's image */
2321 BitBlt (hdcImage, 0, 0, bmp.bmWidth, bmp.bmHeight,
2322 hdcBitmap, 0, 0, SRCCOPY);
2324 SelectObject (hdcImage, hOldBitmapLoad);
2325 SelectObject (hdcBitmap, hOldBitmapBitmap);
2326 DeleteDC (hdcImage);
2327 DeleteDC (hdcBitmap);
2329 nIndex = ImageList_AddMasked (himlDef, hbmLoad, comctl32_color.clrBtnFace);
2330 DeleteObject (hbmLoad);
2332 else if (lpAddBmp->hInst == HINST_COMMCTRL)
2334 /* Add system bitmaps */
2335 switch (lpAddBmp->nID)
2337 case IDB_STD_SMALL_COLOR:
2338 hbmLoad = LoadBitmapA (COMCTL32_hModule,
2339 MAKEINTRESOURCEA(IDB_STD_SMALL));
2340 nIndex = ImageList_AddMasked (himlDef,
2341 hbmLoad, comctl32_color.clrBtnFace);
2342 DeleteObject (hbmLoad);
2343 break;
2345 case IDB_STD_LARGE_COLOR:
2346 hbmLoad = LoadBitmapA (COMCTL32_hModule,
2347 MAKEINTRESOURCEA(IDB_STD_LARGE));
2348 nIndex = ImageList_AddMasked (himlDef,
2349 hbmLoad, comctl32_color.clrBtnFace);
2350 DeleteObject (hbmLoad);
2351 break;
2353 case IDB_VIEW_SMALL_COLOR:
2354 hbmLoad = LoadBitmapA (COMCTL32_hModule,
2355 MAKEINTRESOURCEA(IDB_VIEW_SMALL));
2356 nIndex = ImageList_AddMasked (himlDef,
2357 hbmLoad, comctl32_color.clrBtnFace);
2358 DeleteObject (hbmLoad);
2359 break;
2361 case IDB_VIEW_LARGE_COLOR:
2362 hbmLoad = LoadBitmapA (COMCTL32_hModule,
2363 MAKEINTRESOURCEA(IDB_VIEW_LARGE));
2364 nIndex = ImageList_AddMasked (himlDef,
2365 hbmLoad, comctl32_color.clrBtnFace);
2366 DeleteObject (hbmLoad);
2367 break;
2369 case IDB_HIST_SMALL_COLOR:
2370 hbmLoad = LoadBitmapA (COMCTL32_hModule,
2371 MAKEINTRESOURCEA(IDB_HIST_SMALL));
2372 nIndex = ImageList_AddMasked (himlDef,
2373 hbmLoad, comctl32_color.clrBtnFace);
2374 DeleteObject (hbmLoad);
2375 break;
2377 case IDB_HIST_LARGE_COLOR:
2378 hbmLoad = LoadBitmapA (COMCTL32_hModule,
2379 MAKEINTRESOURCEA(IDB_HIST_LARGE));
2380 nIndex = ImageList_AddMasked (himlDef,
2381 hbmLoad, comctl32_color.clrBtnFace);
2382 DeleteObject (hbmLoad);
2383 break;
2385 default:
2386 nIndex = ImageList_GetImageCount (himlDef);
2387 ERR ("invalid imagelist!\n");
2388 break;
2391 else
2393 hbmLoad = LoadBitmapA (lpAddBmp->hInst, (LPSTR)lpAddBmp->nID);
2394 nIndex = ImageList_AddMasked (himlDef, hbmLoad, comctl32_color.clrBtnFace);
2395 DeleteObject (hbmLoad);
2398 TRACE("Number of bitmap infos: %d\n", infoPtr->nNumBitmapInfos);
2400 if (infoPtr->nNumBitmapInfos == 0)
2402 infoPtr->bitmaps = Alloc(sizeof(TBITMAP_INFO));
2404 else
2406 TBITMAP_INFO *oldBitmaps = infoPtr->bitmaps;
2407 infoPtr->bitmaps = Alloc((infoPtr->nNumBitmapInfos + 1) * sizeof(TBITMAP_INFO));
2408 memcpy(&infoPtr->bitmaps[0], &oldBitmaps[0], infoPtr->nNumBitmapInfos);
2411 infoPtr->bitmaps[infoPtr->nNumBitmapInfos].nButtons = nButtons;
2412 infoPtr->bitmaps[infoPtr->nNumBitmapInfos].hInst = lpAddBmp->hInst;
2413 infoPtr->bitmaps[infoPtr->nNumBitmapInfos].nID = lpAddBmp->nID;
2415 infoPtr->nNumBitmapInfos++;
2416 TRACE("Number of bitmap infos: %d\n", infoPtr->nNumBitmapInfos);
2418 if (nIndex != -1)
2420 INT imagecount = ImageList_GetImageCount(himlDef);
2422 if (infoPtr->nNumBitmaps + nButtons != imagecount)
2424 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",
2425 infoPtr->nNumBitmaps, nCount, imagecount - nCount,
2426 infoPtr->nNumBitmaps+nButtons,imagecount);
2428 infoPtr->nNumBitmaps = imagecount;
2430 else
2431 infoPtr->nNumBitmaps += nButtons;
2434 InvalidateRect(hwnd, NULL, FALSE);
2436 return nIndex;
2440 static LRESULT
2441 TOOLBAR_AddButtonsA (HWND hwnd, WPARAM wParam, LPARAM lParam)
2443 TOOLBAR_INFO *infoPtr = TOOLBAR_GetInfoPtr (hwnd);
2444 LPTBBUTTON lpTbb = (LPTBBUTTON)lParam;
2445 INT nOldButtons, nNewButtons, nAddButtons, nCount;
2447 TRACE("adding %d buttons!\n", wParam);
2449 nAddButtons = (UINT)wParam;
2450 nOldButtons = infoPtr->nNumButtons;
2451 nNewButtons = nOldButtons + nAddButtons;
2453 if (infoPtr->nNumButtons == 0) {
2454 infoPtr->buttons =
2455 Alloc (sizeof(TBUTTON_INFO) * nNewButtons);
2457 else {
2458 TBUTTON_INFO *oldButtons = infoPtr->buttons;
2459 infoPtr->buttons =
2460 Alloc (sizeof(TBUTTON_INFO) * nNewButtons);
2461 memcpy (&infoPtr->buttons[0], &oldButtons[0],
2462 nOldButtons * sizeof(TBUTTON_INFO));
2463 Free (oldButtons);
2466 infoPtr->nNumButtons = nNewButtons;
2468 /* insert new button data */
2469 for (nCount = 0; nCount < nAddButtons; nCount++) {
2470 TBUTTON_INFO *btnPtr = &infoPtr->buttons[nOldButtons+nCount];
2471 btnPtr->iBitmap = lpTbb[nCount].iBitmap;
2472 btnPtr->idCommand = lpTbb[nCount].idCommand;
2473 btnPtr->fsState = lpTbb[nCount].fsState;
2474 btnPtr->fsStyle = lpTbb[nCount].fsStyle;
2475 btnPtr->dwData = lpTbb[nCount].dwData;
2476 if(HIWORD(lpTbb[nCount].iString) && lpTbb[nCount].iString != -1)
2477 Str_SetPtrAtoW ((LPWSTR*)&btnPtr->iString, (LPSTR)lpTbb[nCount].iString );
2478 else
2479 btnPtr->iString = lpTbb[nCount].iString;
2480 btnPtr->bHot = FALSE;
2482 if ((infoPtr->hwndToolTip) && !(btnPtr->fsStyle & BTNS_SEP)) {
2483 TTTOOLINFOA ti;
2485 ZeroMemory (&ti, sizeof(TTTOOLINFOA));
2486 ti.cbSize = sizeof (TTTOOLINFOA);
2487 ti.hwnd = hwnd;
2488 ti.uId = btnPtr->idCommand;
2489 ti.hinst = 0;
2490 ti.lpszText = LPSTR_TEXTCALLBACKA;
2492 SendMessageA (infoPtr->hwndToolTip, TTM_ADDTOOLA,
2493 0, (LPARAM)&ti);
2497 TOOLBAR_CalcToolbar (hwnd);
2499 TOOLBAR_DumpToolbar (infoPtr, __LINE__);
2501 InvalidateRect(hwnd, NULL, FALSE);
2503 return TRUE;
2507 static LRESULT
2508 TOOLBAR_AddButtonsW (HWND hwnd, WPARAM wParam, LPARAM lParam)
2510 TOOLBAR_INFO *infoPtr = TOOLBAR_GetInfoPtr (hwnd);
2511 LPTBBUTTON lpTbb = (LPTBBUTTON)lParam;
2512 INT nOldButtons, nNewButtons, nAddButtons, nCount;
2514 TRACE("adding %d buttons!\n", wParam);
2516 nAddButtons = (UINT)wParam;
2517 nOldButtons = infoPtr->nNumButtons;
2518 nNewButtons = nOldButtons + nAddButtons;
2520 if (infoPtr->nNumButtons == 0) {
2521 infoPtr->buttons =
2522 Alloc (sizeof(TBUTTON_INFO) * nNewButtons);
2524 else {
2525 TBUTTON_INFO *oldButtons = infoPtr->buttons;
2526 infoPtr->buttons =
2527 Alloc (sizeof(TBUTTON_INFO) * nNewButtons);
2528 memcpy (&infoPtr->buttons[0], &oldButtons[0],
2529 nOldButtons * sizeof(TBUTTON_INFO));
2530 Free (oldButtons);
2533 infoPtr->nNumButtons = nNewButtons;
2535 /* insert new button data */
2536 for (nCount = 0; nCount < nAddButtons; nCount++) {
2537 TBUTTON_INFO *btnPtr = &infoPtr->buttons[nOldButtons+nCount];
2538 btnPtr->iBitmap = lpTbb[nCount].iBitmap;
2539 btnPtr->idCommand = lpTbb[nCount].idCommand;
2540 btnPtr->fsState = lpTbb[nCount].fsState;
2541 btnPtr->fsStyle = lpTbb[nCount].fsStyle;
2542 btnPtr->dwData = lpTbb[nCount].dwData;
2543 if(HIWORD(lpTbb[nCount].iString) && lpTbb[nCount].iString != -1)
2544 Str_SetPtrW ((LPWSTR*)&btnPtr->iString, (LPWSTR)lpTbb[nCount].iString );
2545 else
2546 btnPtr->iString = lpTbb[nCount].iString;
2547 btnPtr->bHot = FALSE;
2549 if ((infoPtr->hwndToolTip) && !(btnPtr->fsStyle & BTNS_SEP)) {
2550 TTTOOLINFOW ti;
2552 ZeroMemory (&ti, sizeof(TTTOOLINFOW));
2553 ti.cbSize = sizeof (TTTOOLINFOW);
2554 ti.hwnd = hwnd;
2555 ti.uId = btnPtr->idCommand;
2556 ti.hinst = 0;
2557 ti.lpszText = LPSTR_TEXTCALLBACKW;
2558 ti.lParam = lParam;
2560 SendMessageW (infoPtr->hwndToolTip, TTM_ADDTOOLW,
2561 0, (LPARAM)&ti);
2565 TOOLBAR_CalcToolbar (hwnd);
2567 TOOLBAR_DumpToolbar (infoPtr, __LINE__);
2569 InvalidateRect(hwnd, NULL, FALSE);
2571 return TRUE;
2575 static LRESULT
2576 TOOLBAR_AddStringA (HWND hwnd, WPARAM wParam, LPARAM lParam)
2578 TOOLBAR_INFO *infoPtr = TOOLBAR_GetInfoPtr (hwnd);
2579 INT nIndex;
2581 if ((wParam) && (HIWORD(lParam) == 0)) {
2582 char szString[256];
2583 INT len;
2584 TRACE("adding string from resource!\n");
2586 len = LoadStringA ((HINSTANCE)wParam, (UINT)lParam,
2587 szString, 256);
2589 TRACE("len=%d \"%s\"\n", len, szString);
2590 nIndex = infoPtr->nNumStrings;
2591 if (infoPtr->nNumStrings == 0) {
2592 infoPtr->strings =
2593 Alloc (sizeof(LPWSTR));
2595 else {
2596 LPWSTR *oldStrings = infoPtr->strings;
2597 infoPtr->strings =
2598 Alloc (sizeof(LPWSTR) * (infoPtr->nNumStrings + 1));
2599 memcpy (&infoPtr->strings[0], &oldStrings[0],
2600 sizeof(LPWSTR) * infoPtr->nNumStrings);
2601 Free (oldStrings);
2604 /*Alloc zeros out the allocated memory*/
2605 Str_SetPtrAtoW (&infoPtr->strings[infoPtr->nNumStrings], szString );
2606 infoPtr->nNumStrings++;
2608 else {
2609 LPSTR p = (LPSTR)lParam;
2610 INT len;
2612 if (p == NULL)
2613 return -1;
2614 TRACE("adding string(s) from array!\n");
2616 nIndex = infoPtr->nNumStrings;
2617 while (*p) {
2618 len = strlen (p);
2619 TRACE("len=%d \"%s\"\n", len, p);
2621 if (infoPtr->nNumStrings == 0) {
2622 infoPtr->strings =
2623 Alloc (sizeof(LPWSTR));
2625 else {
2626 LPWSTR *oldStrings = infoPtr->strings;
2627 infoPtr->strings =
2628 Alloc (sizeof(LPWSTR) * (infoPtr->nNumStrings + 1));
2629 memcpy (&infoPtr->strings[0], &oldStrings[0],
2630 sizeof(LPWSTR) * infoPtr->nNumStrings);
2631 Free (oldStrings);
2634 Str_SetPtrAtoW (&infoPtr->strings[infoPtr->nNumStrings], p );
2635 infoPtr->nNumStrings++;
2637 p += (len+1);
2641 return nIndex;
2645 static LRESULT
2646 TOOLBAR_AddStringW (HWND hwnd, WPARAM wParam, LPARAM lParam)
2648 #define MAX_RESOURCE_STRING_LENGTH 512
2649 TOOLBAR_INFO *infoPtr = TOOLBAR_GetInfoPtr (hwnd);
2650 INT nIndex;
2652 if ((wParam) && (HIWORD(lParam) == 0)) {
2653 WCHAR szString[MAX_RESOURCE_STRING_LENGTH];
2654 INT len;
2655 TRACE("adding string from resource!\n");
2657 len = LoadStringW ((HINSTANCE)wParam, (UINT)lParam,
2658 szString, MAX_RESOURCE_STRING_LENGTH);
2660 TRACE("len=%d %s\n", len, debugstr_w(szString));
2661 TRACE("First char: 0x%x\n", *szString);
2662 if (szString[0] == L'|')
2664 PWSTR p = szString + 1;
2666 nIndex = infoPtr->nNumStrings;
2667 while (*p != L'|' && *p != L'\0') {
2668 PWSTR np;
2670 if (infoPtr->nNumStrings == 0) {
2671 infoPtr->strings = Alloc (sizeof(LPWSTR));
2673 else
2675 LPWSTR *oldStrings = infoPtr->strings;
2676 infoPtr->strings = Alloc(sizeof(LPWSTR) * (infoPtr->nNumStrings + 1));
2677 memcpy(&infoPtr->strings[0], &oldStrings[0],
2678 sizeof(LPWSTR) * infoPtr->nNumStrings);
2679 Free(oldStrings);
2682 np=strchrW (p, '|');
2683 if (np!=NULL) {
2684 len = np - p;
2685 np++;
2686 } else {
2687 len = strlenW(p);
2688 np = p + len;
2690 TRACE("len=%d %s\n", len, debugstr_w(p));
2691 infoPtr->strings[infoPtr->nNumStrings] =
2692 Alloc (sizeof(WCHAR)*(len+1));
2693 lstrcpynW (infoPtr->strings[infoPtr->nNumStrings], p, len+1);
2694 infoPtr->nNumStrings++;
2696 p = np;
2699 else
2701 nIndex = infoPtr->nNumStrings;
2702 if (infoPtr->nNumStrings == 0) {
2703 infoPtr->strings =
2704 Alloc (sizeof(LPWSTR));
2706 else {
2707 LPWSTR *oldStrings = infoPtr->strings;
2708 infoPtr->strings =
2709 Alloc (sizeof(LPWSTR) * (infoPtr->nNumStrings + 1));
2710 memcpy (&infoPtr->strings[0], &oldStrings[0],
2711 sizeof(LPWSTR) * infoPtr->nNumStrings);
2712 Free (oldStrings);
2715 Str_SetPtrW (&infoPtr->strings[infoPtr->nNumStrings], szString);
2716 infoPtr->nNumStrings++;
2719 else {
2720 LPWSTR p = (LPWSTR)lParam;
2721 INT len;
2723 if (p == NULL)
2724 return -1;
2725 TRACE("adding string(s) from array!\n");
2726 nIndex = infoPtr->nNumStrings;
2727 while (*p) {
2728 len = strlenW (p);
2730 TRACE("len=%d %s\n", len, debugstr_w(p));
2731 if (infoPtr->nNumStrings == 0) {
2732 infoPtr->strings =
2733 Alloc (sizeof(LPWSTR));
2735 else {
2736 LPWSTR *oldStrings = infoPtr->strings;
2737 infoPtr->strings =
2738 Alloc (sizeof(LPWSTR) * (infoPtr->nNumStrings + 1));
2739 memcpy (&infoPtr->strings[0], &oldStrings[0],
2740 sizeof(LPWSTR) * infoPtr->nNumStrings);
2741 Free (oldStrings);
2744 Str_SetPtrW (&infoPtr->strings[infoPtr->nNumStrings], p);
2745 infoPtr->nNumStrings++;
2747 p += (len+1);
2751 return nIndex;
2755 static LRESULT
2756 TOOLBAR_AutoSize (HWND hwnd)
2758 TOOLBAR_INFO *infoPtr = TOOLBAR_GetInfoPtr (hwnd);
2759 DWORD dwStyle = GetWindowLongA (hwnd, GWL_STYLE);
2760 RECT parent_rect;
2761 RECT window_rect;
2762 HWND parent;
2763 INT x, y;
2764 INT cx, cy;
2765 UINT uPosFlags = SWP_NOZORDER;
2767 TRACE("resize forced, style=%lx!\n", dwStyle);
2769 parent = GetParent (hwnd);
2770 GetClientRect(parent, &parent_rect);
2772 x = parent_rect.left;
2773 y = parent_rect.top;
2775 /* FIXME: we should be able to early out if nothing */
2776 /* has changed with nWidth != parent_rect width */
2778 if (dwStyle & CCS_NORESIZE) {
2779 uPosFlags |= (SWP_NOSIZE | SWP_NOMOVE);
2780 cx = 0;
2781 cy = 0;
2782 TOOLBAR_CalcToolbar (hwnd);
2784 else {
2785 infoPtr->nWidth = parent_rect.right - parent_rect.left;
2786 TOOLBAR_CalcToolbar (hwnd);
2787 InvalidateRect( hwnd, NULL, TRUE );
2788 cy = infoPtr->nHeight;
2789 cx = infoPtr->nWidth;
2791 if ((dwStyle & CCS_BOTTOM) == CCS_NOMOVEY) {
2792 GetWindowRect(hwnd, &window_rect);
2793 ScreenToClient(parent, (LPPOINT)&window_rect.left);
2794 y = window_rect.top;
2796 if ((dwStyle & CCS_BOTTOM) == CCS_BOTTOM) {
2797 GetWindowRect(hwnd, &window_rect);
2798 y = parent_rect.bottom - ( window_rect.bottom - window_rect.top);
2802 if (dwStyle & CCS_NOPARENTALIGN)
2803 uPosFlags |= SWP_NOMOVE;
2805 if (!(dwStyle & CCS_NODIVIDER))
2806 cy += GetSystemMetrics(SM_CYEDGE);
2808 if (dwStyle & WS_BORDER)
2810 x = y = 1;
2811 cy += GetSystemMetrics(SM_CYEDGE);
2812 cx += GetSystemMetrics(SM_CYEDGE);
2815 infoPtr->bAutoSize = TRUE;
2816 SetWindowPos (hwnd, HWND_TOP, x, y, cx, cy, uPosFlags);
2817 /* The following line makes sure that the infoPtr->bAutoSize is turned off
2818 * after the setwindowpos calls */
2819 infoPtr->bAutoSize = FALSE;
2821 return 0;
2825 static LRESULT
2826 TOOLBAR_ButtonCount (HWND hwnd, WPARAM wParam, LPARAM lParam)
2828 TOOLBAR_INFO *infoPtr = TOOLBAR_GetInfoPtr (hwnd);
2830 return infoPtr->nNumButtons;
2834 static LRESULT
2835 TOOLBAR_ButtonStructSize (HWND hwnd, WPARAM wParam, LPARAM lParam)
2837 TOOLBAR_INFO *infoPtr = TOOLBAR_GetInfoPtr (hwnd);
2839 if (infoPtr == NULL) {
2840 ERR("(%p, 0x%x, 0x%lx)\n", hwnd, wParam, lParam);
2841 ERR("infoPtr == NULL!\n");
2842 return 0;
2845 infoPtr->dwStructSize = (DWORD)wParam;
2847 return 0;
2851 static LRESULT
2852 TOOLBAR_ChangeBitmap (HWND hwnd, WPARAM wParam, LPARAM lParam)
2854 TOOLBAR_INFO *infoPtr = TOOLBAR_GetInfoPtr (hwnd);
2855 TBUTTON_INFO *btnPtr;
2856 INT nIndex;
2858 TRACE("button %d, iBitmap now %d\n", wParam, LOWORD(lParam));
2860 nIndex = TOOLBAR_GetButtonIndex (infoPtr, (INT)wParam, FALSE);
2861 if (nIndex == -1)
2862 return FALSE;
2864 btnPtr = &infoPtr->buttons[nIndex];
2865 btnPtr->iBitmap = LOWORD(lParam);
2867 /* we HAVE to erase the background, the new bitmap could be */
2868 /* transparent */
2869 InvalidateRect(hwnd, &btnPtr->rect, TRUE);
2871 return TRUE;
2875 static LRESULT
2876 TOOLBAR_CheckButton (HWND hwnd, WPARAM wParam, LPARAM lParam)
2878 TOOLBAR_INFO *infoPtr = TOOLBAR_GetInfoPtr (hwnd);
2879 TBUTTON_INFO *btnPtr;
2880 INT nIndex;
2881 INT nOldIndex = -1;
2882 BOOL bChecked = FALSE;
2884 nIndex = TOOLBAR_GetButtonIndex (infoPtr, (INT)wParam, FALSE);
2885 if (nIndex == -1)
2886 return FALSE;
2888 btnPtr = &infoPtr->buttons[nIndex];
2890 if (!(btnPtr->fsStyle & BTNS_CHECK))
2891 return FALSE;
2893 bChecked = (btnPtr->fsState & TBSTATE_CHECKED) ? TRUE : FALSE;
2895 if (LOWORD(lParam) == FALSE)
2896 btnPtr->fsState &= ~TBSTATE_CHECKED;
2897 else {
2898 if (btnPtr->fsStyle & BTNS_GROUP) {
2899 nOldIndex =
2900 TOOLBAR_GetCheckedGroupButtonIndex (infoPtr, nIndex);
2901 if (nOldIndex == nIndex)
2902 return 0;
2903 if (nOldIndex != -1)
2904 infoPtr->buttons[nOldIndex].fsState &= ~TBSTATE_CHECKED;
2906 btnPtr->fsState |= TBSTATE_CHECKED;
2909 if( bChecked != LOWORD(lParam) )
2911 if (nOldIndex != -1)
2913 InvalidateRect(hwnd, &infoPtr->buttons[nOldIndex].rect,
2914 TOOLBAR_HasText(infoPtr, &infoPtr->buttons[nOldIndex]));
2916 InvalidateRect(hwnd, &btnPtr->rect, TRUE);
2919 /* FIXME: Send a WM_NOTIFY?? */
2921 return TRUE;
2925 static LRESULT
2926 TOOLBAR_CommandToIndex (HWND hwnd, WPARAM wParam, LPARAM lParam)
2928 TOOLBAR_INFO *infoPtr = TOOLBAR_GetInfoPtr (hwnd);
2930 return TOOLBAR_GetButtonIndex (infoPtr, (INT)wParam, FALSE);
2934 static LRESULT
2935 TOOLBAR_Customize (HWND hwnd)
2937 TOOLBAR_INFO *infoPtr = TOOLBAR_GetInfoPtr (hwnd);
2938 CUSTDLG_INFO custInfo;
2939 LRESULT ret;
2940 LPCVOID template;
2941 HRSRC hRes;
2942 NMHDR nmhdr;
2944 custInfo.tbInfo = infoPtr;
2945 custInfo.tbHwnd = hwnd;
2947 /* send TBN_BEGINADJUST notification */
2948 TOOLBAR_SendNotify ((NMHDR *) &nmhdr, infoPtr,
2949 TBN_BEGINADJUST);
2951 if (!(hRes = FindResourceA (COMCTL32_hModule,
2952 MAKEINTRESOURCEA(IDD_TBCUSTOMIZE),
2953 (LPSTR)RT_DIALOG)))
2954 return FALSE;
2956 if(!(template = (LPVOID)LoadResource (COMCTL32_hModule, hRes)))
2957 return FALSE;
2959 ret = DialogBoxIndirectParamA ((HINSTANCE)GetWindowLongA(hwnd, GWL_HINSTANCE),
2960 (LPDLGTEMPLATEA)template,
2961 hwnd,
2962 TOOLBAR_CustomizeDialogProc,
2963 (LPARAM)&custInfo);
2965 /* send TBN_ENDADJUST notification */
2966 TOOLBAR_SendNotify ((NMHDR *) &nmhdr, infoPtr,
2967 TBN_ENDADJUST);
2969 return ret;
2973 static LRESULT
2974 TOOLBAR_DeleteButton (HWND hwnd, WPARAM wParam, LPARAM lParam)
2976 TOOLBAR_INFO *infoPtr = TOOLBAR_GetInfoPtr (hwnd);
2977 INT nIndex = (INT)wParam;
2979 if ((nIndex < 0) || (nIndex >= infoPtr->nNumButtons))
2980 return FALSE;
2982 if ((infoPtr->hwndToolTip) &&
2983 !(infoPtr->buttons[nIndex].fsStyle & BTNS_SEP)) {
2984 TTTOOLINFOA ti;
2986 ZeroMemory (&ti, sizeof(TTTOOLINFOA));
2987 ti.cbSize = sizeof (TTTOOLINFOA);
2988 ti.hwnd = hwnd;
2989 ti.uId = infoPtr->buttons[nIndex].idCommand;
2991 SendMessageA (infoPtr->hwndToolTip, TTM_DELTOOLA, 0, (LPARAM)&ti);
2994 if (infoPtr->nNumButtons == 1) {
2995 TRACE(" simple delete!\n");
2996 Free (infoPtr->buttons);
2997 infoPtr->buttons = NULL;
2998 infoPtr->nNumButtons = 0;
3000 else {
3001 TBUTTON_INFO *oldButtons = infoPtr->buttons;
3002 TRACE("complex delete! [nIndex=%d]\n", nIndex);
3004 infoPtr->nNumButtons--;
3005 infoPtr->buttons = Alloc (sizeof (TBUTTON_INFO) * infoPtr->nNumButtons);
3006 if (nIndex > 0) {
3007 memcpy (&infoPtr->buttons[0], &oldButtons[0],
3008 nIndex * sizeof(TBUTTON_INFO));
3011 if (nIndex < infoPtr->nNumButtons) {
3012 memcpy (&infoPtr->buttons[nIndex], &oldButtons[nIndex+1],
3013 (infoPtr->nNumButtons - nIndex) * sizeof(TBUTTON_INFO));
3016 Free (oldButtons);
3019 TOOLBAR_CalcToolbar (hwnd);
3021 InvalidateRect (hwnd, NULL, TRUE);
3023 return TRUE;
3027 static LRESULT
3028 TOOLBAR_EnableButton (HWND hwnd, WPARAM wParam, LPARAM lParam)
3030 TOOLBAR_INFO *infoPtr = TOOLBAR_GetInfoPtr (hwnd);
3031 TBUTTON_INFO *btnPtr;
3032 INT nIndex;
3033 DWORD bState;
3035 nIndex = TOOLBAR_GetButtonIndex (infoPtr, (INT)wParam, FALSE);
3036 if (nIndex == -1)
3037 return FALSE;
3039 btnPtr = &infoPtr->buttons[nIndex];
3041 bState = btnPtr->fsState & TBSTATE_ENABLED;
3043 /* update the toolbar button state */
3044 if(LOWORD(lParam) == FALSE) {
3045 btnPtr->fsState &= ~(TBSTATE_ENABLED | TBSTATE_PRESSED);
3046 } else {
3047 btnPtr->fsState |= TBSTATE_ENABLED;
3050 /* redraw the button only if the state of the button changed */
3051 if(bState != (btnPtr->fsState & TBSTATE_ENABLED))
3053 InvalidateRect(hwnd, &btnPtr->rect,
3054 TOOLBAR_HasText(infoPtr, btnPtr));
3057 return TRUE;
3061 static inline LRESULT
3062 TOOLBAR_GetAnchorHighlight (HWND hwnd)
3064 TOOLBAR_INFO *infoPtr = TOOLBAR_GetInfoPtr (hwnd);
3066 return infoPtr->bAnchor;
3070 static LRESULT
3071 TOOLBAR_GetBitmap (HWND hwnd, WPARAM wParam, LPARAM lParam)
3073 TOOLBAR_INFO *infoPtr = TOOLBAR_GetInfoPtr (hwnd);
3074 INT nIndex;
3076 nIndex = TOOLBAR_GetButtonIndex (infoPtr, (INT)wParam, FALSE);
3077 if (nIndex == -1)
3078 return -1;
3080 return infoPtr->buttons[nIndex].iBitmap;
3084 static inline LRESULT
3085 TOOLBAR_GetBitmapFlags (HWND hwnd, WPARAM wParam, LPARAM lParam)
3087 return (GetDeviceCaps (0, LOGPIXELSX) >= 120) ? TBBF_LARGE : 0;
3091 static LRESULT
3092 TOOLBAR_GetButton (HWND hwnd, WPARAM wParam, LPARAM lParam)
3094 TOOLBAR_INFO *infoPtr = TOOLBAR_GetInfoPtr (hwnd);
3095 LPTBBUTTON lpTbb = (LPTBBUTTON)lParam;
3096 INT nIndex = (INT)wParam;
3097 TBUTTON_INFO *btnPtr;
3099 if (infoPtr == NULL)
3100 return FALSE;
3102 if (lpTbb == NULL)
3103 return FALSE;
3105 if ((nIndex < 0) || (nIndex >= infoPtr->nNumButtons))
3106 return FALSE;
3108 btnPtr = &infoPtr->buttons[nIndex];
3109 lpTbb->iBitmap = btnPtr->iBitmap;
3110 lpTbb->idCommand = btnPtr->idCommand;
3111 lpTbb->fsState = btnPtr->fsState;
3112 lpTbb->fsStyle = btnPtr->fsStyle;
3113 lpTbb->bReserved[0] = 0;
3114 lpTbb->bReserved[1] = 0;
3115 lpTbb->dwData = btnPtr->dwData;
3116 lpTbb->iString = btnPtr->iString;
3118 return TRUE;
3122 static LRESULT
3123 TOOLBAR_GetButtonInfoA (HWND hwnd, WPARAM wParam, LPARAM lParam)
3125 TOOLBAR_INFO *infoPtr = TOOLBAR_GetInfoPtr (hwnd);
3126 LPTBBUTTONINFOA lpTbInfo = (LPTBBUTTONINFOA)lParam;
3127 TBUTTON_INFO *btnPtr;
3128 INT nIndex;
3130 if (infoPtr == NULL)
3131 return -1;
3132 if (lpTbInfo == NULL)
3133 return -1;
3134 if (lpTbInfo->cbSize < sizeof(TBBUTTONINFOA))
3135 return -1;
3137 nIndex = TOOLBAR_GetButtonIndex (infoPtr, (INT)wParam,
3138 lpTbInfo->dwMask & 0x80000000);
3139 if (nIndex == -1)
3140 return -1;
3142 if (!(btnPtr = &infoPtr->buttons[nIndex])) return -1;
3144 if (lpTbInfo->dwMask & TBIF_COMMAND)
3145 lpTbInfo->idCommand = btnPtr->idCommand;
3146 if (lpTbInfo->dwMask & TBIF_IMAGE)
3147 lpTbInfo->iImage = btnPtr->iBitmap;
3148 if (lpTbInfo->dwMask & TBIF_LPARAM)
3149 lpTbInfo->lParam = btnPtr->dwData;
3150 if (lpTbInfo->dwMask & TBIF_SIZE)
3151 lpTbInfo->cx = (WORD)(btnPtr->rect.right - btnPtr->rect.left);
3152 if (lpTbInfo->dwMask & TBIF_STATE)
3153 lpTbInfo->fsState = btnPtr->fsState;
3154 if (lpTbInfo->dwMask & TBIF_STYLE)
3155 lpTbInfo->fsStyle = btnPtr->fsStyle;
3156 if (lpTbInfo->dwMask & TBIF_TEXT) {
3157 /* TB_GETBUTTONINFO doesn't retrieve text from the string list, so we
3158 can't use TOOLBAR_GetText here */
3159 LPWSTR lpText;
3160 if (HIWORD(btnPtr->iString) && (btnPtr->iString != -1)) {
3161 lpText = (LPWSTR)btnPtr->iString;
3162 Str_GetPtrWtoA (lpText, lpTbInfo->pszText,lpTbInfo->cchText);
3163 } else
3164 lpTbInfo->pszText[0] = '\0';
3166 return nIndex;
3170 static LRESULT
3171 TOOLBAR_GetButtonInfoW (HWND hwnd, WPARAM wParam, LPARAM lParam)
3173 TOOLBAR_INFO *infoPtr = TOOLBAR_GetInfoPtr (hwnd);
3174 LPTBBUTTONINFOW lpTbInfo = (LPTBBUTTONINFOW)lParam;
3175 TBUTTON_INFO *btnPtr;
3176 INT nIndex;
3178 if (infoPtr == NULL)
3179 return -1;
3180 if (lpTbInfo == NULL)
3181 return -1;
3182 if (lpTbInfo->cbSize < sizeof(TBBUTTONINFOW))
3183 return -1;
3185 nIndex = TOOLBAR_GetButtonIndex (infoPtr, (INT)wParam,
3186 lpTbInfo->dwMask & 0x80000000);
3187 if (nIndex == -1)
3188 return -1;
3190 btnPtr = &infoPtr->buttons[nIndex];
3192 if(!btnPtr)
3193 return -1;
3195 if (lpTbInfo->dwMask & TBIF_COMMAND)
3196 lpTbInfo->idCommand = btnPtr->idCommand;
3197 if (lpTbInfo->dwMask & TBIF_IMAGE)
3198 lpTbInfo->iImage = btnPtr->iBitmap;
3199 if (lpTbInfo->dwMask & TBIF_LPARAM)
3200 lpTbInfo->lParam = btnPtr->dwData;
3201 if (lpTbInfo->dwMask & TBIF_SIZE)
3202 lpTbInfo->cx = (WORD)(btnPtr->rect.right - btnPtr->rect.left);
3203 if (lpTbInfo->dwMask & TBIF_STATE)
3204 lpTbInfo->fsState = btnPtr->fsState;
3205 if (lpTbInfo->dwMask & TBIF_STYLE)
3206 lpTbInfo->fsStyle = btnPtr->fsStyle;
3207 if (lpTbInfo->dwMask & TBIF_TEXT) {
3208 /* TB_GETBUTTONINFO doesn't retrieve text from the string list, so we
3209 can't use TOOLBAR_GetText here */
3210 LPWSTR lpText;
3211 if (HIWORD(btnPtr->iString) && (btnPtr->iString != -1)) {
3212 lpText = (LPWSTR)btnPtr->iString;
3213 Str_GetPtrW (lpText,lpTbInfo->pszText,lpTbInfo->cchText);
3214 } else
3215 lpTbInfo->pszText[0] = '\0';
3218 return nIndex;
3222 static LRESULT
3223 TOOLBAR_GetButtonSize (HWND hwnd)
3225 TOOLBAR_INFO *infoPtr = TOOLBAR_GetInfoPtr (hwnd);
3227 if (infoPtr->nNumButtons > 0)
3228 return MAKELONG((WORD)infoPtr->nButtonWidth,
3229 (WORD)infoPtr->nButtonHeight);
3230 else
3231 return MAKELONG(8,7);
3235 static LRESULT
3236 TOOLBAR_GetButtonTextA (HWND hwnd, WPARAM wParam, LPARAM lParam)
3238 TOOLBAR_INFO *infoPtr = TOOLBAR_GetInfoPtr (hwnd);
3239 INT nIndex;
3240 LPWSTR lpText;
3242 if (lParam == 0)
3243 return -1;
3245 nIndex = TOOLBAR_GetButtonIndex (infoPtr, (INT)wParam, FALSE);
3246 if (nIndex == -1)
3247 return -1;
3249 lpText = TOOLBAR_GetText(infoPtr,&infoPtr->buttons[nIndex]);
3251 return WideCharToMultiByte( CP_ACP, 0, lpText, -1,
3252 (LPSTR)lParam, 0x7fffffff, NULL, NULL ) - 1;
3256 static LRESULT
3257 TOOLBAR_GetButtonTextW (HWND hwnd, WPARAM wParam, LPARAM lParam)
3259 TOOLBAR_INFO *infoPtr = TOOLBAR_GetInfoPtr (hwnd);
3260 INT nIndex;
3261 LPWSTR lpText;
3263 if (lParam == 0)
3264 return -1;
3266 nIndex = TOOLBAR_GetButtonIndex (infoPtr, (INT)wParam, FALSE);
3267 if (nIndex == -1)
3268 return -1;
3270 lpText = TOOLBAR_GetText(infoPtr,&infoPtr->buttons[nIndex]);
3272 strcpyW ((LPWSTR)lParam, lpText);
3274 return strlenW (lpText);
3278 static LRESULT
3279 TOOLBAR_GetDisabledImageList (HWND hwnd, WPARAM wParam, LPARAM lParam)
3281 return (LRESULT)GETDISIMAGELIST(TOOLBAR_GetInfoPtr (hwnd), 0);
3285 inline static LRESULT
3286 TOOLBAR_GetExtendedStyle (HWND hwnd)
3288 TOOLBAR_INFO *infoPtr = TOOLBAR_GetInfoPtr (hwnd);
3290 TRACE("\n");
3292 return infoPtr->dwExStyle;
3296 static LRESULT
3297 TOOLBAR_GetHotImageList (HWND hwnd, WPARAM wParam, LPARAM lParam)
3299 return (LRESULT)GETHOTIMAGELIST(TOOLBAR_GetInfoPtr (hwnd), 0);
3303 static LRESULT
3304 TOOLBAR_GetHotItem (HWND hwnd)
3306 TOOLBAR_INFO *infoPtr = TOOLBAR_GetInfoPtr (hwnd);
3308 if (!(GetWindowLongA (hwnd, GWL_STYLE) & TBSTYLE_FLAT))
3309 return -1;
3311 if (infoPtr->nHotItem < 0)
3312 return -1;
3314 return (LRESULT)infoPtr->nHotItem;
3318 static LRESULT
3319 TOOLBAR_GetDefImageList (HWND hwnd, WPARAM wParam, LPARAM lParam)
3321 return (LRESULT) GETDEFIMAGELIST(TOOLBAR_GetInfoPtr(hwnd), 0);
3325 /* << TOOLBAR_GetInsertMark >> */
3326 /* << TOOLBAR_GetInsertMarkColor >> */
3329 static LRESULT
3330 TOOLBAR_GetItemRect (HWND hwnd, WPARAM wParam, LPARAM lParam)
3332 TOOLBAR_INFO *infoPtr = TOOLBAR_GetInfoPtr (hwnd);
3333 TBUTTON_INFO *btnPtr;
3334 LPRECT lpRect;
3335 INT nIndex;
3337 if (infoPtr == NULL)
3338 return FALSE;
3339 nIndex = (INT)wParam;
3340 btnPtr = &infoPtr->buttons[nIndex];
3341 if ((nIndex < 0) || (nIndex >= infoPtr->nNumButtons))
3342 return FALSE;
3343 lpRect = (LPRECT)lParam;
3344 if (lpRect == NULL)
3345 return FALSE;
3346 if (btnPtr->fsState & TBSTATE_HIDDEN)
3347 return FALSE;
3349 lpRect->left = btnPtr->rect.left;
3350 lpRect->right = btnPtr->rect.right;
3351 lpRect->bottom = btnPtr->rect.bottom;
3352 lpRect->top = btnPtr->rect.top;
3354 return TRUE;
3358 static LRESULT
3359 TOOLBAR_GetMaxSize (HWND hwnd, WPARAM wParam, LPARAM lParam)
3361 TOOLBAR_INFO *infoPtr = TOOLBAR_GetInfoPtr (hwnd);
3362 LPSIZE lpSize = (LPSIZE)lParam;
3364 if (lpSize == NULL)
3365 return FALSE;
3367 lpSize->cx = infoPtr->rcBound.right - infoPtr->rcBound.left;
3368 lpSize->cy = infoPtr->rcBound.bottom - infoPtr->rcBound.top;
3370 TRACE("maximum size %ld x %ld\n",
3371 infoPtr->rcBound.right - infoPtr->rcBound.left,
3372 infoPtr->rcBound.bottom - infoPtr->rcBound.top);
3374 return TRUE;
3378 /* << TOOLBAR_GetObject >> */
3381 static LRESULT
3382 TOOLBAR_GetPadding (HWND hwnd)
3384 TOOLBAR_INFO *infoPtr = TOOLBAR_GetInfoPtr (hwnd);
3385 DWORD oldPad;
3387 oldPad = MAKELONG(infoPtr->szPadding.cx, infoPtr->szPadding.cy);
3388 return (LRESULT) oldPad;
3392 static LRESULT
3393 TOOLBAR_GetRect (HWND hwnd, WPARAM wParam, LPARAM lParam)
3395 TOOLBAR_INFO *infoPtr = TOOLBAR_GetInfoPtr (hwnd);
3396 TBUTTON_INFO *btnPtr;
3397 LPRECT lpRect;
3398 INT nIndex;
3400 if (infoPtr == NULL)
3401 return FALSE;
3402 nIndex = TOOLBAR_GetButtonIndex (infoPtr, (INT)wParam, FALSE);
3403 btnPtr = &infoPtr->buttons[nIndex];
3404 if ((nIndex < 0) || (nIndex >= infoPtr->nNumButtons))
3405 return FALSE;
3406 lpRect = (LPRECT)lParam;
3407 if (lpRect == NULL)
3408 return FALSE;
3410 lpRect->left = btnPtr->rect.left;
3411 lpRect->right = btnPtr->rect.right;
3412 lpRect->bottom = btnPtr->rect.bottom;
3413 lpRect->top = btnPtr->rect.top;
3415 return TRUE;
3419 static LRESULT
3420 TOOLBAR_GetRows (HWND hwnd, WPARAM wParam, LPARAM lParam)
3422 TOOLBAR_INFO *infoPtr = TOOLBAR_GetInfoPtr (hwnd);
3424 if (GetWindowLongA (hwnd, GWL_STYLE) & TBSTYLE_WRAPABLE)
3425 return infoPtr->nRows;
3426 else
3427 return 1;
3431 static LRESULT
3432 TOOLBAR_GetState (HWND hwnd, WPARAM wParam, LPARAM lParam)
3434 TOOLBAR_INFO *infoPtr = TOOLBAR_GetInfoPtr (hwnd);
3435 INT nIndex;
3437 nIndex = TOOLBAR_GetButtonIndex (infoPtr, (INT)wParam, FALSE);
3438 if (nIndex == -1)
3439 return -1;
3441 return infoPtr->buttons[nIndex].fsState;
3445 static LRESULT
3446 TOOLBAR_GetStyle (HWND hwnd, WPARAM wParam, LPARAM lParam)
3448 TOOLBAR_INFO *infoPtr = TOOLBAR_GetInfoPtr (hwnd);
3449 INT nIndex;
3451 nIndex = TOOLBAR_GetButtonIndex (infoPtr, (INT)wParam, FALSE);
3452 if (nIndex == -1)
3453 return -1;
3455 return infoPtr->buttons[nIndex].fsStyle;
3459 static LRESULT
3460 TOOLBAR_GetTextRows (HWND hwnd, WPARAM wParam, LPARAM lParam)
3462 TOOLBAR_INFO *infoPtr = TOOLBAR_GetInfoPtr (hwnd);
3464 if (infoPtr == NULL)
3465 return 0;
3467 return infoPtr->nMaxTextRows;
3471 static LRESULT
3472 TOOLBAR_GetToolTips (HWND hwnd, WPARAM wParam, LPARAM lParam)
3474 TOOLBAR_INFO *infoPtr = TOOLBAR_GetInfoPtr (hwnd);
3476 if (infoPtr == NULL)
3477 return 0;
3478 return (LRESULT)infoPtr->hwndToolTip;
3482 static LRESULT
3483 TOOLBAR_GetUnicodeFormat (HWND hwnd, WPARAM wParam, LPARAM lParam)
3485 TOOLBAR_INFO *infoPtr = TOOLBAR_GetInfoPtr (hwnd);
3487 TRACE("%s hwnd=%p stub!\n",
3488 infoPtr->bUnicode ? "TRUE" : "FALSE", hwnd);
3490 return infoPtr->bUnicode;
3494 inline static LRESULT
3495 TOOLBAR_GetVersion (HWND hwnd)
3497 TOOLBAR_INFO *infoPtr = TOOLBAR_GetInfoPtr (hwnd);
3498 return infoPtr->iVersion;
3502 static LRESULT
3503 TOOLBAR_HideButton (HWND hwnd, WPARAM wParam, LPARAM lParam)
3505 TOOLBAR_INFO *infoPtr = TOOLBAR_GetInfoPtr (hwnd);
3506 TBUTTON_INFO *btnPtr;
3507 INT nIndex;
3509 TRACE("\n");
3511 nIndex = TOOLBAR_GetButtonIndex (infoPtr, (INT)wParam, FALSE);
3512 if (nIndex == -1)
3513 return FALSE;
3515 btnPtr = &infoPtr->buttons[nIndex];
3516 if (LOWORD(lParam) == FALSE)
3517 btnPtr->fsState &= ~TBSTATE_HIDDEN;
3518 else
3519 btnPtr->fsState |= TBSTATE_HIDDEN;
3521 TOOLBAR_CalcToolbar (hwnd);
3523 InvalidateRect (hwnd, NULL, TRUE);
3525 return TRUE;
3529 inline static LRESULT
3530 TOOLBAR_HitTest (HWND hwnd, WPARAM wParam, LPARAM lParam)
3532 return TOOLBAR_InternalHitTest (hwnd, (LPPOINT)lParam);
3536 static LRESULT
3537 TOOLBAR_Indeterminate (HWND hwnd, WPARAM wParam, LPARAM lParam)
3539 TOOLBAR_INFO *infoPtr = TOOLBAR_GetInfoPtr (hwnd);
3540 TBUTTON_INFO *btnPtr;
3541 INT nIndex;
3543 nIndex = TOOLBAR_GetButtonIndex (infoPtr, (INT)wParam, FALSE);
3544 if (nIndex == -1)
3545 return FALSE;
3547 btnPtr = &infoPtr->buttons[nIndex];
3548 if (LOWORD(lParam) == FALSE)
3549 btnPtr->fsState &= ~TBSTATE_INDETERMINATE;
3550 else
3551 btnPtr->fsState |= TBSTATE_INDETERMINATE;
3553 InvalidateRect(hwnd, &btnPtr->rect, TOOLBAR_HasText(infoPtr, btnPtr));
3555 return TRUE;
3559 static LRESULT
3560 TOOLBAR_InsertButtonA (HWND hwnd, WPARAM wParam, LPARAM lParam)
3562 TOOLBAR_INFO *infoPtr = TOOLBAR_GetInfoPtr (hwnd);
3563 LPTBBUTTON lpTbb = (LPTBBUTTON)lParam;
3564 INT nIndex = (INT)wParam;
3565 TBUTTON_INFO *oldButtons;
3567 if (lpTbb == NULL)
3568 return FALSE;
3570 TOOLBAR_DumpButton(infoPtr, (TBUTTON_INFO *)lpTbb, nIndex, FALSE);
3572 if (nIndex == -1) {
3573 /* EPP: this seems to be an undocumented call (from my IE4)
3574 * I assume in that case that:
3575 * - lpTbb->iString is a string pointer (not a string index in strings[] table
3576 * - index of insertion is at the end of existing buttons
3577 * I only see this happen with nIndex == -1, but it could have a special
3578 * meaning (like -nIndex (or ~nIndex) to get the real position of insertion).
3580 nIndex = infoPtr->nNumButtons;
3582 } else if (nIndex < 0)
3583 return FALSE;
3585 /* If the string passed is not an index, assume address of string
3586 and do our own AddString */
3587 if ((HIWORD(lpTbb->iString) != 0) && (lpTbb->iString != -1)) {
3588 LPSTR ptr;
3589 INT len;
3591 TRACE("string %s passed instead of index, adding string\n",
3592 debugstr_a((LPSTR)lpTbb->iString));
3593 len = strlen((LPSTR)lpTbb->iString) + 2;
3594 ptr = Alloc(len);
3595 strcpy(ptr, (LPSTR)lpTbb->iString);
3596 ptr[len - 1] = 0; /* ended by two '\0' */
3597 lpTbb->iString = TOOLBAR_AddStringA(hwnd, 0, (LPARAM)ptr);
3598 Free(ptr);
3601 TRACE("inserting button index=%d\n", nIndex);
3602 if (nIndex > infoPtr->nNumButtons) {
3603 nIndex = infoPtr->nNumButtons;
3604 TRACE("adjust index=%d\n", nIndex);
3607 oldButtons = infoPtr->buttons;
3608 infoPtr->nNumButtons++;
3609 infoPtr->buttons = Alloc (sizeof (TBUTTON_INFO) * infoPtr->nNumButtons);
3610 /* pre insert copy */
3611 if (nIndex > 0) {
3612 memcpy (&infoPtr->buttons[0], &oldButtons[0],
3613 nIndex * sizeof(TBUTTON_INFO));
3616 /* insert new button */
3617 infoPtr->buttons[nIndex].iBitmap = lpTbb->iBitmap;
3618 infoPtr->buttons[nIndex].idCommand = lpTbb->idCommand;
3619 infoPtr->buttons[nIndex].fsState = lpTbb->fsState;
3620 infoPtr->buttons[nIndex].fsStyle = lpTbb->fsStyle;
3621 infoPtr->buttons[nIndex].dwData = lpTbb->dwData;
3622 /* if passed string and not index, then add string */
3623 if(HIWORD(lpTbb->iString) && lpTbb->iString!=-1) {
3624 Str_SetPtrAtoW ((LPWSTR *)&infoPtr->buttons[nIndex].iString, (LPCSTR )lpTbb->iString);
3626 else
3627 infoPtr->buttons[nIndex].iString = lpTbb->iString;
3629 if ((infoPtr->hwndToolTip) && !(lpTbb->fsStyle & BTNS_SEP)) {
3630 TTTOOLINFOA ti;
3632 ZeroMemory (&ti, sizeof(TTTOOLINFOA));
3633 ti.cbSize = sizeof (TTTOOLINFOA);
3634 ti.hwnd = hwnd;
3635 ti.uId = lpTbb->idCommand;
3636 ti.hinst = 0;
3637 ti.lpszText = LPSTR_TEXTCALLBACKA;
3639 SendMessageA (infoPtr->hwndToolTip, TTM_ADDTOOLA,
3640 0, (LPARAM)&ti);
3643 /* post insert copy */
3644 if (nIndex < infoPtr->nNumButtons - 1) {
3645 memcpy (&infoPtr->buttons[nIndex+1], &oldButtons[nIndex],
3646 (infoPtr->nNumButtons - nIndex - 1) * sizeof(TBUTTON_INFO));
3649 Free (oldButtons);
3651 TOOLBAR_CalcToolbar (hwnd);
3653 InvalidateRect (hwnd, NULL, TRUE);
3655 return TRUE;
3659 static LRESULT
3660 TOOLBAR_InsertButtonW (HWND hwnd, WPARAM wParam, LPARAM lParam)
3662 TOOLBAR_INFO *infoPtr = TOOLBAR_GetInfoPtr (hwnd);
3663 LPTBBUTTON lpTbb = (LPTBBUTTON)lParam;
3664 INT nIndex = (INT)wParam;
3665 TBUTTON_INFO *oldButtons;
3667 if (lpTbb == NULL)
3668 return FALSE;
3670 TOOLBAR_DumpButton(infoPtr, (TBUTTON_INFO *)lpTbb, nIndex, FALSE);
3672 if (nIndex == -1) {
3673 /* EPP: this seems to be an undocumented call (from my IE4)
3674 * I assume in that case that:
3675 * - lpTbb->iString is a string pointer (not a string index in strings[] table
3676 * - index of insertion is at the end of existing buttons
3677 * I only see this happen with nIndex == -1, but it could have a special
3678 * meaning (like -nIndex (or ~nIndex) to get the real position of insertion).
3680 nIndex = infoPtr->nNumButtons;
3682 } else if (nIndex < 0)
3683 return FALSE;
3685 /* If the string passed is not an index, assume address of string
3686 and do our own AddString */
3687 if ((HIWORD(lpTbb->iString) != 0) && (lpTbb->iString != -1)) {
3688 LPWSTR ptr;
3689 INT len;
3691 TRACE("string %s passed instead of index, adding string\n",
3692 debugstr_w((LPWSTR)lpTbb->iString));
3693 len = strlenW((LPWSTR)lpTbb->iString) + 2;
3694 ptr = Alloc(len*sizeof(WCHAR));
3695 strcpyW(ptr, (LPWSTR)lpTbb->iString);
3696 ptr[len - 1] = 0; /* ended by two '\0' */
3697 lpTbb->iString = TOOLBAR_AddStringW(hwnd, 0, (LPARAM)ptr);
3698 Free(ptr);
3701 TRACE("inserting button index=%d\n", nIndex);
3702 if (nIndex > infoPtr->nNumButtons) {
3703 nIndex = infoPtr->nNumButtons;
3704 TRACE("adjust index=%d\n", nIndex);
3707 oldButtons = infoPtr->buttons;
3708 infoPtr->nNumButtons++;
3709 infoPtr->buttons = Alloc (sizeof (TBUTTON_INFO) * infoPtr->nNumButtons);
3710 /* pre insert copy */
3711 if (nIndex > 0) {
3712 memcpy (&infoPtr->buttons[0], &oldButtons[0],
3713 nIndex * sizeof(TBUTTON_INFO));
3716 /* insert new button */
3717 infoPtr->buttons[nIndex].iBitmap = lpTbb->iBitmap;
3718 infoPtr->buttons[nIndex].idCommand = lpTbb->idCommand;
3719 infoPtr->buttons[nIndex].fsState = lpTbb->fsState;
3720 infoPtr->buttons[nIndex].fsStyle = lpTbb->fsStyle;
3721 infoPtr->buttons[nIndex].dwData = lpTbb->dwData;
3722 /* if passed string and not index, then add string */
3723 if(HIWORD(lpTbb->iString) && lpTbb->iString!=-1) {
3724 Str_SetPtrW ((LPWSTR *)&infoPtr->buttons[nIndex].iString, (LPWSTR)lpTbb->iString);
3726 else
3727 infoPtr->buttons[nIndex].iString = lpTbb->iString;
3729 if ((infoPtr->hwndToolTip) && !(lpTbb->fsStyle & BTNS_SEP)) {
3730 TTTOOLINFOW ti;
3732 ZeroMemory (&ti, sizeof(TTTOOLINFOW));
3733 ti.cbSize = sizeof (TTTOOLINFOW);
3734 ti.hwnd = hwnd;
3735 ti.uId = lpTbb->idCommand;
3736 ti.hinst = 0;
3737 ti.lpszText = LPSTR_TEXTCALLBACKW;
3739 SendMessageW (infoPtr->hwndToolTip, TTM_ADDTOOLW,
3740 0, (LPARAM)&ti);
3743 /* post insert copy */
3744 if (nIndex < infoPtr->nNumButtons - 1) {
3745 memcpy (&infoPtr->buttons[nIndex+1], &oldButtons[nIndex],
3746 (infoPtr->nNumButtons - nIndex - 1) * sizeof(TBUTTON_INFO));
3749 Free (oldButtons);
3751 TOOLBAR_CalcToolbar (hwnd);
3753 InvalidateRect (hwnd, NULL, TRUE);
3755 return TRUE;
3759 /* << TOOLBAR_InsertMarkHitTest >> */
3762 static LRESULT
3763 TOOLBAR_IsButtonChecked (HWND hwnd, WPARAM wParam, LPARAM lParam)
3765 TOOLBAR_INFO *infoPtr = TOOLBAR_GetInfoPtr (hwnd);
3766 INT nIndex;
3768 nIndex = TOOLBAR_GetButtonIndex (infoPtr, (INT)wParam, FALSE);
3769 if (nIndex == -1)
3770 return FALSE;
3772 return (infoPtr->buttons[nIndex].fsState & TBSTATE_CHECKED);
3776 static LRESULT
3777 TOOLBAR_IsButtonEnabled (HWND hwnd, WPARAM wParam, LPARAM lParam)
3779 TOOLBAR_INFO *infoPtr = TOOLBAR_GetInfoPtr (hwnd);
3780 INT nIndex;
3782 nIndex = TOOLBAR_GetButtonIndex (infoPtr, (INT)wParam, FALSE);
3783 if (nIndex == -1)
3784 return FALSE;
3786 return (infoPtr->buttons[nIndex].fsState & TBSTATE_ENABLED);
3790 static LRESULT
3791 TOOLBAR_IsButtonHidden (HWND hwnd, WPARAM wParam, LPARAM lParam)
3793 TOOLBAR_INFO *infoPtr = TOOLBAR_GetInfoPtr (hwnd);
3794 INT nIndex;
3796 nIndex = TOOLBAR_GetButtonIndex (infoPtr, (INT)wParam, FALSE);
3797 if (nIndex == -1)
3798 return TRUE;
3800 return (infoPtr->buttons[nIndex].fsState & TBSTATE_HIDDEN);
3804 static LRESULT
3805 TOOLBAR_IsButtonHighlighted (HWND hwnd, WPARAM wParam, LPARAM lParam)
3807 TOOLBAR_INFO *infoPtr = TOOLBAR_GetInfoPtr (hwnd);
3808 INT nIndex;
3810 nIndex = TOOLBAR_GetButtonIndex (infoPtr, (INT)wParam, FALSE);
3811 if (nIndex == -1)
3812 return FALSE;
3814 return (infoPtr->buttons[nIndex].fsState & TBSTATE_MARKED);
3818 static LRESULT
3819 TOOLBAR_IsButtonIndeterminate (HWND hwnd, WPARAM wParam, LPARAM lParam)
3821 TOOLBAR_INFO *infoPtr = TOOLBAR_GetInfoPtr (hwnd);
3822 INT nIndex;
3824 nIndex = TOOLBAR_GetButtonIndex (infoPtr, (INT)wParam, FALSE);
3825 if (nIndex == -1)
3826 return FALSE;
3828 return (infoPtr->buttons[nIndex].fsState & TBSTATE_INDETERMINATE);
3832 static LRESULT
3833 TOOLBAR_IsButtonPressed (HWND hwnd, WPARAM wParam, LPARAM lParam)
3835 TOOLBAR_INFO *infoPtr = TOOLBAR_GetInfoPtr (hwnd);
3836 INT nIndex;
3838 nIndex = TOOLBAR_GetButtonIndex (infoPtr, (INT)wParam, FALSE);
3839 if (nIndex == -1)
3840 return FALSE;
3842 return (infoPtr->buttons[nIndex].fsState & TBSTATE_PRESSED);
3846 /* << TOOLBAR_LoadImages >> */
3847 /* << TOOLBAR_MapAccelerator >> */
3848 /* << TOOLBAR_MarkButton >> */
3849 /* << TOOLBAR_MoveButton >> */
3852 static LRESULT
3853 TOOLBAR_PressButton (HWND hwnd, WPARAM wParam, LPARAM lParam)
3855 TOOLBAR_INFO *infoPtr = TOOLBAR_GetInfoPtr (hwnd);
3856 TBUTTON_INFO *btnPtr;
3857 INT nIndex;
3859 nIndex = TOOLBAR_GetButtonIndex (infoPtr, (INT)wParam, FALSE);
3860 if (nIndex == -1)
3861 return FALSE;
3863 btnPtr = &infoPtr->buttons[nIndex];
3864 if (LOWORD(lParam) == FALSE)
3865 btnPtr->fsState &= ~TBSTATE_PRESSED;
3866 else
3867 btnPtr->fsState |= TBSTATE_PRESSED;
3869 InvalidateRect(hwnd, &btnPtr->rect, TOOLBAR_HasText(infoPtr, btnPtr));
3871 return TRUE;
3874 /* FIXME: there might still be some confusion her between number of buttons
3875 * and number of bitmaps */
3876 static LRESULT
3877 TOOLBAR_ReplaceBitmap (HWND hwnd, WPARAM wParam, LPARAM lParam)
3879 TOOLBAR_INFO *infoPtr = TOOLBAR_GetInfoPtr (hwnd);
3880 LPTBREPLACEBITMAP lpReplace = (LPTBREPLACEBITMAP) lParam;
3881 HBITMAP hBitmap;
3882 int i = 0, nOldButtons = 0, pos = 0;
3883 int nOldBitmaps, nNewBitmaps;
3884 HIMAGELIST himlDef = 0;
3886 TRACE("hInstOld %p nIDOld %x hInstNew %p nIDNew %x nButtons %x\n",
3887 lpReplace->hInstOld, lpReplace->nIDOld, lpReplace->hInstNew, lpReplace->nIDNew,
3888 lpReplace->nButtons);
3890 if (lpReplace->hInstOld == HINST_COMMCTRL)
3892 FIXME("changing standard bitmaps not implemented\n");
3893 return FALSE;
3895 else if (lpReplace->hInstOld != 0)
3897 FIXME("resources not in the current module not implemented\n");
3898 return FALSE;
3900 else
3902 hBitmap = (HBITMAP) lpReplace->nIDNew;
3905 TRACE("To be replaced hInstOld %p nIDOld %x\n", lpReplace->hInstOld, lpReplace->nIDOld);
3906 for (i = 0; i < infoPtr->nNumBitmapInfos; i++) {
3907 TBITMAP_INFO *tbi = &infoPtr->bitmaps[i];
3908 TRACE("tbimapinfo %d hInstOld %p nIDOld %x\n", i, tbi->hInst, tbi->nID);
3909 if (tbi->hInst == lpReplace->hInstOld && tbi->nID == lpReplace->nIDOld)
3911 TRACE("Found: nButtons %d hInst %p nID %x\n", tbi->nButtons, tbi->hInst, tbi->nID);
3912 nOldButtons = tbi->nButtons;
3913 tbi->nButtons = lpReplace->nButtons;
3914 tbi->hInst = lpReplace->hInstNew;
3915 tbi->nID = lpReplace->nIDNew;
3916 TRACE("tbimapinfo changed %d hInstOld %p nIDOld %x\n", i, tbi->hInst, tbi->nID);
3917 break;
3919 pos += tbi->nButtons;
3922 if (nOldButtons == 0)
3924 WARN("No hinst/bitmap found! hInst %p nID %x\n", lpReplace->hInstOld, lpReplace->nIDOld);
3925 return FALSE;
3928 himlDef = GETDEFIMAGELIST(infoPtr, 0); /* fixme: correct? */
3929 nOldBitmaps = ImageList_GetImageCount(himlDef);
3931 /* ImageList_Replace(GETDEFIMAGELIST(), pos, hBitmap, NULL); */
3933 for (i = pos + nOldBitmaps - 1; i >= pos; i--)
3934 ImageList_Remove(himlDef, i);
3937 BITMAP bmp;
3938 HBITMAP hOldBitmapBitmap, hOldBitmapLoad, hbmLoad;
3939 HDC hdcImage, hdcBitmap;
3941 /* copy the bitmap before adding it so that the user's bitmap
3942 * doesn't get modified.
3944 GetObjectA (hBitmap, sizeof(BITMAP), (LPVOID)&bmp);
3946 hdcImage = CreateCompatibleDC(0);
3947 hdcBitmap = CreateCompatibleDC(0);
3949 /* create new bitmap */
3950 hbmLoad = CreateBitmap (bmp.bmWidth, bmp.bmHeight, bmp.bmPlanes, bmp.bmBitsPixel, NULL);
3951 hOldBitmapBitmap = SelectObject(hdcBitmap, hBitmap);
3952 hOldBitmapLoad = SelectObject(hdcImage, hbmLoad);
3954 /* Copy the user's image */
3955 BitBlt (hdcImage, 0, 0, bmp.bmWidth, bmp.bmHeight,
3956 hdcBitmap, 0, 0, SRCCOPY);
3958 SelectObject (hdcImage, hOldBitmapLoad);
3959 SelectObject (hdcBitmap, hOldBitmapBitmap);
3960 DeleteDC (hdcImage);
3961 DeleteDC (hdcBitmap);
3963 ImageList_AddMasked (himlDef, hbmLoad, comctl32_color.clrBtnFace);
3964 nNewBitmaps = ImageList_GetImageCount(himlDef);
3965 DeleteObject (hbmLoad);
3968 infoPtr->nNumBitmaps = infoPtr->nNumBitmaps - nOldBitmaps + nNewBitmaps;
3970 TRACE(" pos %d %d old bitmaps replaced by %d new ones.\n",
3971 pos, nOldBitmaps, nNewBitmaps);
3973 InvalidateRect(hwnd, NULL, FALSE);
3975 return TRUE;
3978 static LRESULT
3979 TOOLBAR_SaveRestoreA (HWND hwnd, WPARAM wParam, LPARAM lParam)
3981 #if 0
3982 TOOLBAR_INFO *infoPtr = TOOLBAR_GetInfoPtr (hwnd);
3983 LPTBSAVEPARAMSA lpSave = (LPTBSAVEPARAMSA)lParam;
3985 if (lpSave == NULL) return 0;
3987 if ((BOOL)wParam) {
3988 /* save toolbar information */
3989 FIXME("save to \"%s\" \"%s\"\n",
3990 lpSave->pszSubKey, lpSave->pszValueName);
3994 else {
3995 /* restore toolbar information */
3997 FIXME("restore from \"%s\" \"%s\"\n",
3998 lpSave->pszSubKey, lpSave->pszValueName);
4002 #endif
4004 return 0;
4008 static LRESULT
4009 TOOLBAR_SaveRestoreW (HWND hwnd, WPARAM wParam, LPARAM lParam)
4011 #if 0
4012 TOOLBAR_INFO *infoPtr = TOOLBAR_GetInfoPtr (hwnd);
4013 LPTBSAVEPARAMSW lpSave = (LPTBSAVEPARAMSW)lParam;
4015 if (lpSave == NULL)
4016 return 0;
4018 if ((BOOL)wParam) {
4019 /* save toolbar information */
4020 FIXME("save to \"%s\" \"%s\"\n",
4021 lpSave->pszSubKey, lpSave->pszValueName);
4025 else {
4026 /* restore toolbar information */
4028 FIXME("restore from \"%s\" \"%s\"\n",
4029 lpSave->pszSubKey, lpSave->pszValueName);
4033 #endif
4035 return 0;
4039 static LRESULT
4040 TOOLBAR_SetAnchorHighlight (HWND hwnd, WPARAM wParam)
4042 TOOLBAR_INFO *infoPtr = TOOLBAR_GetInfoPtr (hwnd);
4043 BOOL bOldAnchor = infoPtr->bAnchor;
4045 infoPtr->bAnchor = (BOOL)wParam;
4047 return (LRESULT)bOldAnchor;
4051 static LRESULT
4052 TOOLBAR_SetBitmapSize (HWND hwnd, WPARAM wParam, LPARAM lParam)
4054 TOOLBAR_INFO *infoPtr = TOOLBAR_GetInfoPtr (hwnd);
4055 HIMAGELIST himlDef = GETDEFIMAGELIST(infoPtr, 0);
4057 if ((LOWORD(lParam) <= 0) || (HIWORD(lParam)<=0))
4058 return FALSE;
4060 if (infoPtr->nNumButtons > 0)
4061 WARN("%d buttons, undoc increase to bitmap size : %d-%d -> %d-%d\n",
4062 infoPtr->nNumButtons,
4063 infoPtr->nBitmapWidth, infoPtr->nBitmapHeight,
4064 LOWORD(lParam), HIWORD(lParam));
4066 infoPtr->nBitmapWidth = (INT)LOWORD(lParam);
4067 infoPtr->nBitmapHeight = (INT)HIWORD(lParam);
4070 /* uses image list internals directly */
4071 if (himlDef) {
4072 himlDef->cx = infoPtr->nBitmapWidth;
4073 himlDef->cy = infoPtr->nBitmapHeight;
4076 return TRUE;
4080 static LRESULT
4081 TOOLBAR_SetButtonInfoA (HWND hwnd, WPARAM wParam, LPARAM lParam)
4083 TOOLBAR_INFO *infoPtr = TOOLBAR_GetInfoPtr (hwnd);
4084 LPTBBUTTONINFOA lptbbi = (LPTBBUTTONINFOA)lParam;
4085 TBUTTON_INFO *btnPtr;
4086 INT nIndex;
4088 if (lptbbi == NULL)
4089 return FALSE;
4090 if (lptbbi->cbSize < sizeof(TBBUTTONINFOA))
4091 return FALSE;
4093 nIndex = TOOLBAR_GetButtonIndex (infoPtr, (INT)wParam,
4094 lptbbi->dwMask & 0x80000000);
4095 if (nIndex == -1)
4096 return FALSE;
4098 btnPtr = &infoPtr->buttons[nIndex];
4099 if (lptbbi->dwMask & TBIF_COMMAND)
4100 btnPtr->idCommand = lptbbi->idCommand;
4101 if (lptbbi->dwMask & TBIF_IMAGE)
4102 btnPtr->iBitmap = lptbbi->iImage;
4103 if (lptbbi->dwMask & TBIF_LPARAM)
4104 btnPtr->dwData = lptbbi->lParam;
4105 /* if (lptbbi->dwMask & TBIF_SIZE) */
4106 /* btnPtr->cx = lptbbi->cx; */
4107 if (lptbbi->dwMask & TBIF_STATE)
4108 btnPtr->fsState = lptbbi->fsState;
4109 if (lptbbi->dwMask & TBIF_STYLE)
4110 btnPtr->fsStyle = lptbbi->fsStyle;
4112 if ((lptbbi->dwMask & TBIF_TEXT) && ((INT)lptbbi->pszText != -1)) {
4113 if ((HIWORD(btnPtr->iString) == 0) || (btnPtr->iString == -1))
4114 /* iString is index, zero it to make Str_SetPtr succeed */
4115 btnPtr->iString=0;
4117 Str_SetPtrAtoW ((LPWSTR *)&btnPtr->iString, lptbbi->pszText);
4119 return TRUE;
4123 static LRESULT
4124 TOOLBAR_SetButtonInfoW (HWND hwnd, WPARAM wParam, LPARAM lParam)
4126 TOOLBAR_INFO *infoPtr = TOOLBAR_GetInfoPtr (hwnd);
4127 LPTBBUTTONINFOW lptbbi = (LPTBBUTTONINFOW)lParam;
4128 TBUTTON_INFO *btnPtr;
4129 INT nIndex;
4131 if (lptbbi == NULL)
4132 return FALSE;
4133 if (lptbbi->cbSize < sizeof(TBBUTTONINFOW))
4134 return FALSE;
4136 nIndex = TOOLBAR_GetButtonIndex (infoPtr, (INT)wParam,
4137 lptbbi->dwMask & 0x80000000);
4138 if (nIndex == -1)
4139 return FALSE;
4141 btnPtr = &infoPtr->buttons[nIndex];
4142 if (lptbbi->dwMask & TBIF_COMMAND)
4143 btnPtr->idCommand = lptbbi->idCommand;
4144 if (lptbbi->dwMask & TBIF_IMAGE)
4145 btnPtr->iBitmap = lptbbi->iImage;
4146 if (lptbbi->dwMask & TBIF_LPARAM)
4147 btnPtr->dwData = lptbbi->lParam;
4148 /* if (lptbbi->dwMask & TBIF_SIZE) */
4149 /* btnPtr->cx = lptbbi->cx; */
4150 if (lptbbi->dwMask & TBIF_STATE)
4151 btnPtr->fsState = lptbbi->fsState;
4152 if (lptbbi->dwMask & TBIF_STYLE)
4153 btnPtr->fsStyle = lptbbi->fsStyle;
4155 if ((lptbbi->dwMask & TBIF_TEXT) && ((INT)lptbbi->pszText != -1)) {
4156 if ((HIWORD(btnPtr->iString) == 0) || (btnPtr->iString == -1))
4157 /* iString is index, zero it to make Str_SetPtr succeed */
4158 btnPtr->iString=0;
4159 Str_SetPtrW ((LPWSTR *)&btnPtr->iString, lptbbi->pszText);
4161 return TRUE;
4165 static LRESULT
4166 TOOLBAR_SetButtonSize (HWND hwnd, WPARAM wParam, LPARAM lParam)
4168 TOOLBAR_INFO *infoPtr = TOOLBAR_GetInfoPtr (hwnd);
4169 INT cx = LOWORD(lParam), cy = HIWORD(lParam);
4171 if ((cx < 0) || (cy < 0))
4173 ERR("invalid parameter 0x%08lx\n", (DWORD)lParam);
4174 return FALSE;
4177 /* The documentation claims you can only change the button size before
4178 * any button has been added. But this is wrong.
4179 * WINZIP32.EXE (ver 8) calls this on one of its buttons after adding
4180 * it to the toolbar, and it checks that the return value is nonzero - mjm
4181 * Further testing shows that we must actually perform the change too.
4184 * The documentation also does not mention that if 0 is supplied for
4185 * either size, the system changes it to the default of 24 wide and
4186 * 22 high. Demonstarted in ControlSpy Toolbar. GLA 3/02
4188 infoPtr->nButtonWidth = (cx) ? cx : 24;
4189 infoPtr->nButtonHeight = (cy) ? cy : 22;
4190 return TRUE;
4194 static LRESULT
4195 TOOLBAR_SetButtonWidth (HWND hwnd, WPARAM wParam, LPARAM lParam)
4197 TOOLBAR_INFO *infoPtr = TOOLBAR_GetInfoPtr (hwnd);
4199 if (infoPtr == NULL) {
4200 TRACE("Toolbar not initialized yet?????\n");
4201 return FALSE;
4204 /* if setting to current values, ignore */
4205 if ((infoPtr->cxMin == (INT)LOWORD(lParam)) &&
4206 (infoPtr->cxMax == (INT)HIWORD(lParam))) {
4207 TRACE("matches current width, min=%d, max=%d, no recalc\n",
4208 infoPtr->cxMin, infoPtr->cxMax);
4209 return TRUE;
4212 /* save new values */
4213 infoPtr->cxMin = (INT)LOWORD(lParam);
4214 infoPtr->cxMax = (INT)HIWORD(lParam);
4216 /* if both values are 0 then we are done */
4217 if (lParam == 0) {
4218 TRACE("setting both min and max to 0, norecalc\n");
4219 return TRUE;
4222 /* otherwise we need to recalc the toolbar and in some cases
4223 recalc the bounding rectangle (does DrawText w/ DT_CALCRECT
4224 which doesn't actually draw - GA). */
4225 TRACE("number of buttons %d, cx=%d, cy=%d, recalcing\n",
4226 infoPtr->nNumButtons, infoPtr->cxMin, infoPtr->cxMax);
4228 TOOLBAR_CalcToolbar (hwnd);
4230 InvalidateRect (hwnd, NULL, TRUE);
4232 return TRUE;
4236 static LRESULT
4237 TOOLBAR_SetCmdId (HWND hwnd, WPARAM wParam, LPARAM lParam)
4239 TOOLBAR_INFO *infoPtr = TOOLBAR_GetInfoPtr (hwnd);
4240 INT nIndex = (INT)wParam;
4242 if ((nIndex < 0) || (nIndex >= infoPtr->nNumButtons))
4243 return FALSE;
4245 infoPtr->buttons[nIndex].idCommand = (INT)lParam;
4247 if (infoPtr->hwndToolTip) {
4249 FIXME("change tool tip!\n");
4253 return TRUE;
4257 static LRESULT
4258 TOOLBAR_SetDisabledImageList (HWND hwnd, WPARAM wParam, LPARAM lParam)
4260 TOOLBAR_INFO *infoPtr = TOOLBAR_GetInfoPtr (hwnd);
4261 HIMAGELIST himl = (HIMAGELIST)lParam;
4262 HIMAGELIST himlTemp;
4263 INT id = 0;
4265 if (infoPtr->iVersion >= 5)
4266 id = wParam;
4268 himlTemp = TOOLBAR_InsertImageList(&infoPtr->himlDis,
4269 &infoPtr->cimlDis, himl, id);
4271 /* FIXME: redraw ? */
4273 return (LRESULT)himlTemp;
4277 static LRESULT
4278 TOOLBAR_SetDrawTextFlags (HWND hwnd, WPARAM wParam, LPARAM lParam)
4280 TOOLBAR_INFO *infoPtr = TOOLBAR_GetInfoPtr (hwnd);
4281 DWORD dwTemp;
4283 dwTemp = infoPtr->dwDTFlags;
4284 infoPtr->dwDTFlags =
4285 (infoPtr->dwDTFlags & (DWORD)wParam) | (DWORD)lParam;
4287 return (LRESULT)dwTemp;
4290 static LRESULT
4291 TOOLBAR_SetExtendedStyle (HWND hwnd, WPARAM wParam, LPARAM lParam)
4293 TOOLBAR_INFO *infoPtr = TOOLBAR_GetInfoPtr (hwnd);
4294 DWORD dwTemp;
4296 dwTemp = infoPtr->dwExStyle;
4297 infoPtr->dwExStyle |= (DWORD)lParam;
4299 TRACE("new style 0x%08lx\n", infoPtr->dwExStyle);
4301 if (infoPtr->dwExStyle & ~TBSTYLE_EX_ALL)
4302 FIXME("Unknown Toolbar Extended Style 0x%08lx. Please report.\n",
4303 (infoPtr->dwExStyle & ~TBSTYLE_EX_ALL));
4305 TOOLBAR_CalcToolbar (hwnd);
4307 TOOLBAR_AutoSize(hwnd);
4309 InvalidateRect(hwnd, NULL, FALSE);
4311 return (LRESULT)dwTemp;
4315 static LRESULT
4316 TOOLBAR_SetHotImageList (HWND hwnd, WPARAM wParam, LPARAM lParam)
4318 TOOLBAR_INFO *infoPtr = TOOLBAR_GetInfoPtr(hwnd);
4319 HIMAGELIST himlTemp;
4320 HIMAGELIST himl = (HIMAGELIST)lParam;
4321 INT id = 0;
4323 if (infoPtr->iVersion >= 5)
4324 id = wParam;
4326 TRACE("hwnd = %p, himl = %p, id = %d\n", hwnd, himl, id);
4328 himlTemp = TOOLBAR_InsertImageList(&infoPtr->himlHot,
4329 &infoPtr->cimlHot, himl, id);
4331 /* FIXME: redraw ? */
4333 return (LRESULT)himlTemp;
4337 static LRESULT
4338 TOOLBAR_SetHotItem (HWND hwnd, WPARAM wParam)
4340 TOOLBAR_INFO *infoPtr = TOOLBAR_GetInfoPtr(hwnd);
4341 INT nOldHotItem = infoPtr->nHotItem;
4342 TBUTTON_INFO *btnPtr;
4344 if ((INT) wParam < 0 || (INT)wParam > infoPtr->nNumButtons)
4345 wParam = -2;
4347 if (GetWindowLongA (hwnd, GWL_STYLE) & TBSTYLE_FLAT)
4350 infoPtr->nHotItem = (INT)wParam;
4351 if ((INT)wParam >=0)
4353 btnPtr = &infoPtr->buttons[(INT)wParam];
4354 btnPtr->bHot = TRUE;
4355 InvalidateRect (hwnd, &btnPtr->rect,
4356 TOOLBAR_HasText(infoPtr, btnPtr));
4358 if (nOldHotItem>=0)
4360 btnPtr = &infoPtr->buttons[nOldHotItem];
4361 btnPtr->bHot = FALSE;
4362 InvalidateRect (hwnd, &btnPtr->rect,
4363 TOOLBAR_HasText(infoPtr, btnPtr));
4367 if (nOldHotItem < 0)
4368 return -1;
4370 return (LRESULT)nOldHotItem;
4374 static LRESULT
4375 TOOLBAR_SetImageList (HWND hwnd, WPARAM wParam, LPARAM lParam)
4377 TOOLBAR_INFO *infoPtr = TOOLBAR_GetInfoPtr (hwnd);
4378 HIMAGELIST himlTemp;
4379 HIMAGELIST himl = (HIMAGELIST)lParam;
4380 INT i, id = 0;
4382 if (infoPtr->iVersion >= 5)
4383 id = wParam;
4385 himlTemp = TOOLBAR_InsertImageList(&infoPtr->himlDef,
4386 &infoPtr->cimlDef, himl, id);
4388 infoPtr->nNumBitmaps = 0;
4389 for (i = 0; i < infoPtr->cimlDef; i++)
4390 infoPtr->nNumBitmaps += ImageList_GetImageCount(infoPtr->himlDef[i]->himl);
4392 ImageList_GetIconSize(himl, &infoPtr->nBitmapWidth,
4393 &infoPtr->nBitmapHeight);
4394 TRACE("hwnd %p, new himl=%08x, count=%d, bitmap w=%d, h=%d\n",
4395 hwnd, (INT)infoPtr->himlDef, infoPtr->nNumBitmaps,
4396 infoPtr->nBitmapWidth, infoPtr->nBitmapHeight);
4398 /* FIXME: redraw ? */
4399 InvalidateRect(hwnd, NULL, TRUE);
4401 return (LRESULT)himlTemp;
4405 static LRESULT
4406 TOOLBAR_SetIndent (HWND hwnd, WPARAM wParam, LPARAM lParam)
4408 TOOLBAR_INFO *infoPtr = TOOLBAR_GetInfoPtr (hwnd);
4410 infoPtr->nIndent = (INT)wParam;
4412 TRACE("\n");
4414 /* process only on indent changing */
4415 if(infoPtr->nIndent != (INT)wParam)
4417 infoPtr->nIndent = (INT)wParam;
4418 TOOLBAR_CalcToolbar (hwnd);
4419 InvalidateRect(hwnd, NULL, FALSE);
4422 return TRUE;
4426 /* << TOOLBAR_SetInsertMark >> */
4429 static LRESULT
4430 TOOLBAR_SetInsertMarkColor (HWND hwnd, WPARAM wParam, LPARAM lParam)
4432 TOOLBAR_INFO *infoPtr = TOOLBAR_GetInfoPtr (hwnd);
4434 infoPtr->clrInsertMark = (COLORREF)lParam;
4436 /* FIXME : redraw ??*/
4438 return 0;
4442 static LRESULT
4443 TOOLBAR_SetMaxTextRows (HWND hwnd, WPARAM wParam, LPARAM lParam)
4445 TOOLBAR_INFO *infoPtr = TOOLBAR_GetInfoPtr (hwnd);
4447 if (infoPtr == NULL)
4448 return FALSE;
4450 infoPtr->nMaxTextRows = (INT)wParam;
4452 return TRUE;
4456 static LRESULT
4457 TOOLBAR_SetPadding (HWND hwnd, WPARAM wParam, LPARAM lParam)
4459 TOOLBAR_INFO *infoPtr = TOOLBAR_GetInfoPtr (hwnd);
4460 DWORD oldPad;
4462 oldPad = MAKELONG(infoPtr->szPadding.cx, infoPtr->szPadding.cy);
4463 infoPtr->szPadding.cx = LOWORD((DWORD)lParam);
4464 infoPtr->szPadding.cy = HIWORD((DWORD)lParam);
4465 FIXME("stub - nothing done with values, cx=%ld, cy=%ld\n",
4466 infoPtr->szPadding.cx, infoPtr->szPadding.cy);
4467 return (LRESULT) oldPad;
4471 static LRESULT
4472 TOOLBAR_SetParent (HWND hwnd, WPARAM wParam, LPARAM lParam)
4474 TOOLBAR_INFO *infoPtr = TOOLBAR_GetInfoPtr (hwnd);
4475 HWND hwndOldNotify;
4477 TRACE("\n");
4479 if (infoPtr == NULL)
4480 return 0;
4481 hwndOldNotify = infoPtr->hwndNotify;
4482 infoPtr->hwndNotify = (HWND)wParam;
4484 return (LRESULT)hwndOldNotify;
4488 static LRESULT
4489 TOOLBAR_SetRows (HWND hwnd, WPARAM wParam, LPARAM lParam)
4491 TOOLBAR_INFO *infoPtr = TOOLBAR_GetInfoPtr (hwnd);
4492 LPRECT lprc = (LPRECT)lParam;
4494 TRACE("\n");
4496 if (LOWORD(wParam) > 1) {
4497 FIXME("multiple rows not supported!\n");
4500 if(infoPtr->nRows != LOWORD(wParam))
4502 infoPtr->nRows = LOWORD(wParam);
4504 /* recalculate toolbar */
4505 TOOLBAR_CalcToolbar (hwnd);
4507 /* repaint toolbar */
4508 InvalidateRect(hwnd, NULL, FALSE);
4511 /* return bounding rectangle */
4512 if (lprc) {
4513 lprc->left = infoPtr->rcBound.left;
4514 lprc->right = infoPtr->rcBound.right;
4515 lprc->top = infoPtr->rcBound.top;
4516 lprc->bottom = infoPtr->rcBound.bottom;
4519 return 0;
4523 static LRESULT
4524 TOOLBAR_SetState (HWND hwnd, WPARAM wParam, LPARAM lParam)
4526 TOOLBAR_INFO *infoPtr = TOOLBAR_GetInfoPtr (hwnd);
4527 TBUTTON_INFO *btnPtr;
4528 INT nIndex;
4530 nIndex = TOOLBAR_GetButtonIndex (infoPtr, (INT)wParam, FALSE);
4531 if (nIndex == -1)
4532 return FALSE;
4534 btnPtr = &infoPtr->buttons[nIndex];
4536 /* if hidden state has changed the invalidate entire window and recalc */
4537 if ((btnPtr->fsState & TBSTATE_HIDDEN) != (LOWORD(lParam) & TBSTATE_HIDDEN)) {
4538 btnPtr->fsState = LOWORD(lParam);
4539 TOOLBAR_CalcToolbar (hwnd);
4540 InvalidateRect(hwnd, 0, TOOLBAR_HasText(infoPtr, btnPtr));
4541 return TRUE;
4544 /* process state changing if current state doesn't match new state */
4545 if(btnPtr->fsState != LOWORD(lParam))
4547 btnPtr->fsState = LOWORD(lParam);
4548 InvalidateRect(hwnd, &btnPtr->rect, TOOLBAR_HasText(infoPtr,
4549 btnPtr));
4552 return TRUE;
4556 static LRESULT
4557 TOOLBAR_SetStyle (HWND hwnd, WPARAM wParam, LPARAM lParam)
4559 SetWindowLongW(hwnd, GWL_STYLE, lParam);
4561 return TRUE;
4565 inline static LRESULT
4566 TOOLBAR_SetToolTips (HWND hwnd, WPARAM wParam, LPARAM lParam)
4568 TOOLBAR_INFO *infoPtr = TOOLBAR_GetInfoPtr (hwnd);
4570 if (infoPtr == NULL)
4571 return 0;
4572 infoPtr->hwndToolTip = (HWND)wParam;
4573 return 0;
4577 static LRESULT
4578 TOOLBAR_SetUnicodeFormat (HWND hwnd, WPARAM wParam, LPARAM lParam)
4580 TOOLBAR_INFO *infoPtr = TOOLBAR_GetInfoPtr (hwnd);
4581 BOOL bTemp;
4583 TRACE("%s hwnd=%p stub!\n",
4584 ((BOOL)wParam) ? "TRUE" : "FALSE", hwnd);
4586 bTemp = infoPtr->bUnicode;
4587 infoPtr->bUnicode = (BOOL)wParam;
4589 return bTemp;
4593 static LRESULT
4594 TOOLBAR_GetColorScheme (HWND hwnd, LPCOLORSCHEME lParam)
4596 TOOLBAR_INFO *infoPtr = TOOLBAR_GetInfoPtr (hwnd);
4598 lParam->clrBtnHighlight = (infoPtr->clrBtnHighlight == CLR_DEFAULT) ?
4599 comctl32_color.clrBtnHighlight :
4600 infoPtr->clrBtnHighlight;
4601 lParam->clrBtnShadow = (infoPtr->clrBtnShadow == CLR_DEFAULT) ?
4602 comctl32_color.clrBtnShadow : infoPtr->clrBtnShadow;
4603 return 1;
4607 static LRESULT
4608 TOOLBAR_SetColorScheme (HWND hwnd, LPCOLORSCHEME lParam)
4610 TOOLBAR_INFO *infoPtr = TOOLBAR_GetInfoPtr (hwnd);
4612 TRACE("new colors Hl=%lx Shd=%lx, old colors Hl=%lx Shd=%lx\n",
4613 lParam->clrBtnHighlight, lParam->clrBtnShadow,
4614 infoPtr->clrBtnHighlight, infoPtr->clrBtnShadow);
4616 infoPtr->clrBtnHighlight = lParam->clrBtnHighlight;
4617 infoPtr->clrBtnShadow = lParam->clrBtnShadow;
4618 InvalidateRect(hwnd, 0, 0);
4619 return 0;
4623 static LRESULT
4624 TOOLBAR_SetVersion (HWND hwnd, INT iVersion)
4626 TOOLBAR_INFO *infoPtr = TOOLBAR_GetInfoPtr (hwnd);
4627 INT iOldVersion = infoPtr->iVersion;
4629 infoPtr->iVersion = iVersion;
4631 if (infoPtr->iVersion >= 5)
4632 TOOLBAR_SetUnicodeFormat(hwnd, (WPARAM)TRUE, (LPARAM)0);
4634 return iOldVersion;
4638 /*********************************************************************/
4639 /* */
4640 /* This is undocumented and appears to be a "Super" TB_SETHOTITEM */
4641 /* without the restriction of TBSTYLE_FLAT. This implementation is */
4642 /* based on relay traces of the native control and IE 5.5 */
4643 /* */
4644 /*********************************************************************/
4645 static LRESULT
4646 TOOLBAR_Unkwn45E (HWND hwnd, WPARAM wParam, LPARAM lParam)
4648 TOOLBAR_INFO *infoPtr = TOOLBAR_GetInfoPtr(hwnd);
4649 INT nOldHotItem = infoPtr->nHotItem;
4650 TBUTTON_INFO *btnPtr;
4651 INT no_hi = 0;
4652 NMTBHOTITEM nmhotitem;
4654 if ((INT) wParam < 0 || (INT)wParam > infoPtr->nNumButtons)
4655 wParam = -2;
4657 infoPtr->nHotItem = (INT)wParam;
4658 if (nOldHotItem != infoPtr->nHotItem) {
4659 nmhotitem.dwFlags = (DWORD)lParam;
4660 if ( !(nmhotitem.dwFlags & HICF_ENTERING) )
4661 nmhotitem.idOld = (nOldHotItem >= 0) ?
4662 infoPtr->buttons[nOldHotItem].idCommand : 0;
4663 if ( !(nmhotitem.dwFlags & HICF_LEAVING) )
4664 nmhotitem.idNew = (infoPtr->nHotItem >= 0) ?
4665 infoPtr->buttons[infoPtr->nHotItem].idCommand : 0;
4666 no_hi = TOOLBAR_SendNotify((NMHDR*)&nmhotitem, infoPtr, TBN_HOTITEMCHANGE);
4668 if ((INT)wParam >=0) {
4669 btnPtr = &infoPtr->buttons[(INT)wParam];
4670 btnPtr->bHot = (no_hi) ? FALSE : TRUE;
4671 InvalidateRect (hwnd, &btnPtr->rect,
4672 TOOLBAR_HasText(infoPtr, btnPtr));
4674 if (nOldHotItem>=0) {
4675 btnPtr = &infoPtr->buttons[nOldHotItem];
4676 btnPtr->bHot = FALSE;
4677 InvalidateRect (hwnd, &btnPtr->rect,
4678 TOOLBAR_HasText(infoPtr, btnPtr));
4680 GetFocus();
4681 TRACE("old item=%d, new item=%d, flags=%08lx, notify=%d\n",
4682 nOldHotItem, infoPtr->nHotItem, (DWORD)lParam, no_hi);
4684 if (nOldHotItem < 0)
4685 return -1;
4687 return (LRESULT)nOldHotItem;
4691 static LRESULT
4692 TOOLBAR_Unkwn463 (HWND hwnd, WPARAM wParam, LPARAM lParam)
4694 TOOLBAR_INFO *infoPtr = TOOLBAR_GetInfoPtr (hwnd);
4695 LPSIZE lpsize = (LPSIZE)lParam;
4697 if (lpsize == NULL)
4698 return FALSE;
4701 * Testing shows the following:
4702 * wParam = 0 adjust cx value
4703 * = 1 set cy value to max size.
4704 * lParam pointer to SIZE structure
4707 TRACE("[0463] wParam %d, lParam 0x%08lx -> 0x%08lx 0x%08lx\n",
4708 wParam, lParam, lpsize->cx, lpsize->cy);
4710 switch(wParam) {
4711 case 0:
4712 if (lpsize->cx == -1) {
4713 /* **** this is wrong, native measures each button and sets it */
4714 lpsize->cx = infoPtr->rcBound.right - infoPtr->rcBound.left;
4716 else if(HIWORD(lpsize->cx)) {
4717 RECT rc;
4718 HWND hwndParent = GetParent(hwnd);
4720 InvalidateRect(hwnd, 0, 1);
4721 GetWindowRect(hwnd, &rc);
4722 MapWindowPoints(0, hwndParent, (LPPOINT)&rc, 2);
4723 TRACE("mapped to (%ld,%ld)-(%ld,%ld)\n",
4724 rc.left, rc.top, rc.right, rc.bottom);
4725 lpsize->cx = max(rc.right-rc.left,
4726 infoPtr->rcBound.right - infoPtr->rcBound.left);
4728 else {
4729 lpsize->cx = infoPtr->rcBound.right - infoPtr->rcBound.left;
4731 break;
4732 case 1:
4733 lpsize->cy = infoPtr->rcBound.bottom - infoPtr->rcBound.top;
4734 /* lpsize->cy = infoPtr->nHeight; */
4735 break;
4736 default:
4737 ERR("Unknown wParam %d for Toolbar message [0463]. Please report\n",
4738 wParam);
4739 return 0;
4741 TRACE("[0463] set to -> 0x%08lx 0x%08lx\n",
4742 lpsize->cx, lpsize->cy);
4743 return 1;
4747 static LRESULT
4748 TOOLBAR_Create (HWND hwnd, WPARAM wParam, LPARAM lParam)
4750 TOOLBAR_INFO *infoPtr = TOOLBAR_GetInfoPtr (hwnd);
4751 DWORD dwStyle = GetWindowLongA (hwnd, GWL_STYLE);
4752 LOGFONTA logFont;
4754 /* initialize info structure */
4755 infoPtr->nButtonHeight = 22;
4756 infoPtr->nButtonWidth = 24;
4757 infoPtr->nBitmapHeight = 15;
4758 infoPtr->nBitmapWidth = 16;
4760 infoPtr->nHeight = infoPtr->nButtonHeight + TOP_BORDER + BOTTOM_BORDER;
4761 infoPtr->nMaxTextRows = 1;
4762 infoPtr->cxMin = -1;
4763 infoPtr->cxMax = -1;
4764 infoPtr->nNumBitmaps = 0;
4765 infoPtr->nNumStrings = 0;
4767 infoPtr->bCaptured = FALSE;
4768 infoPtr->bUnicode = IsWindowUnicode (hwnd);
4769 infoPtr->nButtonDown = -1;
4770 infoPtr->nOldHit = -1;
4771 infoPtr->nHotItem = -2; /* It has to be initially different from nOldHit */
4772 infoPtr->hwndNotify = ((LPCREATESTRUCTW)lParam)->hwndParent;
4773 infoPtr->bTransparent = (dwStyle & TBSTYLE_TRANSPARENT);
4774 infoPtr->bBtnTranspnt = (dwStyle & (TBSTYLE_FLAT | TBSTYLE_LIST));
4775 infoPtr->dwDTFlags = (dwStyle & TBSTYLE_LIST) ? DT_LEFT | DT_VCENTER | DT_SINGLELINE : DT_CENTER;
4776 infoPtr->bAnchor = FALSE; /* no anchor highlighting */
4777 infoPtr->iVersion = 0;
4778 infoPtr->hwndSelf = hwnd;
4779 infoPtr->bDoRedraw = TRUE;
4780 infoPtr->clrBtnHighlight = CLR_DEFAULT;
4781 infoPtr->clrBtnShadow = CLR_DEFAULT;
4782 infoPtr->szPadding.cx = 7;
4783 infoPtr->szPadding.cy = 6;
4784 TOOLBAR_NotifyFormat(infoPtr, (WPARAM)hwnd, (LPARAM)NF_REQUERY);
4786 SystemParametersInfoA (SPI_GETICONTITLELOGFONT, 0, &logFont, 0);
4787 infoPtr->hFont = infoPtr->hDefaultFont = CreateFontIndirectA (&logFont);
4789 if (dwStyle & TBSTYLE_TOOLTIPS) {
4790 /* Create tooltip control */
4791 infoPtr->hwndToolTip =
4792 CreateWindowExA (0, TOOLTIPS_CLASSA, NULL, 0,
4793 CW_USEDEFAULT, CW_USEDEFAULT,
4794 CW_USEDEFAULT, CW_USEDEFAULT,
4795 hwnd, 0, 0, 0);
4797 /* Send NM_TOOLTIPSCREATED notification */
4798 if (infoPtr->hwndToolTip) {
4799 NMTOOLTIPSCREATED nmttc;
4801 nmttc.hwndToolTips = infoPtr->hwndToolTip;
4803 TOOLBAR_SendNotify ((NMHDR *) &nmttc, infoPtr,
4804 NM_TOOLTIPSCREATED);
4808 TOOLBAR_CheckStyle (hwnd, dwStyle);
4810 TOOLBAR_CalcToolbar(hwnd);
4812 return 0;
4816 static LRESULT
4817 TOOLBAR_Destroy (HWND hwnd, WPARAM wParam, LPARAM lParam)
4819 TOOLBAR_INFO *infoPtr = TOOLBAR_GetInfoPtr (hwnd);
4821 /* delete tooltip control */
4822 if (infoPtr->hwndToolTip)
4823 DestroyWindow (infoPtr->hwndToolTip);
4825 /* delete button data */
4826 if (infoPtr->buttons)
4827 Free (infoPtr->buttons);
4829 /* delete strings */
4830 if (infoPtr->strings) {
4831 INT i;
4832 for (i = 0; i < infoPtr->nNumStrings; i++)
4833 if (infoPtr->strings[i])
4834 Free (infoPtr->strings[i]);
4836 Free (infoPtr->strings);
4839 /* destroy internal image list */
4840 if (infoPtr->himlInt)
4841 ImageList_Destroy (infoPtr->himlInt);
4843 TOOLBAR_DeleteImageList(&infoPtr->himlDef, &infoPtr->cimlDef);
4844 TOOLBAR_DeleteImageList(&infoPtr->himlDis, &infoPtr->cimlDis);
4845 TOOLBAR_DeleteImageList(&infoPtr->himlHot, &infoPtr->cimlHot);
4847 /* delete default font */
4848 if (infoPtr->hFont)
4849 DeleteObject (infoPtr->hDefaultFont);
4851 /* free toolbar info data */
4852 Free (infoPtr);
4853 SetWindowLongA (hwnd, 0, 0);
4855 return 0;
4859 static LRESULT
4860 TOOLBAR_EraseBackground (HWND hwnd, WPARAM wParam, LPARAM lParam)
4862 TOOLBAR_INFO *infoPtr = TOOLBAR_GetInfoPtr (hwnd);
4863 DWORD dwStyle = GetWindowLongA (hwnd, GWL_STYLE);
4864 NMTBCUSTOMDRAW tbcd;
4865 INT ret = FALSE;
4866 DWORD ntfret;
4868 if (dwStyle & TBSTYLE_CUSTOMERASE) {
4869 ZeroMemory (&tbcd, sizeof(NMTBCUSTOMDRAW));
4870 tbcd.nmcd.dwDrawStage = CDDS_PREERASE;
4871 tbcd.nmcd.hdc = (HDC)wParam;
4872 ntfret = TOOLBAR_SendNotify ((NMHDR *)&tbcd, infoPtr, NM_CUSTOMDRAW);
4873 infoPtr->dwBaseCustDraw = ntfret & 0xffff;
4875 /* FIXME: in general the return flags *can* be or'ed together */
4876 switch (infoPtr->dwBaseCustDraw)
4878 case CDRF_DODEFAULT:
4879 break;
4880 case CDRF_SKIPDEFAULT:
4881 return TRUE;
4882 default:
4883 FIXME("[%p] response %ld not handled to NM_CUSTOMDRAW (CDDS_PREERASE)\n",
4884 hwnd, ntfret);
4888 /* If the toolbar is "transparent" then pass the WM_ERASEBKGND up
4889 * to my parent for processing.
4891 if (infoPtr->bTransparent) {
4892 POINT pt, ptorig;
4893 HDC hdc = (HDC)wParam;
4894 HWND parent;
4896 pt.x = 0;
4897 pt.y = 0;
4898 parent = GetParent(hwnd);
4899 MapWindowPoints(hwnd, parent, &pt, 1);
4900 OffsetWindowOrgEx (hdc, pt.x, pt.y, &ptorig);
4901 ret = SendMessageA (parent, WM_ERASEBKGND, wParam, lParam);
4902 SetWindowOrgEx (hdc, ptorig.x, ptorig.y, 0);
4904 if (!ret)
4905 ret = DefWindowProcA (hwnd, WM_ERASEBKGND, wParam, lParam);
4907 if ((dwStyle & TBSTYLE_CUSTOMERASE) &&
4908 (infoPtr->dwBaseCustDraw & CDRF_NOTIFYPOSTERASE)) {
4909 ZeroMemory (&tbcd, sizeof(NMTBCUSTOMDRAW));
4910 tbcd.nmcd.dwDrawStage = CDDS_POSTERASE;
4911 tbcd.nmcd.hdc = (HDC)wParam;
4912 ntfret = TOOLBAR_SendNotify ((NMHDR *)&tbcd, infoPtr, NM_CUSTOMDRAW);
4913 infoPtr->dwBaseCustDraw = ntfret & 0xffff;
4914 switch (infoPtr->dwBaseCustDraw)
4916 case CDRF_DODEFAULT:
4917 break;
4918 case CDRF_SKIPDEFAULT:
4919 return TRUE;
4920 default:
4921 FIXME("[%p] response %ld not handled to NM_CUSTOMDRAW (CDDS_PREERASE)\n",
4922 hwnd, ntfret);
4925 return ret;
4929 static LRESULT
4930 TOOLBAR_GetFont (HWND hwnd, WPARAM wParam, LPARAM lParam)
4932 TOOLBAR_INFO *infoPtr = TOOLBAR_GetInfoPtr (hwnd);
4934 return (LRESULT)infoPtr->hFont;
4938 static LRESULT
4939 TOOLBAR_LButtonDblClk (HWND hwnd, WPARAM wParam, LPARAM lParam)
4941 TOOLBAR_INFO *infoPtr = TOOLBAR_GetInfoPtr (hwnd);
4942 TBUTTON_INFO *btnPtr;
4943 POINT pt;
4944 INT nHit;
4946 pt.x = (INT)LOWORD(lParam);
4947 pt.y = (INT)HIWORD(lParam);
4948 nHit = TOOLBAR_InternalHitTest (hwnd, &pt);
4950 if (nHit >= 0) {
4951 btnPtr = &infoPtr->buttons[nHit];
4952 if (!(btnPtr->fsState & TBSTATE_ENABLED))
4953 return 0;
4954 SetCapture (hwnd);
4955 infoPtr->bCaptured = TRUE;
4956 infoPtr->nButtonDown = nHit;
4958 btnPtr->fsState |= TBSTATE_PRESSED;
4960 InvalidateRect(hwnd, &btnPtr->rect, TOOLBAR_HasText(infoPtr,
4961 btnPtr));
4963 else if (GetWindowLongA (hwnd, GWL_STYLE) & CCS_ADJUSTABLE)
4964 TOOLBAR_Customize (hwnd);
4966 return 0;
4970 static LRESULT
4971 TOOLBAR_LButtonDown (HWND hwnd, WPARAM wParam, LPARAM lParam)
4973 TOOLBAR_INFO *infoPtr = TOOLBAR_GetInfoPtr (hwnd);
4974 TBUTTON_INFO *btnPtr;
4975 POINT pt;
4976 INT nHit;
4977 NMTOOLBARA nmtb;
4979 if (infoPtr->hwndToolTip)
4980 TOOLBAR_RelayEvent (infoPtr->hwndToolTip, hwnd,
4981 WM_LBUTTONDOWN, wParam, lParam);
4983 pt.x = (INT)LOWORD(lParam);
4984 pt.y = (INT)HIWORD(lParam);
4985 nHit = TOOLBAR_InternalHitTest (hwnd, &pt);
4987 if (nHit >= 0) {
4988 RECT arrowRect;
4989 btnPtr = &infoPtr->buttons[nHit];
4990 infoPtr->nOldHit = nHit;
4992 CopyRect(&arrowRect, &btnPtr->rect);
4993 arrowRect.left = max(btnPtr->rect.left, btnPtr->rect.right - DDARROW_WIDTH);
4995 /* for EX_DRAWDDARROWS style, click must be in the drop-down arrow rect */
4996 if ((btnPtr->fsState & TBSTATE_ENABLED) && (btnPtr->fsStyle & BTNS_DROPDOWN) &&
4997 ((TOOLBAR_HasDropDownArrows(infoPtr->dwExStyle) && PtInRect(&arrowRect, pt)) ||
4998 (!TOOLBAR_HasDropDownArrows(infoPtr->dwExStyle))))
5000 LRESULT res;
5002 * this time we must force a Redraw, so the btn is
5003 * painted down before CaptureChanged repaints it up
5005 RedrawWindow(hwnd,&btnPtr->rect,0,
5006 RDW_ERASE|RDW_INVALIDATE|RDW_UPDATENOW);
5008 nmtb.iItem = btnPtr->idCommand;
5009 memset(&nmtb.tbButton, 0, sizeof(TBBUTTON));
5010 nmtb.cchText = 0;
5011 nmtb.pszText = 0;
5012 memset(&nmtb.rcButton, 0, sizeof(RECT));
5013 res = TOOLBAR_SendNotify ((NMHDR *) &nmtb, infoPtr,
5014 TBN_DROPDOWN);
5015 if (res != TBDDRET_TREATPRESSED)
5016 /* ??? guess (GA) */
5017 return 0;
5018 /* otherwise drop through and process as pushed */
5020 /* SetCapture (hwnd); */
5021 infoPtr->bCaptured = TRUE;
5022 infoPtr->nButtonDown = nHit;
5024 btnPtr->fsState |= TBSTATE_PRESSED;
5025 btnPtr->bHot = FALSE;
5027 if (btnPtr->fsState & TBSTATE_ENABLED)
5028 InvalidateRect(hwnd, &btnPtr->rect, TOOLBAR_HasText(infoPtr, btnPtr));
5029 UpdateWindow(hwnd);
5030 SetCapture (hwnd);
5032 /* native issues the TBN_BEGINDRAG here */
5033 nmtb.iItem = btnPtr->idCommand;
5034 nmtb.tbButton.iBitmap = btnPtr->iBitmap;
5035 nmtb.tbButton.idCommand = btnPtr->idCommand;
5036 nmtb.tbButton.fsState = btnPtr->fsState;
5037 nmtb.tbButton.fsStyle = btnPtr->fsStyle;
5038 nmtb.tbButton.dwData = btnPtr->dwData;
5039 nmtb.tbButton.iString = btnPtr->iString;
5040 nmtb.cchText = 0; /* !!! not correct */
5041 nmtb.pszText = 0; /* !!! not correct */
5042 TOOLBAR_SendNotify ((NMHDR *) &nmtb, infoPtr,
5043 TBN_BEGINDRAG);
5046 return 0;
5049 static LRESULT
5050 TOOLBAR_LButtonUp (HWND hwnd, WPARAM wParam, LPARAM lParam)
5052 TOOLBAR_INFO *infoPtr = TOOLBAR_GetInfoPtr (hwnd);
5053 TBUTTON_INFO *btnPtr;
5054 POINT pt;
5055 INT nHit;
5056 INT nOldIndex = -1;
5057 BOOL bSendMessage = TRUE;
5058 NMHDR hdr;
5059 NMMOUSE nmmouse;
5060 NMTOOLBARA nmtb;
5062 if (infoPtr->hwndToolTip)
5063 TOOLBAR_RelayEvent (infoPtr->hwndToolTip, hwnd,
5064 WM_LBUTTONUP, wParam, lParam);
5066 pt.x = (INT)LOWORD(lParam);
5067 pt.y = (INT)HIWORD(lParam);
5068 nHit = TOOLBAR_InternalHitTest (hwnd, &pt);
5070 /* restore hot effect to hot button disabled by TOOLBAR_LButtonDown() */
5071 /* if the cursor is still inside of the toolbar */
5072 if((infoPtr->nHotItem >= 0) && (nHit != -1))
5073 infoPtr->buttons[infoPtr->nHotItem].bHot = TRUE;
5075 if (0 <= infoPtr->nButtonDown) {
5076 btnPtr = &infoPtr->buttons[infoPtr->nButtonDown];
5077 btnPtr->fsState &= ~TBSTATE_PRESSED;
5079 if (btnPtr->fsStyle & BTNS_CHECK) {
5080 if (btnPtr->fsStyle & BTNS_GROUP) {
5081 nOldIndex = TOOLBAR_GetCheckedGroupButtonIndex (infoPtr,
5082 nHit);
5083 if (nOldIndex == nHit)
5084 bSendMessage = FALSE;
5085 if ((nOldIndex != nHit) &&
5086 (nOldIndex != -1))
5087 infoPtr->buttons[nOldIndex].fsState &= ~TBSTATE_CHECKED;
5088 btnPtr->fsState |= TBSTATE_CHECKED;
5090 else {
5091 if (btnPtr->fsState & TBSTATE_CHECKED)
5092 btnPtr->fsState &= ~TBSTATE_CHECKED;
5093 else
5094 btnPtr->fsState |= TBSTATE_CHECKED;
5098 if (nOldIndex != -1)
5100 InvalidateRect(hwnd, &infoPtr->buttons[nOldIndex].rect,
5101 TOOLBAR_HasText(infoPtr, &infoPtr->buttons[nOldIndex]));
5105 * now we can ReleaseCapture, which triggers CAPTURECHANGED msg,
5106 * that resets bCaptured and btn TBSTATE_PRESSED flags,
5107 * and obliterates nButtonDown and nOldHit (see TOOLBAR_CaptureChanged)
5109 if ((infoPtr->bCaptured) && (infoPtr->nButtonDown >= 0))
5110 ReleaseCapture ();
5111 infoPtr->nButtonDown = -1;
5113 /* Issue NM_RELEASEDCAPTURE to parent to let him know it is released */
5114 TOOLBAR_SendNotify ((NMHDR *) &hdr, infoPtr,
5115 NM_RELEASEDCAPTURE);
5117 /* native issues TBN_ENDDRAG here, if _LBUTTONDOWN issued the
5118 * TBN_BEGINDRAG
5120 nmtb.iItem = btnPtr->idCommand;
5121 nmtb.tbButton.iBitmap = btnPtr->iBitmap;
5122 nmtb.tbButton.idCommand = btnPtr->idCommand;
5123 nmtb.tbButton.fsState = btnPtr->fsState;
5124 nmtb.tbButton.fsStyle = btnPtr->fsStyle;
5125 nmtb.tbButton.dwData = btnPtr->dwData;
5126 nmtb.tbButton.iString = btnPtr->iString;
5127 nmtb.cchText = 0; /* !!! not correct */
5128 nmtb.pszText = 0; /* !!! not correct */
5129 TOOLBAR_SendNotify ((NMHDR *) &nmtb, infoPtr,
5130 TBN_ENDDRAG);
5132 if (btnPtr->fsState & TBSTATE_ENABLED)
5134 SendMessageA (infoPtr->hwndNotify, WM_COMMAND,
5135 MAKEWPARAM(infoPtr->buttons[nHit].idCommand, 0), (LPARAM)hwnd);
5137 /* !!! Undocumented - toolbar at 4.71 level and above sends
5138 * either NMRCLICK or NM_CLICK with the NMMOUSE structure.
5139 * Only NM_RCLICK is documented.
5141 nmmouse.dwItemSpec = btnPtr->idCommand;
5142 nmmouse.dwItemData = btnPtr->dwData;
5143 TOOLBAR_SendNotify ((NMHDR *) &nmmouse, infoPtr, NM_CLICK);
5146 return 0;
5149 static LRESULT
5150 TOOLBAR_CaptureChanged(HWND hwnd)
5152 TOOLBAR_INFO *infoPtr = TOOLBAR_GetInfoPtr (hwnd);
5153 TBUTTON_INFO *btnPtr;
5155 infoPtr->bCaptured = FALSE;
5157 if (infoPtr->nButtonDown >= 0)
5159 btnPtr = &infoPtr->buttons[infoPtr->nButtonDown];
5160 btnPtr->fsState &= ~TBSTATE_PRESSED;
5162 infoPtr->nOldHit = -1;
5164 if (btnPtr->fsState & TBSTATE_ENABLED)
5165 InvalidateRect(hwnd, &btnPtr->rect, TOOLBAR_HasText(infoPtr,
5166 btnPtr));
5168 return 0;
5171 static LRESULT
5172 TOOLBAR_MouseLeave (HWND hwnd, WPARAM wParam, LPARAM lParam)
5174 TOOLBAR_INFO *infoPtr = TOOLBAR_GetInfoPtr (hwnd);
5175 TBUTTON_INFO *hotBtnPtr, *btnPtr;
5176 RECT rc1;
5178 if (infoPtr->nOldHit < 0)
5179 return TRUE;
5181 hotBtnPtr = &infoPtr->buttons[infoPtr->nOldHit];
5183 /* Redraw the button if the last button we were over is the hot button and it
5184 is enabled */
5185 if((infoPtr->nOldHit == infoPtr->nHotItem) && (hotBtnPtr->fsState & TBSTATE_ENABLED))
5187 hotBtnPtr->bHot = FALSE;
5188 rc1 = hotBtnPtr->rect;
5189 InflateRect (&rc1, 1, 1);
5190 InvalidateRect (hwnd, &rc1, TOOLBAR_HasText(infoPtr,
5191 hotBtnPtr));
5194 /* If the last button we were over is depressed then make it not */
5195 /* depressed and redraw it */
5196 if(infoPtr->nOldHit == infoPtr->nButtonDown)
5198 btnPtr = &infoPtr->buttons[infoPtr->nButtonDown];
5200 btnPtr->fsState &= ~TBSTATE_PRESSED;
5202 rc1 = hotBtnPtr->rect;
5203 InflateRect (&rc1, 1, 1);
5204 InvalidateRect (hwnd, &rc1, TRUE);
5207 infoPtr->nOldHit = -1; /* reset the old hit index as we've left the toolbar */
5208 infoPtr->nHotItem = -2; /* It has to be initially different from nOldHit */
5210 return TRUE;
5213 static LRESULT
5214 TOOLBAR_MouseMove (HWND hwnd, WPARAM wParam, LPARAM lParam)
5216 TBUTTON_INFO *btnPtr = NULL, *oldBtnPtr = NULL;
5217 TOOLBAR_INFO *infoPtr = TOOLBAR_GetInfoPtr (hwnd);
5218 POINT pt;
5219 INT nHit;
5220 TRACKMOUSEEVENT trackinfo;
5221 NMTBHOTITEM nmhotitem;
5223 /* fill in the TRACKMOUSEEVENT struct */
5224 trackinfo.cbSize = sizeof(TRACKMOUSEEVENT);
5225 trackinfo.dwFlags = TME_QUERY;
5226 trackinfo.hwndTrack = hwnd;
5227 trackinfo.dwHoverTime = HOVER_DEFAULT;
5229 /* call _TrackMouseEvent to see if we are currently tracking for this hwnd */
5230 _TrackMouseEvent(&trackinfo);
5232 /* Make sure tracking is enabled so we receive a WM_MOUSELEAVE message */
5233 if(!(trackinfo.dwFlags & TME_LEAVE)) {
5234 trackinfo.dwFlags = TME_LEAVE; /* notify upon leaving */
5236 /* call TRACKMOUSEEVENT so we receive a WM_MOUSELEAVE message */
5237 /* and can properly deactivate the hot toolbar button */
5238 _TrackMouseEvent(&trackinfo);
5241 if (infoPtr->hwndToolTip)
5242 TOOLBAR_RelayEvent (infoPtr->hwndToolTip, hwnd,
5243 WM_MOUSEMOVE, wParam, lParam);
5245 pt.x = (INT)LOWORD(lParam);
5246 pt.y = (INT)HIWORD(lParam);
5248 nHit = TOOLBAR_InternalHitTest (hwnd, &pt);
5250 if (infoPtr->nOldHit != nHit)
5252 /* Remove the effect of an old hot button if the button was
5253 drawn with the hot button effect */
5254 if(infoPtr->nOldHit >= 0 && infoPtr->nOldHit == infoPtr->nHotItem)
5256 oldBtnPtr = &infoPtr->buttons[infoPtr->nOldHit];
5257 oldBtnPtr->bHot = FALSE;
5260 /* It's not a separator or in nowhere. It's a hot button. */
5261 if (nHit >= 0)
5263 btnPtr = &infoPtr->buttons[nHit];
5265 infoPtr->nHotItem = nHit;
5267 btnPtr->bHot = TRUE;
5270 nmhotitem.dwFlags = HICF_MOUSE;
5271 if (oldBtnPtr)
5272 nmhotitem.idOld = oldBtnPtr->idCommand;
5273 else
5274 nmhotitem.dwFlags |= HICF_ENTERING;
5275 if (btnPtr)
5276 nmhotitem.idNew = btnPtr->idCommand;
5277 else
5278 nmhotitem.dwFlags |= HICF_LEAVING;
5279 TOOLBAR_SendNotify((NMHDR*)&nmhotitem, infoPtr, TBN_HOTITEMCHANGE);
5281 /* now invalidate the old and new buttons so they will be painted */
5282 if (oldBtnPtr)
5283 InvalidateRect (hwnd, &oldBtnPtr->rect,
5284 TOOLBAR_HasText(infoPtr, oldBtnPtr));
5285 if (btnPtr)
5286 InvalidateRect(hwnd, &btnPtr->rect,
5287 TOOLBAR_HasText(infoPtr, btnPtr));
5289 if (infoPtr->bCaptured) {
5290 btnPtr = &infoPtr->buttons[infoPtr->nButtonDown];
5291 if (infoPtr->nOldHit == infoPtr->nButtonDown) {
5292 btnPtr->fsState &= ~TBSTATE_PRESSED;
5293 InvalidateRect(hwnd, &btnPtr->rect, TRUE);
5295 else if (nHit == infoPtr->nButtonDown) {
5296 btnPtr->fsState |= TBSTATE_PRESSED;
5297 InvalidateRect(hwnd, &btnPtr->rect, TRUE);
5300 infoPtr->nOldHit = nHit;
5302 return 0;
5306 inline static LRESULT
5307 TOOLBAR_NCActivate (HWND hwnd, WPARAM wParam, LPARAM lParam)
5309 /* if (wndPtr->dwStyle & CCS_NODIVIDER) */
5310 return DefWindowProcA (hwnd, WM_NCACTIVATE, wParam, lParam);
5311 /* else */
5312 /* return TOOLBAR_NCPaint (wndPtr, wParam, lParam); */
5316 inline static LRESULT
5317 TOOLBAR_NCCalcSize (HWND hwnd, WPARAM wParam, LPARAM lParam)
5319 if (!(GetWindowLongA (hwnd, GWL_STYLE) & CCS_NODIVIDER))
5320 ((LPRECT)lParam)->top += GetSystemMetrics(SM_CYEDGE);
5322 return DefWindowProcA (hwnd, WM_NCCALCSIZE, wParam, lParam);
5326 static LRESULT
5327 TOOLBAR_NCCreate (HWND hwnd, WPARAM wParam, LPARAM lParam)
5329 TOOLBAR_INFO *infoPtr;
5330 LPCREATESTRUCTA cs = (LPCREATESTRUCTA)lParam;
5331 DWORD styleadd = 0;
5333 /* allocate memory for info structure */
5334 infoPtr = (TOOLBAR_INFO *)Alloc (sizeof(TOOLBAR_INFO));
5335 SetWindowLongA (hwnd, 0, (DWORD)infoPtr);
5337 /* paranoid!! */
5338 infoPtr->dwStructSize = sizeof(TBBUTTON);
5339 infoPtr->nRows = 1;
5341 /* fix instance handle, if the toolbar was created by CreateToolbarEx() */
5342 if (!GetWindowLongA (hwnd, GWL_HINSTANCE)) {
5343 HINSTANCE hInst = (HINSTANCE)GetWindowLongA (GetParent (hwnd), GWL_HINSTANCE);
5344 SetWindowLongA (hwnd, GWL_HINSTANCE, (DWORD)hInst);
5347 /* native control does:
5348 * Get a lot of colors and brushes
5349 * WM_NOTIFYFORMAT
5350 * SystemParametersInfoA(0x1f, 0x3c, adr1, 0)
5351 * CreateFontIndirectA(adr1)
5352 * CreateBitmap(0x27, 0x24, 1, 1, 0)
5353 * hdc = GetDC(toolbar)
5354 * GetSystemMetrics(0x48)
5355 * fnt2=CreateFontA(0xe, 0, 0, 0, 0x190, 0, 0, 0, 0, 2,
5356 * 0, 0, 0, 0, "MARLETT")
5357 * oldfnt = SelectObject(hdc, fnt2)
5358 * GetCharWidthA(hdc, 0x36, 0x36, adr2)
5359 * GetTextMetricsA(hdc, adr3)
5360 * SelectObject(hdc, oldfnt)
5361 * DeleteObject(fnt2)
5362 * ReleaseDC(hdc)
5363 * InvalidateRect(toolbar, 0, 1)
5364 * SetWindowLongA(toolbar, 0, addr)
5365 * SetWindowLongA(toolbar, -16, xxx) **sometimes**
5366 * WM_STYLECHANGING
5367 * CallWinEx old new
5368 * ie 1 0x56000a4c 0x46000a4c 0x56008a4d
5369 * ie 2 0x4600094c 0x4600094c 0x4600894d
5370 * ie 3 0x56000b4c 0x46000b4c 0x56008b4d
5371 * rebar 0x50008844 0x40008844 0x50008845
5372 * pager 0x50000844 0x40000844 0x50008845
5373 * IC35mgr 0x5400084e **nochange**
5374 * on entry to _NCCREATE 0x5400084e
5375 * rowlist 0x5400004e **nochange**
5376 * on entry to _NCCREATE 0x5400004e
5380 /* I think the code below is a bug, but it is the way that the native
5381 * controls seem to work. The effect is that if the user of TBSTYLE_FLAT
5382 * forgets to specify TBSTYLE_TRANSPARENT but does specify either
5383 * CCS_TOP or CCS_BOTTOM (_NOMOVEY and _TOP), then the control
5384 * does *not* set TBSTYLE_TRANSPARENT even though it should!!!!
5385 * Some how, the only cases of this seem to be MFC programs.
5387 * Note also that the addition of _TRANSPARENT occurs *only* here. It
5388 * does not occur in the WM_STYLECHANGING routine.
5389 * (Guy Albertelli 9/2001)
5392 if ((cs->style & TBSTYLE_FLAT) && !(cs->style & TBSTYLE_TRANSPARENT))
5393 styleadd |= TBSTYLE_TRANSPARENT;
5394 if (!(cs->style & (CCS_TOP | CCS_NOMOVEY))) {
5395 styleadd |= CCS_TOP; /* default to top */
5396 SetWindowLongA (hwnd, GWL_STYLE, cs->style | styleadd);
5399 return DefWindowProcA (hwnd, WM_NCCREATE, wParam, lParam);
5403 static LRESULT
5404 TOOLBAR_NCPaint (HWND hwnd, WPARAM wParam, LPARAM lParam)
5406 DWORD dwStyle = GetWindowLongA (hwnd, GWL_STYLE);
5407 RECT rcWindow;
5408 HDC hdc;
5410 if (dwStyle & WS_MINIMIZE)
5411 return 0; /* Nothing to do */
5413 DefWindowProcA (hwnd, WM_NCPAINT, wParam, lParam);
5415 if (!(hdc = GetDCEx (hwnd, 0, DCX_USESTYLE | DCX_WINDOW)))
5416 return 0;
5418 if (!(dwStyle & CCS_NODIVIDER))
5420 GetWindowRect (hwnd, &rcWindow);
5421 OffsetRect (&rcWindow, -rcWindow.left, -rcWindow.top);
5422 if( dwStyle & WS_BORDER )
5423 OffsetRect (&rcWindow, 1, 1);
5424 DrawEdge (hdc, &rcWindow, EDGE_ETCHED, BF_TOP);
5427 ReleaseDC( hwnd, hdc );
5429 return 0;
5433 inline static LRESULT
5434 TOOLBAR_Notify (HWND hwnd, WPARAM wParam, LPARAM lParam)
5436 TOOLBAR_INFO *infoPtr = TOOLBAR_GetInfoPtr (hwnd);
5437 LPNMHDR lpnmh = (LPNMHDR)lParam;
5439 if (lpnmh->code == PGN_CALCSIZE) {
5440 LPNMPGCALCSIZE lppgc = (LPNMPGCALCSIZE)lParam;
5442 if (lppgc->dwFlag == PGF_CALCWIDTH) {
5443 lppgc->iWidth = infoPtr->rcBound.right - infoPtr->rcBound.left;
5444 TRACE("processed PGN_CALCSIZE, returning horz size = %d\n",
5445 lppgc->iWidth);
5447 else {
5448 lppgc->iHeight = infoPtr->rcBound.bottom - infoPtr->rcBound.top;
5449 TRACE("processed PGN_CALCSIZE, returning vert size = %d\n",
5450 lppgc->iHeight);
5452 return 0;
5455 if (lpnmh->code == PGN_SCROLL) {
5456 LPNMPGSCROLL lppgs = (LPNMPGSCROLL)lParam;
5458 lppgs->iScroll = (lppgs->iDir & (PGF_SCROLLLEFT | PGF_SCROLLRIGHT)) ?
5459 infoPtr->nButtonWidth : infoPtr->nButtonHeight;
5460 TRACE("processed PGN_SCROLL, returning scroll=%d, dir=%d\n",
5461 lppgs->iScroll, lppgs->iDir);
5462 return 0;
5466 TRACE("passing WM_NOTIFY!\n");
5468 if ((infoPtr->hwndToolTip) && (lpnmh->hwndFrom == infoPtr->hwndToolTip)) {
5469 if (infoPtr->bNtfUnicode)
5470 return SendMessageW (infoPtr->hwndNotify, WM_NOTIFY,
5471 wParam, lParam);
5472 else
5473 return SendMessageA (infoPtr->hwndNotify, WM_NOTIFY,
5474 wParam, lParam);
5476 #if 0
5477 if (lpnmh->code == TTN_GETDISPINFOA) {
5478 LPNMTTDISPINFOA lpdi = (LPNMTTDISPINFOA)lParam;
5480 FIXME("retrieving ASCII string\n");
5483 else if (lpnmh->code == TTN_GETDISPINFOW) {
5484 LPNMTTDISPINFOW lpdi = (LPNMTTDISPINFOW)lParam;
5486 FIXME("retrieving UNICODE string\n");
5489 #endif
5492 return 0;
5496 static LRESULT
5497 TOOLBAR_NotifyFormatFake(HWND hwnd, WPARAM wParam, LPARAM lParam)
5499 /* remove this routine when Toolbar is improved to pass infoPtr
5500 * around instead of hwnd.
5502 TOOLBAR_INFO *infoPtr = TOOLBAR_GetInfoPtr(hwnd);
5503 return TOOLBAR_NotifyFormat(infoPtr, wParam, lParam);
5507 static LRESULT
5508 TOOLBAR_NotifyFormat(TOOLBAR_INFO *infoPtr, WPARAM wParam, LPARAM lParam)
5510 INT i;
5512 if (lParam == NF_REQUERY) {
5513 i = SendMessageA(infoPtr->hwndNotify,
5514 WM_NOTIFYFORMAT, (WPARAM)infoPtr->hwndSelf, NF_QUERY);
5515 if ((i < NFR_ANSI) || (i > NFR_UNICODE)) {
5516 ERR("wrong response to WM_NOTIFYFORMAT (%d), assuming ANSI\n",
5518 i = NFR_ANSI;
5520 infoPtr->bNtfUnicode = (i == NFR_UNICODE) ? 1 : 0;
5521 return (LRESULT)i;
5523 return (LRESULT)((infoPtr->bUnicode) ? NFR_UNICODE : NFR_ANSI);
5527 static LRESULT
5528 TOOLBAR_Paint (HWND hwnd, WPARAM wParam)
5530 TOOLBAR_INFO *infoPtr = TOOLBAR_GetInfoPtr(hwnd);
5531 HDC hdc;
5532 PAINTSTRUCT ps;
5534 /* fill ps.rcPaint with a default rect */
5535 memcpy(&(ps.rcPaint), &(infoPtr->rcBound), sizeof(infoPtr->rcBound));
5537 hdc = wParam==0 ? BeginPaint(hwnd, &ps) : (HDC)wParam;
5539 TRACE("psrect=(%ld,%ld)-(%ld,%ld)\n",
5540 ps.rcPaint.left, ps.rcPaint.top,
5541 ps.rcPaint.right, ps.rcPaint.bottom);
5543 TOOLBAR_Refresh (hwnd, hdc, &ps);
5544 if (!wParam) EndPaint (hwnd, &ps);
5546 return 0;
5550 static LRESULT
5551 TOOLBAR_SetRedraw (HWND hwnd, WPARAM wParam, LPARAM lParam)
5552 /*****************************************************
5554 * Function;
5555 * Handles the WM_SETREDRAW message.
5557 * Documentation:
5558 * According to testing V4.71 of COMCTL32 returns the
5559 * *previous* status of the redraw flag (either 0 or 1)
5560 * instead of the MSDN documented value of 0 if handled.
5561 * (For laughs see the "consistency" with same function
5562 * in rebar.)
5564 *****************************************************/
5566 TOOLBAR_INFO *infoPtr = TOOLBAR_GetInfoPtr (hwnd);
5567 BOOL oldredraw = infoPtr->bDoRedraw;
5569 TRACE("set to %s\n",
5570 (wParam) ? "TRUE" : "FALSE");
5571 infoPtr->bDoRedraw = (BOOL) wParam;
5572 if (wParam) {
5573 InvalidateRect (infoPtr->hwndSelf, 0, TRUE);
5575 return (oldredraw) ? 1 : 0;
5579 static LRESULT
5580 TOOLBAR_Size (HWND hwnd, WPARAM wParam, LPARAM lParam)
5582 TOOLBAR_INFO *infoPtr = TOOLBAR_GetInfoPtr (hwnd);
5583 DWORD dwStyle = GetWindowLongA (hwnd, GWL_STYLE);
5584 RECT parent_rect;
5585 RECT window_rect;
5586 HWND parent;
5587 INT x, y;
5588 INT cx, cy;
5589 INT flags;
5590 UINT uPosFlags = 0;
5592 /* Resize deadlock check */
5593 if (infoPtr->bAutoSize) {
5594 infoPtr->bAutoSize = FALSE;
5595 return 0;
5598 /* FIXME: optimize to only update size if the new size doesn't */
5599 /* match the current size */
5601 flags = (INT) wParam;
5603 /* FIXME for flags =
5604 * SIZE_MAXIMIZED, SIZE_MAXSHOW, SIZE_MINIMIZED
5607 TRACE("sizing toolbar!\n");
5609 if (flags == SIZE_RESTORED) {
5610 /* width and height don't apply */
5611 parent = GetParent (hwnd);
5612 GetClientRect(parent, &parent_rect);
5613 x = parent_rect.left;
5614 y = parent_rect.top;
5616 if (dwStyle & CCS_NORESIZE) {
5617 uPosFlags |= (SWP_NOSIZE | SWP_NOMOVE);
5620 * this sets the working width of the toolbar, and
5621 * Calc Toolbar will not adjust it, only the height
5623 infoPtr->nWidth = parent_rect.right - parent_rect.left;
5624 cy = infoPtr->nHeight;
5625 cx = infoPtr->nWidth;
5626 TOOLBAR_CalcToolbar (hwnd);
5627 infoPtr->nWidth = cx;
5628 infoPtr->nHeight = cy;
5630 else {
5631 infoPtr->nWidth = parent_rect.right - parent_rect.left;
5632 TOOLBAR_CalcToolbar (hwnd);
5633 cy = infoPtr->nHeight;
5634 cx = infoPtr->nWidth;
5636 if ((dwStyle & CCS_BOTTOM) == CCS_NOMOVEY) {
5637 GetWindowRect(hwnd, &window_rect);
5638 ScreenToClient(parent, (LPPOINT)&window_rect.left);
5639 y = window_rect.top;
5641 if ((dwStyle & CCS_BOTTOM) == CCS_BOTTOM) {
5642 GetWindowRect(hwnd, &window_rect);
5643 y = parent_rect.bottom -
5644 ( window_rect.bottom - window_rect.top);
5648 if (dwStyle & CCS_NOPARENTALIGN) {
5649 uPosFlags |= SWP_NOMOVE;
5650 cy = infoPtr->nHeight;
5651 cx = infoPtr->nWidth;
5654 if (!(dwStyle & CCS_NODIVIDER))
5655 cy += GetSystemMetrics(SM_CYEDGE);
5657 if (dwStyle & WS_BORDER)
5659 x = y = 1;
5660 cy += GetSystemMetrics(SM_CYEDGE);
5661 cx += GetSystemMetrics(SM_CYEDGE);
5664 SetWindowPos (hwnd, 0, x, y, cx, cy, uPosFlags | SWP_NOZORDER);
5666 return 0;
5670 static LRESULT
5671 TOOLBAR_StyleChanged (HWND hwnd, INT nType, LPSTYLESTRUCT lpStyle)
5673 TOOLBAR_INFO *infoPtr = TOOLBAR_GetInfoPtr (hwnd);
5675 if (nType == GWL_STYLE) {
5676 if (lpStyle->styleNew & TBSTYLE_LIST) {
5677 infoPtr->dwDTFlags = DT_LEFT | DT_VCENTER | DT_SINGLELINE;
5679 else {
5680 infoPtr->dwDTFlags = DT_CENTER;
5682 infoPtr->bTransparent = (lpStyle->styleNew & TBSTYLE_TRANSPARENT);
5683 infoPtr->bBtnTranspnt = (lpStyle->styleNew &
5684 (TBSTYLE_FLAT | TBSTYLE_LIST));
5685 TOOLBAR_CheckStyle (hwnd, lpStyle->styleNew);
5687 TRACE("new style 0x%08lx\n", lpStyle->styleNew);
5690 TOOLBAR_CalcToolbar(hwnd);
5692 TOOLBAR_AutoSize (hwnd);
5694 InvalidateRect(hwnd, NULL, FALSE);
5696 return 0;
5700 static LRESULT
5701 TOOLBAR_SysColorChange (HWND hwnd)
5703 COMCTL32_RefreshSysColors();
5705 return 0;
5710 static LRESULT WINAPI
5711 ToolbarWindowProc (HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
5713 TOOLBAR_INFO *infoPtr = TOOLBAR_GetInfoPtr (hwnd);
5715 TRACE("hwnd=%p msg=%x wparam=%x lparam=%lx\n",
5716 hwnd, uMsg, /* SPY_GetMsgName(uMsg), */ wParam, lParam);
5718 if (!TOOLBAR_GetInfoPtr(hwnd) && (uMsg != WM_NCCREATE))
5719 return DefWindowProcA( hwnd, uMsg, wParam, lParam );
5721 switch (uMsg)
5723 case TB_ADDBITMAP:
5724 return TOOLBAR_AddBitmap (hwnd, wParam, lParam);
5726 case TB_ADDBUTTONSA:
5727 return TOOLBAR_AddButtonsA (hwnd, wParam, lParam);
5729 case TB_ADDBUTTONSW:
5730 return TOOLBAR_AddButtonsW (hwnd, wParam, lParam);
5732 case TB_ADDSTRINGA:
5733 return TOOLBAR_AddStringA (hwnd, wParam, lParam);
5735 case TB_ADDSTRINGW:
5736 return TOOLBAR_AddStringW (hwnd, wParam, lParam);
5738 case TB_AUTOSIZE:
5739 return TOOLBAR_AutoSize (hwnd);
5741 case TB_BUTTONCOUNT:
5742 return TOOLBAR_ButtonCount (hwnd, wParam, lParam);
5744 case TB_BUTTONSTRUCTSIZE:
5745 return TOOLBAR_ButtonStructSize (hwnd, wParam, lParam);
5747 case TB_CHANGEBITMAP:
5748 return TOOLBAR_ChangeBitmap (hwnd, wParam, lParam);
5750 case TB_CHECKBUTTON:
5751 return TOOLBAR_CheckButton (hwnd, wParam, lParam);
5753 case TB_COMMANDTOINDEX:
5754 return TOOLBAR_CommandToIndex (hwnd, wParam, lParam);
5756 case TB_CUSTOMIZE:
5757 return TOOLBAR_Customize (hwnd);
5759 case TB_DELETEBUTTON:
5760 return TOOLBAR_DeleteButton (hwnd, wParam, lParam);
5762 case TB_ENABLEBUTTON:
5763 return TOOLBAR_EnableButton (hwnd, wParam, lParam);
5765 case TB_GETANCHORHIGHLIGHT:
5766 return TOOLBAR_GetAnchorHighlight (hwnd);
5768 case TB_GETBITMAP:
5769 return TOOLBAR_GetBitmap (hwnd, wParam, lParam);
5771 case TB_GETBITMAPFLAGS:
5772 return TOOLBAR_GetBitmapFlags (hwnd, wParam, lParam);
5774 case TB_GETBUTTON:
5775 return TOOLBAR_GetButton (hwnd, wParam, lParam);
5777 case TB_GETBUTTONINFOA:
5778 return TOOLBAR_GetButtonInfoA (hwnd, wParam, lParam);
5780 case TB_GETBUTTONINFOW:
5781 return TOOLBAR_GetButtonInfoW (hwnd, wParam, lParam);
5783 case TB_GETBUTTONSIZE:
5784 return TOOLBAR_GetButtonSize (hwnd);
5786 case TB_GETBUTTONTEXTA:
5787 return TOOLBAR_GetButtonTextA (hwnd, wParam, lParam);
5789 case TB_GETBUTTONTEXTW:
5790 return TOOLBAR_GetButtonTextW (hwnd, wParam, lParam);
5792 case TB_GETDISABLEDIMAGELIST:
5793 return TOOLBAR_GetDisabledImageList (hwnd, wParam, lParam);
5795 case TB_GETEXTENDEDSTYLE:
5796 return TOOLBAR_GetExtendedStyle (hwnd);
5798 case TB_GETHOTIMAGELIST:
5799 return TOOLBAR_GetHotImageList (hwnd, wParam, lParam);
5801 case TB_GETHOTITEM:
5802 return TOOLBAR_GetHotItem (hwnd);
5804 case TB_GETIMAGELIST:
5805 return TOOLBAR_GetDefImageList (hwnd, wParam, lParam);
5807 /* case TB_GETINSERTMARK: */ /* 4.71 */
5808 /* case TB_GETINSERTMARKCOLOR: */ /* 4.71 */
5810 case TB_GETITEMRECT:
5811 return TOOLBAR_GetItemRect (hwnd, wParam, lParam);
5813 case TB_GETMAXSIZE:
5814 return TOOLBAR_GetMaxSize (hwnd, wParam, lParam);
5816 /* case TB_GETOBJECT: */ /* 4.71 */
5818 case TB_GETPADDING:
5819 return TOOLBAR_GetPadding (hwnd);
5821 case TB_GETRECT:
5822 return TOOLBAR_GetRect (hwnd, wParam, lParam);
5824 case TB_GETROWS:
5825 return TOOLBAR_GetRows (hwnd, wParam, lParam);
5827 case TB_GETSTATE:
5828 return TOOLBAR_GetState (hwnd, wParam, lParam);
5830 case TB_GETSTYLE:
5831 return TOOLBAR_GetStyle (hwnd, wParam, lParam);
5833 case TB_GETTEXTROWS:
5834 return TOOLBAR_GetTextRows (hwnd, wParam, lParam);
5836 case TB_GETTOOLTIPS:
5837 return TOOLBAR_GetToolTips (hwnd, wParam, lParam);
5839 case TB_GETUNICODEFORMAT:
5840 return TOOLBAR_GetUnicodeFormat (hwnd, wParam, lParam);
5842 case TB_HIDEBUTTON:
5843 return TOOLBAR_HideButton (hwnd, wParam, lParam);
5845 case TB_HITTEST:
5846 return TOOLBAR_HitTest (hwnd, wParam, lParam);
5848 case TB_INDETERMINATE:
5849 return TOOLBAR_Indeterminate (hwnd, wParam, lParam);
5851 case TB_INSERTBUTTONA:
5852 return TOOLBAR_InsertButtonA (hwnd, wParam, lParam);
5854 case TB_INSERTBUTTONW:
5855 return TOOLBAR_InsertButtonW (hwnd, wParam, lParam);
5857 /* case TB_INSERTMARKHITTEST: */ /* 4.71 */
5859 case TB_ISBUTTONCHECKED:
5860 return TOOLBAR_IsButtonChecked (hwnd, wParam, lParam);
5862 case TB_ISBUTTONENABLED:
5863 return TOOLBAR_IsButtonEnabled (hwnd, wParam, lParam);
5865 case TB_ISBUTTONHIDDEN:
5866 return TOOLBAR_IsButtonHidden (hwnd, wParam, lParam);
5868 case TB_ISBUTTONHIGHLIGHTED:
5869 return TOOLBAR_IsButtonHighlighted (hwnd, wParam, lParam);
5871 case TB_ISBUTTONINDETERMINATE:
5872 return TOOLBAR_IsButtonIndeterminate (hwnd, wParam, lParam);
5874 case TB_ISBUTTONPRESSED:
5875 return TOOLBAR_IsButtonPressed (hwnd, wParam, lParam);
5877 case TB_LOADIMAGES: /* 4.70 */
5878 FIXME("missing standard imagelists\n");
5879 return 0;
5881 /* case TB_MAPACCELERATORA: */ /* 4.71 */
5882 /* case TB_MAPACCELERATORW: */ /* 4.71 */
5883 /* case TB_MARKBUTTON: */ /* 4.71 */
5884 /* case TB_MOVEBUTTON: */ /* 4.71 */
5886 case TB_PRESSBUTTON:
5887 return TOOLBAR_PressButton (hwnd, wParam, lParam);
5889 case TB_REPLACEBITMAP:
5890 return TOOLBAR_ReplaceBitmap (hwnd, wParam, lParam);
5892 case TB_SAVERESTOREA:
5893 return TOOLBAR_SaveRestoreA (hwnd, wParam, lParam);
5895 case TB_SAVERESTOREW:
5896 return TOOLBAR_SaveRestoreW (hwnd, wParam, lParam);
5898 case TB_SETANCHORHIGHLIGHT:
5899 return TOOLBAR_SetAnchorHighlight (hwnd, wParam);
5901 case TB_SETBITMAPSIZE:
5902 return TOOLBAR_SetBitmapSize (hwnd, wParam, lParam);
5904 case TB_SETBUTTONINFOA:
5905 return TOOLBAR_SetButtonInfoA (hwnd, wParam, lParam);
5907 case TB_SETBUTTONINFOW:
5908 return TOOLBAR_SetButtonInfoW (hwnd, wParam, lParam);
5910 case TB_SETBUTTONSIZE:
5911 return TOOLBAR_SetButtonSize (hwnd, wParam, lParam);
5913 case TB_SETBUTTONWIDTH:
5914 return TOOLBAR_SetButtonWidth (hwnd, wParam, lParam);
5916 case TB_SETCMDID:
5917 return TOOLBAR_SetCmdId (hwnd, wParam, lParam);
5919 case TB_SETDISABLEDIMAGELIST:
5920 return TOOLBAR_SetDisabledImageList (hwnd, wParam, lParam);
5922 case TB_SETDRAWTEXTFLAGS:
5923 return TOOLBAR_SetDrawTextFlags (hwnd, wParam, lParam);
5925 case TB_SETEXTENDEDSTYLE:
5926 return TOOLBAR_SetExtendedStyle (hwnd, wParam, lParam);
5928 case TB_SETHOTIMAGELIST:
5929 return TOOLBAR_SetHotImageList (hwnd, wParam, lParam);
5931 case TB_SETHOTITEM:
5932 return TOOLBAR_SetHotItem (hwnd, wParam);
5934 case TB_SETIMAGELIST:
5935 return TOOLBAR_SetImageList (hwnd, wParam, lParam);
5937 case TB_SETINDENT:
5938 return TOOLBAR_SetIndent (hwnd, wParam, lParam);
5940 /* case TB_SETINSERTMARK: */ /* 4.71 */
5942 case TB_SETINSERTMARKCOLOR:
5943 return TOOLBAR_SetInsertMarkColor (hwnd, wParam, lParam);
5945 case TB_SETMAXTEXTROWS:
5946 return TOOLBAR_SetMaxTextRows (hwnd, wParam, lParam);
5948 case TB_SETPADDING:
5949 return TOOLBAR_SetPadding (hwnd, wParam, lParam);
5951 case TB_SETPARENT:
5952 return TOOLBAR_SetParent (hwnd, wParam, lParam);
5954 case TB_SETROWS:
5955 return TOOLBAR_SetRows (hwnd, wParam, lParam);
5957 case TB_SETSTATE:
5958 return TOOLBAR_SetState (hwnd, wParam, lParam);
5960 case TB_SETSTYLE:
5961 return TOOLBAR_SetStyle (hwnd, wParam, lParam);
5963 case TB_SETTOOLTIPS:
5964 return TOOLBAR_SetToolTips (hwnd, wParam, lParam);
5966 case TB_SETUNICODEFORMAT:
5967 return TOOLBAR_SetUnicodeFormat (hwnd, wParam, lParam);
5969 case TB_UNKWN45E:
5970 return TOOLBAR_Unkwn45E (hwnd, wParam, lParam);
5972 case TB_UNKWN463:
5973 return TOOLBAR_Unkwn463 (hwnd, wParam, lParam);
5976 /* Common Control Messages */
5978 /* case TB_GETCOLORSCHEME: */ /* identical to CCM_ */
5979 case CCM_GETCOLORSCHEME:
5980 return TOOLBAR_GetColorScheme (hwnd, (LPCOLORSCHEME)lParam);
5982 /* case TB_SETCOLORSCHEME: */ /* identical to CCM_ */
5983 case CCM_SETCOLORSCHEME:
5984 return TOOLBAR_SetColorScheme (hwnd, (LPCOLORSCHEME)lParam);
5986 case CCM_GETVERSION:
5987 return TOOLBAR_GetVersion (hwnd);
5989 case CCM_SETVERSION:
5990 return TOOLBAR_SetVersion (hwnd, (INT)wParam);
5993 /* case WM_CHAR: */
5995 case WM_CREATE:
5996 return TOOLBAR_Create (hwnd, wParam, lParam);
5998 case WM_DESTROY:
5999 return TOOLBAR_Destroy (hwnd, wParam, lParam);
6001 case WM_ERASEBKGND:
6002 return TOOLBAR_EraseBackground (hwnd, wParam, lParam);
6004 case WM_GETFONT:
6005 return TOOLBAR_GetFont (hwnd, wParam, lParam);
6007 /* case WM_KEYDOWN: */
6008 /* case WM_KILLFOCUS: */
6010 case WM_LBUTTONDBLCLK:
6011 return TOOLBAR_LButtonDblClk (hwnd, wParam, lParam);
6013 case WM_LBUTTONDOWN:
6014 return TOOLBAR_LButtonDown (hwnd, wParam, lParam);
6016 case WM_LBUTTONUP:
6017 return TOOLBAR_LButtonUp (hwnd, wParam, lParam);
6019 case WM_MOUSEMOVE:
6020 return TOOLBAR_MouseMove (hwnd, wParam, lParam);
6022 case WM_MOUSELEAVE:
6023 return TOOLBAR_MouseLeave (hwnd, wParam, lParam);
6025 case WM_CAPTURECHANGED:
6026 return TOOLBAR_CaptureChanged(hwnd);
6028 case WM_NCACTIVATE:
6029 return TOOLBAR_NCActivate (hwnd, wParam, lParam);
6031 case WM_NCCALCSIZE:
6032 return TOOLBAR_NCCalcSize (hwnd, wParam, lParam);
6034 case WM_NCCREATE:
6035 return TOOLBAR_NCCreate (hwnd, wParam, lParam);
6037 case WM_NCPAINT:
6038 return TOOLBAR_NCPaint (hwnd, wParam, lParam);
6040 case WM_NOTIFY:
6041 return TOOLBAR_Notify (hwnd, wParam, lParam);
6043 case WM_NOTIFYFORMAT:
6044 return TOOLBAR_NotifyFormatFake (hwnd, wParam, lParam);
6046 case WM_PAINT:
6047 return TOOLBAR_Paint (hwnd, wParam);
6049 case WM_SETREDRAW:
6050 return TOOLBAR_SetRedraw (hwnd, wParam, lParam);
6052 case WM_SIZE:
6053 return TOOLBAR_Size (hwnd, wParam, lParam);
6055 case WM_STYLECHANGED:
6056 return TOOLBAR_StyleChanged (hwnd, (INT)wParam, (LPSTYLESTRUCT)lParam);
6058 case WM_SYSCOLORCHANGE:
6059 return TOOLBAR_SysColorChange (hwnd);
6061 /* case WM_WININICHANGE: */
6063 case WM_CHARTOITEM:
6064 case WM_COMMAND:
6065 case WM_DRAWITEM:
6066 case WM_MEASUREITEM:
6067 case WM_VKEYTOITEM:
6068 return SendMessageA (infoPtr->hwndNotify, uMsg, wParam, lParam);
6070 /* We see this in Outlook Express 5.x and just does DefWindowProc */
6071 case PGM_FORWARDMOUSE:
6072 return DefWindowProcA (hwnd, uMsg, wParam, lParam);
6074 default:
6075 if ((uMsg >= WM_USER) && (uMsg < WM_APP))
6076 ERR("unknown msg %04x wp=%08x lp=%08lx\n",
6077 uMsg, wParam, lParam);
6078 return DefWindowProcA (hwnd, uMsg, wParam, lParam);
6080 return 0;
6084 VOID
6085 TOOLBAR_Register (void)
6087 WNDCLASSA wndClass;
6089 ZeroMemory (&wndClass, sizeof(WNDCLASSA));
6090 wndClass.style = CS_GLOBALCLASS | CS_DBLCLKS;
6091 wndClass.lpfnWndProc = (WNDPROC)ToolbarWindowProc;
6092 wndClass.cbClsExtra = 0;
6093 wndClass.cbWndExtra = sizeof(TOOLBAR_INFO *);
6094 wndClass.hCursor = LoadCursorA (0, (LPSTR)IDC_ARROW);
6095 wndClass.hbrBackground = (HBRUSH)(COLOR_3DFACE + 1);
6096 wndClass.lpszClassName = TOOLBARCLASSNAMEA;
6098 RegisterClassA (&wndClass);
6102 VOID
6103 TOOLBAR_Unregister (void)
6105 UnregisterClassA (TOOLBARCLASSNAMEA, NULL);
6108 static HIMAGELIST TOOLBAR_InsertImageList(PIMLENTRY **pies, INT *cies, HIMAGELIST himl, INT id)
6110 HIMAGELIST himlold;
6111 PIMLENTRY c = NULL;
6113 /* Check if the entry already exists */
6114 c = TOOLBAR_GetImageListEntry(*pies, *cies, id);
6116 /* If this is a new entry we must create it and insert into the array */
6117 if (!c)
6119 PIMLENTRY *pnies;
6121 c = (PIMLENTRY) Alloc(sizeof(IMLENTRY));
6122 c->id = id;
6124 pnies = Alloc((*cies + 1) * sizeof(PIMLENTRY));
6125 memcpy(pnies, *pies, ((*cies) * sizeof(PIMLENTRY)));
6126 pnies[*cies] = c;
6127 (*cies)++;
6129 Free(*pies);
6130 *pies = pnies;
6133 himlold = c->himl;
6134 c->himl = himl;
6136 return himlold;
6140 static VOID TOOLBAR_DeleteImageList(PIMLENTRY **pies, INT *cies)
6142 int i;
6144 for (i = 0; i < *cies; i++)
6145 Free((*pies)[i]);
6147 Free(*pies);
6149 *cies = 0;
6150 *pies = NULL;
6154 static PIMLENTRY TOOLBAR_GetImageListEntry(PIMLENTRY *pies, INT cies, INT id)
6156 PIMLENTRY c = NULL;
6158 if (pies != NULL)
6160 int i;
6162 for (i = 0; i < cies; i++)
6164 if (pies[i]->id == id)
6166 c = pies[i];
6167 break;
6172 return c;
6176 static HIMAGELIST TOOLBAR_GetImageList(PIMLENTRY *pies, INT cies, INT id)
6178 HIMAGELIST himlDef = 0;
6179 PIMLENTRY pie = TOOLBAR_GetImageListEntry(pies, cies, id);
6181 if (pie)
6182 himlDef = pie->himl;
6184 return himlDef;
6188 static BOOL TOOLBAR_GetButtonInfo(TOOLBAR_INFO *infoPtr, NMTOOLBARW *nmtb)
6190 if (infoPtr->bUnicode)
6191 return TOOLBAR_SendNotify ((NMHDR *) nmtb, infoPtr, TBN_GETBUTTONINFOW);
6192 else
6194 CHAR Buffer[256];
6195 NMTOOLBARA nmtba;
6196 BOOL bRet = FALSE;
6198 nmtba.iItem = nmtb->iItem;
6199 nmtba.pszText = Buffer;
6200 nmtba.cchText = 256;
6201 ZeroMemory(nmtba.pszText, nmtba.cchText);
6203 if (TOOLBAR_SendNotify ((NMHDR *) &nmtba, infoPtr, TBN_GETBUTTONINFOA))
6205 int ccht = strlen(nmtba.pszText);
6206 if (ccht)
6207 MultiByteToWideChar(CP_ACP, 0, (LPCSTR)nmtba.pszText, -1,
6208 nmtb->pszText, nmtb->cchText);
6210 memcpy(&nmtb->tbButton, &nmtba.tbButton, sizeof(TBBUTTON));
6211 bRet = TRUE;
6214 return bRet;
6219 static BOOL TOOLBAR_IsButtonRemovable(TOOLBAR_INFO *infoPtr,
6220 int iItem, PCUSTOMBUTTON btnInfo)
6222 NMTOOLBARA nmtb;
6224 nmtb.iItem = iItem;
6225 memcpy(&nmtb.tbButton, &btnInfo->btn, sizeof(TBBUTTON));
6227 return TOOLBAR_SendNotify ((NMHDR *) &nmtb, infoPtr, TBN_QUERYDELETE);