comctl32: toolbar: Set correcly hwndTrack in TrackMouseEvent call.
[wine] / dlls / comctl32 / toolbar.c
1 /*
2  * Toolbar control
3  *
4  * Copyright 1998,1999 Eric Kohl
5  * Copyright 2000 Eric Kohl for CodeWeavers
6  * Copyright 2004 Robert Shearman
7  *
8  * This library is free software; you can redistribute it and/or
9  * modify it under the terms of the GNU Lesser General Public
10  * License as published by the Free Software Foundation; either
11  * version 2.1 of the License, or (at your option) any later version.
12  *
13  * This library is distributed in the hope that it will be useful,
14  * but WITHOUT ANY WARRANTY; without even the implied warranty of
15  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
16  * Lesser General Public License for more details.
17  *
18  * You should have received a copy of the GNU Lesser General Public
19  * License along with this library; if not, write to the Free Software
20  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
21  *
22  * NOTES
23  *
24  * This code was audited for completeness against the documented features
25  * of Comctl32.dll version 6.0 on Mar. 14, 2004, by Robert Shearman.
26  * 
27  * Unless otherwise noted, we believe this code to be complete, as per
28  * the specification mentioned above.
29  * If you discover missing features or bugs please note them below.
30  * 
31  * TODO:
32  *   - Styles:
33  *     - TBSTYLE_REGISTERDROP
34  *     - TBSTYLE_EX_DOUBLEBUFFER
35  *   - Messages:
36  *     - TB_GETMETRICS
37  *     - TB_GETOBJECT
38  *     - TB_INSERTMARKHITTEST
39  *     - TB_SAVERESTORE
40  *     - TB_SETMETRICS
41  *     - WM_WININICHANGE
42  *   - Notifications:
43  *     - NM_CHAR
44  *     - TBN_GETOBJECT
45  *     - TBN_SAVE
46  *   - Button wrapping (under construction).
47  *   - Fix TB_SETROWS.
48  *   - iListGap custom draw support.
49  *
50  * Testing:
51  *   - Run tests using Waite Group Windows95 API Bible Volume 2.
52  *     The second cdrom contains executables addstr.exe, btncount.exe,
53  *     btnstate.exe, butstrsz.exe, chkbtn.exe, chngbmp.exe, customiz.exe,
54  *     enablebtn.exe, getbmp.exe, getbtn.exe, getflags.exe, hidebtn.exe,
55  *     indetbtn.exe, insbtn.exe, pressbtn.exe, setbtnsz.exe, setcmdid.exe,
56  *     setparnt.exe, setrows.exe, toolwnd.exe.
57  *   - Microsoft's controlspy examples.
58  *   - Charles Petzold's 'Programming Windows': gadgets.exe
59  *
60  *  Differences between MSDN and actual native control operation:
61  *   1. MSDN says: "TBSTYLE_LIST: Creates a flat toolbar with button text
62  *                  to the right of the bitmap. Otherwise, this style is
63  *                  identical to TBSTYLE_FLAT."
64  *      As implemented by both v4.71 and v5.80 of the native COMCTL32.DLL
65  *      you can create a TBSTYLE_LIST without TBSTYLE_FLAT and the result
66  *      is non-flat non-transparent buttons. Therefore TBSTYLE_LIST does
67  *      *not* imply TBSTYLE_FLAT as documented.  (GA 8/2001)
68  *
69  */
70
71 #include <stdarg.h>
72 #include <string.h>
73
74 #include "windef.h"
75 #include "winbase.h"
76 #include "winreg.h"
77 #include "wingdi.h"
78 #include "winuser.h"
79 #include "wine/unicode.h"
80 #include "winnls.h"
81 #include "commctrl.h"
82 #include "comctl32.h"
83 #include "uxtheme.h"
84 #include "tmschema.h"
85 #include "wine/debug.h"
86
87 WINE_DEFAULT_DEBUG_CHANNEL(toolbar);
88
89 static HCURSOR hCursorDrag = NULL;
90
91 typedef struct
92 {
93     INT iBitmap;
94     INT idCommand;
95     BYTE  fsState;
96     BYTE  fsStyle;
97     BYTE  bHot;
98     BYTE  bDropDownPressed;
99     DWORD dwData;
100     INT_PTR iString;
101     INT nRow;
102     RECT rect;
103     INT cx; /* manually set size */
104 } TBUTTON_INFO;
105
106 typedef struct
107 {
108     UINT nButtons;
109     HINSTANCE hInst;
110     UINT nID;
111 } TBITMAP_INFO;
112
113 typedef struct
114 {
115     HIMAGELIST himl;
116     INT id;
117 } IMLENTRY, *PIMLENTRY;
118
119 typedef struct
120 {
121     DWORD    dwStructSize;    /* size of TBBUTTON struct */
122     INT      nWidth;          /* width of the toolbar */
123     RECT     client_rect;
124     RECT     rcBound;         /* bounding rectangle */
125     INT      nButtonHeight;
126     INT      nButtonWidth;
127     INT      nBitmapHeight;
128     INT      nBitmapWidth;
129     INT      nIndent;
130     INT      nRows;           /* number of button rows */
131     INT      nMaxTextRows;    /* maximum number of text rows */
132     INT      cxMin;           /* minimum button width */
133     INT      cxMax;           /* maximum button width */
134     INT      nNumButtons;     /* number of buttons */
135     INT      nNumBitmaps;     /* number of bitmaps */
136     INT      nNumStrings;     /* number of strings */
137     INT      nNumBitmapInfos;
138     INT      nButtonDown;     /* toolbar button being pressed or -1 if none */
139     INT      nButtonDrag;     /* toolbar button being dragged or -1 if none */
140     INT      nOldHit;
141     INT      nHotItem;        /* index of the "hot" item */
142     DWORD    dwBaseCustDraw;  /* CDRF_ response (w/o TBCDRF_) from PREPAINT */
143     DWORD    dwItemCustDraw;  /* CDRF_ response (w/o TBCDRF_) from ITEMPREP */
144     DWORD    dwItemCDFlag;    /* TBCDRF_ flags from last ITEMPREPAINT    */
145     SIZE     szPadding;       /* padding values around button */
146     INT      iListGap;        /* default gap between text and image for toolbar with list style */
147     HFONT    hDefaultFont;
148     HFONT    hFont;           /* text font */
149     HIMAGELIST himlInt;       /* image list created internally */
150     PIMLENTRY *himlDef;       /* default image list array */
151     INT       cimlDef;        /* default image list array count */
152     PIMLENTRY *himlHot;       /* hot image list array */
153     INT       cimlHot;        /* hot image list array count */
154     PIMLENTRY *himlDis;       /* disabled image list array */
155     INT       cimlDis;        /* disabled image list array count */
156     HWND     hwndToolTip;     /* handle to tool tip control */
157     HWND     hwndNotify;      /* handle to the window that gets notifications */
158     HWND     hwndSelf;        /* my own handle */
159     BOOL     bAnchor;         /* anchor highlight enabled */
160     BOOL     bDoRedraw;       /* Redraw status */
161     BOOL     bDragOutSent;    /* has TBN_DRAGOUT notification been sent for this drag? */
162     BOOL     bUnicode;        /* Notifications are ASCII (FALSE) or Unicode (TRUE)? */
163     BOOL     bCaptured;       /* mouse captured? */
164     DWORD      dwStyle;       /* regular toolbar style */
165     DWORD      dwExStyle;     /* extended toolbar style */
166     DWORD      dwDTFlags;     /* DrawText flags */
167
168     COLORREF   clrInsertMark;   /* insert mark color */
169     COLORREF   clrBtnHighlight; /* color for Flat Separator */
170     COLORREF   clrBtnShadow;    /* color for Flag Separator */
171     INT      iVersion;
172     LPWSTR   pszTooltipText;    /* temporary store for a string > 80 characters
173                                  * for TTN_GETDISPINFOW notification */
174     TBINSERTMARK  tbim;         /* info on insertion mark */
175     TBUTTON_INFO *buttons;      /* pointer to button array */
176     LPWSTR       *strings;      /* pointer to string array */
177     TBITMAP_INFO *bitmaps;
178 } TOOLBAR_INFO, *PTOOLBAR_INFO;
179
180
181 /* used by customization dialog */
182 typedef struct
183 {
184     PTOOLBAR_INFO tbInfo;
185     HWND          tbHwnd;
186 } CUSTDLG_INFO, *PCUSTDLG_INFO;
187
188 typedef struct
189 {
190     TBBUTTON btn;
191     BOOL     bVirtual;
192     BOOL     bRemovable;
193     WCHAR    text[64];
194 } CUSTOMBUTTON, *PCUSTOMBUTTON;
195
196 typedef enum
197 {
198     IMAGE_LIST_DEFAULT,
199     IMAGE_LIST_HOT,
200     IMAGE_LIST_DISABLED
201 } IMAGE_LIST_TYPE;
202
203 #define SEPARATOR_WIDTH    8
204 #define TOP_BORDER         2
205 #define BOTTOM_BORDER      2
206 #define DDARROW_WIDTH      11
207 #define ARROW_HEIGHT       3
208 #define INSERTMARK_WIDTH   2
209
210 #define DEFPAD_CX 7
211 #define DEFPAD_CY 6
212 #define DEFLISTGAP 4
213
214 /* vertical padding used in list mode when image is present */
215 #define LISTPAD_CY 9
216
217 /* how wide to treat the bitmap if it isn't present */
218 #define NONLIST_NOTEXT_OFFSET 2
219
220 #define TOOLBAR_NOWHERE (-1)
221
222 #define TOOLBAR_GetInfoPtr(hwnd) ((TOOLBAR_INFO *)GetWindowLongPtrW(hwnd,0))
223 #define TOOLBAR_HasText(x, y) (TOOLBAR_GetText(x, y) ? TRUE : FALSE)
224 #define TOOLBAR_HasDropDownArrows(exStyle) ((exStyle & TBSTYLE_EX_DRAWDDARROWS) ? TRUE : FALSE)
225
226 /* Used to find undocumented extended styles */
227 #define TBSTYLE_EX_ALL (TBSTYLE_EX_DRAWDDARROWS | \
228                         TBSTYLE_EX_UNDOC1 | \
229                         TBSTYLE_EX_MIXEDBUTTONS | \
230                         TBSTYLE_EX_HIDECLIPPEDBUTTONS)
231
232 /* all of the CCS_ styles */
233 #define COMMON_STYLES (CCS_TOP|CCS_NOMOVEY|CCS_BOTTOM|CCS_NORESIZE| \
234                        CCS_NOPARENTALIGN|CCS_ADJUSTABLE|CCS_NODIVIDER|CCS_VERT)
235
236 #define GETIBITMAP(infoPtr, i) (infoPtr->iVersion >= 5 ? LOWORD(i) : i)
237 #define GETHIMLID(infoPtr, i) (infoPtr->iVersion >= 5 ? HIWORD(i) : 0)
238 #define GETDEFIMAGELIST(infoPtr, id) TOOLBAR_GetImageList(infoPtr->himlDef, infoPtr->cimlDef, id)
239 #define GETHOTIMAGELIST(infoPtr, id) TOOLBAR_GetImageList(infoPtr->himlHot, infoPtr->cimlHot, id)
240 #define GETDISIMAGELIST(infoPtr, id) TOOLBAR_GetImageList(infoPtr->himlDis, infoPtr->cimlDis, id)
241
242 static const WCHAR themeClass[] = { 'T','o','o','l','b','a','r',0 };
243
244 static BOOL TOOLBAR_GetButtonInfo(TOOLBAR_INFO *infoPtr, NMTOOLBARW *nmtb);
245 static BOOL TOOLBAR_IsButtonRemovable(TOOLBAR_INFO *infoPtr, int iItem, PCUSTOMBUTTON btnInfo);
246 static HIMAGELIST TOOLBAR_GetImageList(PIMLENTRY *pies, INT cies, INT id);
247 static PIMLENTRY TOOLBAR_GetImageListEntry(PIMLENTRY *pies, INT cies, INT id);
248 static VOID TOOLBAR_DeleteImageList(PIMLENTRY **pies, INT *cies);
249 static HIMAGELIST TOOLBAR_InsertImageList(PIMLENTRY **pies, INT *cies, HIMAGELIST himl, INT id);
250 static LRESULT TOOLBAR_LButtonDown(HWND hwnd, WPARAM wParam, LPARAM lParam);
251 static void TOOLBAR_SetHotItemEx (TOOLBAR_INFO *infoPtr, INT nHit, DWORD dwReason);
252 static LRESULT TOOLBAR_AutoSize(HWND hwnd);
253 static void TOOLBAR_CheckImageListIconSize(TOOLBAR_INFO *infoPtr);
254
255 static LRESULT
256 TOOLBAR_NotifyFormat(TOOLBAR_INFO *infoPtr, WPARAM wParam, LPARAM lParam);
257
258
259 static LPWSTR
260 TOOLBAR_GetText(TOOLBAR_INFO *infoPtr, TBUTTON_INFO *btnPtr)
261 {
262     LPWSTR lpText = NULL;
263
264     /* NOTE: iString == -1 is undocumented */
265     if ((HIWORD(btnPtr->iString) != 0) && (btnPtr->iString != -1))
266         lpText = (LPWSTR)btnPtr->iString;
267     else if ((btnPtr->iString >= 0) && (btnPtr->iString < infoPtr->nNumStrings))
268         lpText = infoPtr->strings[btnPtr->iString];
269
270     return lpText;
271 }
272
273 static void
274 TOOLBAR_DumpButton(TOOLBAR_INFO *infoPtr, TBUTTON_INFO *bP, INT btn_num, BOOL internal)
275 {
276     if (TRACE_ON(toolbar)){
277         TRACE("button %d id %d, bitmap=%d, state=%02x, style=%02x, data=%08lx, stringid=0x%08x\n",
278               btn_num, bP->idCommand, GETIBITMAP(infoPtr, bP->iBitmap), 
279               bP->fsState, bP->fsStyle, bP->dwData, bP->iString);
280         TRACE("string %s\n", debugstr_w(TOOLBAR_GetText(infoPtr,bP)));
281         if (internal)
282             TRACE("button %d id %d, hot=%s, row=%d, rect=(%ld,%ld)-(%ld,%ld)\n",
283                   btn_num, bP->idCommand,
284                   (bP->bHot) ? "TRUE":"FALSE", bP->nRow,
285                   bP->rect.left, bP->rect.top,
286                   bP->rect.right, bP->rect.bottom);
287     }
288 }
289
290
291 static void
292 TOOLBAR_DumpToolbar(TOOLBAR_INFO *iP, INT line)
293 {
294     if (TRACE_ON(toolbar)) {
295         INT i;
296
297         TRACE("toolbar %p at line %d, exStyle=%08lx, buttons=%d, bitmaps=%d, strings=%d, style=%08lx\n",
298               iP->hwndSelf, line,
299               iP->dwExStyle, iP->nNumButtons, iP->nNumBitmaps,
300               iP->nNumStrings, iP->dwStyle);
301         TRACE("toolbar %p at line %d, himlInt=%p, himlDef=%p, himlHot=%p, himlDis=%p, redrawable=%s\n",
302               iP->hwndSelf, line,
303               iP->himlInt, iP->himlDef, iP->himlHot, iP->himlDis,
304               (iP->bDoRedraw) ? "TRUE" : "FALSE");
305         for(i=0; i<iP->nNumButtons; i++) {
306             TOOLBAR_DumpButton(iP, &iP->buttons[i], i, TRUE);
307         }
308     }
309 }
310
311
312 /***********************************************************************
313 *               TOOLBAR_CheckStyle
314 *
315 * This function validates that the styles set are implemented and
316 * issues FIXME's warning of possible problems. In a perfect world this
317 * function should be null.
318 */
319 static void
320 TOOLBAR_CheckStyle (HWND hwnd, DWORD dwStyle)
321 {
322     if (dwStyle & TBSTYLE_REGISTERDROP)
323         FIXME("[%p] TBSTYLE_REGISTERDROP not implemented\n", hwnd);
324 }
325
326
327 static INT
328 TOOLBAR_SendNotify (NMHDR *nmhdr, TOOLBAR_INFO *infoPtr, UINT code)
329 {
330         if(!IsWindow(infoPtr->hwndSelf))
331             return 0;   /* we have just been destroyed */
332
333     nmhdr->idFrom = GetDlgCtrlID (infoPtr->hwndSelf);
334     nmhdr->hwndFrom = infoPtr->hwndSelf;
335     nmhdr->code = code;
336
337     TRACE("to window %p, code=%08x, %s\n", infoPtr->hwndNotify, code,
338           (infoPtr->bUnicode) ? "via Unicode" : "via ANSI");
339
340     return SendMessageW(infoPtr->hwndNotify, WM_NOTIFY, 
341         (WPARAM)nmhdr->idFrom, (LPARAM)nmhdr);
342 }
343
344 /***********************************************************************
345 *               TOOLBAR_GetBitmapIndex
346 *
347 * This function returns the bitmap index associated with a button.
348 * If the button specifies I_IMAGECALLBACK, then the TBN_GETDISPINFO
349 * is issued to retrieve the index.
350 */
351 static INT
352 TOOLBAR_GetBitmapIndex(TOOLBAR_INFO *infoPtr, TBUTTON_INFO *btnPtr)
353 {
354     INT ret = btnPtr->iBitmap;
355
356     if (ret == I_IMAGECALLBACK)
357     {
358         /* issue TBN_GETDISPINFO */
359         NMTBDISPINFOA nmgd;
360
361         memset(&nmgd, 0, sizeof(nmgd));
362         nmgd.idCommand = btnPtr->idCommand;
363         nmgd.lParam = btnPtr->dwData;
364         nmgd.dwMask = TBNF_IMAGE;
365         TOOLBAR_SendNotify(&nmgd.hdr, infoPtr,
366                         infoPtr->bUnicode ? TBN_GETDISPINFOW : TBN_GETDISPINFOA);
367         if (nmgd.dwMask & TBNF_DI_SETITEM)
368             btnPtr->iBitmap = nmgd.iImage;
369         ret = nmgd.iImage;
370         TRACE("TBN_GETDISPINFO returned bitmap id %d, mask=%08lx, nNumBitmaps=%d\n",
371             ret, nmgd.dwMask, infoPtr->nNumBitmaps);
372     }
373
374     if (ret != I_IMAGENONE)
375         ret = GETIBITMAP(infoPtr, ret);
376
377     return ret;
378 }
379
380
381 static BOOL
382 TOOLBAR_IsValidBitmapIndex(TOOLBAR_INFO *infoPtr, INT index)
383 {
384     HIMAGELIST himl;
385     INT id = GETHIMLID(infoPtr, index);
386     INT iBitmap = GETIBITMAP(infoPtr, index);
387
388     if (((himl = GETDEFIMAGELIST(infoPtr, id)) &&
389         iBitmap >= 0 && iBitmap < ImageList_GetImageCount(himl)) ||
390         (index == I_IMAGECALLBACK))
391       return TRUE;
392     else
393       return FALSE;
394 }
395
396
397 static inline BOOL
398 TOOLBAR_IsValidImageList(TOOLBAR_INFO *infoPtr, INT index)
399 {
400     HIMAGELIST himl = GETDEFIMAGELIST(infoPtr, GETHIMLID(infoPtr, index));
401     return (himl != NULL) && (ImageList_GetImageCount(himl) > 0);
402 }
403
404
405 /***********************************************************************
406 *               TOOLBAR_GetImageListForDrawing
407 *
408 * This function validates the bitmap index (including I_IMAGECALLBACK
409 * functionality) and returns the corresponding image list.
410 */
411 static HIMAGELIST
412 TOOLBAR_GetImageListForDrawing (TOOLBAR_INFO *infoPtr, TBUTTON_INFO *btnPtr, IMAGE_LIST_TYPE imagelist, INT * index)
413 {
414     HIMAGELIST himl;
415
416     if (!TOOLBAR_IsValidBitmapIndex(infoPtr,btnPtr->iBitmap)) {
417         if (btnPtr->iBitmap == I_IMAGENONE) return NULL;
418         ERR("bitmap for ID %d, index %d is not valid, number of bitmaps in imagelist: %d\n",
419             HIWORD(btnPtr->iBitmap), LOWORD(btnPtr->iBitmap), infoPtr->nNumBitmaps);
420         return NULL;
421     }
422
423     if ((*index = TOOLBAR_GetBitmapIndex(infoPtr, btnPtr)) < 0) {
424         if ((*index == I_IMAGECALLBACK) ||
425             (*index == I_IMAGENONE)) return NULL;
426         ERR("TBN_GETDISPINFO returned invalid index %d\n",
427             *index);
428         return NULL;
429     }
430
431     switch(imagelist)
432     {
433     case IMAGE_LIST_DEFAULT:
434         himl = GETDEFIMAGELIST(infoPtr, GETHIMLID(infoPtr, btnPtr->iBitmap));
435         break;
436     case IMAGE_LIST_HOT:
437         himl = GETHOTIMAGELIST(infoPtr, GETHIMLID(infoPtr, btnPtr->iBitmap));
438         break;
439     case IMAGE_LIST_DISABLED:
440         himl = GETDISIMAGELIST(infoPtr, GETHIMLID(infoPtr, btnPtr->iBitmap));
441         break;
442     default:
443         himl = NULL;
444         FIXME("Shouldn't reach here\n");
445     }
446
447     if (!himl)
448        TRACE("no image list\n");
449
450     return himl;
451 }
452
453
454 static void
455 TOOLBAR_DrawFlatSeparator (LPRECT lpRect, HDC hdc, TOOLBAR_INFO *infoPtr)
456 {
457     RECT myrect;
458     COLORREF oldcolor, newcolor;
459
460     myrect.left = (lpRect->left + lpRect->right) / 2 - 1;
461     myrect.right = myrect.left + 1;
462     myrect.top = lpRect->top + 2;
463     myrect.bottom = lpRect->bottom - 2;
464
465     newcolor = (infoPtr->clrBtnShadow == CLR_DEFAULT) ?
466                 comctl32_color.clrBtnShadow : infoPtr->clrBtnShadow;
467     oldcolor = SetBkColor (hdc, newcolor);
468     ExtTextOutW (hdc, 0, 0, ETO_OPAQUE, &myrect, 0, 0, 0);
469
470     myrect.left = myrect.right;
471     myrect.right = myrect.left + 1;
472
473     newcolor = (infoPtr->clrBtnHighlight == CLR_DEFAULT) ?
474                 comctl32_color.clrBtnHighlight : infoPtr->clrBtnHighlight;
475     SetBkColor (hdc, newcolor);
476     ExtTextOutW (hdc, 0, 0, ETO_OPAQUE, &myrect, 0, 0, 0);
477
478     SetBkColor (hdc, oldcolor);
479 }
480
481
482 /***********************************************************************
483 *               TOOLBAR_DrawDDFlatSeparator
484 *
485 * This function draws the separator that was flagged as BTNS_DROPDOWN.
486 * In this case, the separator is a pixel high line of COLOR_BTNSHADOW,
487 * followed by a pixel high line of COLOR_BTNHIGHLIGHT. These separators
488 * are horizontal as opposed to the vertical separators for not dropdown
489 * type.
490 *
491 * FIXME: It is possible that the height of each line is really SM_CYBORDER.
492 */
493 static void
494 TOOLBAR_DrawDDFlatSeparator (LPRECT lpRect, HDC hdc, TBUTTON_INFO *btnPtr, TOOLBAR_INFO *infoPtr)
495 {
496     RECT myrect;
497     COLORREF oldcolor, newcolor;
498
499     myrect.left = lpRect->left;
500     myrect.right = lpRect->right;
501     myrect.top = lpRect->top + (lpRect->bottom - lpRect->top - 2)/2;
502     myrect.bottom = myrect.top + 1;
503
504     InflateRect (&myrect, -2, 0);
505
506     TRACE("rect=(%ld,%ld)-(%ld,%ld)\n",
507           myrect.left, myrect.top, myrect.right, myrect.bottom);
508
509     newcolor = (infoPtr->clrBtnShadow == CLR_DEFAULT) ?
510                 comctl32_color.clrBtnShadow : infoPtr->clrBtnShadow;
511     oldcolor = SetBkColor (hdc, newcolor);
512     ExtTextOutW (hdc, 0, 0, ETO_OPAQUE, &myrect, 0, 0, 0);
513
514     myrect.top = myrect.bottom;
515     myrect.bottom = myrect.top + 1;
516
517     newcolor = (infoPtr->clrBtnHighlight == CLR_DEFAULT) ?
518                 comctl32_color.clrBtnHighlight : infoPtr->clrBtnHighlight;
519     SetBkColor (hdc, newcolor);
520     ExtTextOutW (hdc, 0, 0, ETO_OPAQUE, &myrect, 0, 0, 0);
521
522     SetBkColor (hdc, oldcolor);
523 }
524
525
526 static void
527 TOOLBAR_DrawArrow (HDC hdc, INT left, INT top, COLORREF clr)
528 {
529     INT x, y;
530     HPEN hPen, hOldPen;
531
532     if (!(hPen = CreatePen( PS_SOLID, 1, clr))) return;
533     hOldPen = SelectObject ( hdc, hPen );
534     x = left + 2;
535     y = top;
536     MoveToEx (hdc, x, y, NULL);
537     LineTo (hdc, x+5, y++); x++;
538     MoveToEx (hdc, x, y, NULL);
539     LineTo (hdc, x+3, y++); x++;
540     MoveToEx (hdc, x, y, NULL);
541     LineTo (hdc, x+1, y++);
542     SelectObject( hdc, hOldPen );
543     DeleteObject( hPen );
544 }
545
546 /*
547  * Draw the text string for this button.
548  * note: infoPtr->himlDis *SHOULD* be non-zero when infoPtr->himlDef
549  *      is non-zero, so we can simply check himlDef to see if we have
550  *      an image list
551  */
552 static void
553 TOOLBAR_DrawString (TOOLBAR_INFO *infoPtr, RECT *rcText, LPWSTR lpText,
554                     NMTBCUSTOMDRAW *tbcd)
555 {
556     HDC hdc = tbcd->nmcd.hdc;
557     HFONT  hOldFont = 0;
558     COLORREF clrOld = 0;
559     COLORREF clrOldBk = 0;
560     int oldBkMode = 0;
561     UINT state = tbcd->nmcd.uItemState;
562
563     /* draw text */
564     if (lpText) {
565         TRACE("string=%s rect=(%ld,%ld)-(%ld,%ld)\n", debugstr_w(lpText),
566               rcText->left, rcText->top, rcText->right, rcText->bottom);
567
568         hOldFont = SelectObject (hdc, infoPtr->hFont);
569         if ((state & CDIS_HOT) && (infoPtr->dwItemCDFlag & TBCDRF_HILITEHOTTRACK )) {
570             clrOld = SetTextColor (hdc, tbcd->clrTextHighlight);
571         }
572         else if (state & CDIS_DISABLED) {
573             clrOld = SetTextColor (hdc, tbcd->clrBtnHighlight);
574             OffsetRect (rcText, 1, 1);
575             DrawTextW (hdc, lpText, -1, rcText, infoPtr->dwDTFlags);
576             SetTextColor (hdc, comctl32_color.clr3dShadow);
577             OffsetRect (rcText, -1, -1);
578         }
579         else if (state & CDIS_INDETERMINATE) {
580             clrOld = SetTextColor (hdc, comctl32_color.clr3dShadow);
581         }
582         else if ((state & CDIS_MARKED) && !(infoPtr->dwItemCDFlag & TBCDRF_NOMARK)) {
583             clrOld = SetTextColor (hdc, tbcd->clrTextHighlight);
584             clrOldBk = SetBkColor (hdc, tbcd->clrMark);
585             oldBkMode = SetBkMode (hdc, tbcd->nHLStringBkMode);
586         }
587         else {
588             clrOld = SetTextColor (hdc, tbcd->clrText);
589         }
590
591         DrawTextW (hdc, lpText, -1, rcText, infoPtr->dwDTFlags);
592         SetTextColor (hdc, clrOld);
593         if ((state & CDIS_MARKED) && !(infoPtr->dwItemCDFlag & TBCDRF_NOMARK))
594         {
595             SetBkColor (hdc, clrOldBk);
596             SetBkMode (hdc, oldBkMode);
597         }
598         SelectObject (hdc, hOldFont);
599     }
600 }
601
602
603 static void
604 TOOLBAR_DrawPattern (LPRECT lpRect, NMTBCUSTOMDRAW *tbcd)
605 {
606     HDC hdc = tbcd->nmcd.hdc;
607     HBRUSH hbr = SelectObject (hdc, tbcd->hbrMonoDither);
608     COLORREF clrTextOld;
609     COLORREF clrBkOld;
610     INT cx = lpRect->right - lpRect->left;
611     INT cy = lpRect->bottom - lpRect->top;
612     INT cxEdge = GetSystemMetrics(SM_CXEDGE);
613     INT cyEdge = GetSystemMetrics(SM_CYEDGE);
614     clrTextOld = SetTextColor(hdc, tbcd->clrBtnHighlight);
615     clrBkOld = SetBkColor(hdc, tbcd->clrBtnFace);
616     PatBlt (hdc, lpRect->left + cxEdge, lpRect->top + cyEdge,
617             cx - (2 * cxEdge), cy - (2 * cyEdge), PATCOPY);
618     SetBkColor(hdc, clrBkOld);
619     SetTextColor(hdc, clrTextOld);
620     SelectObject (hdc, hbr);
621 }
622
623
624 static void TOOLBAR_DrawMasked(HIMAGELIST himl, int index, HDC hdc, INT x, INT y, UINT draw_flags)
625 {
626     INT cx, cy;
627     HBITMAP hbmMask, hbmImage;
628     HDC hdcMask, hdcImage;
629
630     ImageList_GetIconSize(himl, &cx, &cy);
631
632     /* Create src image */
633     hdcImage = CreateCompatibleDC(hdc);
634     hbmImage = CreateCompatibleBitmap(hdc, cx, cy);
635     SelectObject(hdcImage, hbmImage);
636     ImageList_DrawEx(himl, index, hdcImage, 0, 0, cx, cy,
637                      RGB(0xff, 0xff, 0xff), RGB(0,0,0), draw_flags);
638
639     /* Create Mask */
640     hdcMask = CreateCompatibleDC(0);
641     hbmMask = CreateBitmap(cx, cy, 1, 1, NULL);
642     SelectObject(hdcMask, hbmMask);
643
644     /* Remove the background and all white pixels */
645     ImageList_DrawEx(himl, index, hdcMask, 0, 0, cx, cy,
646                      RGB(0xff, 0xff, 0xff), RGB(0,0,0), ILD_MASK);
647     SetBkColor(hdcImage, RGB(0xff, 0xff, 0xff));
648     BitBlt(hdcMask, 0, 0, cx, cy, hdcImage, 0, 0, NOTSRCERASE);
649
650     /* draw the new mask 'etched' to hdc */
651     SetBkColor(hdc, RGB(255, 255, 255));
652     SelectObject(hdc, GetSysColorBrush(COLOR_3DHILIGHT));
653     /* E20746 op code is (Dst ^ (Src & (Pat ^ Dst))) */
654     BitBlt(hdc, x + 1, y + 1, cx, cy, hdcMask, 0, 0, 0xE20746);
655     SelectObject(hdc, GetSysColorBrush(COLOR_3DSHADOW));
656     BitBlt(hdc, x, y, cx, cy, hdcMask, 0, 0, 0xE20746);
657
658     /* Cleanup */
659     DeleteObject(hbmImage);
660     DeleteDC(hdcImage);
661     DeleteObject (hbmMask);
662     DeleteDC(hdcMask);
663 }
664
665
666 static UINT
667 TOOLBAR_TranslateState(TBUTTON_INFO *btnPtr)
668 {
669     UINT retstate = 0;
670
671     retstate |= (btnPtr->fsState & TBSTATE_CHECKED) ? CDIS_CHECKED  : 0;
672     retstate |= (btnPtr->fsState & TBSTATE_PRESSED) ? CDIS_SELECTED : 0;
673     retstate |= (btnPtr->fsState & TBSTATE_ENABLED) ? 0 : CDIS_DISABLED;
674     retstate |= (btnPtr->fsState & TBSTATE_MARKED ) ? CDIS_MARKED   : 0;
675     retstate |= (btnPtr->bHot                     ) ? CDIS_HOT      : 0;
676     retstate |= ((btnPtr->fsState & (TBSTATE_ENABLED|TBSTATE_INDETERMINATE)) == (TBSTATE_ENABLED|TBSTATE_INDETERMINATE)) ? CDIS_INDETERMINATE : 0;
677     /* NOTE: we don't set CDIS_GRAYED, CDIS_FOCUS, CDIS_DEFAULT */
678     return retstate;
679 }
680
681 /* draws the image on a toolbar button */
682 static void
683 TOOLBAR_DrawImage(TOOLBAR_INFO *infoPtr, TBUTTON_INFO *btnPtr, INT left, INT top, const NMTBCUSTOMDRAW *tbcd)
684 {
685     HIMAGELIST himl = NULL;
686     BOOL draw_masked = FALSE;
687     INT index;
688     INT offset = 0;
689     UINT draw_flags = ILD_TRANSPARENT;
690
691     if (tbcd->nmcd.uItemState & (CDIS_DISABLED | CDIS_INDETERMINATE))
692     {
693         himl = TOOLBAR_GetImageListForDrawing(infoPtr, btnPtr, IMAGE_LIST_DISABLED, &index);
694         if (!himl)
695         {
696             himl = TOOLBAR_GetImageListForDrawing(infoPtr, btnPtr, IMAGE_LIST_DEFAULT, &index);
697             draw_masked = TRUE;
698         }
699     }
700     else if (tbcd->nmcd.uItemState & CDIS_CHECKED ||
701       ((tbcd->nmcd.uItemState & CDIS_HOT) 
702       && ((infoPtr->dwStyle & TBSTYLE_FLAT) || GetWindowTheme (infoPtr->hwndSelf))))
703     {
704         /* if hot, attempt to draw with hot image list, if fails, 
705            use default image list */
706         himl = TOOLBAR_GetImageListForDrawing(infoPtr, btnPtr, IMAGE_LIST_HOT, &index);
707         if (!himl)
708             himl = TOOLBAR_GetImageListForDrawing(infoPtr, btnPtr, IMAGE_LIST_DEFAULT, &index);
709         }
710     else
711         himl = TOOLBAR_GetImageListForDrawing(infoPtr, btnPtr, IMAGE_LIST_DEFAULT, &index);
712
713     if (!himl)
714         return;
715
716     if (!(infoPtr->dwItemCDFlag & TBCDRF_NOOFFSET) && 
717         (tbcd->nmcd.uItemState & (CDIS_SELECTED | CDIS_CHECKED)))
718         offset = 1;
719
720     if (!(infoPtr->dwItemCDFlag & TBCDRF_NOMARK) &&
721         (tbcd->nmcd.uItemState & CDIS_MARKED))
722         draw_flags |= ILD_BLEND50;
723
724     TRACE("drawing index=%d, himl=%p, left=%d, top=%d, offset=%d\n",
725       index, himl, left, top, offset);
726
727     if (draw_masked)
728         TOOLBAR_DrawMasked (himl, index, tbcd->nmcd.hdc, left + offset, top + offset, draw_flags);
729     else
730         ImageList_Draw (himl, index, tbcd->nmcd.hdc, left + offset, top + offset, draw_flags);
731 }
732
733 /* draws a blank frame for a toolbar button */
734 static void
735 TOOLBAR_DrawFrame(const TOOLBAR_INFO *infoPtr, const NMTBCUSTOMDRAW *tbcd)
736 {
737     HDC hdc = tbcd->nmcd.hdc;
738     RECT rc = tbcd->nmcd.rc;
739     /* if the state is disabled or indeterminate then the button
740      * cannot have an interactive look like pressed or hot */
741     BOOL non_interactive_state = (tbcd->nmcd.uItemState & CDIS_DISABLED) ||
742                                  (tbcd->nmcd.uItemState & CDIS_INDETERMINATE);
743     BOOL pressed_look = !non_interactive_state &&
744                         ((tbcd->nmcd.uItemState & CDIS_SELECTED) || 
745                          (tbcd->nmcd.uItemState & CDIS_CHECKED));
746
747     /* app don't want us to draw any edges */
748     if (infoPtr->dwItemCDFlag & TBCDRF_NOEDGES)
749         return;
750
751     if (infoPtr->dwStyle & TBSTYLE_FLAT)
752     {
753         if (pressed_look)
754             DrawEdge (hdc, &rc, BDR_SUNKENOUTER, BF_RECT);
755         else if ((tbcd->nmcd.uItemState & CDIS_HOT) && !non_interactive_state)
756             DrawEdge (hdc, &rc, BDR_RAISEDINNER, BF_RECT);
757     }
758     else
759     {
760         if (pressed_look)
761             DrawEdge (hdc, &rc, EDGE_SUNKEN, BF_RECT | BF_MIDDLE);
762         else
763             DrawEdge (hdc, &rc, EDGE_RAISED,
764               BF_SOFT | BF_RECT | BF_MIDDLE);
765     }
766 }
767
768 static void
769 TOOLBAR_DrawSepDDArrow(const TOOLBAR_INFO *infoPtr, const NMTBCUSTOMDRAW *tbcd, RECT *rcArrow, BOOL bDropDownPressed)
770 {
771     HDC hdc = tbcd->nmcd.hdc;
772     int offset = 0;
773     BOOL pressed = bDropDownPressed ||
774         (tbcd->nmcd.uItemState & (CDIS_SELECTED | CDIS_CHECKED));
775
776     if (infoPtr->dwStyle & TBSTYLE_FLAT)
777     {
778         if (pressed)
779             DrawEdge (hdc, rcArrow, BDR_SUNKENOUTER, BF_RECT);
780         else if ( (tbcd->nmcd.uItemState & CDIS_HOT) &&
781                  !(tbcd->nmcd.uItemState & CDIS_DISABLED) &&
782                  !(tbcd->nmcd.uItemState & CDIS_INDETERMINATE))
783             DrawEdge (hdc, rcArrow, BDR_RAISEDINNER, BF_RECT);
784     }
785     else
786     {
787         if (pressed)
788             DrawEdge (hdc, rcArrow, EDGE_SUNKEN, BF_RECT | BF_MIDDLE);
789         else
790             DrawEdge (hdc, rcArrow, EDGE_RAISED,
791               BF_SOFT | BF_RECT | BF_MIDDLE);
792     }
793
794     if (pressed)
795         offset = (infoPtr->dwItemCDFlag & TBCDRF_NOOFFSET) ? 0 : 1;
796
797     if (tbcd->nmcd.uItemState & (CDIS_DISABLED | CDIS_INDETERMINATE))
798     {
799         TOOLBAR_DrawArrow(hdc, rcArrow->left+1, rcArrow->top+1 + (rcArrow->bottom - rcArrow->top - ARROW_HEIGHT) / 2, comctl32_color.clrBtnHighlight);
800         TOOLBAR_DrawArrow(hdc, rcArrow->left, rcArrow->top + (rcArrow->bottom - rcArrow->top - ARROW_HEIGHT) / 2, comctl32_color.clr3dShadow);
801     }
802     else
803         TOOLBAR_DrawArrow(hdc, rcArrow->left + offset, rcArrow->top + offset + (rcArrow->bottom - rcArrow->top - ARROW_HEIGHT) / 2, comctl32_color.clrBtnText);
804 }
805
806 /* draws a complete toolbar button */
807 static void
808 TOOLBAR_DrawButton (HWND hwnd, TBUTTON_INFO *btnPtr, HDC hdc)
809 {
810     TOOLBAR_INFO *infoPtr = TOOLBAR_GetInfoPtr (hwnd);
811     DWORD dwStyle = infoPtr->dwStyle;
812     BOOL hasDropDownArrow = (TOOLBAR_HasDropDownArrows(infoPtr->dwExStyle) &&
813                             (btnPtr->fsStyle & BTNS_DROPDOWN)) ||
814                             (btnPtr->fsStyle & BTNS_WHOLEDROPDOWN);
815     BOOL drawSepDropDownArrow = hasDropDownArrow && 
816                                 (~btnPtr->fsStyle & BTNS_WHOLEDROPDOWN);
817     RECT rc, rcArrow, rcBitmap, rcText;
818     LPWSTR lpText = NULL;
819     NMTBCUSTOMDRAW tbcd;
820     DWORD ntfret;
821     INT offset;
822     INT oldBkMode;
823     HTHEME theme = GetWindowTheme (hwnd);
824
825     rc = btnPtr->rect;
826     CopyRect (&rcArrow, &rc);
827
828     /* get a pointer to the text */
829     lpText = TOOLBAR_GetText(infoPtr, btnPtr);
830
831     if (hasDropDownArrow)
832     {
833         int right;
834
835         if (dwStyle & TBSTYLE_FLAT)
836             right = max(rc.left, rc.right - DDARROW_WIDTH);
837         else
838             right = max(rc.left, rc.right - DDARROW_WIDTH - 2);
839
840         if (drawSepDropDownArrow)
841            rc.right = right;
842
843         rcArrow.left = right;
844     }
845
846     /* copy text & bitmap rects after adjusting for drop-down arrow
847      * so that text & bitmap is centred in the rectangle not containing
848      * the arrow */
849     CopyRect(&rcText, &rc);
850     CopyRect(&rcBitmap, &rc);
851
852     /* Center the bitmap horizontally and vertically */
853     if (dwStyle & TBSTYLE_LIST)
854     {
855         if (lpText &&
856             infoPtr->nMaxTextRows > 0 &&
857             (!(infoPtr->dwExStyle & TBSTYLE_EX_MIXEDBUTTONS) ||
858             (btnPtr->fsStyle & BTNS_SHOWTEXT)) )
859             rcBitmap.left += GetSystemMetrics(SM_CXEDGE) + infoPtr->szPadding.cx / 2;
860         else
861             rcBitmap.left += GetSystemMetrics(SM_CXEDGE) + infoPtr->iListGap / 2;
862     }
863     else
864         rcBitmap.left += (infoPtr->nButtonWidth - infoPtr->nBitmapWidth) / 2;
865
866     rcBitmap.top += infoPtr->szPadding.cy / 2;
867
868     TRACE("iBitmap=%d, start=(%ld,%ld) w=%d, h=%d\n",
869       btnPtr->iBitmap, rcBitmap.left, rcBitmap.top,
870       infoPtr->nBitmapWidth, infoPtr->nBitmapHeight);
871     TRACE("Text=%s\n", debugstr_w(lpText));
872     TRACE("iListGap=%d, padding = { %ld, %ld }\n", infoPtr->iListGap, infoPtr->szPadding.cx, infoPtr->szPadding.cy);
873
874     /* calculate text position */
875     if (lpText)
876     {
877         rcText.left += GetSystemMetrics(SM_CXEDGE);
878         rcText.right -= GetSystemMetrics(SM_CXEDGE);
879         if (dwStyle & TBSTYLE_LIST)
880         {
881             if (TOOLBAR_IsValidBitmapIndex(infoPtr,btnPtr->iBitmap))
882                 rcText.left += infoPtr->nBitmapWidth + infoPtr->iListGap + 2;
883         }
884         else
885         {
886             if (ImageList_GetImageCount(GETDEFIMAGELIST(infoPtr, 0)) > 0)
887                 rcText.top += infoPtr->szPadding.cy/2 + infoPtr->nBitmapHeight + 1;
888             else
889                 rcText.top += infoPtr->szPadding.cy/2 + 2;
890         }
891     }
892
893     /* Initialize fields in all cases, because we use these later
894      * NOTE: applications can and do alter these to customize their
895      * toolbars */
896     ZeroMemory (&tbcd, sizeof(NMTBCUSTOMDRAW));
897     tbcd.clrText = comctl32_color.clrBtnText;
898     tbcd.clrTextHighlight = comctl32_color.clrHighlightText;
899     tbcd.clrBtnFace = comctl32_color.clrBtnFace;
900     tbcd.clrBtnHighlight = comctl32_color.clrBtnHighlight;
901     tbcd.clrMark = comctl32_color.clrHighlight;
902     tbcd.clrHighlightHotTrack = 0;
903     tbcd.nStringBkMode = TRANSPARENT;
904     tbcd.nHLStringBkMode = OPAQUE;
905     /* MSDN says that this is the text rectangle.
906      * But (why always a but) tracing of v5.7 of native shows
907      * that this is really a *relative* rectangle based on the
908      * the nmcd.rc. Also the left and top are always 0 ignoring
909      * any bitmap that might be present. */
910     tbcd.rcText.left = 0;
911     tbcd.rcText.top = 0;
912     tbcd.rcText.right = rcText.right - rc.left;
913     tbcd.rcText.bottom = rcText.bottom - rc.top;
914     tbcd.nmcd.uItemState = TOOLBAR_TranslateState(btnPtr);
915     tbcd.nmcd.hdc = hdc;
916     tbcd.nmcd.rc = rc;
917     tbcd.hbrMonoDither = COMCTL32_hPattern55AABrush;
918
919     /* FIXME: what are these used for? */
920     tbcd.hbrLines = 0;
921     tbcd.hpenLines = 0;
922
923     /* Issue Item Prepaint notify */
924     infoPtr->dwItemCustDraw = 0;
925     infoPtr->dwItemCDFlag = 0;
926     if (infoPtr->dwBaseCustDraw & CDRF_NOTIFYITEMDRAW)
927     {
928         tbcd.nmcd.dwDrawStage = CDDS_ITEMPREPAINT;
929         tbcd.nmcd.dwItemSpec = btnPtr->idCommand;
930         tbcd.nmcd.lItemlParam = btnPtr->dwData;
931         ntfret = TOOLBAR_SendNotify(&tbcd.nmcd.hdr, infoPtr, NM_CUSTOMDRAW);
932         /* reset these fields so the user can't alter the behaviour like native */
933         tbcd.nmcd.hdc = hdc;
934         tbcd.nmcd.rc = rc;
935
936         infoPtr->dwItemCustDraw = ntfret & 0xffff;
937         infoPtr->dwItemCDFlag = ntfret & 0xffff0000;
938         if (infoPtr->dwItemCustDraw & CDRF_SKIPDEFAULT)
939             return;
940         /* save the only part of the rect that the user can change */
941         rcText.right = tbcd.rcText.right + rc.left;
942         rcText.bottom = tbcd.rcText.bottom + rc.top;
943     }
944
945     /* separator */
946     if (btnPtr->fsStyle & BTNS_SEP) {
947         if (theme)
948         {
949             DrawThemeBackground (theme, hdc, 
950                 (dwStyle & CCS_VERT) ? TP_SEPARATORVERT : TP_SEPARATOR, 0, 
951                 &tbcd.nmcd.rc, NULL);
952         }
953         else
954         /* with the FLAT style, iBitmap is the width and has already */
955         /* been taken into consideration in calculating the width    */
956         /* so now we need to draw the vertical separator             */
957         /* empirical tests show that iBitmap can/will be non-zero    */
958         /* when drawing the vertical bar...      */
959         if ((dwStyle & TBSTYLE_FLAT) /* && (btnPtr->iBitmap == 0) */) {
960             if (btnPtr->fsStyle & BTNS_DROPDOWN)
961                 TOOLBAR_DrawDDFlatSeparator (&rc, hdc, btnPtr, infoPtr);
962             else
963                 TOOLBAR_DrawFlatSeparator (&rc, hdc, infoPtr);
964         }
965         else if (btnPtr->fsStyle != BTNS_SEP) {
966             FIXME("Draw some kind of separator: fsStyle=%x\n",
967                   btnPtr->fsStyle);
968         }
969         goto FINALNOTIFY;
970     }
971
972     if (!(infoPtr->dwItemCDFlag & TBCDRF_NOOFFSET) &&
973         (btnPtr->fsState & (TBSTATE_PRESSED | TBSTATE_CHECKED)))
974         OffsetRect(&rcText, 1, 1);
975
976     if (!(tbcd.nmcd.uItemState & CDIS_HOT) && 
977         ((tbcd.nmcd.uItemState & CDIS_CHECKED) || (tbcd.nmcd.uItemState & CDIS_INDETERMINATE)))
978         TOOLBAR_DrawPattern (&rc, &tbcd);
979
980     if (((infoPtr->dwStyle & TBSTYLE_FLAT) || GetWindowTheme (infoPtr->hwndSelf)) 
981         && (tbcd.nmcd.uItemState & CDIS_HOT))
982     {
983         if ( infoPtr->dwItemCDFlag & TBCDRF_HILITEHOTTRACK )
984         {
985             COLORREF oldclr;
986
987             oldclr = SetBkColor(hdc, tbcd.clrHighlightHotTrack);
988             ExtTextOutW(hdc, 0, 0, ETO_OPAQUE, &rc, NULL, 0, 0);
989             if (hasDropDownArrow)
990                 ExtTextOutW(hdc, 0, 0, ETO_OPAQUE, &rcArrow, NULL, 0, 0);
991             SetBkColor(hdc, oldclr);
992         }
993     }
994
995     if (theme)
996     {
997         int partId = drawSepDropDownArrow ? TP_SPLITBUTTON : TP_BUTTON;
998         int stateId = TS_NORMAL;
999         
1000         if (tbcd.nmcd.uItemState & CDIS_DISABLED)
1001             stateId = TS_DISABLED;
1002         else if (tbcd.nmcd.uItemState & CDIS_SELECTED)
1003             stateId = TS_PRESSED;
1004         else if (tbcd.nmcd.uItemState & CDIS_CHECKED)
1005             stateId = (tbcd.nmcd.uItemState & CDIS_HOT) ? TS_HOTCHECKED : TS_HOT;
1006         else if ((tbcd.nmcd.uItemState & CDIS_HOT)
1007             || (drawSepDropDownArrow && btnPtr->bDropDownPressed))
1008             stateId = TS_HOT;
1009             
1010         DrawThemeBackground (theme, hdc, partId, stateId, &tbcd.nmcd.rc, NULL);
1011     }
1012     else
1013         TOOLBAR_DrawFrame(infoPtr, &tbcd);
1014
1015     if (drawSepDropDownArrow)
1016     {
1017         if (theme)
1018         {
1019             int stateId = TS_NORMAL;
1020             
1021             if (tbcd.nmcd.uItemState & CDIS_DISABLED)
1022                 stateId = TS_DISABLED;
1023             else if (btnPtr->bDropDownPressed || (tbcd.nmcd.uItemState & CDIS_SELECTED))
1024                 stateId = TS_PRESSED;
1025             else if (tbcd.nmcd.uItemState & CDIS_CHECKED)
1026                 stateId = (tbcd.nmcd.uItemState & CDIS_HOT) ? TS_HOTCHECKED : TS_HOT;
1027             else if (tbcd.nmcd.uItemState & CDIS_HOT)
1028                 stateId = TS_HOT;
1029                 
1030             DrawThemeBackground (theme, hdc, TP_DROPDOWNBUTTON, stateId, &rcArrow, NULL);
1031             DrawThemeBackground (theme, hdc, TP_SPLITBUTTONDROPDOWN, stateId, &rcArrow, NULL);
1032         }
1033         else
1034             TOOLBAR_DrawSepDDArrow(infoPtr, &tbcd, &rcArrow, btnPtr->bDropDownPressed);
1035     }
1036
1037     oldBkMode = SetBkMode (hdc, tbcd.nStringBkMode);
1038     if (!(infoPtr->dwExStyle & TBSTYLE_EX_MIXEDBUTTONS) || (btnPtr->fsStyle & BTNS_SHOWTEXT))
1039         TOOLBAR_DrawString (infoPtr, &rcText, lpText, &tbcd);
1040     SetBkMode (hdc, oldBkMode);
1041
1042     TOOLBAR_DrawImage(infoPtr, btnPtr, rcBitmap.left, rcBitmap.top, &tbcd);
1043
1044     if (hasDropDownArrow && !drawSepDropDownArrow)
1045     {
1046         if (tbcd.nmcd.uItemState & (CDIS_DISABLED | CDIS_INDETERMINATE))
1047         {
1048             TOOLBAR_DrawArrow(hdc, rcArrow.left+1, rcArrow.top+1 + (rcArrow.bottom - rcArrow.top - ARROW_HEIGHT) / 2, comctl32_color.clrBtnHighlight);
1049             TOOLBAR_DrawArrow(hdc, rcArrow.left, rcArrow.top + (rcArrow.bottom - rcArrow.top - ARROW_HEIGHT) / 2, comctl32_color.clr3dShadow);
1050         }
1051         else if (tbcd.nmcd.uItemState & (CDIS_SELECTED | CDIS_CHECKED))
1052         {
1053             offset = (infoPtr->dwItemCDFlag & TBCDRF_NOOFFSET) ? 0 : 1;
1054             TOOLBAR_DrawArrow(hdc, rcArrow.left + offset, rcArrow.top + offset + (rcArrow.bottom - rcArrow.top - ARROW_HEIGHT) / 2, comctl32_color.clrBtnText);
1055         }
1056         else
1057             TOOLBAR_DrawArrow(hdc, rcArrow.left, rcArrow.top + (rcArrow.bottom - rcArrow.top - ARROW_HEIGHT) / 2, comctl32_color.clrBtnText);
1058     }
1059
1060 FINALNOTIFY:
1061     if (infoPtr->dwItemCustDraw & CDRF_NOTIFYPOSTPAINT)
1062     {
1063         tbcd.nmcd.dwDrawStage = CDDS_ITEMPOSTPAINT;
1064         TOOLBAR_SendNotify(&tbcd.nmcd.hdr, infoPtr, NM_CUSTOMDRAW);
1065     }
1066
1067 }
1068
1069
1070 static void
1071 TOOLBAR_Refresh (HWND hwnd, HDC hdc, PAINTSTRUCT* ps)
1072 {
1073     TOOLBAR_INFO *infoPtr = TOOLBAR_GetInfoPtr (hwnd);
1074     TBUTTON_INFO *btnPtr;
1075     INT i;
1076     RECT rcTemp, rcClient;
1077     NMTBCUSTOMDRAW tbcd;
1078     DWORD ntfret;
1079
1080     /* the app has told us not to redraw the toolbar */
1081     if (!infoPtr->bDoRedraw)
1082         return;
1083
1084     /* if imagelist belongs to the app, it can be changed
1085        by the app after setting it */
1086     if (GETDEFIMAGELIST(infoPtr, 0) != infoPtr->himlInt)
1087     {
1088         infoPtr->nNumBitmaps = 0;
1089         for (i = 0; i < infoPtr->cimlDef; i++)
1090             infoPtr->nNumBitmaps += ImageList_GetImageCount(infoPtr->himlDef[i]->himl);
1091     }
1092
1093     TOOLBAR_DumpToolbar (infoPtr, __LINE__);
1094
1095     /* change the imagelist icon size if we manage the list and it is necessary */
1096     TOOLBAR_CheckImageListIconSize(infoPtr);
1097
1098     /* Send initial notify */
1099     ZeroMemory (&tbcd, sizeof(NMTBCUSTOMDRAW));
1100     tbcd.nmcd.dwDrawStage = CDDS_PREPAINT;
1101     tbcd.nmcd.hdc = hdc;
1102     tbcd.nmcd.rc = ps->rcPaint;
1103     ntfret = TOOLBAR_SendNotify(&tbcd.nmcd.hdr, infoPtr, NM_CUSTOMDRAW);
1104     infoPtr->dwBaseCustDraw = ntfret & 0xffff;
1105
1106     GetClientRect(hwnd, &rcClient);
1107
1108     /* redraw necessary buttons */
1109     btnPtr = infoPtr->buttons;
1110     for (i = 0; i < infoPtr->nNumButtons; i++, btnPtr++)
1111     {
1112         BOOL bDraw;
1113         if (infoPtr->dwExStyle & TBSTYLE_EX_HIDECLIPPEDBUTTONS)
1114         {
1115             IntersectRect(&rcTemp, &rcClient, &btnPtr->rect);
1116             bDraw = EqualRect(&rcTemp, &btnPtr->rect);
1117         }
1118         else
1119             bDraw = TRUE;
1120         bDraw &= IntersectRect(&rcTemp, &(ps->rcPaint), &(btnPtr->rect));
1121         bDraw = (btnPtr->fsState & TBSTATE_HIDDEN) ? FALSE : bDraw;
1122         if (bDraw)
1123             TOOLBAR_DrawButton (hwnd, btnPtr, hdc);
1124     }
1125
1126     /* draw insert mark if required */
1127     if (infoPtr->tbim.iButton != -1)
1128     {
1129         RECT rcButton = infoPtr->buttons[infoPtr->tbim.iButton].rect;
1130         RECT rcInsertMark;
1131         rcInsertMark.top = rcButton.top;
1132         rcInsertMark.bottom = rcButton.bottom;
1133         if (infoPtr->tbim.dwFlags & TBIMHT_AFTER)
1134             rcInsertMark.left = rcInsertMark.right = rcButton.right;
1135         else
1136             rcInsertMark.left = rcInsertMark.right = rcButton.left - INSERTMARK_WIDTH;
1137         COMCTL32_DrawInsertMark(hdc, &rcInsertMark, infoPtr->clrInsertMark, FALSE);
1138     }
1139
1140     if (infoPtr->dwBaseCustDraw & CDRF_NOTIFYPOSTPAINT)
1141     {
1142         ZeroMemory (&tbcd, sizeof(NMTBCUSTOMDRAW));
1143         tbcd.nmcd.dwDrawStage = CDDS_POSTPAINT;
1144         tbcd.nmcd.hdc = hdc;
1145         tbcd.nmcd.rc = ps->rcPaint;
1146         ntfret = TOOLBAR_SendNotify(&tbcd.nmcd.hdr, infoPtr, NM_CUSTOMDRAW);
1147     }
1148 }
1149
1150 /***********************************************************************
1151 *               TOOLBAR_MeasureString
1152 *
1153 * This function gets the width and height of a string in pixels. This
1154 * is done first by using GetTextExtentPoint to get the basic width
1155 * and height. The DrawText is called with DT_CALCRECT to get the exact
1156 * width. The reason is because the text may have more than one "&" (or
1157 * prefix characters as M$ likes to call them). The prefix character
1158 * indicates where the underline goes, except for the string "&&" which
1159 * is reduced to a single "&". GetTextExtentPoint does not process these
1160 * only DrawText does. Note that the BTNS_NOPREFIX is handled here.
1161 */
1162 static void
1163 TOOLBAR_MeasureString(TOOLBAR_INFO *infoPtr, TBUTTON_INFO *btnPtr,
1164                       HDC hdc, LPSIZE lpSize)
1165 {
1166     RECT myrect;
1167
1168     lpSize->cx = 0;
1169     lpSize->cy = 0;
1170
1171     if (infoPtr->nMaxTextRows > 0 &&
1172         !(btnPtr->fsState & TBSTATE_HIDDEN) &&
1173         (!(infoPtr->dwExStyle & TBSTYLE_EX_MIXEDBUTTONS) ||
1174         (btnPtr->fsStyle & BTNS_SHOWTEXT)) )
1175     {
1176         LPWSTR lpText = TOOLBAR_GetText(infoPtr, btnPtr);
1177
1178         if(lpText != NULL) {
1179             /* first get size of all the text */
1180             GetTextExtentPoint32W (hdc, lpText, strlenW (lpText), lpSize);
1181
1182             /* feed above size into the rectangle for DrawText */
1183             myrect.left = myrect.top = 0;
1184             myrect.right = lpSize->cx;
1185             myrect.bottom = lpSize->cy;
1186
1187             /* Use DrawText to get true size as drawn (less pesky "&") */
1188             DrawTextW (hdc, lpText, -1, &myrect, DT_VCENTER | DT_SINGLELINE |
1189                    DT_CALCRECT | ((btnPtr->fsStyle & BTNS_NOPREFIX) ?
1190                                   DT_NOPREFIX : 0));
1191
1192             /* feed back to caller  */
1193             lpSize->cx = myrect.right;
1194             lpSize->cy = myrect.bottom;
1195         }
1196     }
1197
1198     TRACE("string size %ld x %ld!\n", lpSize->cx, lpSize->cy);
1199 }
1200
1201 /***********************************************************************
1202 *               TOOLBAR_CalcStrings
1203 *
1204 * This function walks through each string and measures it and returns
1205 * the largest height and width to caller.
1206 */
1207 static void
1208 TOOLBAR_CalcStrings (HWND hwnd, LPSIZE lpSize)
1209 {
1210     TOOLBAR_INFO *infoPtr = TOOLBAR_GetInfoPtr (hwnd);
1211     TBUTTON_INFO *btnPtr;
1212     INT i;
1213     SIZE sz;
1214     HDC hdc;
1215     HFONT hOldFont;
1216
1217     lpSize->cx = 0;
1218     lpSize->cy = 0;
1219
1220     if (infoPtr->nMaxTextRows == 0)
1221         return;
1222
1223     hdc = GetDC (hwnd);
1224     hOldFont = SelectObject (hdc, infoPtr->hFont);
1225
1226     if (infoPtr->nNumButtons == 0)
1227     {
1228         TEXTMETRICW tm;
1229
1230         GetTextMetricsW(hdc, &tm);
1231         lpSize->cy = tm.tmHeight;
1232     }
1233
1234     btnPtr = infoPtr->buttons;
1235     for (i = 0; i < infoPtr->nNumButtons; i++, btnPtr++) {
1236         if(TOOLBAR_HasText(infoPtr, btnPtr))
1237         {
1238             TOOLBAR_MeasureString(infoPtr, btnPtr, hdc, &sz);
1239             if (sz.cx > lpSize->cx)
1240                 lpSize->cx = sz.cx;
1241             if (sz.cy > lpSize->cy)
1242                 lpSize->cy = sz.cy;
1243         }
1244     }
1245
1246     SelectObject (hdc, hOldFont);
1247     ReleaseDC (hwnd, hdc);
1248
1249     TRACE("max string size %ld x %ld!\n", lpSize->cx, lpSize->cy);
1250 }
1251
1252 /***********************************************************************
1253 *               TOOLBAR_WrapToolbar
1254 *
1255 * This function walks through the buttons and separators in the
1256 * toolbar, and sets the TBSTATE_WRAP flag only on those items where
1257 * wrapping should occur based on the width of the toolbar window.
1258 * It does *not* calculate button placement itself.  That task
1259 * takes place in TOOLBAR_CalcToolbar. If the program wants to manage
1260 * the toolbar wrapping on its own, it can use the TBSTYLE_WRAPABLE
1261 * flag, and set the TBSTATE_WRAP flags manually on the appropriate items.
1262 *
1263 * Note: TBSTYLE_WRAPABLE or TBSTYLE_EX_UNDOC1 can be used also to allow
1264 * vertical toolbar lists.
1265 */
1266
1267 static void
1268 TOOLBAR_WrapToolbar( HWND hwnd, DWORD dwStyle )
1269 {
1270     TOOLBAR_INFO *infoPtr = TOOLBAR_GetInfoPtr (hwnd);
1271     TBUTTON_INFO *btnPtr;
1272     INT x, cx, i, j;
1273     RECT rc;
1274     BOOL bWrap, bButtonWrap;
1275
1276     /*  When the toolbar window style is not TBSTYLE_WRAPABLE,  */
1277     /*  no layout is necessary. Applications may use this style */
1278     /*  to perform their own layout on the toolbar.             */
1279     if( !(dwStyle & TBSTYLE_WRAPABLE) &&
1280         !(infoPtr->dwExStyle & TBSTYLE_EX_UNDOC1) )  return;
1281
1282     btnPtr = infoPtr->buttons;
1283     x  = infoPtr->nIndent;
1284
1285     if (GetParent(hwnd))
1286     {
1287         /* this can get the parents width, to know how far we can extend
1288          * this toolbar.  We cannot use its height, as there may be multiple
1289          * toolbars in a rebar control
1290          */
1291         GetClientRect( GetParent(hwnd), &rc );
1292         infoPtr->nWidth = rc.right - rc.left;
1293     }
1294     else
1295     {
1296         GetWindowRect( hwnd, &rc );
1297         infoPtr->nWidth = rc.right - rc.left;
1298     }
1299
1300     bButtonWrap = FALSE;
1301
1302     TRACE("start ButtonWidth=%d, BitmapWidth=%d, nWidth=%d, nIndent=%d\n",
1303           infoPtr->nButtonWidth, infoPtr->nBitmapWidth, infoPtr->nWidth,
1304           infoPtr->nIndent);
1305
1306     for (i = 0; i < infoPtr->nNumButtons; i++ )
1307     {
1308         bWrap = FALSE;
1309         btnPtr[i].fsState &= ~TBSTATE_WRAP;
1310
1311         if (btnPtr[i].fsState & TBSTATE_HIDDEN)
1312             continue;
1313
1314         /* UNDOCUMENTED: If a separator has a non zero bitmap index, */
1315         /* it is the actual width of the separator. This is used for */
1316         /* custom controls in toolbars.                              */
1317         /*                                                           */
1318         /* BTNS_DROPDOWN separators are treated as buttons for    */
1319         /* width.  - GA 8/01                                         */
1320         if ((btnPtr[i].fsStyle & BTNS_SEP) &&
1321             !(btnPtr[i].fsStyle & BTNS_DROPDOWN))
1322             cx = (btnPtr[i].iBitmap > 0) ?
1323                         btnPtr[i].iBitmap : SEPARATOR_WIDTH;
1324         else
1325             cx = infoPtr->nButtonWidth;
1326
1327         /* Two or more adjacent separators form a separator group.   */
1328         /* The first separator in a group should be wrapped to the   */
1329         /* next row if the previous wrapping is on a button.         */
1330         if( bButtonWrap &&
1331                 (btnPtr[i].fsStyle & BTNS_SEP) &&
1332                 (i + 1 < infoPtr->nNumButtons ) &&
1333                 (btnPtr[i + 1].fsStyle & BTNS_SEP) )
1334         {
1335             TRACE("wrap point 1 btn %d style %02x\n", i, btnPtr[i].fsStyle);
1336             btnPtr[i].fsState |= TBSTATE_WRAP;
1337             x = infoPtr->nIndent;
1338             i++;
1339             bButtonWrap = FALSE;
1340             continue;
1341         }
1342
1343         /* The layout makes sure the bitmap is visible, but not the button. */
1344         /* Test added to also wrap after a button that starts a row but     */
1345         /* is bigger than the area.  - GA  8/01                             */
1346         if (( x + cx - (infoPtr->nButtonWidth - infoPtr->nBitmapWidth) / 2
1347            > infoPtr->nWidth ) ||
1348             ((x == infoPtr->nIndent) && (cx > infoPtr->nWidth)))
1349         {
1350             BOOL bFound = FALSE;
1351
1352             /*  If the current button is a separator and not hidden,  */
1353             /*  go to the next until it reaches a non separator.      */
1354             /*  Wrap the last separator if it is before a button.     */
1355             while( ( ((btnPtr[i].fsStyle & BTNS_SEP) &&
1356                       !(btnPtr[i].fsStyle & BTNS_DROPDOWN)) ||
1357                      (btnPtr[i].fsState & TBSTATE_HIDDEN) ) &&
1358                         i < infoPtr->nNumButtons )
1359             {
1360                 i++;
1361                 bFound = TRUE;
1362             }
1363
1364             if( bFound && i < infoPtr->nNumButtons )
1365             {
1366                 i--;
1367                 TRACE("wrap point 2 btn %d style %02x, x=%d, cx=%d\n",
1368                       i, btnPtr[i].fsStyle, x, cx);
1369                 btnPtr[i].fsState |= TBSTATE_WRAP;
1370                 x = infoPtr->nIndent;
1371                 bButtonWrap = FALSE;
1372                 continue;
1373             }
1374             else if ( i >= infoPtr->nNumButtons)
1375                 break;
1376
1377             /*  If the current button is not a separator, find the last  */
1378             /*  separator and wrap it.                                   */
1379             for ( j = i - 1; j >= 0  &&  !(btnPtr[j].fsState & TBSTATE_WRAP); j--)
1380             {
1381                 if ((btnPtr[j].fsStyle & BTNS_SEP) &&
1382                         !(btnPtr[j].fsState & TBSTATE_HIDDEN))
1383                 {
1384                     bFound = TRUE;
1385                     i = j;
1386                     TRACE("wrap point 3 btn %d style %02x, x=%d, cx=%d\n",
1387                           i, btnPtr[i].fsStyle, x, cx);
1388                     x = infoPtr->nIndent;
1389                     btnPtr[j].fsState |= TBSTATE_WRAP;
1390                     bButtonWrap = FALSE;
1391                     break;
1392                 }
1393             }
1394
1395             /*  If no separator available for wrapping, wrap one of     */
1396             /*  non-hidden previous button.                             */
1397             if (!bFound)
1398             {
1399                 for ( j = i - 1;
1400                         j >= 0 && !(btnPtr[j].fsState & TBSTATE_WRAP); j--)
1401                 {
1402                     if (btnPtr[j].fsState & TBSTATE_HIDDEN)
1403                         continue;
1404
1405                     bFound = TRUE;
1406                     i = j;
1407                     TRACE("wrap point 4 btn %d style %02x, x=%d, cx=%d\n",
1408                           i, btnPtr[i].fsStyle, x, cx);
1409                     x = infoPtr->nIndent;
1410                     btnPtr[j].fsState |= TBSTATE_WRAP;
1411                     bButtonWrap = TRUE;
1412                     break;
1413                 }
1414             }
1415
1416             /* If all above failed, wrap the current button. */
1417             if (!bFound)
1418             {
1419                 TRACE("wrap point 5 btn %d style %02x, x=%d, cx=%d\n",
1420                       i, btnPtr[i].fsStyle, x, cx);
1421                 btnPtr[i].fsState |= TBSTATE_WRAP;
1422                 bFound = TRUE;
1423                 x = infoPtr->nIndent;
1424                 if (btnPtr[i].fsStyle & BTNS_SEP )
1425                     bButtonWrap = FALSE;
1426                 else
1427                     bButtonWrap = TRUE;
1428             }
1429         }
1430         else {
1431             TRACE("wrap point 6 btn %d style %02x, x=%d, cx=%d\n",
1432                   i, btnPtr[i].fsStyle, x, cx);
1433             x += cx;
1434         }
1435     }
1436 }
1437
1438
1439 /***********************************************************************
1440 *               TOOLBAR_MeasureButton
1441 *
1442 * Calculates the width and height required for a button. Used in
1443 * TOOLBAR_CalcToolbar to set the all-button width and height and also for
1444 * the width of buttons that are autosized.
1445 *
1446 * Note that it would have been rather elegant to use one piece of code for
1447 * both the laying out of the toolbar and for controlling where button parts
1448 * are drawn, but the native control has inconsistencies between the two that
1449 * prevent this from being effectively. These inconsistencies can be seen as
1450 * artefacts where parts of the button appear outside of the bounding button
1451 * rectangle.
1452 *
1453 * There are several cases for the calculation of the button dimensions and
1454 * button part positioning:
1455 *
1456 * List
1457 * ====
1458 *
1459 * With Bitmap:
1460 *
1461 * +--------------------------------------------------------+ ^
1462 * |                    ^                     ^             | |
1463 * |                    | pad.cy / 2          | centred     | |
1464 * | pad.cx/2 + cxedge +--------------+     +------------+  | | DEFPAD_CY +
1465 * |<----------------->| nBitmapWidth |     | Text       |  | | max(nBitmapHeight, szText.cy)
1466 * |                   |<------------>|     |            |  | |
1467 * |                   +--------------+     +------------+  | |
1468 * |<-------------------------------------->|               | |
1469 * |  cxedge + iListGap + nBitmapWidth + 2  |<----------->  | |
1470 * |                                           szText.cx    | |
1471 * +--------------------------------------------------------+ -
1472 * <-------------------------------------------------------->
1473 *  2*cxedge + nBitmapWidth + iListGap + szText.cx + pad.cx
1474 *
1475 * Without Bitmap (I_IMAGENONE):
1476 *
1477 * +-----------------------------------+ ^
1478 * |                     ^             | |
1479 * |                     | centred     | | LISTPAD_CY +
1480 * |                   +------------+  | | szText.cy
1481 * |                   | Text       |  | |
1482 * |                   |            |  | |
1483 * |                   +------------+  | |
1484 * |<----------------->|               | |
1485 * |      cxedge       |<----------->  | |
1486 * |                      szText.cx    | |
1487 * +-----------------------------------+ -
1488 * <----------------------------------->
1489 *          szText.cx + pad.cx
1490 *
1491 * Without text:
1492 *
1493 * +--------------------------------------+ ^
1494 * |                       ^              | |
1495 * |                       | padding.cy/2 | | DEFPAD_CY +
1496 * |                     +------------+   | | nBitmapHeight
1497 * |                     | Bitmap     |   | |
1498 * |                     |            |   | |
1499 * |                     +------------+   | |
1500 * |<------------------->|                | |
1501 * | cxedge + iListGap/2 |<----------->   | |
1502 * |                       nBitmapWidth   | |
1503 * +--------------------------------------+ -
1504 * <-------------------------------------->
1505 *     2*cxedge + nBitmapWidth + iListGap
1506 *
1507 * Non-List
1508 * ========
1509 *
1510 * With bitmap:
1511 *
1512 * +-----------------------------------+ ^
1513 * |                     ^             | |
1514 * |                     | pad.cy / 2  | | nBitmapHeight +
1515 * |                     -             | | szText.cy +
1516 * |                   +------------+  | | DEFPAD_CY + 1
1517 * |    centred        |   Bitmap   |  | |
1518 * |<----------------->|            |  | |
1519 * |                   +------------+  | |
1520 * |                         ^         | |
1521 * |                       1 |         | |
1522 * |                         -         | |
1523 * |     centred     +---------------+ | |
1524 * |<--------------->|      Text     | | |
1525 * |                 +---------------+ | |
1526 * +-----------------------------------+ -
1527 * <----------------------------------->
1528 * pad.cx + max(nBitmapWidth, szText.cx)
1529 *
1530 * Without bitmaps (NULL imagelist or ImageList_GetImageCount() = 0):
1531 *
1532 * +---------------------------------------+ ^
1533 * |                     ^                 | |
1534 * |                     | 2 + pad.cy / 2  | |
1535 * |                     -                 | | szText.cy +
1536 * |    centred      +-----------------+   | | pad.cy + 2
1537 * |<--------------->|   Text          |   | |
1538 * |                 +-----------------+   | |
1539 * |                                       | |
1540 * +---------------------------------------+ -
1541 * <--------------------------------------->
1542 *          2*cxedge + pad.cx + szText.cx
1543 *
1544 * Without text:
1545 *   As for with bitmaps, but with szText.cx zero.
1546 */
1547 static inline SIZE TOOLBAR_MeasureButton(TOOLBAR_INFO *infoPtr, SIZE sizeString, BOOL bHasBitmap, BOOL bValidImageList)
1548 {
1549     SIZE sizeButton;
1550     if (infoPtr->dwStyle & TBSTYLE_LIST)
1551     {
1552         /* set button height from bitmap / text height... */
1553         sizeButton.cy = max((bHasBitmap ? infoPtr->nBitmapHeight : 0),
1554             sizeString.cy);
1555
1556         /* ... add on the necessary padding */
1557         if (bValidImageList)
1558         {
1559             if (bHasBitmap)
1560                 sizeButton.cy += DEFPAD_CY;
1561             else
1562                 sizeButton.cy += LISTPAD_CY;
1563         }
1564         else
1565             sizeButton.cy += infoPtr->szPadding.cy;
1566
1567         /* calculate button width */
1568         if (bHasBitmap)
1569         {
1570             sizeButton.cx = 2*GetSystemMetrics(SM_CXEDGE) +
1571                 infoPtr->nBitmapWidth + infoPtr->iListGap;
1572             if (sizeString.cx > 0)
1573                 sizeButton.cx += sizeString.cx + infoPtr->szPadding.cx;
1574         }
1575         else
1576             sizeButton.cx = sizeString.cx + infoPtr->szPadding.cx;
1577     }
1578     else
1579     {
1580         if (bHasBitmap)
1581         {
1582             sizeButton.cy = infoPtr->nBitmapHeight + 1 +
1583                 sizeString.cy + DEFPAD_CY;
1584             sizeButton.cx = infoPtr->szPadding.cx +
1585                 max(sizeString.cx, infoPtr->nBitmapWidth);
1586         }
1587         else
1588         {
1589             sizeButton.cy = sizeString.cy + infoPtr->szPadding.cy +
1590                 NONLIST_NOTEXT_OFFSET;
1591             sizeButton.cx = 2*GetSystemMetrics(SM_CXEDGE) +
1592                 infoPtr->szPadding.cx + sizeString.cx;
1593         }
1594     }
1595     return sizeButton;
1596 }
1597
1598
1599 /***********************************************************************
1600 *               TOOLBAR_CalcToolbar
1601 *
1602 * This function calculates button and separator placement. It first
1603 * calculates the button sizes, gets the toolbar window width and then
1604 * calls TOOLBAR_WrapToolbar to determine which buttons we need to wrap
1605 * on. It assigns a new location to each item and sends this location to
1606 * the tooltip window if appropriate. Finally, it updates the rcBound
1607 * rect and calculates the new required toolbar window height.
1608 */
1609 static void
1610 TOOLBAR_CalcToolbar (HWND hwnd)
1611 {
1612     TOOLBAR_INFO *infoPtr = TOOLBAR_GetInfoPtr(hwnd);
1613     DWORD dwStyle = infoPtr->dwStyle;
1614     TBUTTON_INFO *btnPtr;
1615     INT i, nRows, nSepRows;
1616     INT x, y, cx, cy;
1617     SIZE  sizeString, sizeButton;
1618     BOOL bWrap;
1619     BOOL validImageList = FALSE;
1620     BOOL hasDropDownArrows = TOOLBAR_HasDropDownArrows(infoPtr->dwExStyle);
1621
1622     TOOLBAR_CalcStrings (hwnd, &sizeString);
1623
1624     TOOLBAR_DumpToolbar (infoPtr, __LINE__);
1625
1626     if (TOOLBAR_IsValidImageList(infoPtr, 0))
1627         validImageList = TRUE;
1628     sizeButton = TOOLBAR_MeasureButton(infoPtr, sizeString, TRUE, validImageList);
1629     infoPtr->nButtonWidth = sizeButton.cx;
1630     infoPtr->nButtonHeight = sizeButton.cy;
1631
1632     if ( infoPtr->cxMin >= 0 && infoPtr->nButtonWidth < infoPtr->cxMin )
1633         infoPtr->nButtonWidth = infoPtr->cxMin;
1634     if ( infoPtr->cxMax > 0 && infoPtr->nButtonWidth > infoPtr->cxMax )
1635         infoPtr->nButtonWidth = infoPtr->cxMax;
1636
1637     TOOLBAR_WrapToolbar( hwnd, dwStyle );
1638
1639     x  = infoPtr->nIndent;
1640     if (infoPtr->dwStyle & TBSTYLE_FLAT)
1641         y = 0;
1642     else
1643         y = TOP_BORDER;
1644
1645     /* from above, minimum is a button, and possible text */
1646     cx = infoPtr->nButtonWidth;
1647     cy = infoPtr->nButtonHeight;
1648
1649     nRows = nSepRows = 0;
1650
1651     infoPtr->rcBound.top = y;
1652     infoPtr->rcBound.left = x;
1653     infoPtr->rcBound.bottom = y + cy;
1654     infoPtr->rcBound.right = x;
1655
1656     btnPtr = infoPtr->buttons;
1657
1658     TRACE("cy=%d\n", cy);
1659
1660     for (i = 0; i < infoPtr->nNumButtons; i++, btnPtr++ )
1661     {
1662         bWrap = FALSE;
1663         if (btnPtr->fsState & TBSTATE_HIDDEN)
1664         {
1665             SetRectEmpty (&btnPtr->rect);
1666             continue;
1667         }
1668
1669         cy = infoPtr->nButtonHeight;
1670
1671         /* UNDOCUMENTED: If a separator has a non zero bitmap index, */
1672         /* it is the actual width of the separator. This is used for */
1673         /* custom controls in toolbars.                              */
1674         if (btnPtr->fsStyle & BTNS_SEP) {
1675             if (btnPtr->fsStyle & BTNS_DROPDOWN) {
1676                 cy = (btnPtr->iBitmap > 0) ?
1677                      btnPtr->iBitmap : SEPARATOR_WIDTH;
1678                 cx = infoPtr->nButtonWidth;
1679             }
1680             else
1681                 cx = (btnPtr->iBitmap > 0) ?
1682                      btnPtr->iBitmap : SEPARATOR_WIDTH;
1683         }
1684         else
1685         {
1686             if (btnPtr->cx)
1687               cx = btnPtr->cx;
1688             else if ((infoPtr->dwExStyle & TBSTYLE_EX_MIXEDBUTTONS) || 
1689                 (btnPtr->fsStyle & BTNS_AUTOSIZE))
1690             {
1691               SIZE sz;
1692               HDC hdc;
1693               HFONT hOldFont;
1694
1695               hdc = GetDC (hwnd);
1696               hOldFont = SelectObject (hdc, infoPtr->hFont);
1697
1698               TOOLBAR_MeasureString(infoPtr, btnPtr, hdc, &sz);
1699
1700               SelectObject (hdc, hOldFont);
1701               ReleaseDC (hwnd, hdc);
1702
1703               sizeButton = TOOLBAR_MeasureButton(infoPtr, sz,
1704                   TOOLBAR_IsValidBitmapIndex(infoPtr, infoPtr->buttons[i].iBitmap),
1705                   validImageList);
1706               cx = sizeButton.cx;
1707             }
1708             else
1709               cx = infoPtr->nButtonWidth;
1710
1711             /* if size has been set manually then don't add on extra space
1712              * for the drop down arrow */
1713             if (!btnPtr->cx && hasDropDownArrows && 
1714                 ((btnPtr->fsStyle & BTNS_DROPDOWN) || (btnPtr->fsStyle & BTNS_WHOLEDROPDOWN)))
1715               cx += DDARROW_WIDTH;
1716         }
1717         if (btnPtr->fsState & TBSTATE_WRAP )
1718                     bWrap = TRUE;
1719
1720         SetRect (&btnPtr->rect, x, y, x + cx, y + cy);
1721
1722         if (infoPtr->rcBound.left > x)
1723             infoPtr->rcBound.left = x;
1724         if (infoPtr->rcBound.right < x + cx)
1725             infoPtr->rcBound.right = x + cx;
1726         if (infoPtr->rcBound.bottom < y + cy)
1727             infoPtr->rcBound.bottom = y + cy;
1728
1729         /* Set the toolTip only for non-hidden, non-separator button */
1730         if (infoPtr->hwndToolTip && !(btnPtr->fsStyle & BTNS_SEP ))
1731         {
1732             TTTOOLINFOW ti;
1733
1734             ZeroMemory (&ti, sizeof(ti));
1735             ti.cbSize = sizeof(ti);
1736             ti.hwnd = hwnd;
1737             ti.uId = btnPtr->idCommand;
1738             ti.rect = btnPtr->rect;
1739             SendMessageW (infoPtr->hwndToolTip, TTM_NEWTOOLRECTW,
1740                             0, (LPARAM)&ti);
1741         }
1742
1743         /* btnPtr->nRow is zero based. The space between the rows is    */
1744         /* also considered as a row.                                    */
1745         btnPtr->nRow = nRows + nSepRows;
1746
1747         TRACE("button %d style=%x, bWrap=%d, nRows=%d, nSepRows=%d, btnrow=%d, (%d,%d)-(%d,%d)\n",
1748               i, btnPtr->fsStyle, bWrap, nRows, nSepRows, btnPtr->nRow,
1749               x, y, x+cx, y+cy);
1750
1751         if( bWrap )
1752         {
1753             if ( !(btnPtr->fsStyle & BTNS_SEP) )
1754                 y += cy;
1755             else
1756             {
1757                 /* UNDOCUMENTED: If a separator has a non zero bitmap index, */
1758                 /* it is the actual width of the separator. This is used for */
1759                 /* custom controls in toolbars.                              */
1760                 if ( !(btnPtr->fsStyle & BTNS_DROPDOWN))
1761                     y += cy + ( (btnPtr->iBitmap > 0 ) ?
1762                                 btnPtr->iBitmap : SEPARATOR_WIDTH) * 2 /3;
1763                 else
1764                     y += cy;
1765
1766                 /* nSepRows is used to calculate the extra height follwoing  */
1767                 /* the last row.                                             */
1768                 nSepRows++;
1769             }
1770             x = infoPtr->nIndent;
1771
1772             /* Increment row number unless this is the last button    */
1773             /* and it has Wrap set.                                   */
1774             if (i != infoPtr->nNumButtons-1)
1775                 nRows++;
1776         }
1777         else
1778             x += cx;
1779     }
1780
1781     /* infoPtr->nRows is the number of rows on the toolbar */
1782     infoPtr->nRows = nRows + nSepRows + 1;
1783
1784     TRACE("toolbar button width %d\n", infoPtr->nButtonWidth);
1785 }
1786
1787
1788 static INT
1789 TOOLBAR_InternalHitTest (HWND hwnd, LPPOINT lpPt)
1790 {
1791     TOOLBAR_INFO *infoPtr = TOOLBAR_GetInfoPtr (hwnd);
1792     TBUTTON_INFO *btnPtr;
1793     INT i;
1794
1795     btnPtr = infoPtr->buttons;
1796     for (i = 0; i < infoPtr->nNumButtons; i++, btnPtr++) {
1797         if (btnPtr->fsState & TBSTATE_HIDDEN)
1798             continue;
1799
1800         if (btnPtr->fsStyle & BTNS_SEP) {
1801             if (PtInRect (&btnPtr->rect, *lpPt)) {
1802                 TRACE(" ON SEPARATOR %d!\n", i);
1803                 return -i;
1804             }
1805         }
1806         else {
1807             if (PtInRect (&btnPtr->rect, *lpPt)) {
1808                 TRACE(" ON BUTTON %d!\n", i);
1809                 return i;
1810             }
1811         }
1812     }
1813
1814     TRACE(" NOWHERE!\n");
1815     return TOOLBAR_NOWHERE;
1816 }
1817
1818
1819 static INT
1820 TOOLBAR_GetButtonIndex (TOOLBAR_INFO *infoPtr, INT idCommand, BOOL CommandIsIndex)
1821 {
1822     TBUTTON_INFO *btnPtr;
1823     INT i;
1824
1825     if (CommandIsIndex) {
1826         TRACE("command is really index command=%d\n", idCommand);
1827         if (idCommand >= infoPtr->nNumButtons) return -1;
1828         return idCommand;
1829     }
1830     btnPtr = infoPtr->buttons;
1831     for (i = 0; i < infoPtr->nNumButtons; i++, btnPtr++) {
1832         if (btnPtr->idCommand == idCommand) {
1833             TRACE("command=%d index=%d\n", idCommand, i);
1834             return i;
1835         }
1836     }
1837     TRACE("no index found for command=%d\n", idCommand);
1838     return -1;
1839 }
1840
1841
1842 static INT
1843 TOOLBAR_GetCheckedGroupButtonIndex (TOOLBAR_INFO *infoPtr, INT nIndex)
1844 {
1845     TBUTTON_INFO *btnPtr;
1846     INT nRunIndex;
1847
1848     if ((nIndex < 0) || (nIndex > infoPtr->nNumButtons))
1849         return -1;
1850
1851     /* check index button */
1852     btnPtr = &infoPtr->buttons[nIndex];
1853     if ((btnPtr->fsStyle & BTNS_CHECKGROUP) == BTNS_CHECKGROUP) {
1854         if (btnPtr->fsState & TBSTATE_CHECKED)
1855             return nIndex;
1856     }
1857
1858     /* check previous buttons */
1859     nRunIndex = nIndex - 1;
1860     while (nRunIndex >= 0) {
1861         btnPtr = &infoPtr->buttons[nRunIndex];
1862         if ((btnPtr->fsStyle & BTNS_GROUP) == BTNS_GROUP) {
1863             if (btnPtr->fsState & TBSTATE_CHECKED)
1864                 return nRunIndex;
1865         }
1866         else
1867             break;
1868         nRunIndex--;
1869     }
1870
1871     /* check next buttons */
1872     nRunIndex = nIndex + 1;
1873     while (nRunIndex < infoPtr->nNumButtons) {
1874         btnPtr = &infoPtr->buttons[nRunIndex];
1875         if ((btnPtr->fsStyle & BTNS_GROUP) == BTNS_GROUP) {
1876             if (btnPtr->fsState & TBSTATE_CHECKED)
1877                 return nRunIndex;
1878         }
1879         else
1880             break;
1881         nRunIndex++;
1882     }
1883
1884     return -1;
1885 }
1886
1887
1888 static VOID
1889 TOOLBAR_RelayEvent (HWND hwndTip, HWND hwndMsg, UINT uMsg,
1890                     WPARAM wParam, LPARAM lParam)
1891 {
1892     MSG msg;
1893
1894     msg.hwnd = hwndMsg;
1895     msg.message = uMsg;
1896     msg.wParam = wParam;
1897     msg.lParam = lParam;
1898     msg.time = GetMessageTime ();
1899     msg.pt.x = LOWORD(GetMessagePos ());
1900     msg.pt.y = HIWORD(GetMessagePos ());
1901
1902     SendMessageW (hwndTip, TTM_RELAYEVENT, 0, (LPARAM)&msg);
1903 }
1904
1905 /* keeps available button list box sorted by button id */
1906 static void TOOLBAR_Cust_InsertAvailButton(HWND hwnd, PCUSTOMBUTTON btnInfoNew)
1907 {
1908     int i;
1909     int count;
1910     PCUSTOMBUTTON btnInfo;
1911     HWND hwndAvail = GetDlgItem(hwnd, IDC_AVAILBTN_LBOX);
1912
1913     TRACE("button %s, idCommand %d\n", debugstr_w(btnInfoNew->text), btnInfoNew->btn.idCommand);
1914
1915     count = SendMessageW(hwndAvail, LB_GETCOUNT, 0, 0);
1916
1917     /* position 0 is always separator */
1918     for (i = 1; i < count; i++)
1919     {
1920         btnInfo = (PCUSTOMBUTTON)SendMessageW(hwndAvail, LB_GETITEMDATA, i, 0);
1921         if (btnInfoNew->btn.idCommand < btnInfo->btn.idCommand)
1922         {
1923             i = SendMessageW(hwndAvail, LB_INSERTSTRING, i, 0);
1924             SendMessageW(hwndAvail, LB_SETITEMDATA, i, (LPARAM)btnInfoNew);
1925             return;
1926         }
1927     }
1928     /* id higher than all others add to end */
1929     i = SendMessageW(hwndAvail, LB_ADDSTRING, 0, 0);
1930     SendMessageW(hwndAvail, LB_SETITEMDATA, i, (LPARAM)btnInfoNew);
1931 }
1932
1933 static void TOOLBAR_Cust_MoveButton(PCUSTDLG_INFO custInfo, HWND hwnd, INT nIndexFrom, INT nIndexTo)
1934 {
1935     NMTOOLBARW nmtb;
1936
1937         TRACE("index from %d, index to %d\n", nIndexFrom, nIndexTo);
1938
1939     if (nIndexFrom == nIndexTo)
1940         return;
1941
1942     /* MSDN states that iItem is the index of the button, rather than the
1943      * command ID as used by every other NMTOOLBAR notification */
1944     nmtb.iItem = nIndexFrom;
1945     if (TOOLBAR_SendNotify(&nmtb.hdr, custInfo->tbInfo, TBN_QUERYINSERT))
1946     {
1947         PCUSTOMBUTTON btnInfo;
1948         NMHDR hdr;
1949         HWND hwndList = GetDlgItem(hwnd, IDC_TOOLBARBTN_LBOX);
1950         int count = SendMessageW(hwndList, LB_GETCOUNT, 0, 0);
1951
1952         btnInfo = (PCUSTOMBUTTON)SendMessageW(hwndList, LB_GETITEMDATA, nIndexFrom, 0);
1953
1954         SendMessageW(hwndList, LB_DELETESTRING, nIndexFrom, 0);
1955         SendMessageW(hwndList, LB_INSERTSTRING, nIndexTo, 0);
1956         SendMessageW(hwndList, LB_SETITEMDATA, nIndexTo, (LPARAM)btnInfo);
1957         SendMessageW(hwndList, LB_SETCURSEL, nIndexTo, 0);
1958
1959         if (nIndexTo <= 0)
1960             EnableWindow(GetDlgItem(hwnd,IDC_MOVEUP_BTN), FALSE);
1961         else
1962             EnableWindow(GetDlgItem(hwnd,IDC_MOVEUP_BTN), TRUE);
1963
1964         /* last item is always separator, so -2 instead of -1 */
1965         if (nIndexTo >= (count - 2))
1966             EnableWindow(GetDlgItem(hwnd,IDC_MOVEDN_BTN), FALSE);
1967         else
1968             EnableWindow(GetDlgItem(hwnd,IDC_MOVEDN_BTN), TRUE);
1969
1970         SendMessageW(custInfo->tbHwnd, TB_DELETEBUTTON, nIndexFrom, 0);
1971         SendMessageW(custInfo->tbHwnd, TB_INSERTBUTTONW, nIndexTo, (LPARAM)&(btnInfo->btn));
1972
1973         TOOLBAR_SendNotify(&hdr, custInfo->tbInfo, TBN_TOOLBARCHANGE);
1974     }
1975 }
1976
1977 static void TOOLBAR_Cust_AddButton(PCUSTDLG_INFO custInfo, HWND hwnd, INT nIndexAvail, INT nIndexTo)
1978 {
1979     NMTOOLBARW nmtb;
1980
1981     TRACE("Add: nIndexAvail %d, nIndexTo %d\n", nIndexAvail, nIndexTo);
1982
1983     /* MSDN states that iItem is the index of the button, rather than the
1984      * command ID as used by every other NMTOOLBAR notification */
1985     nmtb.iItem = nIndexAvail;
1986     if (TOOLBAR_SendNotify(&nmtb.hdr, custInfo->tbInfo, TBN_QUERYINSERT))
1987     {
1988         PCUSTOMBUTTON btnInfo;
1989         NMHDR hdr;
1990         HWND hwndList = GetDlgItem(hwnd, IDC_TOOLBARBTN_LBOX);
1991         HWND hwndAvail = GetDlgItem(hwnd, IDC_AVAILBTN_LBOX);
1992         int count = SendMessageW(hwndAvail, LB_GETCOUNT, 0, 0);
1993
1994         btnInfo = (PCUSTOMBUTTON)SendMessageW(hwndAvail, LB_GETITEMDATA, nIndexAvail, 0);
1995
1996         if (nIndexAvail != 0) /* index == 0 indicates separator */
1997         {
1998             /* remove from 'available buttons' list */
1999             SendMessageW(hwndAvail, LB_DELETESTRING, nIndexAvail, 0);
2000             if (nIndexAvail == count-1)
2001                 SendMessageW(hwndAvail, LB_SETCURSEL, nIndexAvail-1 , 0);
2002             else
2003                 SendMessageW(hwndAvail, LB_SETCURSEL, nIndexAvail , 0);
2004         }
2005         else
2006         {
2007             PCUSTOMBUTTON btnNew;
2008
2009             /* duplicate 'separator' button */
2010             btnNew = (PCUSTOMBUTTON)Alloc(sizeof(CUSTOMBUTTON));
2011             memcpy(btnNew, btnInfo, sizeof(CUSTOMBUTTON));
2012             btnInfo = btnNew;
2013         }
2014
2015         /* insert into 'toolbar button' list */
2016         SendMessageW(hwndList, LB_INSERTSTRING, nIndexTo, 0);
2017         SendMessageW(hwndList, LB_SETITEMDATA, nIndexTo, (LPARAM)btnInfo);
2018
2019         SendMessageW(custInfo->tbHwnd, TB_INSERTBUTTONW, nIndexTo, (LPARAM)&(btnInfo->btn));
2020
2021         TOOLBAR_SendNotify(&hdr, custInfo->tbInfo, TBN_TOOLBARCHANGE);
2022     }
2023 }
2024
2025 static void TOOLBAR_Cust_RemoveButton(PCUSTDLG_INFO custInfo, HWND hwnd, INT index)
2026 {
2027     PCUSTOMBUTTON btnInfo;
2028     HWND hwndList = GetDlgItem(hwnd, IDC_TOOLBARBTN_LBOX);
2029
2030     TRACE("Remove: index %d\n", index);
2031
2032     btnInfo = (PCUSTOMBUTTON)SendMessageW(hwndList, LB_GETITEMDATA, index, 0);
2033
2034     /* send TBN_QUERYDELETE notification */
2035     if (TOOLBAR_IsButtonRemovable(custInfo->tbInfo, index, btnInfo))
2036     {
2037         NMHDR hdr;
2038
2039         SendMessageW(hwndList, LB_DELETESTRING, index, 0);
2040         SendMessageW(hwndList, LB_SETCURSEL, index , 0);
2041
2042         SendMessageW(custInfo->tbHwnd, TB_DELETEBUTTON, index, 0);
2043
2044         /* insert into 'available button' list */
2045         if (!(btnInfo->btn.fsStyle & BTNS_SEP))
2046             TOOLBAR_Cust_InsertAvailButton(hwnd, btnInfo);
2047         else
2048             Free(btnInfo);
2049
2050         TOOLBAR_SendNotify(&hdr, custInfo->tbInfo, TBN_TOOLBARCHANGE);
2051     }
2052 }
2053
2054 /* drag list notification function for toolbar buttons list box */
2055 static LRESULT TOOLBAR_Cust_ToolbarDragListNotification(PCUSTDLG_INFO custInfo, HWND hwnd, DRAGLISTINFO *pDLI)
2056 {
2057     HWND hwndList = GetDlgItem(hwnd, IDC_TOOLBARBTN_LBOX);
2058     switch (pDLI->uNotification)
2059     {
2060     case DL_BEGINDRAG:
2061     {
2062         INT nCurrentItem = LBItemFromPt(hwndList, pDLI->ptCursor, TRUE);
2063         INT nCount = SendMessageW(hwndList, LB_GETCOUNT, 0, 0);
2064         /* no dragging for last item (separator) */
2065         if (nCurrentItem >= (nCount - 1)) return FALSE;
2066         return TRUE;
2067     }
2068     case DL_DRAGGING:
2069     {
2070         INT nCurrentItem = LBItemFromPt(hwndList, pDLI->ptCursor, TRUE);
2071         INT nCount = SendMessageW(hwndList, LB_GETCOUNT, 0, 0);
2072         /* no dragging past last item (separator) */
2073         if ((nCurrentItem >= 0) && (nCurrentItem < (nCount - 1)))
2074         {
2075             DrawInsert(hwnd, hwndList, nCurrentItem);
2076             /* FIXME: native uses "move button" cursor */
2077             return DL_COPYCURSOR;
2078         }
2079
2080         /* not over toolbar buttons list */
2081         if (nCurrentItem < 0)
2082         {
2083             POINT ptWindow = pDLI->ptCursor;
2084             HWND hwndListAvail = GetDlgItem(hwnd, IDC_AVAILBTN_LBOX);
2085             MapWindowPoints(NULL, hwnd, &ptWindow, 1);
2086             /* over available buttons list? */
2087             if (ChildWindowFromPoint(hwnd, ptWindow) == hwndListAvail)
2088                 /* FIXME: native uses "move button" cursor */
2089                 return DL_COPYCURSOR;
2090         }
2091         /* clear drag arrow */
2092         DrawInsert(hwnd, hwndList, -1);
2093         return DL_STOPCURSOR;
2094     }
2095     case DL_DROPPED:
2096     {
2097         INT nIndexTo = LBItemFromPt(hwndList, pDLI->ptCursor, TRUE);
2098         INT nIndexFrom = SendMessageW(hwndList, LB_GETCURSEL, 0, 0);
2099         INT nCount = SendMessageW(hwndList, LB_GETCOUNT, 0, 0);
2100         if ((nIndexTo >= 0) && (nIndexTo < (nCount - 1)))
2101         {
2102             /* clear drag arrow */
2103             DrawInsert(hwnd, hwndList, -1);
2104             /* move item */
2105             TOOLBAR_Cust_MoveButton(custInfo, hwnd, nIndexFrom, nIndexTo);
2106         }
2107         /* not over toolbar buttons list */
2108         if (nIndexTo < 0)
2109         {
2110             POINT ptWindow = pDLI->ptCursor;
2111             HWND hwndListAvail = GetDlgItem(hwnd, IDC_AVAILBTN_LBOX);
2112             MapWindowPoints(NULL, hwnd, &ptWindow, 1);
2113             /* over available buttons list? */
2114             if (ChildWindowFromPoint(hwnd, ptWindow) == hwndListAvail)
2115                 TOOLBAR_Cust_RemoveButton(custInfo, hwnd, nIndexFrom);
2116         }
2117         break;
2118     }
2119     case DL_CANCELDRAG:
2120         /* Clear drag arrow */
2121         DrawInsert(hwnd, hwndList, -1);
2122         break;
2123     }
2124
2125     return 0;
2126 }
2127
2128 /* drag list notification function for available buttons list box */
2129 static LRESULT TOOLBAR_Cust_AvailDragListNotification(PCUSTDLG_INFO custInfo, HWND hwnd, DRAGLISTINFO *pDLI)
2130 {
2131     HWND hwndList = GetDlgItem(hwnd, IDC_TOOLBARBTN_LBOX);
2132     switch (pDLI->uNotification)
2133     {
2134     case DL_BEGINDRAG:
2135         return TRUE;
2136     case DL_DRAGGING:
2137     {
2138         INT nCurrentItem = LBItemFromPt(hwndList, pDLI->ptCursor, TRUE);
2139         INT nCount = SendMessageW(hwndList, LB_GETCOUNT, 0, 0);
2140         /* no dragging past last item (separator) */
2141         if ((nCurrentItem >= 0) && (nCurrentItem < nCount))
2142         {
2143             DrawInsert(hwnd, hwndList, nCurrentItem);
2144             /* FIXME: native uses "move button" cursor */
2145             return DL_COPYCURSOR;
2146         }
2147
2148         /* not over toolbar buttons list */
2149         if (nCurrentItem < 0)
2150         {
2151             POINT ptWindow = pDLI->ptCursor;
2152             HWND hwndListAvail = GetDlgItem(hwnd, IDC_AVAILBTN_LBOX);
2153             MapWindowPoints(NULL, hwnd, &ptWindow, 1);
2154             /* over available buttons list? */
2155             if (ChildWindowFromPoint(hwnd, ptWindow) == hwndListAvail)
2156                 /* FIXME: native uses "move button" cursor */
2157                 return DL_COPYCURSOR;
2158         }
2159         /* clear drag arrow */
2160         DrawInsert(hwnd, hwndList, -1);
2161         return DL_STOPCURSOR;
2162     }
2163     case DL_DROPPED:
2164     {
2165         INT nIndexTo = LBItemFromPt(hwndList, pDLI->ptCursor, TRUE);
2166         INT nCount = SendMessageW(hwndList, LB_GETCOUNT, 0, 0);
2167         INT nIndexFrom = SendDlgItemMessageW(hwnd, IDC_AVAILBTN_LBOX, LB_GETCURSEL, 0, 0);
2168         if ((nIndexTo >= 0) && (nIndexTo < nCount))
2169         {
2170             /* clear drag arrow */
2171             DrawInsert(hwnd, hwndList, -1);
2172             /* add item */
2173             TOOLBAR_Cust_AddButton(custInfo, hwnd, nIndexFrom, nIndexTo);
2174         }
2175     }
2176     case DL_CANCELDRAG:
2177         /* Clear drag arrow */
2178         DrawInsert(hwnd, hwndList, -1);
2179         break;
2180     }
2181     return 0;
2182 }
2183
2184 extern UINT uDragListMessage;
2185
2186 /***********************************************************************
2187  * TOOLBAR_CustomizeDialogProc
2188  * This function implements the toolbar customization dialog.
2189  */
2190 static INT_PTR CALLBACK
2191 TOOLBAR_CustomizeDialogProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
2192 {
2193     PCUSTDLG_INFO custInfo = (PCUSTDLG_INFO)GetWindowLongPtrW (hwnd, DWLP_USER);
2194     PCUSTOMBUTTON btnInfo;
2195     NMTOOLBARA nmtb;
2196     TOOLBAR_INFO *infoPtr = custInfo ? custInfo->tbInfo : NULL;
2197
2198     switch (uMsg)
2199     {
2200         case WM_INITDIALOG:
2201             custInfo = (PCUSTDLG_INFO)lParam;
2202             SetWindowLongPtrW (hwnd, DWLP_USER, (LONG_PTR)custInfo);
2203
2204             if (custInfo)
2205             {
2206                 WCHAR Buffer[256];
2207                 int i = 0;
2208                 int index;
2209                 NMTBINITCUSTOMIZE nmtbic;
2210
2211                 infoPtr = custInfo->tbInfo;
2212
2213                 /* send TBN_QUERYINSERT notification */
2214                 nmtb.iItem = custInfo->tbInfo->nNumButtons;
2215
2216                 if (!TOOLBAR_SendNotify(&nmtb.hdr, infoPtr, TBN_QUERYINSERT))
2217                     return FALSE;
2218
2219                 nmtbic.hwndDialog = hwnd;
2220                 /* Send TBN_INITCUSTOMIZE notification */
2221                 if (TOOLBAR_SendNotify (&nmtbic.hdr, infoPtr, TBN_INITCUSTOMIZE) ==
2222                     TBNRF_HIDEHELP)
2223                 {
2224                     TRACE("TBNRF_HIDEHELP requested\n");
2225                     ShowWindow(GetDlgItem(hwnd, IDC_HELP_BTN), SW_HIDE);
2226                 }
2227
2228                 /* add items to 'toolbar buttons' list and check if removable */
2229                 for (i = 0; i < custInfo->tbInfo->nNumButtons; i++)
2230                 {
2231                     btnInfo = (PCUSTOMBUTTON)Alloc(sizeof(CUSTOMBUTTON));
2232                     memset (&btnInfo->btn, 0, sizeof(TBBUTTON));
2233                     btnInfo->btn.fsStyle = BTNS_SEP;
2234                     btnInfo->bVirtual = FALSE;
2235                     LoadStringW (COMCTL32_hModule, IDS_SEPARATOR, btnInfo->text, 64);
2236
2237                     /* send TBN_QUERYDELETE notification */
2238                     btnInfo->bRemovable = TOOLBAR_IsButtonRemovable(infoPtr, i, btnInfo);
2239
2240                     index = (int)SendDlgItemMessageW (hwnd, IDC_TOOLBARBTN_LBOX, LB_ADDSTRING, 0, 0);
2241                     SendDlgItemMessageW (hwnd, IDC_TOOLBARBTN_LBOX, LB_SETITEMDATA, index, (LPARAM)btnInfo);
2242                 }
2243
2244                 SendDlgItemMessageW (hwnd, IDC_TOOLBARBTN_LBOX, LB_SETITEMHEIGHT, 0, infoPtr->nBitmapHeight + 8);
2245
2246                 /* insert separator button into 'available buttons' list */
2247                 btnInfo = (PCUSTOMBUTTON)Alloc(sizeof(CUSTOMBUTTON));
2248                 memset (&btnInfo->btn, 0, sizeof(TBBUTTON));
2249                 btnInfo->btn.fsStyle = BTNS_SEP;
2250                 btnInfo->bVirtual = FALSE;
2251                 btnInfo->bRemovable = TRUE;
2252                 LoadStringW (COMCTL32_hModule, IDS_SEPARATOR, btnInfo->text, 64);
2253                 index = (int)SendDlgItemMessageW (hwnd, IDC_AVAILBTN_LBOX, LB_ADDSTRING, 0, (LPARAM)btnInfo);
2254                 SendDlgItemMessageW (hwnd, IDC_AVAILBTN_LBOX, LB_SETITEMDATA, index, (LPARAM)btnInfo);
2255
2256                 /* insert all buttons into dsa */
2257                 for (i = 0;; i++)
2258                 {
2259                     /* send TBN_GETBUTTONINFO notification */
2260                     NMTOOLBARW nmtb;
2261                     nmtb.iItem = i;
2262                     nmtb.pszText = Buffer;
2263                     nmtb.cchText = 256;
2264
2265                     /* Clear previous button's text */
2266                     ZeroMemory(nmtb.pszText, nmtb.cchText * sizeof(WCHAR));
2267
2268                     if (!TOOLBAR_GetButtonInfo(infoPtr, &nmtb))
2269                         break;
2270
2271                     TRACE("WM_INITDIALOG style: %x iItem(%d) idCommand(%d) iString(%d) %s\n", 
2272                         nmtb.tbButton.fsStyle, i, 
2273                         nmtb.tbButton.idCommand,
2274                         nmtb.tbButton.iString,
2275                         nmtb.tbButton.iString >= 0 ? debugstr_w(infoPtr->strings[nmtb.tbButton.iString])
2276                         : "");
2277
2278                     /* insert button into the apropriate list */
2279                     index = TOOLBAR_GetButtonIndex (custInfo->tbInfo, nmtb.tbButton.idCommand, FALSE);
2280                     if (index == -1)
2281                     {
2282                         btnInfo = (PCUSTOMBUTTON)Alloc(sizeof(CUSTOMBUTTON));
2283                         btnInfo->bVirtual = FALSE;
2284                         btnInfo->bRemovable = TRUE;
2285                     }
2286                     else
2287                     {
2288                         btnInfo = (PCUSTOMBUTTON)SendDlgItemMessageW (hwnd, 
2289                             IDC_TOOLBARBTN_LBOX, LB_GETITEMDATA, index, 0);
2290                     }
2291
2292                     memcpy (&btnInfo->btn, &nmtb.tbButton, sizeof(TBBUTTON));
2293                     if (!(nmtb.tbButton.fsStyle & BTNS_SEP))
2294                     {
2295                         if (lstrlenW(nmtb.pszText))
2296                             lstrcpyW(btnInfo->text, nmtb.pszText);
2297                         else if (nmtb.tbButton.iString >= 0 && 
2298                             nmtb.tbButton.iString < infoPtr->nNumStrings)
2299                         {
2300                             lstrcpyW(btnInfo->text, 
2301                                 infoPtr->strings[nmtb.tbButton.iString]);
2302                         }
2303                     }
2304
2305                     if (index == -1)
2306                         TOOLBAR_Cust_InsertAvailButton(hwnd, btnInfo);
2307                 }
2308
2309                 SendDlgItemMessageW (hwnd, IDC_AVAILBTN_LBOX, LB_SETITEMHEIGHT, 0, infoPtr->nBitmapHeight + 8);
2310
2311                 /* select first item in the 'available' list */
2312                 SendDlgItemMessageW (hwnd, IDC_AVAILBTN_LBOX, LB_SETCURSEL, 0, 0);
2313
2314                 /* append 'virtual' separator button to the 'toolbar buttons' list */
2315                 btnInfo = (PCUSTOMBUTTON)Alloc(sizeof(CUSTOMBUTTON));
2316                 memset (&btnInfo->btn, 0, sizeof(TBBUTTON));
2317                 btnInfo->btn.fsStyle = BTNS_SEP;
2318                 btnInfo->bVirtual = TRUE;
2319                 btnInfo->bRemovable = FALSE;
2320                 LoadStringW (COMCTL32_hModule, IDS_SEPARATOR, btnInfo->text, 64);
2321                 index = (int)SendDlgItemMessageW (hwnd, IDC_TOOLBARBTN_LBOX, LB_ADDSTRING, 0, (LPARAM)btnInfo);
2322                 SendDlgItemMessageW (hwnd, IDC_TOOLBARBTN_LBOX, LB_SETITEMDATA, index, (LPARAM)btnInfo);
2323
2324                 /* select last item in the 'toolbar' list */
2325                 SendDlgItemMessageW (hwnd, IDC_TOOLBARBTN_LBOX, LB_SETCURSEL, index, 0);
2326                 SendDlgItemMessageW (hwnd, IDC_TOOLBARBTN_LBOX, LB_SETTOPINDEX, index, 0);
2327
2328         MakeDragList(GetDlgItem(hwnd, IDC_TOOLBARBTN_LBOX));
2329         MakeDragList(GetDlgItem(hwnd, IDC_AVAILBTN_LBOX));
2330
2331                 /* set focus and disable buttons */
2332                 PostMessageW (hwnd, WM_USER, 0, 0);
2333             }
2334             return TRUE;
2335
2336         case WM_USER:
2337             EnableWindow (GetDlgItem (hwnd,IDC_MOVEUP_BTN), FALSE);
2338             EnableWindow (GetDlgItem (hwnd,IDC_MOVEDN_BTN), FALSE);
2339             EnableWindow (GetDlgItem (hwnd,IDC_REMOVE_BTN), FALSE);
2340             SetFocus (GetDlgItem (hwnd, IDC_TOOLBARBTN_LBOX));
2341             return TRUE;
2342
2343         case WM_CLOSE:
2344             EndDialog(hwnd, FALSE);
2345             return TRUE;
2346
2347         case WM_COMMAND:
2348             switch (LOWORD(wParam))
2349             {
2350                 case IDC_TOOLBARBTN_LBOX:
2351                     if (HIWORD(wParam) == LBN_SELCHANGE)
2352                     {
2353                         PCUSTOMBUTTON btnInfo;
2354                         NMTOOLBARA nmtb;
2355                         int count;
2356                         int index;
2357
2358                         count = SendDlgItemMessageW (hwnd, IDC_TOOLBARBTN_LBOX, LB_GETCOUNT, 0, 0);
2359                         index = SendDlgItemMessageW (hwnd, IDC_TOOLBARBTN_LBOX, LB_GETCURSEL, 0, 0);
2360
2361                         /* send TBN_QUERYINSERT notification */
2362                         nmtb.iItem = index;
2363                         TOOLBAR_SendNotify(&nmtb.hdr, infoPtr, TBN_QUERYINSERT);
2364
2365                         /* get list box item */
2366                         btnInfo = (PCUSTOMBUTTON)SendDlgItemMessageW (hwnd, IDC_TOOLBARBTN_LBOX, LB_GETITEMDATA, index, 0);
2367
2368                         if (index == (count - 1))
2369                         {
2370                             /* last item (virtual separator) */
2371                             EnableWindow (GetDlgItem (hwnd,IDC_MOVEUP_BTN), FALSE);
2372                             EnableWindow (GetDlgItem (hwnd,IDC_MOVEDN_BTN), FALSE);
2373                         }
2374                         else if (index == (count - 2))
2375                         {
2376                             /* second last item (last non-virtual item) */
2377                             EnableWindow (GetDlgItem (hwnd,IDC_MOVEUP_BTN), TRUE);
2378                             EnableWindow (GetDlgItem (hwnd,IDC_MOVEDN_BTN), FALSE);
2379                         }
2380                         else if (index == 0)
2381                         {
2382                             /* first item */
2383                             EnableWindow (GetDlgItem (hwnd,IDC_MOVEUP_BTN), FALSE);
2384                             EnableWindow (GetDlgItem (hwnd,IDC_MOVEDN_BTN), TRUE);
2385                         }
2386                         else
2387                         {
2388                             EnableWindow (GetDlgItem (hwnd,IDC_MOVEUP_BTN), TRUE);
2389                             EnableWindow (GetDlgItem (hwnd,IDC_MOVEDN_BTN), TRUE);
2390                         }
2391
2392                         EnableWindow (GetDlgItem (hwnd,IDC_REMOVE_BTN), btnInfo->bRemovable);
2393                     }
2394                     break;
2395
2396                 case IDC_MOVEUP_BTN:
2397                     {
2398                         int index = SendDlgItemMessageW (hwnd, IDC_TOOLBARBTN_LBOX, LB_GETCURSEL, 0, 0);
2399                         TOOLBAR_Cust_MoveButton(custInfo, hwnd, index, index-1);
2400                     }
2401                     break;
2402
2403                 case IDC_MOVEDN_BTN: /* move down */
2404                     {
2405                         int index = SendDlgItemMessageW (hwnd, IDC_TOOLBARBTN_LBOX, LB_GETCURSEL, 0, 0);
2406                         TOOLBAR_Cust_MoveButton(custInfo, hwnd, index, index+1);
2407                     }
2408                     break;
2409
2410                 case IDC_REMOVE_BTN: /* remove button */
2411                     {
2412                         int index = SendDlgItemMessageW (hwnd, IDC_TOOLBARBTN_LBOX, LB_GETCURSEL, 0, 0);
2413
2414                         if (LB_ERR == index)
2415                                 break;
2416
2417                         TOOLBAR_Cust_RemoveButton(custInfo, hwnd, index);
2418                     }
2419                     break;
2420                 case IDC_HELP_BTN:
2421                         TOOLBAR_SendNotify(&nmtb.hdr, infoPtr, TBN_CUSTHELP);
2422                         break;
2423                 case IDC_RESET_BTN:
2424                         TOOLBAR_SendNotify(&nmtb.hdr, infoPtr, TBN_RESET);
2425                         break;
2426
2427                 case IDOK: /* Add button */
2428                     {
2429                         int index;
2430                         int indexto;
2431
2432                         index = SendDlgItemMessageW(hwnd, IDC_AVAILBTN_LBOX, LB_GETCURSEL, 0, 0);
2433                         indexto = SendDlgItemMessageW(hwnd, IDC_TOOLBARBTN_LBOX, LB_GETCURSEL, 0, 0);
2434
2435                         TOOLBAR_Cust_AddButton(custInfo, hwnd, index, indexto);
2436                     }
2437                     break;
2438
2439                 case IDCANCEL:
2440                     EndDialog(hwnd, FALSE);
2441                     break;
2442             }
2443             return TRUE;
2444
2445         case WM_DESTROY:
2446             {
2447                 int count;
2448                 int i;
2449
2450                 /* delete items from 'toolbar buttons' listbox*/
2451                 count = SendDlgItemMessageW (hwnd, IDC_TOOLBARBTN_LBOX, LB_GETCOUNT, 0, 0);
2452                 for (i = 0; i < count; i++)
2453                 {
2454                     btnInfo = (PCUSTOMBUTTON)SendDlgItemMessageW (hwnd, IDC_TOOLBARBTN_LBOX, LB_GETITEMDATA, i, 0);
2455                     Free(btnInfo);
2456                     SendDlgItemMessageW (hwnd, IDC_TOOLBARBTN_LBOX, LB_SETITEMDATA, 0, 0);
2457                 }
2458                 SendDlgItemMessageW (hwnd, IDC_TOOLBARBTN_LBOX, LB_RESETCONTENT, 0, 0);
2459
2460
2461                 /* delete items from 'available buttons' listbox*/
2462                 count = SendDlgItemMessageW (hwnd, IDC_AVAILBTN_LBOX, LB_GETCOUNT, 0, 0);
2463                 for (i = 0; i < count; i++)
2464                 {
2465                     btnInfo = (PCUSTOMBUTTON)SendDlgItemMessageW (hwnd, IDC_AVAILBTN_LBOX, LB_GETITEMDATA, i, 0);
2466                     Free(btnInfo);
2467                     SendDlgItemMessageW (hwnd, IDC_AVAILBTN_LBOX, LB_SETITEMDATA, i, 0);
2468                 }
2469                 SendDlgItemMessageW (hwnd, IDC_AVAILBTN_LBOX, LB_RESETCONTENT, 0, 0);
2470             }
2471             return TRUE;
2472
2473         case WM_DRAWITEM:
2474             if (wParam == IDC_AVAILBTN_LBOX || wParam == IDC_TOOLBARBTN_LBOX)
2475             {
2476                 LPDRAWITEMSTRUCT lpdis = (LPDRAWITEMSTRUCT)lParam;
2477                 RECT rcButton;
2478                 RECT rcText;
2479                 HPEN hPen, hOldPen;
2480                 HBRUSH hOldBrush;
2481                 COLORREF oldText = 0;
2482                 COLORREF oldBk = 0;
2483
2484                 /* get item data */
2485                 btnInfo = (PCUSTOMBUTTON)SendDlgItemMessageW (hwnd, wParam, LB_GETITEMDATA, (WPARAM)lpdis->itemID, 0);
2486                 if (btnInfo == NULL)
2487                 {
2488                     FIXME("btnInfo invalid!\n");
2489                     return TRUE;
2490                 }
2491
2492                 /* set colors and select objects */
2493                 oldBk = SetBkColor (lpdis->hDC, (lpdis->itemState & ODS_FOCUS)?comctl32_color.clrHighlight:comctl32_color.clrWindow);
2494                 if (btnInfo->bVirtual)
2495                    oldText = SetTextColor (lpdis->hDC, comctl32_color.clrGrayText);
2496                 else
2497                    oldText = SetTextColor (lpdis->hDC, (lpdis->itemState & ODS_FOCUS)?comctl32_color.clrHighlightText:comctl32_color.clrWindowText);
2498                 hPen = CreatePen( PS_SOLID, 1,
2499                      GetSysColor( (lpdis->itemState & ODS_SELECTED)?COLOR_HIGHLIGHT:COLOR_WINDOW));
2500                 hOldPen = SelectObject (lpdis->hDC, hPen );
2501                 hOldBrush = SelectObject (lpdis->hDC, GetSysColorBrush ((lpdis->itemState & ODS_FOCUS)?COLOR_HIGHLIGHT:COLOR_WINDOW));
2502
2503                 /* fill background rectangle */
2504                 Rectangle (lpdis->hDC, lpdis->rcItem.left, lpdis->rcItem.top,
2505                            lpdis->rcItem.right, lpdis->rcItem.bottom);
2506
2507                 /* calculate button and text rectangles */
2508                 CopyRect (&rcButton, &lpdis->rcItem);
2509                 InflateRect (&rcButton, -1, -1);
2510                 CopyRect (&rcText, &rcButton);
2511                 rcButton.right = rcButton.left + custInfo->tbInfo->nBitmapWidth + 6;
2512                 rcText.left = rcButton.right + 2;
2513
2514                 /* draw focus rectangle */
2515                 if (lpdis->itemState & ODS_FOCUS)
2516                     DrawFocusRect (lpdis->hDC, &lpdis->rcItem);
2517
2518                 /* draw button */
2519                 if (!(infoPtr->dwStyle & TBSTYLE_FLAT))
2520                     DrawEdge (lpdis->hDC, &rcButton, EDGE_RAISED, BF_RECT|BF_MIDDLE|BF_SOFT);
2521
2522                 /* draw image and text */
2523                 if ((btnInfo->btn.fsStyle & BTNS_SEP) == 0) {
2524                         HIMAGELIST himl = GETDEFIMAGELIST(infoPtr, GETHIMLID(infoPtr, 
2525                                 btnInfo->btn.iBitmap));
2526                     ImageList_Draw (himl, GETIBITMAP(infoPtr, btnInfo->btn.iBitmap), 
2527                                 lpdis->hDC, rcButton.left+3, rcButton.top+3, ILD_NORMAL);
2528                 }
2529                 DrawTextW (lpdis->hDC,  btnInfo->text, -1, &rcText,
2530                                DT_LEFT | DT_VCENTER | DT_SINGLELINE);
2531
2532                 /* delete objects and reset colors */
2533                 SelectObject (lpdis->hDC, hOldBrush);
2534                 SelectObject (lpdis->hDC, hOldPen);
2535                 SetBkColor (lpdis->hDC, oldBk);
2536                 SetTextColor (lpdis->hDC, oldText);
2537                 DeleteObject( hPen );
2538                 return TRUE;
2539             }
2540             return FALSE;
2541
2542         case WM_MEASUREITEM:
2543             if (wParam == IDC_AVAILBTN_LBOX || wParam == IDC_TOOLBARBTN_LBOX)
2544             {
2545                 MEASUREITEMSTRUCT *lpmis = (MEASUREITEMSTRUCT*)lParam;
2546
2547                 lpmis->itemHeight = 15 + 8; /* default height */
2548
2549                 return TRUE;
2550             }
2551             return FALSE;
2552
2553         default:
2554             if (uDragListMessage && (uMsg == uDragListMessage))
2555             {
2556                 if (wParam == IDC_TOOLBARBTN_LBOX)
2557                 {
2558                     LRESULT res = TOOLBAR_Cust_ToolbarDragListNotification(
2559                         custInfo, hwnd, (DRAGLISTINFO *)lParam);
2560                     SetWindowLongPtrW(hwnd, DWLP_MSGRESULT, res);
2561                     return TRUE;
2562                 }
2563                 else if (wParam == IDC_AVAILBTN_LBOX)
2564                 {
2565                     LRESULT res = TOOLBAR_Cust_AvailDragListNotification(
2566                         custInfo, hwnd, (DRAGLISTINFO *)lParam);
2567                     SetWindowLongPtrW(hwnd, DWLP_MSGRESULT, res);
2568                     return TRUE;
2569                 }
2570             }
2571             return FALSE;
2572     }
2573 }
2574
2575 static BOOL
2576 TOOLBAR_AddBitmapToImageList(TOOLBAR_INFO *infoPtr, HIMAGELIST himlDef, const TBITMAP_INFO *bitmap)
2577 {
2578     HBITMAP hbmLoad;
2579     INT nCountBefore = ImageList_GetImageCount(himlDef);
2580     INT nCountAfter;
2581     INT cxIcon, cyIcon;
2582     INT nAdded;
2583     INT nIndex;
2584
2585     TRACE("adding hInst=%p nID=%d nButtons=%d\n", bitmap->hInst, bitmap->nID, bitmap->nButtons);
2586     /* Add bitmaps to the default image list */
2587     if (bitmap->hInst == NULL)         /* a handle was passed */
2588     {
2589        BITMAP  bmp;
2590        HBITMAP hOldBitmapBitmap, hOldBitmapLoad;
2591        HDC     hdcImage, hdcBitmap;
2592
2593        /* copy the bitmap before adding it so that the user's bitmap
2594         * doesn't get modified.
2595         */
2596        GetObjectW ((HBITMAP)bitmap->nID, sizeof(BITMAP), (LPVOID)&bmp);
2597
2598        hdcImage  = CreateCompatibleDC(0);
2599        hdcBitmap = CreateCompatibleDC(0);
2600
2601        /* create new bitmap */
2602        hbmLoad = CreateBitmap (bmp.bmWidth, bmp.bmHeight, bmp.bmPlanes, bmp.bmBitsPixel, NULL);
2603        hOldBitmapBitmap = SelectObject(hdcBitmap, (HBITMAP)bitmap->nID);
2604        hOldBitmapLoad = SelectObject(hdcImage, hbmLoad);
2605
2606        /* Copy the user's image */
2607        BitBlt (hdcImage, 0, 0, bmp.bmWidth, bmp.bmHeight,
2608                hdcBitmap, 0, 0, SRCCOPY);
2609
2610        SelectObject (hdcImage, hOldBitmapLoad);
2611        SelectObject (hdcBitmap, hOldBitmapBitmap);
2612        DeleteDC (hdcImage);
2613        DeleteDC (hdcBitmap);
2614     }
2615     else
2616         hbmLoad = CreateMappedBitmap(bitmap->hInst, bitmap->nID, 0, NULL, 0);
2617
2618     /* enlarge the bitmap if needed */
2619     ImageList_GetIconSize(himlDef, &cxIcon, &cyIcon);
2620     COMCTL32_EnsureBitmapSize(&hbmLoad, cxIcon*(INT)bitmap->nButtons, cyIcon, comctl32_color.clrBtnFace);
2621     
2622     nIndex = ImageList_AddMasked(himlDef, hbmLoad, comctl32_color.clrBtnFace);
2623     DeleteObject(hbmLoad);
2624     if (nIndex == -1)
2625         return FALSE;
2626     
2627     nCountAfter = ImageList_GetImageCount(himlDef);
2628     nAdded =  nCountAfter - nCountBefore;
2629     if (bitmap->nButtons == 0) /* wParam == 0 is special and means add only one image */
2630     {
2631         ImageList_SetImageCount(himlDef, nCountBefore + 1);
2632     } else if (nAdded > (INT)bitmap->nButtons) {
2633         TRACE("Added more images than wParam: Previous image number %i added %i while wParam %i. Images in list %i\n",
2634             nCountBefore, nAdded, bitmap->nButtons, nCountAfter);
2635     }
2636
2637     infoPtr->nNumBitmaps += nAdded;
2638     return TRUE;
2639 }
2640
2641 static void
2642 TOOLBAR_CheckImageListIconSize(TOOLBAR_INFO *infoPtr)
2643 {
2644     HIMAGELIST himlDef;
2645     HIMAGELIST himlNew;
2646     INT cx, cy;
2647     INT i;
2648     
2649     himlDef = GETDEFIMAGELIST(infoPtr, 0);
2650     if (himlDef == NULL || himlDef != infoPtr->himlInt)
2651         return;
2652     if (!ImageList_GetIconSize(himlDef, &cx, &cy))
2653         return;
2654     if (cx == infoPtr->nBitmapWidth && cy == infoPtr->nBitmapHeight)
2655         return;
2656
2657     TRACE("Update icon size: %dx%d -> %dx%d\n",
2658         cx, cy, infoPtr->nBitmapWidth, infoPtr->nBitmapHeight);
2659
2660     himlNew = ImageList_Create(infoPtr->nBitmapWidth, infoPtr->nBitmapHeight,
2661                                 ILC_COLORDDB|ILC_MASK, 8, 2);
2662     for (i = 0; i < infoPtr->nNumBitmapInfos; i++)
2663         TOOLBAR_AddBitmapToImageList(infoPtr, himlNew, &infoPtr->bitmaps[i]);
2664     TOOLBAR_InsertImageList(&infoPtr->himlDef, &infoPtr->cimlDef, himlNew, 0);
2665     infoPtr->himlInt = himlNew;
2666
2667     infoPtr->nNumBitmaps -= ImageList_GetImageCount(himlDef);
2668     ImageList_Destroy(himlDef);
2669 }
2670
2671 /***********************************************************************
2672  * TOOLBAR_AddBitmap:  Add the bitmaps to the default image list.
2673  *
2674  */
2675 static LRESULT
2676 TOOLBAR_AddBitmap (HWND hwnd, WPARAM wParam, LPARAM lParam)
2677 {
2678     TOOLBAR_INFO *infoPtr = TOOLBAR_GetInfoPtr (hwnd);
2679     LPTBADDBITMAP lpAddBmp = (LPTBADDBITMAP)lParam;
2680     TBITMAP_INFO info;
2681     INT iSumButtons, i;
2682     HIMAGELIST himlDef;
2683
2684     TRACE("hwnd=%p wParam=%x lParam=%lx\n", hwnd, wParam, lParam);
2685     if (!lpAddBmp)
2686         return -1;
2687
2688     if (lpAddBmp->hInst == HINST_COMMCTRL)
2689     {
2690         info.hInst = COMCTL32_hModule;
2691         switch (lpAddBmp->nID)
2692         {
2693             case IDB_STD_SMALL_COLOR:
2694                 info.nButtons = 15;
2695                 info.nID = IDB_STD_SMALL;
2696                 break;
2697             case IDB_STD_LARGE_COLOR:
2698                 info.nButtons = 15;
2699                 info.nID = IDB_STD_LARGE;
2700                 break;
2701             case IDB_VIEW_SMALL_COLOR:
2702                 info.nButtons = 12;
2703                 info.nID = IDB_VIEW_SMALL;
2704                 break;
2705             case IDB_VIEW_LARGE_COLOR:
2706                 info.nButtons = 12;
2707                 info.nID = IDB_VIEW_LARGE;
2708                 break;
2709             case IDB_HIST_SMALL_COLOR:
2710                 info.nButtons = 5;
2711                 info.nID = IDB_HIST_SMALL;
2712                 break;
2713             case IDB_HIST_LARGE_COLOR:
2714                 info.nButtons = 5;
2715                 info.nID = IDB_HIST_LARGE;
2716                 break;
2717             default:
2718                 return -1;
2719         }
2720
2721         TRACE ("adding %d internal bitmaps!\n", info.nButtons);
2722
2723         /* Windows resize all the buttons to the size of a newly added standard image */
2724         if (lpAddBmp->nID & 1)
2725         {
2726             /* large icons */
2727             /* FIXME: on windows the size of the images is 25x24 but the size of the bitmap
2728              * in rsrc is only 24x24. Fix the bitmap (how?) and then fix this
2729              */
2730             SendMessageW (hwnd, TB_SETBITMAPSIZE, 0,
2731                           MAKELPARAM((WORD)24, (WORD)24));
2732             SendMessageW (hwnd, TB_SETBUTTONSIZE, 0,
2733                           MAKELPARAM((WORD)31, (WORD)30));
2734         }
2735         else
2736         {
2737             /* small icons */
2738             SendMessageW (hwnd, TB_SETBITMAPSIZE, 0,
2739                           MAKELPARAM((WORD)16, (WORD)16));
2740             SendMessageW (hwnd, TB_SETBUTTONSIZE, 0,
2741                           MAKELPARAM((WORD)22, (WORD)22));
2742         }
2743
2744         TOOLBAR_CalcToolbar (hwnd);
2745     }
2746     else
2747     {
2748         info.nButtons = (INT)wParam;
2749         info.hInst = lpAddBmp->hInst;
2750         info.nID = lpAddBmp->nID;
2751         TRACE("adding %d bitmaps!\n", info.nButtons);
2752     }
2753     
2754     /* check if the bitmap is already loaded and compute iSumButtons */
2755     iSumButtons = 0;
2756     for (i = 0; i < infoPtr->nNumBitmapInfos; i++)
2757     {
2758         if (infoPtr->bitmaps[i].hInst == info.hInst &&
2759             infoPtr->bitmaps[i].nID == info.nID)
2760             return iSumButtons;
2761         iSumButtons += infoPtr->bitmaps[i].nButtons;
2762     }
2763
2764     if (!infoPtr->cimlDef) {
2765         /* create new default image list */
2766         TRACE ("creating default image list!\n");
2767
2768         himlDef = ImageList_Create (infoPtr->nBitmapWidth, infoPtr->nBitmapHeight,
2769                                     ILC_COLORDDB | ILC_MASK, info.nButtons, 2);
2770         TOOLBAR_InsertImageList(&infoPtr->himlDef, &infoPtr->cimlDef, himlDef, 0);
2771         infoPtr->himlInt = himlDef;
2772     }
2773     else {
2774         himlDef = GETDEFIMAGELIST(infoPtr, 0);
2775     }
2776
2777     if (!himlDef) {
2778         WARN("No default image list available\n");
2779         return -1;
2780     }
2781
2782     if (!TOOLBAR_AddBitmapToImageList(infoPtr, himlDef, &info))
2783         return -1;
2784
2785     TRACE("Number of bitmap infos: %d\n", infoPtr->nNumBitmapInfos);
2786     infoPtr->bitmaps = ReAlloc(infoPtr->bitmaps, (infoPtr->nNumBitmapInfos + 1) * sizeof(TBITMAP_INFO));
2787     infoPtr->bitmaps[infoPtr->nNumBitmapInfos] = info;
2788     infoPtr->nNumBitmapInfos++;
2789     TRACE("Number of bitmap infos: %d\n", infoPtr->nNumBitmapInfos);
2790
2791     InvalidateRect(hwnd, NULL, TRUE);
2792     return iSumButtons;
2793 }
2794
2795
2796 static LRESULT
2797 TOOLBAR_AddButtonsA (HWND hwnd, WPARAM wParam, LPARAM lParam)
2798 {
2799     TOOLBAR_INFO *infoPtr = TOOLBAR_GetInfoPtr (hwnd);
2800     LPTBBUTTON lpTbb = (LPTBBUTTON)lParam;
2801     INT nOldButtons, nNewButtons, nAddButtons, nCount;
2802
2803     TRACE("adding %d buttons!\n", wParam);
2804
2805     nAddButtons = (UINT)wParam;
2806     nOldButtons = infoPtr->nNumButtons;
2807     nNewButtons = nOldButtons + nAddButtons;
2808
2809     if (infoPtr->nNumButtons == 0) {
2810         infoPtr->buttons =
2811             Alloc (sizeof(TBUTTON_INFO) * nNewButtons);
2812     }
2813     else {
2814         TBUTTON_INFO *oldButtons = infoPtr->buttons;
2815         infoPtr->buttons =
2816             Alloc (sizeof(TBUTTON_INFO) * nNewButtons);
2817         memcpy (&infoPtr->buttons[0], &oldButtons[0],
2818                 nOldButtons * sizeof(TBUTTON_INFO));
2819         Free (oldButtons);
2820     }
2821
2822     infoPtr->nNumButtons = nNewButtons;
2823
2824     /* insert new button data */
2825     for (nCount = 0; nCount < nAddButtons; nCount++) {
2826         TBUTTON_INFO *btnPtr = &infoPtr->buttons[nOldButtons+nCount];
2827         btnPtr->iBitmap   = lpTbb[nCount].iBitmap;
2828         btnPtr->idCommand = lpTbb[nCount].idCommand;
2829         btnPtr->fsState   = lpTbb[nCount].fsState;
2830         btnPtr->fsStyle   = lpTbb[nCount].fsStyle;
2831         btnPtr->dwData    = lpTbb[nCount].dwData;
2832         if(HIWORD(lpTbb[nCount].iString) && lpTbb[nCount].iString != -1)
2833             Str_SetPtrAtoW ((LPWSTR*)&btnPtr->iString, (LPSTR)lpTbb[nCount].iString );
2834         else
2835             btnPtr->iString   = lpTbb[nCount].iString;
2836         btnPtr->bHot      = FALSE;
2837
2838         if ((infoPtr->hwndToolTip) && !(btnPtr->fsStyle & BTNS_SEP)) {
2839             TTTOOLINFOW ti;
2840
2841             ZeroMemory (&ti, sizeof(ti));
2842             ti.cbSize   = sizeof(ti);
2843             ti.hwnd     = hwnd;
2844             ti.uId      = btnPtr->idCommand;
2845             ti.hinst    = 0;
2846             ti.lpszText = LPSTR_TEXTCALLBACKW;
2847
2848             SendMessageW (infoPtr->hwndToolTip, TTM_ADDTOOLW,
2849                             0, (LPARAM)&ti);
2850         }
2851     }
2852
2853     TOOLBAR_CalcToolbar (hwnd);
2854     TOOLBAR_AutoSize (hwnd);
2855
2856     TOOLBAR_DumpToolbar (infoPtr, __LINE__);
2857
2858     InvalidateRect(hwnd, NULL, TRUE);
2859
2860     return TRUE;
2861 }
2862
2863
2864 static LRESULT
2865 TOOLBAR_AddButtonsW (HWND hwnd, WPARAM wParam, LPARAM lParam)
2866 {
2867     TOOLBAR_INFO *infoPtr = TOOLBAR_GetInfoPtr (hwnd);
2868     LPTBBUTTON lpTbb = (LPTBBUTTON)lParam;
2869     INT nOldButtons, nNewButtons, nAddButtons, nCount;
2870
2871     TRACE("adding %d buttons!\n", wParam);
2872
2873     nAddButtons = (UINT)wParam;
2874     nOldButtons = infoPtr->nNumButtons;
2875     nNewButtons = nOldButtons + nAddButtons;
2876
2877     if (infoPtr->nNumButtons == 0) {
2878         infoPtr->buttons =
2879             Alloc (sizeof(TBUTTON_INFO) * nNewButtons);
2880     }
2881     else {
2882         TBUTTON_INFO *oldButtons = infoPtr->buttons;
2883         infoPtr->buttons =
2884             Alloc (sizeof(TBUTTON_INFO) * nNewButtons);
2885         memcpy (&infoPtr->buttons[0], &oldButtons[0],
2886                 nOldButtons * sizeof(TBUTTON_INFO));
2887         Free (oldButtons);
2888     }
2889
2890     infoPtr->nNumButtons = nNewButtons;
2891
2892     /* insert new button data */
2893     for (nCount = 0; nCount < nAddButtons; nCount++) {
2894         TBUTTON_INFO *btnPtr = &infoPtr->buttons[nOldButtons+nCount];
2895         btnPtr->iBitmap   = lpTbb[nCount].iBitmap;
2896         btnPtr->idCommand = lpTbb[nCount].idCommand;
2897         btnPtr->fsState   = lpTbb[nCount].fsState;
2898         btnPtr->fsStyle   = lpTbb[nCount].fsStyle;
2899         btnPtr->dwData    = lpTbb[nCount].dwData;
2900         if(HIWORD(lpTbb[nCount].iString) && lpTbb[nCount].iString != -1)
2901             Str_SetPtrW ((LPWSTR*)&btnPtr->iString, (LPWSTR)lpTbb[nCount].iString );
2902         else
2903             btnPtr->iString   = lpTbb[nCount].iString;
2904         btnPtr->bHot      = FALSE;
2905
2906         if ((infoPtr->hwndToolTip) && !(btnPtr->fsStyle & BTNS_SEP)) {
2907             TTTOOLINFOW ti;
2908
2909             ZeroMemory (&ti, sizeof(TTTOOLINFOW));
2910             ti.cbSize   = sizeof (TTTOOLINFOW);
2911             ti.hwnd     = hwnd;
2912             ti.uId      = btnPtr->idCommand;
2913             ti.hinst    = 0;
2914             ti.lpszText = LPSTR_TEXTCALLBACKW;
2915             ti.lParam   = lParam;
2916
2917             SendMessageW (infoPtr->hwndToolTip, TTM_ADDTOOLW,
2918                             0, (LPARAM)&ti);
2919         }
2920     }
2921
2922     TOOLBAR_CalcToolbar (hwnd);
2923     TOOLBAR_AutoSize (hwnd);
2924
2925     TOOLBAR_DumpToolbar (infoPtr, __LINE__);
2926
2927     InvalidateRect(hwnd, NULL, TRUE);
2928
2929     return TRUE;
2930 }
2931
2932
2933 static LRESULT
2934 TOOLBAR_AddStringW (HWND hwnd, WPARAM wParam, LPARAM lParam)
2935 {
2936 #define MAX_RESOURCE_STRING_LENGTH 512
2937     TOOLBAR_INFO *infoPtr = TOOLBAR_GetInfoPtr (hwnd);
2938     INT nIndex = infoPtr->nNumStrings;
2939
2940     if ((wParam) && (HIWORD(lParam) == 0)) {
2941         WCHAR szString[MAX_RESOURCE_STRING_LENGTH];
2942         WCHAR delimiter;
2943         WCHAR *next_delim;
2944         WCHAR *p;
2945         INT len;
2946         TRACE("adding string from resource!\n");
2947
2948         LoadStringW ((HINSTANCE)wParam, (UINT)lParam,
2949                              szString, MAX_RESOURCE_STRING_LENGTH);
2950         len = lstrlenW(szString);
2951
2952         TRACE("len=%d %s\n", len, debugstr_w(szString));
2953         if (len == 0 || len == 1)
2954             return nIndex;
2955
2956         TRACE("Delimiter: 0x%x\n", *szString);
2957         delimiter = *szString;
2958         p = szString + 1;
2959         if (szString[len-1] == delimiter)
2960             szString[len-1] = 0;
2961
2962         while ((next_delim = strchrW(p, delimiter)) != NULL) {
2963             *next_delim = 0;
2964
2965             infoPtr->strings = ReAlloc(infoPtr->strings, sizeof(LPWSTR)*(infoPtr->nNumStrings+1));
2966             Str_SetPtrW(&infoPtr->strings[infoPtr->nNumStrings], p);
2967             infoPtr->nNumStrings++;
2968
2969             p = next_delim + 1;
2970         }
2971     }
2972     else {
2973         LPWSTR p = (LPWSTR)lParam;
2974         INT len;
2975
2976         if (p == NULL)
2977             return -1;
2978         TRACE("adding string(s) from array!\n");
2979         while (*p) {
2980             len = strlenW (p);
2981
2982             TRACE("len=%d %s\n", len, debugstr_w(p));
2983             infoPtr->strings = ReAlloc(infoPtr->strings, sizeof(LPWSTR)*(infoPtr->nNumStrings+1));
2984             Str_SetPtrW (&infoPtr->strings[infoPtr->nNumStrings], p);
2985             infoPtr->nNumStrings++;
2986
2987             p += (len+1);
2988         }
2989     }
2990
2991     return nIndex;
2992 }
2993
2994
2995 static LRESULT
2996 TOOLBAR_AddStringA (HWND hwnd, WPARAM wParam, LPARAM lParam)
2997 {
2998     TOOLBAR_INFO *infoPtr = TOOLBAR_GetInfoPtr (hwnd);
2999     LPSTR p;
3000     INT nIndex;
3001     INT len;
3002
3003     if ((wParam) && (HIWORD(lParam) == 0))  /* load from resources */
3004         return TOOLBAR_AddStringW(hwnd, wParam, lParam);
3005
3006     p = (LPSTR)lParam;
3007     if (p == NULL)
3008         return -1;
3009
3010     TRACE("adding string(s) from array!\n");
3011     nIndex = infoPtr->nNumStrings;
3012     while (*p) {
3013         len = strlen (p);
3014         TRACE("len=%d \"%s\"\n", len, p);
3015
3016         infoPtr->strings = ReAlloc(infoPtr->strings, sizeof(LPWSTR)*(infoPtr->nNumStrings+1));
3017         Str_SetPtrAtoW(&infoPtr->strings[infoPtr->nNumStrings], p);
3018         infoPtr->nNumStrings++;
3019
3020         p += (len+1);
3021     }
3022
3023     return nIndex;
3024 }
3025
3026
3027 static LRESULT
3028 TOOLBAR_AutoSize (HWND hwnd)
3029 {
3030     TOOLBAR_INFO *infoPtr = TOOLBAR_GetInfoPtr (hwnd);
3031     RECT parent_rect;
3032     HWND parent;
3033     INT  x, y;
3034     INT  cx, cy;
3035
3036     TRACE("auto sizing, style=%lx!\n", infoPtr->dwStyle);
3037
3038     parent = GetParent (hwnd);
3039
3040     if (!parent || !infoPtr->bDoRedraw)
3041         return 0;
3042
3043     GetClientRect(parent, &parent_rect);
3044
3045     x = parent_rect.left;
3046     y = parent_rect.top;
3047
3048     TRACE("nRows: %d, infoPtr->nButtonHeight: %d\n", infoPtr->nRows, infoPtr->nButtonHeight);
3049
3050     cy = TOP_BORDER + infoPtr->nRows * infoPtr->nButtonHeight + BOTTOM_BORDER;
3051     cx = parent_rect.right - parent_rect.left;
3052
3053     if ((infoPtr->dwStyle & TBSTYLE_WRAPABLE) || (infoPtr->dwExStyle & TBSTYLE_EX_UNDOC1))
3054     {
3055         TOOLBAR_CalcToolbar(hwnd);
3056         InvalidateRect( hwnd, NULL, TRUE );
3057     }
3058
3059     if (!(infoPtr->dwStyle & CCS_NORESIZE))
3060     {
3061         RECT window_rect;
3062         UINT uPosFlags = SWP_NOZORDER;
3063
3064         if ((infoPtr->dwStyle & CCS_BOTTOM) == CCS_NOMOVEY)
3065         {
3066             GetWindowRect(hwnd, &window_rect);
3067             ScreenToClient(parent, (LPPOINT)&window_rect.left);
3068             y = window_rect.top;
3069         }
3070         if ((infoPtr->dwStyle & CCS_BOTTOM) == CCS_BOTTOM)
3071         {
3072             GetWindowRect(hwnd, &window_rect);
3073             y = parent_rect.bottom - ( window_rect.bottom - window_rect.top);
3074         }
3075
3076         if (infoPtr->dwStyle & CCS_NOPARENTALIGN)
3077             uPosFlags |= SWP_NOMOVE;
3078     
3079         if (!(infoPtr->dwStyle & CCS_NODIVIDER))
3080             cy += GetSystemMetrics(SM_CYEDGE);
3081
3082         if (infoPtr->dwStyle & WS_BORDER)
3083         {
3084             x = y = 1; /* FIXME: this looks wrong */
3085             cy += GetSystemMetrics(SM_CYEDGE);
3086             cx += GetSystemMetrics(SM_CXEDGE);
3087         }
3088
3089         SetWindowPos(hwnd, NULL, x, y, cx, cy, uPosFlags);
3090     }
3091
3092     return 0;
3093 }
3094
3095
3096 static LRESULT
3097 TOOLBAR_ButtonCount (HWND hwnd, WPARAM wParam, LPARAM lParam)
3098 {
3099     TOOLBAR_INFO *infoPtr = TOOLBAR_GetInfoPtr (hwnd);
3100
3101     return infoPtr->nNumButtons;
3102 }
3103
3104
3105 static LRESULT
3106 TOOLBAR_ButtonStructSize (HWND hwnd, WPARAM wParam, LPARAM lParam)
3107 {
3108     TOOLBAR_INFO *infoPtr = TOOLBAR_GetInfoPtr (hwnd);
3109
3110     infoPtr->dwStructSize = (DWORD)wParam;
3111
3112     return 0;
3113 }
3114
3115
3116 static LRESULT
3117 TOOLBAR_ChangeBitmap (HWND hwnd, WPARAM wParam, LPARAM lParam)
3118 {
3119     TOOLBAR_INFO *infoPtr = TOOLBAR_GetInfoPtr (hwnd);
3120     TBUTTON_INFO *btnPtr;
3121     INT nIndex;
3122
3123     TRACE("button %d, iBitmap now %d\n", wParam, LOWORD(lParam));
3124
3125     nIndex = TOOLBAR_GetButtonIndex (infoPtr, (INT)wParam, FALSE);
3126     if (nIndex == -1)
3127         return FALSE;
3128
3129     btnPtr = &infoPtr->buttons[nIndex];
3130     btnPtr->iBitmap = LOWORD(lParam);
3131
3132     /* we HAVE to erase the background, the new bitmap could be */
3133     /* transparent */
3134     InvalidateRect(hwnd, &btnPtr->rect, TRUE);
3135
3136     return TRUE;
3137 }
3138
3139
3140 static LRESULT
3141 TOOLBAR_CheckButton (HWND hwnd, WPARAM wParam, LPARAM lParam)
3142 {
3143     TOOLBAR_INFO *infoPtr = TOOLBAR_GetInfoPtr (hwnd);
3144     TBUTTON_INFO *btnPtr;
3145     INT nIndex;
3146     INT nOldIndex = -1;
3147     BOOL bChecked = FALSE;
3148
3149     nIndex = TOOLBAR_GetButtonIndex (infoPtr, (INT)wParam, FALSE);
3150
3151     TRACE("hwnd=%p, btn index=%d, lParam=0x%08lx\n", hwnd, nIndex, lParam);
3152
3153     if (nIndex == -1)
3154         return FALSE;
3155
3156     btnPtr = &infoPtr->buttons[nIndex];
3157
3158     bChecked = (btnPtr->fsState & TBSTATE_CHECKED) ? TRUE : FALSE;
3159
3160     if (LOWORD(lParam) == FALSE)
3161         btnPtr->fsState &= ~TBSTATE_CHECKED;
3162     else {
3163         if (btnPtr->fsStyle & BTNS_GROUP) {
3164             nOldIndex =
3165                 TOOLBAR_GetCheckedGroupButtonIndex (infoPtr, nIndex);
3166             if (nOldIndex == nIndex)
3167                 return 0;
3168             if (nOldIndex != -1)
3169                 infoPtr->buttons[nOldIndex].fsState &= ~TBSTATE_CHECKED;
3170         }
3171         btnPtr->fsState |= TBSTATE_CHECKED;
3172     }
3173
3174     if( bChecked != LOWORD(lParam) )
3175     {
3176         if (nOldIndex != -1)
3177             InvalidateRect(hwnd, &infoPtr->buttons[nOldIndex].rect, TRUE);
3178         InvalidateRect(hwnd, &btnPtr->rect, TRUE);
3179     }
3180
3181     /* FIXME: Send a WM_NOTIFY?? */
3182
3183     return TRUE;
3184 }
3185
3186
3187 static LRESULT
3188 TOOLBAR_CommandToIndex (HWND hwnd, WPARAM wParam, LPARAM lParam)
3189 {
3190     TOOLBAR_INFO *infoPtr = TOOLBAR_GetInfoPtr (hwnd);
3191
3192     return TOOLBAR_GetButtonIndex (infoPtr, (INT)wParam, FALSE);
3193 }
3194
3195
3196 static LRESULT
3197 TOOLBAR_Customize (HWND hwnd)
3198 {
3199     TOOLBAR_INFO *infoPtr = TOOLBAR_GetInfoPtr (hwnd);
3200     CUSTDLG_INFO custInfo;
3201     LRESULT ret;
3202     LPCVOID template;
3203     HRSRC hRes;
3204     NMHDR nmhdr;
3205
3206     custInfo.tbInfo = infoPtr;
3207     custInfo.tbHwnd = hwnd;
3208
3209     /* send TBN_BEGINADJUST notification */
3210     TOOLBAR_SendNotify (&nmhdr, infoPtr, TBN_BEGINADJUST);
3211
3212     if (!(hRes = FindResourceW (COMCTL32_hModule,
3213                                 MAKEINTRESOURCEW(IDD_TBCUSTOMIZE),
3214                                 (LPWSTR)RT_DIALOG)))
3215         return FALSE;
3216
3217     if(!(template = (LPVOID)LoadResource (COMCTL32_hModule, hRes)))
3218         return FALSE;
3219
3220     ret = DialogBoxIndirectParamW ((HINSTANCE)GetWindowLongPtrW(hwnd, GWLP_HINSTANCE),
3221                                    (LPCDLGTEMPLATEW)template,
3222                                    hwnd,
3223                                    TOOLBAR_CustomizeDialogProc,
3224                                    (LPARAM)&custInfo);
3225
3226     /* send TBN_ENDADJUST notification */
3227     TOOLBAR_SendNotify (&nmhdr, infoPtr, TBN_ENDADJUST);
3228
3229     return ret;
3230 }
3231
3232
3233 static LRESULT
3234 TOOLBAR_DeleteButton (HWND hwnd, WPARAM wParam, LPARAM lParam)
3235 {
3236     TOOLBAR_INFO *infoPtr = TOOLBAR_GetInfoPtr (hwnd);
3237     INT nIndex = (INT)wParam;
3238     NMTOOLBARW nmtb;
3239     TBUTTON_INFO *btnPtr = &infoPtr->buttons[nIndex];
3240
3241     if ((nIndex < 0) || (nIndex >= infoPtr->nNumButtons))
3242         return FALSE;
3243
3244     memset(&nmtb, 0, sizeof(nmtb));
3245     nmtb.iItem = btnPtr->idCommand;
3246     nmtb.tbButton.iBitmap = btnPtr->iBitmap;
3247     nmtb.tbButton.idCommand = btnPtr->idCommand;
3248     nmtb.tbButton.fsState = btnPtr->fsState;
3249     nmtb.tbButton.fsStyle = btnPtr->fsStyle;
3250     nmtb.tbButton.dwData = btnPtr->dwData;
3251     nmtb.tbButton.iString = btnPtr->iString;
3252     TOOLBAR_SendNotify(&nmtb.hdr, infoPtr, TBN_DELETINGBUTTON);
3253
3254     if ((infoPtr->hwndToolTip) &&
3255         !(btnPtr->fsStyle & BTNS_SEP)) {
3256         TTTOOLINFOW ti;
3257
3258         ZeroMemory (&ti, sizeof(ti));
3259         ti.cbSize   = sizeof(ti);
3260         ti.hwnd     = hwnd;
3261         ti.uId      = infoPtr->buttons[nIndex].idCommand;
3262
3263         SendMessageW (infoPtr->hwndToolTip, TTM_DELTOOLW, 0, (LPARAM)&ti);
3264     }
3265
3266     if (infoPtr->nNumButtons == 1) {
3267         TRACE(" simple delete!\n");
3268         Free (infoPtr->buttons);
3269         infoPtr->buttons = NULL;
3270         infoPtr->nNumButtons = 0;
3271     }
3272     else {
3273         TBUTTON_INFO *oldButtons = infoPtr->buttons;
3274         TRACE("complex delete! [nIndex=%d]\n", nIndex);
3275
3276         infoPtr->nNumButtons--;
3277         infoPtr->buttons = Alloc (sizeof (TBUTTON_INFO) * infoPtr->nNumButtons);
3278         if (nIndex > 0) {
3279             memcpy (&infoPtr->buttons[0], &oldButtons[0],
3280                     nIndex * sizeof(TBUTTON_INFO));
3281         }
3282
3283         if (nIndex < infoPtr->nNumButtons) {
3284             memcpy (&infoPtr->buttons[nIndex], &oldButtons[nIndex+1],
3285                     (infoPtr->nNumButtons - nIndex) * sizeof(TBUTTON_INFO));
3286         }
3287
3288         Free (oldButtons);
3289     }
3290
3291     TOOLBAR_CalcToolbar (hwnd);
3292
3293     InvalidateRect (hwnd, NULL, TRUE);
3294
3295     return TRUE;
3296 }
3297
3298
3299 static LRESULT
3300 TOOLBAR_EnableButton (HWND hwnd, WPARAM wParam, LPARAM lParam)
3301 {
3302     TOOLBAR_INFO *infoPtr = TOOLBAR_GetInfoPtr (hwnd);
3303     TBUTTON_INFO *btnPtr;
3304     INT nIndex;
3305     DWORD bState;
3306
3307     nIndex = TOOLBAR_GetButtonIndex (infoPtr, (INT)wParam, FALSE);
3308
3309     TRACE("hwnd=%p, btn index=%d, lParam=0x%08lx\n", hwnd, wParam, lParam);
3310
3311     if (nIndex == -1)
3312         return FALSE;
3313
3314     btnPtr = &infoPtr->buttons[nIndex];
3315
3316     bState = btnPtr->fsState & TBSTATE_ENABLED;
3317
3318     /* update the toolbar button state */
3319     if(LOWORD(lParam) == FALSE) {
3320         btnPtr->fsState &= ~(TBSTATE_ENABLED | TBSTATE_PRESSED);
3321     } else {
3322         btnPtr->fsState |= TBSTATE_ENABLED;
3323     }
3324
3325     /* redraw the button only if the state of the button changed */
3326     if(bState != (btnPtr->fsState & TBSTATE_ENABLED))
3327         InvalidateRect(hwnd, &btnPtr->rect, TRUE);
3328
3329     return TRUE;
3330 }
3331
3332
3333 static inline LRESULT
3334 TOOLBAR_GetAnchorHighlight (HWND hwnd)
3335 {
3336     TOOLBAR_INFO *infoPtr = TOOLBAR_GetInfoPtr (hwnd);
3337
3338     return infoPtr->bAnchor;
3339 }
3340
3341
3342 static LRESULT
3343 TOOLBAR_GetBitmap (HWND hwnd, WPARAM wParam, LPARAM lParam)
3344 {
3345     TOOLBAR_INFO *infoPtr = TOOLBAR_GetInfoPtr (hwnd);
3346     INT nIndex;
3347
3348     nIndex = TOOLBAR_GetButtonIndex (infoPtr, (INT)wParam, FALSE);
3349     if (nIndex == -1)
3350         return -1;
3351
3352     return infoPtr->buttons[nIndex].iBitmap;
3353 }
3354
3355
3356 static inline LRESULT
3357 TOOLBAR_GetBitmapFlags (HWND hwnd, WPARAM wParam, LPARAM lParam)
3358 {
3359     return (GetDeviceCaps (0, LOGPIXELSX) >= 120) ? TBBF_LARGE : 0;
3360 }
3361
3362
3363 static LRESULT
3364 TOOLBAR_GetButton (HWND hwnd, WPARAM wParam, LPARAM lParam)
3365 {
3366     TOOLBAR_INFO *infoPtr = TOOLBAR_GetInfoPtr (hwnd);
3367     LPTBBUTTON lpTbb = (LPTBBUTTON)lParam;
3368     INT nIndex = (INT)wParam;
3369     TBUTTON_INFO *btnPtr;
3370
3371     if (lpTbb == NULL)
3372         return FALSE;
3373
3374     if ((nIndex < 0) || (nIndex >= infoPtr->nNumButtons))
3375         return FALSE;
3376
3377     btnPtr = &infoPtr->buttons[nIndex];
3378     lpTbb->iBitmap   = btnPtr->iBitmap;
3379     lpTbb->idCommand = btnPtr->idCommand;
3380     lpTbb->fsState   = btnPtr->fsState;
3381     lpTbb->fsStyle   = btnPtr->fsStyle;
3382     lpTbb->bReserved[0] = 0;
3383     lpTbb->bReserved[1] = 0;
3384     lpTbb->dwData    = btnPtr->dwData;
3385     lpTbb->iString   = btnPtr->iString;
3386
3387     return TRUE;
3388 }
3389
3390
3391 static LRESULT
3392 TOOLBAR_GetButtonInfoA (HWND hwnd, WPARAM wParam, LPARAM lParam)
3393 {
3394     TOOLBAR_INFO *infoPtr = TOOLBAR_GetInfoPtr (hwnd);
3395     LPTBBUTTONINFOA lpTbInfo = (LPTBBUTTONINFOA)lParam;
3396     TBUTTON_INFO *btnPtr;
3397     INT nIndex;
3398
3399     if (lpTbInfo == NULL)
3400         return -1;
3401     if (lpTbInfo->cbSize < sizeof(TBBUTTONINFOA))
3402         return -1;
3403
3404     nIndex = TOOLBAR_GetButtonIndex (infoPtr, (INT)wParam,
3405                                      lpTbInfo->dwMask & 0x80000000);
3406     if (nIndex == -1)
3407         return -1;
3408
3409     if (!(btnPtr = &infoPtr->buttons[nIndex])) return -1;
3410
3411     if (lpTbInfo->dwMask & TBIF_COMMAND)
3412         lpTbInfo->idCommand = btnPtr->idCommand;
3413     if (lpTbInfo->dwMask & TBIF_IMAGE)
3414         lpTbInfo->iImage = btnPtr->iBitmap;
3415     if (lpTbInfo->dwMask & TBIF_LPARAM)
3416         lpTbInfo->lParam = btnPtr->dwData;
3417     if (lpTbInfo->dwMask & TBIF_SIZE)
3418         lpTbInfo->cx = (WORD)(btnPtr->rect.right - btnPtr->rect.left);
3419     if (lpTbInfo->dwMask & TBIF_STATE)
3420         lpTbInfo->fsState = btnPtr->fsState;
3421     if (lpTbInfo->dwMask & TBIF_STYLE)
3422         lpTbInfo->fsStyle = btnPtr->fsStyle;
3423     if (lpTbInfo->dwMask & TBIF_TEXT) {
3424         /* TB_GETBUTTONINFO doesn't retrieve text from the string list, so we
3425            can't use TOOLBAR_GetText here */
3426         LPWSTR lpText;
3427         if (HIWORD(btnPtr->iString) && (btnPtr->iString != -1)) {
3428             lpText = (LPWSTR)btnPtr->iString;
3429             Str_GetPtrWtoA (lpText, lpTbInfo->pszText,lpTbInfo->cchText);
3430         } else
3431             lpTbInfo->pszText[0] = '\0';
3432     }
3433     return nIndex;
3434 }
3435
3436
3437 static LRESULT
3438 TOOLBAR_GetButtonInfoW (HWND hwnd, WPARAM wParam, LPARAM lParam)
3439 {
3440     TOOLBAR_INFO *infoPtr = TOOLBAR_GetInfoPtr (hwnd);
3441     LPTBBUTTONINFOW lpTbInfo = (LPTBBUTTONINFOW)lParam;
3442     TBUTTON_INFO *btnPtr;
3443     INT nIndex;
3444
3445     if (lpTbInfo == NULL)
3446         return -1;
3447     if (lpTbInfo->cbSize < sizeof(TBBUTTONINFOW))
3448         return -1;
3449
3450     nIndex = TOOLBAR_GetButtonIndex (infoPtr, (INT)wParam,
3451                                      lpTbInfo->dwMask & 0x80000000);
3452     if (nIndex == -1)
3453         return -1;
3454
3455     btnPtr = &infoPtr->buttons[nIndex];
3456
3457     if(!btnPtr)
3458         return -1;
3459
3460     if (lpTbInfo->dwMask & TBIF_COMMAND)
3461         lpTbInfo->idCommand = btnPtr->idCommand;
3462     if (lpTbInfo->dwMask & TBIF_IMAGE)
3463         lpTbInfo->iImage = btnPtr->iBitmap;
3464     if (lpTbInfo->dwMask & TBIF_LPARAM)
3465         lpTbInfo->lParam = btnPtr->dwData;
3466     if (lpTbInfo->dwMask & TBIF_SIZE)
3467         lpTbInfo->cx = (WORD)(btnPtr->rect.right - btnPtr->rect.left);
3468     if (lpTbInfo->dwMask & TBIF_STATE)
3469         lpTbInfo->fsState = btnPtr->fsState;
3470     if (lpTbInfo->dwMask & TBIF_STYLE)
3471         lpTbInfo->fsStyle = btnPtr->fsStyle;
3472     if (lpTbInfo->dwMask & TBIF_TEXT) {
3473         /* TB_GETBUTTONINFO doesn't retrieve text from the string list, so we
3474            can't use TOOLBAR_GetText here */
3475         LPWSTR lpText;
3476         if (HIWORD(btnPtr->iString) && (btnPtr->iString != -1)) {
3477             lpText = (LPWSTR)btnPtr->iString;
3478             Str_GetPtrW (lpText,lpTbInfo->pszText,lpTbInfo->cchText);
3479         } else
3480             lpTbInfo->pszText[0] = '\0';
3481     }
3482
3483     return nIndex;
3484 }
3485
3486
3487 static LRESULT
3488 TOOLBAR_GetButtonSize (HWND hwnd)
3489 {
3490     TOOLBAR_INFO *infoPtr = TOOLBAR_GetInfoPtr (hwnd);
3491
3492     if (infoPtr->nNumButtons > 0)
3493         return MAKELONG((WORD)infoPtr->nButtonWidth,
3494                         (WORD)infoPtr->nButtonHeight);
3495     else
3496         return MAKELONG(23,22);
3497 }
3498
3499
3500 static LRESULT
3501 TOOLBAR_GetButtonTextA (HWND hwnd, WPARAM wParam, LPARAM lParam)
3502 {
3503     TOOLBAR_INFO *infoPtr = TOOLBAR_GetInfoPtr (hwnd);
3504     INT nIndex;
3505     LPWSTR lpText;
3506
3507     if (lParam == 0)
3508         return -1;
3509
3510     nIndex = TOOLBAR_GetButtonIndex (infoPtr, (INT)wParam, FALSE);
3511     if (nIndex == -1)
3512         return -1;
3513
3514     lpText = TOOLBAR_GetText(infoPtr,&infoPtr->buttons[nIndex]);
3515
3516     return WideCharToMultiByte( CP_ACP, 0, lpText, -1,
3517                                 (LPSTR)lParam, 0x7fffffff, NULL, NULL ) - 1;
3518 }
3519
3520
3521 static LRESULT
3522 TOOLBAR_GetButtonTextW (HWND hwnd, WPARAM wParam, LPARAM lParam)
3523 {
3524     TOOLBAR_INFO *infoPtr = TOOLBAR_GetInfoPtr (hwnd);
3525     INT nIndex;
3526     LPWSTR lpText;
3527     LRESULT ret = 0;
3528
3529     nIndex = TOOLBAR_GetButtonIndex (infoPtr, (INT)wParam, FALSE);
3530     if (nIndex == -1)
3531         return -1;
3532
3533     lpText = TOOLBAR_GetText(infoPtr,&infoPtr->buttons[nIndex]);
3534
3535     if (lpText)
3536     {
3537         ret = strlenW (lpText);
3538
3539         if (lParam)
3540             strcpyW ((LPWSTR)lParam, lpText);
3541     }
3542
3543     return ret;
3544 }
3545
3546
3547 static LRESULT
3548 TOOLBAR_GetDisabledImageList (HWND hwnd, WPARAM wParam, LPARAM lParam)
3549 {
3550     TRACE("hwnd=%p, wParam=%d, lParam=0x%lx\n", hwnd, wParam, lParam);
3551     /* UNDOCUMENTED: wParam is actually the ID of the image list to return */
3552     return (LRESULT)GETDISIMAGELIST(TOOLBAR_GetInfoPtr (hwnd), wParam);
3553 }
3554
3555
3556 inline static LRESULT
3557 TOOLBAR_GetExtendedStyle (HWND hwnd)
3558 {
3559     TOOLBAR_INFO *infoPtr = TOOLBAR_GetInfoPtr (hwnd);
3560
3561     TRACE("\n");
3562
3563     return infoPtr->dwExStyle;
3564 }
3565
3566
3567 static LRESULT
3568 TOOLBAR_GetHotImageList (HWND hwnd, WPARAM wParam, LPARAM lParam)
3569 {
3570     TRACE("hwnd=%p, wParam=%d, lParam=0x%lx\n", hwnd, wParam, lParam);
3571     /* UNDOCUMENTED: wParam is actually the ID of the image list to return */
3572     return (LRESULT)GETHOTIMAGELIST(TOOLBAR_GetInfoPtr (hwnd), wParam);
3573 }
3574
3575
3576 static LRESULT
3577 TOOLBAR_GetHotItem (HWND hwnd)
3578 {
3579     TOOLBAR_INFO *infoPtr = TOOLBAR_GetInfoPtr (hwnd);
3580
3581     if (!((infoPtr->dwStyle & TBSTYLE_FLAT) || GetWindowTheme (infoPtr->hwndSelf)))
3582         return -1;
3583
3584     if (infoPtr->nHotItem < 0)
3585         return -1;
3586
3587     return (LRESULT)infoPtr->nHotItem;
3588 }
3589
3590
3591 static LRESULT
3592 TOOLBAR_GetDefImageList (HWND hwnd, WPARAM wParam, LPARAM lParam)
3593 {
3594     TRACE("hwnd=%p, wParam=%d, lParam=0x%lx\n", hwnd, wParam, lParam);
3595     /* UNDOCUMENTED: wParam is actually the ID of the image list to return */
3596     return (LRESULT) GETDEFIMAGELIST(TOOLBAR_GetInfoPtr(hwnd), wParam);
3597 }
3598
3599
3600 static LRESULT
3601 TOOLBAR_GetInsertMark (HWND hwnd, WPARAM wParam, LPARAM lParam)
3602 {
3603     TOOLBAR_INFO *infoPtr = TOOLBAR_GetInfoPtr (hwnd);
3604     TBINSERTMARK *lptbim = (TBINSERTMARK*)lParam;
3605
3606     TRACE("hwnd = %p, lptbim = %p\n", hwnd, lptbim);
3607
3608     *lptbim = infoPtr->tbim;
3609
3610     return 0;
3611 }
3612
3613
3614 static LRESULT
3615 TOOLBAR_GetInsertMarkColor (HWND hwnd, WPARAM wParam, LPARAM lParam)
3616 {
3617     TOOLBAR_INFO *infoPtr = TOOLBAR_GetInfoPtr (hwnd);
3618
3619     TRACE("hwnd = %p\n", hwnd);
3620
3621     return (LRESULT)infoPtr->clrInsertMark;
3622 }
3623
3624
3625 static LRESULT
3626 TOOLBAR_GetItemRect (HWND hwnd, WPARAM wParam, LPARAM lParam)
3627 {
3628     TOOLBAR_INFO *infoPtr = TOOLBAR_GetInfoPtr (hwnd);
3629     TBUTTON_INFO *btnPtr;
3630     LPRECT     lpRect;
3631     INT        nIndex;
3632
3633     nIndex = (INT)wParam;
3634     btnPtr = &infoPtr->buttons[nIndex];
3635     if ((nIndex < 0) || (nIndex >= infoPtr->nNumButtons))
3636         return FALSE;
3637     lpRect = (LPRECT)lParam;
3638     if (lpRect == NULL)
3639         return FALSE;
3640     if (btnPtr->fsState & TBSTATE_HIDDEN)
3641         return FALSE;
3642
3643     lpRect->left   = btnPtr->rect.left;
3644     lpRect->right  = btnPtr->rect.right;
3645     lpRect->bottom = btnPtr->rect.bottom;
3646     lpRect->top    = btnPtr->rect.top;
3647
3648     return TRUE;
3649 }
3650
3651
3652 static LRESULT
3653 TOOLBAR_GetMaxSize (HWND hwnd, WPARAM wParam, LPARAM lParam)
3654 {
3655     TOOLBAR_INFO *infoPtr = TOOLBAR_GetInfoPtr (hwnd);
3656     LPSIZE lpSize = (LPSIZE)lParam;
3657
3658     if (lpSize == NULL)
3659         return FALSE;
3660
3661     lpSize->cx = infoPtr->rcBound.right - infoPtr->rcBound.left;
3662     lpSize->cy = infoPtr->rcBound.bottom - infoPtr->rcBound.top;
3663
3664     TRACE("maximum size %ld x %ld\n",
3665            infoPtr->rcBound.right - infoPtr->rcBound.left,
3666            infoPtr->rcBound.bottom - infoPtr->rcBound.top);
3667
3668     return TRUE;
3669 }
3670
3671
3672 /* << TOOLBAR_GetObject >> */
3673
3674
3675 static LRESULT
3676 TOOLBAR_GetPadding (HWND hwnd)
3677 {
3678     TOOLBAR_INFO *infoPtr = TOOLBAR_GetInfoPtr (hwnd);
3679     DWORD oldPad;
3680
3681     oldPad = MAKELONG(infoPtr->szPadding.cx, infoPtr->szPadding.cy);
3682     return (LRESULT) oldPad;
3683 }
3684
3685
3686 static LRESULT
3687 TOOLBAR_GetRect (HWND hwnd, WPARAM wParam, LPARAM lParam)
3688 {
3689     TOOLBAR_INFO *infoPtr = TOOLBAR_GetInfoPtr (hwnd);
3690     TBUTTON_INFO *btnPtr;
3691     LPRECT     lpRect;
3692     INT        nIndex;
3693
3694     nIndex = TOOLBAR_GetButtonIndex (infoPtr, (INT)wParam, FALSE);
3695     btnPtr = &infoPtr->buttons[nIndex];
3696     if ((nIndex < 0) || (nIndex >= infoPtr->nNumButtons))
3697         return FALSE;
3698     lpRect = (LPRECT)lParam;
3699     if (lpRect == NULL)
3700         return FALSE;
3701
3702     lpRect->left   = btnPtr->rect.left;
3703     lpRect->right  = btnPtr->rect.right;
3704     lpRect->bottom = btnPtr->rect.bottom;
3705     lpRect->top    = btnPtr->rect.top;
3706
3707     return TRUE;
3708 }
3709
3710
3711 static LRESULT
3712 TOOLBAR_GetRows (HWND hwnd, WPARAM wParam, LPARAM lParam)
3713 {
3714     TOOLBAR_INFO *infoPtr = TOOLBAR_GetInfoPtr (hwnd);
3715
3716     if (infoPtr->dwStyle & TBSTYLE_WRAPABLE)
3717         return infoPtr->nRows;
3718     else
3719         return 1;
3720 }
3721
3722
3723 static LRESULT
3724 TOOLBAR_GetState (HWND hwnd, WPARAM wParam, LPARAM lParam)
3725 {
3726     TOOLBAR_INFO *infoPtr = TOOLBAR_GetInfoPtr (hwnd);
3727     INT nIndex;
3728
3729     nIndex = TOOLBAR_GetButtonIndex (infoPtr, (INT)wParam, FALSE);
3730     if (nIndex == -1)
3731         return -1;
3732
3733     return infoPtr->buttons[nIndex].fsState;
3734 }
3735
3736
3737 static LRESULT
3738 TOOLBAR_GetStyle (HWND hwnd, WPARAM wParam, LPARAM lParam)
3739 {
3740     return GetWindowLongW(hwnd, GWL_STYLE);
3741 }
3742
3743
3744 static LRESULT
3745 TOOLBAR_GetTextRows (HWND hwnd, WPARAM wParam, LPARAM lParam)
3746 {
3747     TOOLBAR_INFO *infoPtr = TOOLBAR_GetInfoPtr (hwnd);
3748
3749     return infoPtr->nMaxTextRows;
3750 }
3751
3752
3753 static LRESULT
3754 TOOLBAR_GetToolTips (HWND hwnd, WPARAM wParam, LPARAM lParam)
3755 {
3756     TOOLBAR_INFO *infoPtr = TOOLBAR_GetInfoPtr (hwnd);
3757
3758     return (LRESULT)infoPtr->hwndToolTip;
3759 }
3760
3761
3762 static LRESULT
3763 TOOLBAR_GetUnicodeFormat (HWND hwnd, WPARAM wParam, LPARAM lParam)
3764 {
3765     TOOLBAR_INFO *infoPtr = TOOLBAR_GetInfoPtr (hwnd);
3766
3767     TRACE("%s hwnd=%p\n",
3768            infoPtr->bUnicode ? "TRUE" : "FALSE", hwnd);
3769
3770     return infoPtr->bUnicode;
3771 }
3772
3773
3774 inline static LRESULT
3775 TOOLBAR_GetVersion (HWND hwnd)
3776 {
3777     TOOLBAR_INFO *infoPtr = TOOLBAR_GetInfoPtr (hwnd);
3778     return infoPtr->iVersion;
3779 }
3780
3781
3782 static LRESULT
3783 TOOLBAR_HideButton (HWND hwnd, WPARAM wParam, LPARAM lParam)
3784 {
3785     TOOLBAR_INFO *infoPtr = TOOLBAR_GetInfoPtr (hwnd);
3786     TBUTTON_INFO *btnPtr;
3787     INT nIndex;
3788
3789     TRACE("\n");
3790
3791     nIndex = TOOLBAR_GetButtonIndex (infoPtr, (INT)wParam, FALSE);
3792     if (nIndex == -1)
3793         return FALSE;
3794
3795     btnPtr = &infoPtr->buttons[nIndex];
3796     if (LOWORD(lParam) == FALSE)
3797         btnPtr->fsState &= ~TBSTATE_HIDDEN;
3798     else
3799         btnPtr->fsState |= TBSTATE_HIDDEN;
3800
3801     TOOLBAR_CalcToolbar (hwnd);
3802
3803     InvalidateRect (hwnd, NULL, TRUE);
3804
3805     return TRUE;
3806 }
3807
3808
3809 inline static LRESULT
3810 TOOLBAR_HitTest (HWND hwnd, WPARAM wParam, LPARAM lParam)
3811 {
3812     return TOOLBAR_InternalHitTest (hwnd, (LPPOINT)lParam);
3813 }
3814
3815
3816 static LRESULT
3817 TOOLBAR_Indeterminate (HWND hwnd, WPARAM wParam, LPARAM lParam)
3818 {
3819     TOOLBAR_INFO *infoPtr = TOOLBAR_GetInfoPtr (hwnd);
3820     TBUTTON_INFO *btnPtr;
3821     INT nIndex;
3822     DWORD oldState;
3823
3824     nIndex = TOOLBAR_GetButtonIndex (infoPtr, (INT)wParam, FALSE);
3825     if (nIndex == -1)
3826         return FALSE;
3827
3828     btnPtr = &infoPtr->buttons[nIndex];
3829     oldState = btnPtr->fsState;
3830     if (LOWORD(lParam) == FALSE)
3831         btnPtr->fsState &= ~TBSTATE_INDETERMINATE;
3832     else
3833         btnPtr->fsState |= TBSTATE_INDETERMINATE;
3834
3835     if(oldState != btnPtr->fsState)
3836         InvalidateRect(hwnd, &btnPtr->rect, TRUE);
3837
3838     return TRUE;
3839 }
3840
3841
3842 static LRESULT
3843 TOOLBAR_InsertButtonA (HWND hwnd, WPARAM wParam, LPARAM lParam)
3844 {
3845     TOOLBAR_INFO *infoPtr = TOOLBAR_GetInfoPtr (hwnd);
3846     LPTBBUTTON lpTbb = (LPTBBUTTON)lParam;
3847     INT nIndex = (INT)wParam;
3848     TBUTTON_INFO *oldButtons;
3849
3850     if (lpTbb == NULL)
3851         return FALSE;
3852
3853     TOOLBAR_DumpButton(infoPtr, (TBUTTON_INFO *)lpTbb, nIndex, FALSE);
3854
3855     if (nIndex == -1) {
3856        /* EPP: this seems to be an undocumented call (from my IE4)
3857         * I assume in that case that:
3858         * - lpTbb->iString is a string pointer (not a string index in strings[] table
3859         * - index of insertion is at the end of existing buttons
3860         * I only see this happen with nIndex == -1, but it could have a special
3861         * meaning (like -nIndex (or ~nIndex) to get the real position of insertion).
3862         */
3863         nIndex = infoPtr->nNumButtons;
3864
3865     } else if (nIndex < 0)
3866        return FALSE;
3867
3868     /* If the string passed is not an index, assume address of string
3869        and do our own AddString */
3870     if ((HIWORD(lpTbb->iString) != 0) && (lpTbb->iString != -1)) {
3871         LPSTR ptr;
3872         INT len;
3873
3874         TRACE("string %s passed instead of index, adding string\n",
3875               debugstr_a((LPSTR)lpTbb->iString));
3876         len = strlen((LPSTR)lpTbb->iString) + 2;
3877         ptr = Alloc(len);
3878         strcpy(ptr, (LPSTR)lpTbb->iString);
3879         ptr[len - 1] = 0; /* ended by two '\0' */
3880         lpTbb->iString = TOOLBAR_AddStringA(hwnd, 0, (LPARAM)ptr);
3881         Free(ptr);
3882     }
3883
3884     TRACE("inserting button index=%d\n", nIndex);
3885     if (nIndex > infoPtr->nNumButtons) {
3886         nIndex = infoPtr->nNumButtons;
3887         TRACE("adjust index=%d\n", nIndex);
3888     }
3889
3890     oldButtons = infoPtr->buttons;
3891     infoPtr->nNumButtons++;
3892     infoPtr->buttons = Alloc (sizeof (TBUTTON_INFO) * infoPtr->nNumButtons);
3893     /* pre insert copy */
3894     if (nIndex > 0) {
3895         memcpy (&infoPtr->buttons[0], &oldButtons[0],
3896                 nIndex * sizeof(TBUTTON_INFO));
3897     }
3898
3899     /* insert new button */
3900     infoPtr->buttons[nIndex].iBitmap   = lpTbb->iBitmap;
3901     infoPtr->buttons[nIndex].idCommand = lpTbb->idCommand;
3902     infoPtr->buttons[nIndex].fsState   = lpTbb->fsState;
3903     infoPtr->buttons[nIndex].fsStyle   = lpTbb->fsStyle;
3904     infoPtr->buttons[nIndex].dwData    = lpTbb->dwData;
3905     /* if passed string and not index, then add string */
3906     if(HIWORD(lpTbb->iString) && lpTbb->iString!=-1) {
3907         Str_SetPtrAtoW ((LPWSTR *)&infoPtr->buttons[nIndex].iString, (LPCSTR )lpTbb->iString);
3908     }
3909     else
3910         infoPtr->buttons[nIndex].iString   = lpTbb->iString;
3911
3912     if ((infoPtr->hwndToolTip) && !(lpTbb->fsStyle & BTNS_SEP)) {
3913         TTTOOLINFOW ti;
3914
3915         ZeroMemory (&ti, sizeof(ti));
3916         ti.cbSize   = sizeof (ti);
3917         ti.hwnd     = hwnd;
3918         ti.uId      = lpTbb->idCommand;
3919         ti.hinst    = 0;
3920         ti.lpszText = LPSTR_TEXTCALLBACKW;
3921
3922         SendMessageW (infoPtr->hwndToolTip, TTM_ADDTOOLW,
3923                         0, (LPARAM)&ti);
3924     }
3925
3926     /* post insert copy */
3927     if (nIndex < infoPtr->nNumButtons - 1) {
3928         memcpy (&infoPtr->buttons[nIndex+1], &oldButtons[nIndex],
3929                 (infoPtr->nNumButtons - nIndex - 1) * sizeof(TBUTTON_INFO));
3930     }
3931
3932     Free (oldButtons);
3933
3934     TOOLBAR_CalcToolbar (hwnd);
3935     TOOLBAR_AutoSize (hwnd);
3936
3937     InvalidateRect (hwnd, NULL, TRUE);
3938
3939     return TRUE;
3940 }
3941
3942
3943 static LRESULT
3944 TOOLBAR_InsertButtonW (HWND hwnd, WPARAM wParam, LPARAM lParam)
3945 {
3946     TOOLBAR_INFO *infoPtr = TOOLBAR_GetInfoPtr (hwnd);
3947     LPTBBUTTON lpTbb = (LPTBBUTTON)lParam;
3948     INT nIndex = (INT)wParam;
3949     TBUTTON_INFO *oldButtons;
3950
3951     if (lpTbb == NULL)
3952         return FALSE;
3953
3954     TOOLBAR_DumpButton(infoPtr, (TBUTTON_INFO *)lpTbb, nIndex, FALSE);
3955
3956     if (nIndex == -1) {
3957        /* EPP: this seems to be an undocumented call (from my IE4)
3958         * I assume in that case that:
3959         * - lpTbb->iString is a string pointer (not a string index in strings[] table
3960         * - index of insertion is at the end of existing buttons
3961         * I only see this happen with nIndex == -1, but it could have a special
3962         * meaning (like -nIndex (or ~nIndex) to get the real position of insertion).
3963         */
3964         nIndex = infoPtr->nNumButtons;
3965
3966     } else if (nIndex < 0)
3967        return FALSE;
3968
3969     /* If the string passed is not an index, assume address of string
3970        and do our own AddString */
3971     if ((HIWORD(lpTbb->iString) != 0) && (lpTbb->iString != -1)) {
3972         LPWSTR ptr;
3973         INT len;
3974
3975         TRACE("string %s passed instead of index, adding string\n",
3976               debugstr_w((LPWSTR)lpTbb->iString));
3977         len = strlenW((LPWSTR)lpTbb->iString) + 2;
3978         ptr = Alloc(len*sizeof(WCHAR));
3979         strcpyW(ptr, (LPWSTR)lpTbb->iString);
3980         ptr[len - 1] = 0; /* ended by two '\0' */
3981         lpTbb->iString = TOOLBAR_AddStringW(hwnd, 0, (LPARAM)ptr);
3982         Free(ptr);
3983     }
3984
3985     TRACE("inserting button index=%d\n", nIndex);
3986     if (nIndex > infoPtr->nNumButtons) {
3987         nIndex = infoPtr->nNumButtons;
3988         TRACE("adjust index=%d\n", nIndex);
3989     }
3990
3991     oldButtons = infoPtr->buttons;
3992     infoPtr->nNumButtons++;
3993     infoPtr->buttons = Alloc (sizeof (TBUTTON_INFO) * infoPtr->nNumButtons);
3994     /* pre insert copy */
3995     if (nIndex > 0) {
3996         memcpy (&infoPtr->buttons[0], &oldButtons[0],
3997                 nIndex * sizeof(TBUTTON_INFO));
3998     }
3999
4000     /* insert new button */
4001     infoPtr->buttons[nIndex].iBitmap   = lpTbb->iBitmap;
4002     infoPtr->buttons[nIndex].idCommand = lpTbb->idCommand;
4003     infoPtr->buttons[nIndex].fsState   = lpTbb->fsState;
4004     infoPtr->buttons[nIndex].fsStyle   = lpTbb->fsStyle;
4005     infoPtr->buttons[nIndex].dwData    = lpTbb->dwData;
4006     /* if passed string and not index, then add string */
4007     if(HIWORD(lpTbb->iString) && lpTbb->iString!=-1) {
4008         Str_SetPtrW ((LPWSTR *)&infoPtr->buttons[nIndex].iString, (LPWSTR)lpTbb->iString);
4009     }
4010     else
4011         infoPtr->buttons[nIndex].iString   = lpTbb->iString;
4012
4013     if ((infoPtr->hwndToolTip) && !(lpTbb->fsStyle & BTNS_SEP)) {
4014         TTTOOLINFOW ti;
4015
4016         ZeroMemory (&ti, sizeof(TTTOOLINFOW));
4017         ti.cbSize   = sizeof (TTTOOLINFOW);
4018         ti.hwnd     = hwnd;
4019         ti.uId      = lpTbb->idCommand;
4020         ti.hinst    = 0;
4021         ti.lpszText = LPSTR_TEXTCALLBACKW;
4022
4023         SendMessageW (infoPtr->hwndToolTip, TTM_ADDTOOLW,
4024                         0, (LPARAM)&ti);
4025     }
4026
4027     /* post insert copy */
4028     if (nIndex < infoPtr->nNumButtons - 1) {
4029         memcpy (&infoPtr->buttons[nIndex+1], &oldButtons[nIndex],
4030                 (infoPtr->nNumButtons - nIndex - 1) * sizeof(TBUTTON_INFO));
4031     }
4032
4033     Free (oldButtons);
4034
4035     TOOLBAR_CalcToolbar (hwnd);
4036     TOOLBAR_AutoSize (hwnd);
4037
4038     InvalidateRect (hwnd, NULL, TRUE);
4039
4040     return TRUE;
4041 }
4042
4043
4044 /* << TOOLBAR_InsertMarkHitTest >> */
4045
4046
4047 static LRESULT
4048 TOOLBAR_IsButtonChecked (HWND hwnd, WPARAM wParam, LPARAM lParam)
4049 {
4050     TOOLBAR_INFO *infoPtr = TOOLBAR_GetInfoPtr (hwnd);
4051     INT nIndex;
4052
4053     nIndex = TOOLBAR_GetButtonIndex (infoPtr, (INT)wParam, FALSE);
4054     if (nIndex == -1)
4055         return FALSE;
4056
4057     return (infoPtr->buttons[nIndex].fsState & TBSTATE_CHECKED);
4058 }
4059
4060
4061 static LRESULT
4062 TOOLBAR_IsButtonEnabled (HWND hwnd, WPARAM wParam, LPARAM lParam)
4063 {
4064     TOOLBAR_INFO *infoPtr = TOOLBAR_GetInfoPtr (hwnd);
4065     INT nIndex;
4066
4067     nIndex = TOOLBAR_GetButtonIndex (infoPtr, (INT)wParam, FALSE);
4068     if (nIndex == -1)
4069         return FALSE;
4070
4071     return (infoPtr->buttons[nIndex].fsState & TBSTATE_ENABLED);
4072 }
4073
4074
4075 static LRESULT
4076 TOOLBAR_IsButtonHidden (HWND hwnd, WPARAM wParam, LPARAM lParam)
4077 {
4078     TOOLBAR_INFO *infoPtr = TOOLBAR_GetInfoPtr (hwnd);
4079     INT nIndex;
4080
4081     nIndex = TOOLBAR_GetButtonIndex (infoPtr, (INT)wParam, FALSE);
4082     if (nIndex == -1)
4083         return TRUE;
4084
4085     return (infoPtr->buttons[nIndex].fsState & TBSTATE_HIDDEN);
4086 }
4087
4088
4089 static LRESULT
4090 TOOLBAR_IsButtonHighlighted (HWND hwnd, WPARAM wParam, LPARAM lParam)
4091 {
4092     TOOLBAR_INFO *infoPtr = TOOLBAR_GetInfoPtr (hwnd);
4093     INT nIndex;
4094
4095     nIndex = TOOLBAR_GetButtonIndex (infoPtr, (INT)wParam, FALSE);
4096     if (nIndex == -1)
4097         return FALSE;
4098
4099     return (infoPtr->buttons[nIndex].fsState & TBSTATE_MARKED);
4100 }
4101
4102
4103 static LRESULT
4104 TOOLBAR_IsButtonIndeterminate (HWND hwnd, WPARAM wParam, LPARAM lParam)
4105 {
4106     TOOLBAR_INFO *infoPtr = TOOLBAR_GetInfoPtr (hwnd);
4107     INT nIndex;
4108
4109     nIndex = TOOLBAR_GetButtonIndex (infoPtr, (INT)wParam, FALSE);
4110     if (nIndex == -1)
4111         return FALSE;
4112
4113     return (infoPtr->buttons[nIndex].fsState & TBSTATE_INDETERMINATE);
4114 }
4115
4116
4117 static LRESULT
4118 TOOLBAR_IsButtonPressed (HWND hwnd, WPARAM wParam, LPARAM lParam)
4119 {
4120     TOOLBAR_INFO *infoPtr = TOOLBAR_GetInfoPtr (hwnd);
4121     INT nIndex;
4122
4123     nIndex = TOOLBAR_GetButtonIndex (infoPtr, (INT)wParam, FALSE);
4124     if (nIndex == -1)
4125         return FALSE;
4126
4127     return (infoPtr->buttons[nIndex].fsState & TBSTATE_PRESSED);
4128 }
4129
4130
4131 static LRESULT
4132 TOOLBAR_LoadImages (HWND hwnd, WPARAM wParam, LPARAM lParam)
4133 {
4134     TBADDBITMAP tbab;
4135     tbab.hInst = (HINSTANCE)lParam;
4136     tbab.nID = (UINT_PTR)wParam;
4137
4138     TRACE("hwnd = %p, hInst = %p, nID = %u\n", hwnd, tbab.hInst, tbab.nID);
4139
4140     return TOOLBAR_AddBitmap(hwnd, 0, (LPARAM)&tbab);
4141 }
4142
4143
4144 static LRESULT
4145 TOOLBAR_MapAccelerator (HWND hwnd, WPARAM wParam, LPARAM lParam)
4146 {
4147     TOOLBAR_INFO *infoPtr = TOOLBAR_GetInfoPtr (hwnd);
4148     WCHAR wAccel = (WCHAR)wParam;
4149     UINT* pIDButton = (UINT*)lParam;
4150     WCHAR wszAccel[] = {'&',wAccel,0};
4151     int i;
4152     
4153     TRACE("hwnd = %p, wAccel = %x(%s), pIDButton = %p\n",
4154         hwnd, wAccel, debugstr_wn(&wAccel,1), pIDButton);
4155     
4156     for (i = 0; i < infoPtr->nNumButtons; i++)
4157     {
4158         TBUTTON_INFO *btnPtr = infoPtr->buttons+i;
4159         if (!(btnPtr->fsStyle & BTNS_NOPREFIX) &&
4160             !(btnPtr->fsState & TBSTATE_HIDDEN))
4161         {
4162             int iLen = strlenW(wszAccel);
4163             LPCWSTR lpszStr = TOOLBAR_GetText(infoPtr, btnPtr);
4164             
4165             if (!lpszStr)
4166                 continue;
4167
4168             while (*lpszStr)
4169             {
4170                 if ((lpszStr[0] == '&') && (lpszStr[1] == '&'))
4171                 {
4172                     lpszStr += 2;
4173                     continue;
4174                 }
4175                 if (!strncmpiW(lpszStr, wszAccel, iLen))
4176                 {
4177                     *pIDButton = btnPtr->idCommand;
4178                     return TRUE;
4179                 }
4180                 lpszStr++;
4181             }
4182         }
4183     }
4184     return FALSE;
4185 }
4186
4187
4188 static LRESULT
4189 TOOLBAR_MarkButton (HWND hwnd, WPARAM wParam, LPARAM lParam)
4190 {
4191     TOOLBAR_INFO *infoPtr = TOOLBAR_GetInfoPtr (hwnd);
4192     INT nIndex;
4193     DWORD oldState;
4194     TBUTTON_INFO *btnPtr;
4195
4196     TRACE("hwnd = %p, wParam = %d, lParam = 0x%08lx\n", hwnd, wParam, lParam);
4197
4198     nIndex = TOOLBAR_GetButtonIndex (infoPtr, (INT)wParam, FALSE);
4199     if (nIndex == -1)
4200         return FALSE;
4201
4202     btnPtr = &infoPtr->buttons[nIndex];
4203     oldState = btnPtr->fsState;
4204
4205     if (LOWORD(lParam))
4206         btnPtr->fsState |= TBSTATE_MARKED;
4207     else
4208         btnPtr->fsState &= ~TBSTATE_MARKED;
4209
4210     if(oldState != btnPtr->fsState)
4211         InvalidateRect(hwnd, &btnPtr->rect, TRUE);
4212
4213     return TRUE;
4214 }
4215
4216
4217 /* fixes up an index of a button affected by a move */
4218 inline static void TOOLBAR_MoveFixupIndex(INT* pIndex, INT nIndex, INT nMoveIndex, BOOL bMoveUp)
4219 {
4220     if (bMoveUp)
4221     {
4222         if (*pIndex > nIndex && *pIndex <= nMoveIndex)
4223             (*pIndex)--;
4224         else if (*pIndex == nIndex)
4225             *pIndex = nMoveIndex;
4226     }
4227     else
4228     {
4229         if (*pIndex >= nMoveIndex && *pIndex < nIndex)
4230             (*pIndex)++;
4231         else if (*pIndex == nIndex)
4232             *pIndex = nMoveIndex;
4233     }
4234 }
4235
4236
4237 static LRESULT
4238 TOOLBAR_MoveButton (HWND hwnd, WPARAM wParam, LPARAM lParam)
4239 {
4240     TOOLBAR_INFO *infoPtr = TOOLBAR_GetInfoPtr (hwnd);
4241     INT nIndex;
4242     INT nCount;
4243     INT nMoveIndex = (INT)lParam;
4244     TBUTTON_INFO button;
4245
4246     TRACE("hwnd=%p, wParam=%d, lParam=%ld\n", hwnd, wParam, lParam);
4247
4248     nIndex = TOOLBAR_GetButtonIndex (infoPtr, (INT)wParam, TRUE);
4249     if ((nIndex == -1) || (nMoveIndex < 0))
4250         return FALSE;
4251
4252     if (nMoveIndex > infoPtr->nNumButtons - 1)
4253         nMoveIndex = infoPtr->nNumButtons - 1;
4254
4255     button = infoPtr->buttons[nIndex];
4256
4257     /* move button right */
4258     if (nIndex < nMoveIndex)
4259     {
4260         nCount = nMoveIndex - nIndex;
4261         memmove(&infoPtr->buttons[nIndex], &infoPtr->buttons[nIndex+1], nCount*sizeof(TBUTTON_INFO));
4262         infoPtr->buttons[nMoveIndex] = button;
4263
4264         TOOLBAR_MoveFixupIndex(&infoPtr->nButtonDown, nIndex, nMoveIndex, TRUE);
4265         TOOLBAR_MoveFixupIndex(&infoPtr->nButtonDrag, nIndex, nMoveIndex, TRUE);
4266         TOOLBAR_MoveFixupIndex(&infoPtr->nOldHit, nIndex, nMoveIndex, TRUE);
4267         TOOLBAR_MoveFixupIndex(&infoPtr->nHotItem, nIndex, nMoveIndex, TRUE);
4268     }
4269     else if (nIndex > nMoveIndex) /* move button left */
4270     {
4271         nCount = nIndex - nMoveIndex;
4272         memmove(&infoPtr->buttons[nMoveIndex+1], &infoPtr->buttons[nMoveIndex], nCount*sizeof(TBUTTON_INFO));
4273         infoPtr->buttons[nMoveIndex] = button;
4274
4275         TOOLBAR_MoveFixupIndex(&infoPtr->nButtonDown, nIndex, nMoveIndex, FALSE);
4276         TOOLBAR_MoveFixupIndex(&infoPtr->nButtonDrag, nIndex, nMoveIndex, FALSE);
4277         TOOLBAR_MoveFixupIndex(&infoPtr->nOldHit, nIndex, nMoveIndex, FALSE);
4278         TOOLBAR_MoveFixupIndex(&infoPtr->nHotItem, nIndex, nMoveIndex, FALSE);
4279     }
4280
4281     TOOLBAR_CalcToolbar(hwnd);
4282     TOOLBAR_AutoSize(hwnd);
4283     InvalidateRect(hwnd, NULL, TRUE);
4284
4285     return TRUE;
4286 }
4287
4288
4289 static LRESULT
4290 TOOLBAR_PressButton (HWND hwnd, WPARAM wParam, LPARAM lParam)
4291 {
4292     TOOLBAR_INFO *infoPtr = TOOLBAR_GetInfoPtr (hwnd);
4293     TBUTTON_INFO *btnPtr;
4294     INT nIndex;
4295     DWORD oldState;
4296
4297     nIndex = TOOLBAR_GetButtonIndex (infoPtr, (INT)wParam, FALSE);
4298     if (nIndex == -1)
4299         return FALSE;
4300
4301     btnPtr = &infoPtr->buttons[nIndex];
4302     oldState = btnPtr->fsState;
4303     if (LOWORD(lParam) == FALSE)
4304         btnPtr->fsState &= ~TBSTATE_PRESSED;
4305     else
4306         btnPtr->fsState |= TBSTATE_PRESSED;
4307
4308     if(oldState != btnPtr->fsState)
4309         InvalidateRect(hwnd, &btnPtr->rect, TRUE);
4310
4311     return TRUE;
4312 }
4313
4314 /* FIXME: there might still be some confusion her between number of buttons
4315  * and number of bitmaps */
4316 static LRESULT
4317 TOOLBAR_ReplaceBitmap (HWND hwnd, WPARAM wParam, LPARAM lParam)
4318 {
4319     TOOLBAR_INFO *infoPtr = TOOLBAR_GetInfoPtr (hwnd);
4320     LPTBREPLACEBITMAP lpReplace = (LPTBREPLACEBITMAP) lParam;
4321     HBITMAP hBitmap;
4322     HBITMAP hbmLoad = NULL;
4323     int i = 0, nOldButtons = 0, pos = 0;
4324     int nOldBitmaps, nNewBitmaps = 0;
4325     HIMAGELIST himlDef = 0;
4326
4327     TRACE("hInstOld %p nIDOld %x hInstNew %p nIDNew %x nButtons %x\n",
4328           lpReplace->hInstOld, lpReplace->nIDOld, lpReplace->hInstNew, lpReplace->nIDNew,
4329           lpReplace->nButtons);
4330
4331     if (lpReplace->hInstOld == HINST_COMMCTRL)
4332     {
4333         FIXME("changing standard bitmaps not implemented\n");
4334         return FALSE;
4335     }
4336     else if (lpReplace->hInstOld != 0)
4337         FIXME("resources not in the current module not implemented\n");
4338
4339     if (lpReplace->hInstNew)
4340     {
4341         hbmLoad = LoadBitmapW(lpReplace->hInstNew,(LPWSTR)lpReplace->nIDNew);
4342         hBitmap = hbmLoad;
4343     }
4344     else
4345     {
4346         hBitmap = (HBITMAP) lpReplace->nIDNew;
4347     }
4348
4349     TRACE("To be replaced hInstOld %p nIDOld %x\n", lpReplace->hInstOld, lpReplace->nIDOld);
4350     for (i = 0; i < infoPtr->nNumBitmapInfos; i++) {
4351         TBITMAP_INFO *tbi = &infoPtr->bitmaps[i];
4352         TRACE("tbimapinfo %d hInstOld %p nIDOld %x\n", i, tbi->hInst, tbi->nID);
4353         if (tbi->hInst == lpReplace->hInstOld && tbi->nID == lpReplace->nIDOld)
4354         {
4355             TRACE("Found: nButtons %d hInst %p nID %x\n", tbi->nButtons, tbi->hInst, tbi->nID);
4356             nOldButtons = tbi->nButtons;
4357             tbi->nButtons = lpReplace->nButtons;
4358             tbi->hInst = lpReplace->hInstNew;
4359             tbi->nID = lpReplace->nIDNew;
4360             TRACE("tbimapinfo changed %d hInstOld %p nIDOld %x\n", i, tbi->hInst, tbi->nID);
4361             break;
4362         }
4363         pos += tbi->nButtons;
4364     }
4365
4366     if (nOldButtons == 0)
4367     {
4368         WARN("No hinst/bitmap found! hInst %p nID %x\n", lpReplace->hInstOld, lpReplace->nIDOld);
4369         if (hbmLoad)
4370             DeleteObject (hbmLoad);
4371         return FALSE;
4372     }
4373     
4374     himlDef = GETDEFIMAGELIST(infoPtr, 0); /* fixme: correct? */
4375     nOldBitmaps = ImageList_GetImageCount(himlDef);
4376
4377     /* ImageList_Replace(GETDEFIMAGELIST(), pos, hBitmap, NULL); */
4378
4379     for (i = pos + nOldBitmaps - 1; i >= pos; i--)
4380         ImageList_Remove(himlDef, i);
4381
4382     if (hBitmap)
4383     {
4384        BITMAP  bmp;
4385        HBITMAP hOldBitmapBitmap, hOldBitmapLoad, hbmLoad;
4386        HDC     hdcImage, hdcBitmap;
4387
4388        /* copy the bitmap before adding it so that the user's bitmap
4389         * doesn't get modified.
4390         */
4391        GetObjectW (hBitmap, sizeof(BITMAP), (LPVOID)&bmp);
4392
4393        hdcImage  = CreateCompatibleDC(0);
4394        hdcBitmap = CreateCompatibleDC(0);
4395
4396        /* create new bitmap */
4397        hbmLoad = CreateBitmap (bmp.bmWidth, bmp.bmHeight, bmp.bmPlanes, bmp.bmBitsPixel, NULL);
4398        hOldBitmapBitmap = SelectObject(hdcBitmap, hBitmap);
4399        hOldBitmapLoad = SelectObject(hdcImage, hbmLoad);
4400
4401        /* Copy the user's image */
4402        BitBlt (hdcImage, 0, 0, bmp.bmWidth, bmp.bmHeight,
4403                hdcBitmap, 0, 0, SRCCOPY);
4404
4405        SelectObject (hdcImage, hOldBitmapLoad);
4406        SelectObject (hdcBitmap, hOldBitmapBitmap);
4407        DeleteDC (hdcImage);
4408        DeleteDC (hdcBitmap);
4409
4410        ImageList_AddMasked (himlDef, hbmLoad, comctl32_color.clrBtnFace);
4411        nNewBitmaps = ImageList_GetImageCount(himlDef);
4412        DeleteObject (hbmLoad);
4413     }
4414
4415     infoPtr->nNumBitmaps = infoPtr->nNumBitmaps - nOldBitmaps + nNewBitmaps;
4416
4417     TRACE(" pos %d  %d old bitmaps replaced by %d new ones.\n",
4418             pos, nOldBitmaps, nNewBitmaps);
4419
4420     InvalidateRect(hwnd, NULL, TRUE);
4421
4422     if (hbmLoad)
4423         DeleteObject (hbmLoad);
4424     return TRUE;
4425 }
4426
4427
4428 /* helper for TOOLBAR_SaveRestoreW */
4429 static BOOL
4430 TOOLBAR_Save(TOOLBAR_INFO *infoPtr, LPTBSAVEPARAMSW lpSave)
4431 {
4432     FIXME("save to %s %s\n", debugstr_w(lpSave->pszSubKey),
4433         debugstr_w(lpSave->pszValueName));
4434
4435     return FALSE;
4436 }
4437
4438
4439 /* helper for TOOLBAR_Restore */
4440 static void
4441 TOOLBAR_DeleteAllButtons(TOOLBAR_INFO *infoPtr)
4442 {
4443     INT i;
4444     TTTOOLINFOW ti;
4445
4446     ZeroMemory(&ti, sizeof(ti));
4447     ti.cbSize   = sizeof(ti);
4448     ti.hwnd     = infoPtr->hwndSelf;
4449
4450     for (i = 0; i < infoPtr->nNumButtons; i++)
4451     {
4452         if ((infoPtr->hwndToolTip) &&
4453             !(infoPtr->buttons[i].fsStyle & BTNS_SEP))
4454         {
4455             ti.uId      = infoPtr->buttons[i].idCommand;
4456             SendMessageW(infoPtr->hwndToolTip, TTM_DELTOOLW, 0, (LPARAM)&ti);
4457         }
4458     }
4459
4460     Free(infoPtr->buttons);
4461     infoPtr->buttons = NULL;
4462     infoPtr->nNumButtons = 0;
4463 }
4464
4465
4466 /* helper for TOOLBAR_SaveRestoreW */
4467 static BOOL
4468 TOOLBAR_Restore(TOOLBAR_INFO *infoPtr, LPTBSAVEPARAMSW lpSave)
4469 {
4470     LONG res;
4471     HKEY hkey = NULL;
4472     BOOL ret = FALSE;
4473     DWORD dwType;
4474     DWORD dwSize = 0;
4475     NMTBRESTORE nmtbr;
4476
4477     /* restore toolbar information */
4478     TRACE("restore from %s %s\n", debugstr_w(lpSave->pszSubKey),
4479         debugstr_w(lpSave->pszValueName));
4480
4481     memset(&nmtbr, 0, sizeof(nmtbr));
4482
4483     res = RegOpenKeyExW(lpSave->hkr, lpSave->pszSubKey, 0,
4484         KEY_QUERY_VALUE, &hkey);
4485     if (!res)
4486         res = RegQueryValueExW(hkey, lpSave->pszValueName, NULL, &dwType,
4487             NULL, &dwSize);
4488     if (!res && dwType != REG_BINARY)
4489         res = ERROR_FILE_NOT_FOUND;
4490     if (!res)
4491     {
4492         nmtbr.pData = Alloc(dwSize);
4493         nmtbr.cbData = (UINT)dwSize;
4494         if (!nmtbr.pData) res = ERROR_OUTOFMEMORY;
4495     }
4496     if (!res)
4497         res = RegQueryValueExW(hkey, lpSave->pszValueName, NULL, &dwType,
4498             (LPBYTE)nmtbr.pData, &dwSize);
4499     if (!res)
4500     {
4501         nmtbr.pCurrent = nmtbr.pData;
4502         nmtbr.iItem = -1;
4503         nmtbr.cbBytesPerRecord = sizeof(DWORD);
4504         nmtbr.cButtons = nmtbr.cbData / nmtbr.cbBytesPerRecord;
4505
4506         if (!TOOLBAR_SendNotify(&nmtbr.hdr, infoPtr, TBN_RESTORE))
4507         {
4508             INT i;
4509
4510             /* remove all existing buttons as this function is designed to
4511              * restore the toolbar to a previously saved state */
4512             TOOLBAR_DeleteAllButtons(infoPtr);
4513
4514             for (i = 0; i < nmtbr.cButtons; i++)
4515             {
4516                 nmtbr.iItem = i;
4517                 nmtbr.tbButton.iBitmap = -1;
4518                 nmtbr.tbButton.fsState = 0;
4519                 nmtbr.tbButton.fsStyle = 0;
4520                 nmtbr.tbButton.idCommand = 0;
4521                 if (*nmtbr.pCurrent == (DWORD)-1)
4522                 {
4523                     /* separator */
4524                     nmtbr.tbButton.fsStyle = TBSTYLE_SEP;
4525                     nmtbr.tbButton.iBitmap = SEPARATOR_WIDTH;
4526                 }
4527                 else if (*nmtbr.pCurrent == (DWORD)-2)
4528                     /* hidden button */
4529                     nmtbr.tbButton.fsState = TBSTATE_HIDDEN;
4530                 else
4531                     nmtbr.tbButton.idCommand = (int)*nmtbr.pCurrent;
4532
4533                 nmtbr.pCurrent++;
4534                 
4535                 TOOLBAR_SendNotify(&nmtbr.hdr, infoPtr, TBN_RESTORE);
4536
4537                 /* can't contain real string as we don't know whether
4538                  * the client put an ANSI or Unicode string in there */
4539                 if (HIWORD(nmtbr.tbButton.iString))
4540                     nmtbr.tbButton.iString = 0;
4541
4542                 TOOLBAR_InsertButtonW(infoPtr->hwndSelf, -1,
4543                     (LPARAM)&nmtbr.tbButton);
4544             }
4545
4546             /* do legacy notifications */
4547             if (infoPtr->iVersion < 5)
4548             {
4549                 /* FIXME: send TBN_BEGINADJUST */
4550                 FIXME("send TBN_GETBUTTONINFO for each button\n");
4551                 /* FIXME: send TBN_ENDADJUST */
4552             }
4553
4554             /* remove all uninitialised buttons
4555              * note: loop backwards to avoid having to fixup i on a
4556              * delete */
4557             for (i = infoPtr->nNumButtons - 1; i >= 0; i--)
4558                 if (infoPtr->buttons[i].iBitmap == -1)
4559                     TOOLBAR_DeleteButton(infoPtr->hwndSelf, i, 0);
4560
4561             /* only indicate success if at least one button survived */
4562             if (infoPtr->nNumButtons > 0) ret = TRUE;
4563         }
4564     }
4565     Free (nmtbr.pData);
4566     RegCloseKey(hkey);
4567
4568     return ret;
4569 }
4570
4571
4572 static LRESULT
4573 TOOLBAR_SaveRestoreW (HWND hwnd, WPARAM wParam, LPTBSAVEPARAMSW lpSave)
4574 {
4575     TOOLBAR_INFO *infoPtr = TOOLBAR_GetInfoPtr (hwnd);
4576
4577     if (lpSave == NULL) return 0;
4578
4579     if (wParam)
4580         return TOOLBAR_Save(infoPtr, lpSave);
4581     else
4582         return TOOLBAR_Restore(infoPtr, lpSave);
4583 }
4584
4585
4586 static LRESULT
4587 TOOLBAR_SaveRestoreA (HWND hwnd, WPARAM wParam, LPTBSAVEPARAMSA lpSave)
4588 {
4589     LPWSTR pszValueName = 0, pszSubKey = 0;
4590     TBSAVEPARAMSW SaveW;
4591     LRESULT result = 0;
4592     int len;
4593
4594     if (lpSave == NULL) return 0;
4595
4596     len = MultiByteToWideChar(CP_ACP, 0, lpSave->pszSubKey, -1, NULL, 0);
4597     pszSubKey = Alloc(len * sizeof(WCHAR));
4598     if (pszSubKey) goto exit;
4599     MultiByteToWideChar(CP_ACP, 0, lpSave->pszSubKey, -1, pszSubKey, len);
4600
4601     len = MultiByteToWideChar(CP_ACP, 0, lpSave->pszValueName, -1, NULL, 0);
4602     pszValueName = Alloc(len * sizeof(WCHAR));
4603     if (!pszValueName) goto exit;
4604     MultiByteToWideChar(CP_ACP, 0, lpSave->pszValueName, -1, pszValueName, len);
4605
4606     SaveW.pszValueName = pszValueName;
4607     SaveW.pszSubKey = pszSubKey;
4608     SaveW.hkr = lpSave->hkr;
4609     result = TOOLBAR_SaveRestoreW(hwnd, wParam, &SaveW);
4610
4611 exit:
4612     Free (pszValueName);
4613     Free (pszSubKey);
4614
4615     return result;
4616 }
4617
4618
4619 static LRESULT
4620 TOOLBAR_SetAnchorHighlight (HWND hwnd, WPARAM wParam)
4621 {
4622     TOOLBAR_INFO *infoPtr = TOOLBAR_GetInfoPtr (hwnd);
4623     BOOL bOldAnchor = infoPtr->bAnchor;
4624
4625     TRACE("hwnd=%p, bAnchor = %s\n", hwnd, wParam ? "TRUE" : "FALSE");
4626
4627     infoPtr->bAnchor = (BOOL)wParam;
4628
4629     /* Native does not remove the hot effect from an already hot button */
4630
4631     return (LRESULT)bOldAnchor;
4632 }
4633
4634
4635 static LRESULT
4636 TOOLBAR_SetBitmapSize (HWND hwnd, WPARAM wParam, LPARAM lParam)
4637 {
4638     TOOLBAR_INFO *infoPtr = TOOLBAR_GetInfoPtr (hwnd);
4639     HIMAGELIST himlDef = GETDEFIMAGELIST(infoPtr, 0);
4640
4641     TRACE("hwnd=%p, wParam=%d, lParam=%ld\n", hwnd, wParam, lParam);
4642
4643     if (wParam != 0)
4644         FIXME("wParam is %d. Perhaps image list index?\n", wParam);
4645
4646     if ((LOWORD(lParam) <= 0) || (HIWORD(lParam)<=0))
4647         lParam = MAKELPARAM(16, 15);
4648
4649     if (infoPtr->nNumButtons > 0)
4650         WARN("%d buttons, undoc increase to bitmap size : %d-%d -> %d-%d\n",
4651              infoPtr->nNumButtons,
4652              infoPtr->nBitmapWidth, infoPtr->nBitmapHeight,
4653              LOWORD(lParam), HIWORD(lParam));
4654
4655     infoPtr->nBitmapWidth = (INT)LOWORD(lParam);
4656     infoPtr->nBitmapHeight = (INT)HIWORD(lParam);
4657
4658
4659     if ((himlDef == infoPtr->himlInt) &&
4660         (ImageList_GetImageCount(infoPtr->himlInt) == 0))
4661     {
4662         ImageList_SetIconSize(infoPtr->himlInt, infoPtr->nBitmapWidth,
4663             infoPtr->nBitmapHeight);
4664     }
4665
4666     InvalidateRect(infoPtr->hwndSelf, NULL, FALSE);
4667     return TRUE;
4668 }
4669
4670
4671 static LRESULT
4672 TOOLBAR_SetButtonInfoA (HWND hwnd, WPARAM wParam, LPARAM lParam)
4673 {
4674     TOOLBAR_INFO *infoPtr = TOOLBAR_GetInfoPtr (hwnd);
4675     LPTBBUTTONINFOA lptbbi = (LPTBBUTTONINFOA)lParam;
4676     TBUTTON_INFO *btnPtr;
4677     INT nIndex;
4678     RECT oldBtnRect;
4679
4680     if (lptbbi == NULL)
4681         return FALSE;
4682     if (lptbbi->cbSize < sizeof(TBBUTTONINFOA))
4683         return FALSE;
4684
4685     nIndex = TOOLBAR_GetButtonIndex (infoPtr, (INT)wParam,
4686                                      lptbbi->dwMask & 0x80000000);
4687     if (nIndex == -1)
4688         return FALSE;
4689
4690     btnPtr = &infoPtr->buttons[nIndex];
4691     if (lptbbi->dwMask & TBIF_COMMAND)
4692         btnPtr->idCommand = lptbbi->idCommand;
4693     if (lptbbi->dwMask & TBIF_IMAGE)
4694         btnPtr->iBitmap = lptbbi->iImage;
4695     if (lptbbi->dwMask & TBIF_LPARAM)
4696         btnPtr->dwData = lptbbi->lParam;
4697     if (lptbbi->dwMask & TBIF_SIZE)
4698         btnPtr->cx = lptbbi->cx;
4699     if (lptbbi->dwMask & TBIF_STATE)
4700         btnPtr->fsState = lptbbi->fsState;
4701     if (lptbbi->dwMask & TBIF_STYLE)
4702         btnPtr->fsStyle = lptbbi->fsStyle;
4703
4704     if ((lptbbi->dwMask & TBIF_TEXT) && ((INT_PTR)lptbbi->pszText != -1)) {
4705         if ((HIWORD(btnPtr->iString) == 0) || (btnPtr->iString == -1))
4706             /* iString is index, zero it to make Str_SetPtr succeed */
4707             btnPtr->iString=0;
4708
4709          Str_SetPtrAtoW ((LPWSTR *)&btnPtr->iString, lptbbi->pszText);
4710     }
4711
4712     /* save the button rect to see if we need to redraw the whole toolbar */
4713     oldBtnRect = btnPtr->rect;
4714     TOOLBAR_CalcToolbar(hwnd);
4715
4716     if (!EqualRect(&oldBtnRect, &btnPtr->rect))
4717         InvalidateRect(hwnd, NULL, TRUE);
4718     else
4719         InvalidateRect(hwnd, &btnPtr->rect, TRUE);
4720
4721     return TRUE;
4722 }
4723
4724
4725 static LRESULT
4726 TOOLBAR_SetButtonInfoW (HWND hwnd, WPARAM wParam, LPARAM lParam)
4727 {
4728     TOOLBAR_INFO *infoPtr = TOOLBAR_GetInfoPtr (hwnd);
4729     LPTBBUTTONINFOW lptbbi = (LPTBBUTTONINFOW)lParam;
4730     TBUTTON_INFO *btnPtr;
4731     INT nIndex;
4732     RECT oldBtnRect;
4733
4734     if (lptbbi == NULL)
4735         return FALSE;
4736     if (lptbbi->cbSize < sizeof(TBBUTTONINFOW))
4737         return FALSE;
4738
4739     nIndex = TOOLBAR_GetButtonIndex (infoPtr, (INT)wParam,
4740                                      lptbbi->dwMask & 0x80000000);
4741     if (nIndex == -1)
4742         return FALSE;
4743
4744     btnPtr = &infoPtr->buttons[nIndex];
4745     if (lptbbi->dwMask & TBIF_COMMAND)
4746         btnPtr->idCommand = lptbbi->idCommand;
4747     if (lptbbi->dwMask & TBIF_IMAGE)
4748         btnPtr->iBitmap = lptbbi->iImage;
4749     if (lptbbi->dwMask & TBIF_LPARAM)
4750         btnPtr->dwData = lptbbi->lParam;
4751     if (lptbbi->dwMask & TBIF_SIZE)
4752         btnPtr->cx = lptbbi->cx;
4753     if (lptbbi->dwMask & TBIF_STATE)
4754         btnPtr->fsState = lptbbi->fsState;
4755     if (lptbbi->dwMask & TBIF_STYLE)
4756         btnPtr->fsStyle = lptbbi->fsStyle;
4757
4758     if ((lptbbi->dwMask & TBIF_TEXT) && ((INT_PTR)lptbbi->pszText != -1)) {
4759         if ((HIWORD(btnPtr->iString) == 0) || (btnPtr->iString == -1))
4760             /* iString is index, zero it to make Str_SetPtr succeed */
4761             btnPtr->iString=0;
4762         Str_SetPtrW ((LPWSTR *)&btnPtr->iString, lptbbi->pszText);
4763     }
4764
4765     /* save the button rect to see if we need to redraw the whole toolbar */
4766     oldBtnRect = btnPtr->rect;
4767     TOOLBAR_CalcToolbar(hwnd);
4768
4769     if (!EqualRect(&oldBtnRect, &btnPtr->rect))
4770         InvalidateRect(hwnd, NULL, TRUE);
4771     else
4772         InvalidateRect(hwnd, &btnPtr->rect, TRUE);
4773
4774     return TRUE;
4775 }
4776
4777
4778 static LRESULT
4779 TOOLBAR_SetButtonSize (HWND hwnd, WPARAM wParam, LPARAM lParam)
4780 {
4781     TOOLBAR_INFO *infoPtr = TOOLBAR_GetInfoPtr (hwnd);
4782     INT cx = LOWORD(lParam), cy = HIWORD(lParam);
4783
4784     if ((cx < 0) || (cy < 0))
4785     {
4786         ERR("invalid parameter 0x%08lx\n", (DWORD)lParam);
4787         return FALSE;
4788     }
4789
4790     TRACE("%p, cx = %d, cy = %d\n", hwnd, cx, cy);
4791
4792     /* The documentation claims you can only change the button size before
4793      * any button has been added. But this is wrong.
4794      * WINZIP32.EXE (ver 8) calls this on one of its buttons after adding
4795      * it to the toolbar, and it checks that the return value is nonzero - mjm
4796      * Further testing shows that we must actually perform the change too.
4797      */
4798     /*
4799      * The documentation also does not mention that if 0 is supplied for
4800      * either size, the system changes it to the default of 24 wide and
4801      * 22 high. Demonstarted in ControlSpy Toolbar. GLA 3/02
4802      */
4803     infoPtr->nButtonWidth = (cx) ? cx : 24;
4804     infoPtr->nButtonHeight = (cy) ? cy : 22;
4805     return TRUE;
4806 }
4807
4808
4809 static LRESULT
4810 TOOLBAR_SetButtonWidth (HWND hwnd, WPARAM wParam, LPARAM lParam)
4811 {
4812     TOOLBAR_INFO *infoPtr = TOOLBAR_GetInfoPtr (hwnd);
4813
4814     /* if setting to current values, ignore */
4815     if ((infoPtr->cxMin == (INT)LOWORD(lParam)) &&
4816         (infoPtr->cxMax == (INT)HIWORD(lParam))) {
4817         TRACE("matches current width, min=%d, max=%d, no recalc\n",
4818               infoPtr->cxMin, infoPtr->cxMax);
4819         return TRUE;
4820     }
4821
4822     /* save new values */
4823     infoPtr->cxMin = (INT)LOWORD(lParam);
4824     infoPtr->cxMax = (INT)HIWORD(lParam);
4825
4826     /* otherwise we need to recalc the toolbar and in some cases
4827        recalc the bounding rectangle (does DrawText w/ DT_CALCRECT
4828        which doesn't actually draw - GA). */
4829     TRACE("number of buttons %d, cx=%d, cy=%d, recalcing\n",
4830         infoPtr->nNumButtons, infoPtr->cxMin, infoPtr->cxMax);
4831
4832     TOOLBAR_CalcToolbar (hwnd);
4833
4834     InvalidateRect (hwnd, NULL, TRUE);
4835
4836     return TRUE;
4837 }
4838
4839
4840 static LRESULT
4841 TOOLBAR_SetCmdId (HWND hwnd, WPARAM wParam, LPARAM lParam)
4842 {
4843     TOOLBAR_INFO *infoPtr = TOOLBAR_GetInfoPtr (hwnd);
4844     INT nIndex = (INT)wParam;
4845
4846     if ((nIndex < 0) || (nIndex >= infoPtr->nNumButtons))
4847         return FALSE;
4848
4849     infoPtr->buttons[nIndex].idCommand = (INT)lParam;
4850
4851     if (infoPtr->hwndToolTip) {
4852
4853         FIXME("change tool tip!\n");
4854
4855     }
4856
4857     return TRUE;
4858 }
4859
4860
4861 static LRESULT
4862 TOOLBAR_SetDisabledImageList (HWND hwnd, WPARAM wParam, LPARAM lParam)
4863 {
4864     TOOLBAR_INFO *infoPtr = TOOLBAR_GetInfoPtr (hwnd);
4865     HIMAGELIST himl = (HIMAGELIST)lParam;
4866     HIMAGELIST himlTemp;
4867     INT id = 0;
4868
4869     if (infoPtr->iVersion >= 5)
4870         id = wParam;
4871
4872     himlTemp = TOOLBAR_InsertImageList(&infoPtr->himlDis, 
4873         &infoPtr->cimlDis, himl, id);
4874
4875     /* FIXME: redraw ? */
4876
4877     return (LRESULT)himlTemp;
4878 }
4879
4880
4881 static LRESULT
4882 TOOLBAR_SetDrawTextFlags (HWND hwnd, WPARAM wParam, LPARAM lParam)
4883 {
4884     TOOLBAR_INFO *infoPtr = TOOLBAR_GetInfoPtr (hwnd);
4885     DWORD dwTemp;
4886
4887     TRACE("hwnd = %p, dwMask = 0x%08lx, dwDTFlags = 0x%08lx\n", hwnd, (DWORD)wParam, (DWORD)lParam);
4888
4889     dwTemp = infoPtr->dwDTFlags;
4890     infoPtr->dwDTFlags =
4891         (infoPtr->dwDTFlags & (DWORD)wParam) | (DWORD)lParam;
4892
4893     return (LRESULT)dwTemp;
4894 }
4895
4896 /* This function differs a bit from what MSDN says it does:
4897  * 1. lParam contains extended style flags to OR with current style
4898  *  (MSDN isn't clear on the OR bit)
4899  * 2. wParam appears to contain extended style flags to be reset
4900  *  (MSDN says that this parameter is reserved)
4901  */
4902 static LRESULT
4903 TOOLBAR_SetExtendedStyle (HWND hwnd, WPARAM wParam, LPARAM lParam)
4904 {
4905     TOOLBAR_INFO *infoPtr = TOOLBAR_GetInfoPtr (hwnd);
4906     DWORD dwTemp;
4907
4908     dwTemp = infoPtr->dwExStyle;
4909     infoPtr->dwExStyle &= ~wParam;
4910     infoPtr->dwExStyle |= (DWORD)lParam;
4911
4912     TRACE("new style 0x%08lx\n", infoPtr->dwExStyle);
4913
4914     if (infoPtr->dwExStyle & ~TBSTYLE_EX_ALL)
4915         FIXME("Unknown Toolbar Extended Style 0x%08lx. Please report.\n",
4916               (infoPtr->dwExStyle & ~TBSTYLE_EX_ALL));
4917
4918     TOOLBAR_CalcToolbar (hwnd);
4919
4920     TOOLBAR_AutoSize(hwnd);
4921
4922     InvalidateRect(hwnd, NULL, TRUE);
4923
4924     return (LRESULT)dwTemp;
4925 }
4926
4927
4928 static LRESULT
4929 TOOLBAR_SetHotImageList (HWND hwnd, WPARAM wParam, LPARAM lParam)
4930 {
4931     TOOLBAR_INFO *infoPtr = TOOLBAR_GetInfoPtr(hwnd);
4932     HIMAGELIST himlTemp;
4933     HIMAGELIST himl = (HIMAGELIST)lParam;
4934     INT id = 0;
4935
4936     if (infoPtr->iVersion >= 5)
4937         id = wParam;
4938
4939     TRACE("hwnd = %p, himl = %p, id = %d\n", hwnd, himl, id);
4940
4941     himlTemp = TOOLBAR_InsertImageList(&infoPtr->himlHot, 
4942         &infoPtr->cimlHot, himl, id);
4943
4944     /* FIXME: redraw ? */
4945
4946     return (LRESULT)himlTemp;
4947 }
4948
4949
4950 /* Makes previous hot button no longer hot, makes the specified
4951  * button hot and sends appropriate notifications. dwReason is one or
4952  * more HICF_ flags. Specify nHit < 0 to make no buttons hot.
4953  * NOTE 1: this function does not validate nHit
4954  * NOTE 2: the name of this function is completely made up and
4955  * not based on any documentation from Microsoft. */
4956 static void
4957 TOOLBAR_SetHotItemEx (TOOLBAR_INFO *infoPtr, INT nHit, DWORD dwReason)
4958 {
4959     if (infoPtr->nHotItem != nHit)
4960     {
4961         NMTBHOTITEM nmhotitem;
4962         TBUTTON_INFO *btnPtr = NULL, *oldBtnPtr = NULL;
4963         LRESULT no_highlight;
4964
4965         /* Remove the effect of an old hot button if the button was
4966            drawn with the hot button effect */
4967         if(infoPtr->nHotItem >= 0)
4968         {
4969             oldBtnPtr = &infoPtr->buttons[infoPtr->nHotItem];
4970             oldBtnPtr->bHot = FALSE;
4971         }
4972
4973         infoPtr->nHotItem = nHit;
4974
4975         /* It's not a separator or in nowhere. It's a hot button. */
4976         if (nHit >= 0)
4977             btnPtr = &infoPtr->buttons[nHit];
4978
4979         nmhotitem.dwFlags = dwReason;
4980         if (oldBtnPtr)
4981             nmhotitem.idOld = oldBtnPtr->idCommand;
4982         else
4983             nmhotitem.dwFlags |= HICF_ENTERING;
4984         if (btnPtr)
4985             nmhotitem.idNew = btnPtr->idCommand;
4986         else
4987             nmhotitem.dwFlags |= HICF_LEAVING;
4988
4989         no_highlight = TOOLBAR_SendNotify(&nmhotitem.hdr, infoPtr, TBN_HOTITEMCHANGE);
4990
4991         /* now invalidate the old and new buttons so they will be painted,
4992          * but only if they are enabled - disabled buttons cannot become hot */
4993         if (oldBtnPtr && (oldBtnPtr->fsState & TBSTATE_ENABLED))
4994             InvalidateRect(infoPtr->hwndSelf, &oldBtnPtr->rect, TRUE);
4995         if (btnPtr && !no_highlight && (btnPtr->fsState & TBSTATE_ENABLED))
4996         {
4997             btnPtr->bHot = TRUE;
4998             InvalidateRect(infoPtr->hwndSelf, &btnPtr->rect, TRUE);
4999         }
5000     }
5001 }
5002
5003 static LRESULT
5004 TOOLBAR_SetHotItem (HWND hwnd, WPARAM wParam)
5005 {
5006     TOOLBAR_INFO *infoPtr = TOOLBAR_GetInfoPtr(hwnd);
5007     INT nOldHotItem = infoPtr->nHotItem;
5008
5009     TRACE("hwnd = %p, nHit = %d\n", hwnd, (INT)wParam);
5010
5011     if ((INT) wParam < 0 || (INT)wParam > infoPtr->nNumButtons)
5012         wParam = -1;
5013
5014     /* NOTE: an application can still remove the hot item even if anchor
5015      * highlighting is enabled */
5016
5017     if ((infoPtr->dwStyle & TBSTYLE_FLAT) || GetWindowTheme (infoPtr->hwndSelf))
5018         TOOLBAR_SetHotItemEx(infoPtr, wParam, HICF_OTHER);
5019
5020     if (nOldHotItem < 0)
5021         return -1;
5022
5023     return (LRESULT)nOldHotItem;
5024 }
5025
5026
5027 static LRESULT
5028 TOOLBAR_SetImageList (HWND hwnd, WPARAM wParam, LPARAM lParam)
5029 {
5030     TOOLBAR_INFO *infoPtr = TOOLBAR_GetInfoPtr (hwnd);
5031     HIMAGELIST himlTemp;
5032     HIMAGELIST himl = (HIMAGELIST)lParam;
5033     INT i, id = 0;
5034
5035     if (infoPtr->iVersion >= 5)
5036         id = wParam;
5037
5038     himlTemp = TOOLBAR_InsertImageList(&infoPtr->himlDef, 
5039         &infoPtr->cimlDef, himl, id);
5040
5041     infoPtr->nNumBitmaps = 0;
5042     for (i = 0; i < infoPtr->cimlDef; i++)
5043         infoPtr->nNumBitmaps += ImageList_GetImageCount(infoPtr->himlDef[i]->himl);
5044
5045     if (!ImageList_GetIconSize(himl, &infoPtr->nBitmapWidth,
5046             &infoPtr->nBitmapHeight))
5047     {
5048         infoPtr->nBitmapWidth = 1;
5049         infoPtr->nBitmapHeight = 1;
5050     }
5051
5052     TRACE("hwnd %p, new himl=%p, id = %d, count=%d, bitmap w=%d, h=%d\n",
5053           hwnd, infoPtr->himlDef, id, infoPtr->nNumBitmaps,
5054           infoPtr->nBitmapWidth, infoPtr->nBitmapHeight);
5055
5056     InvalidateRect(hwnd, NULL, TRUE);
5057
5058     return (LRESULT)himlTemp;
5059 }
5060
5061
5062 static LRESULT
5063 TOOLBAR_SetIndent (HWND hwnd, WPARAM wParam, LPARAM lParam)
5064 {
5065     TOOLBAR_INFO *infoPtr = TOOLBAR_GetInfoPtr (hwnd);
5066
5067     infoPtr->nIndent = (INT)wParam;
5068
5069     TRACE("\n");
5070
5071     /* process only on indent changing */
5072     if(infoPtr->nIndent != (INT)wParam)
5073     {
5074         infoPtr->nIndent = (INT)wParam;
5075         TOOLBAR_CalcToolbar (hwnd);
5076         InvalidateRect(hwnd, NULL, FALSE);
5077     }
5078
5079     return TRUE;
5080 }
5081
5082
5083 static LRESULT
5084 TOOLBAR_SetInsertMark (HWND hwnd, WPARAM wParam, LPARAM lParam)
5085 {
5086     TOOLBAR_INFO *infoPtr = TOOLBAR_GetInfoPtr (hwnd);
5087     TBINSERTMARK *lptbim = (TBINSERTMARK*)lParam;
5088
5089     TRACE("hwnd = %p, lptbim = { %d, 0x%08lx}\n", hwnd, lptbim->iButton, lptbim->dwFlags);
5090
5091     if ((lptbim->dwFlags & ~TBIMHT_AFTER) != 0)
5092     {
5093         FIXME("Unrecognized flag(s): 0x%08lx\n", (lptbim->dwFlags & ~TBIMHT_AFTER));
5094         return 0;
5095     }
5096
5097     if ((lptbim->iButton == -1) || 
5098         ((lptbim->iButton < infoPtr->nNumButtons) &&
5099          (lptbim->iButton >= 0)))
5100     {
5101         infoPtr->tbim = *lptbim;
5102         /* FIXME: don't need to update entire toolbar */
5103         InvalidateRect(hwnd, NULL, TRUE);
5104     }
5105     else
5106         ERR("Invalid button index %d\n", lptbim->iButton);
5107
5108     return 0;
5109 }
5110
5111
5112 static LRESULT
5113 TOOLBAR_SetInsertMarkColor (HWND hwnd, WPARAM wParam, LPARAM lParam)
5114 {
5115     TOOLBAR_INFO *infoPtr = TOOLBAR_GetInfoPtr (hwnd);
5116
5117     infoPtr->clrInsertMark = (COLORREF)lParam;
5118
5119     /* FIXME: don't need to update entire toolbar */
5120     InvalidateRect(hwnd, NULL, TRUE);
5121
5122     return 0;
5123 }
5124
5125
5126 static LRESULT
5127 TOOLBAR_SetMaxTextRows (HWND hwnd, WPARAM wParam, LPARAM lParam)
5128 {
5129     TOOLBAR_INFO *infoPtr = TOOLBAR_GetInfoPtr (hwnd);
5130
5131     infoPtr->nMaxTextRows = (INT)wParam;
5132
5133     TOOLBAR_CalcToolbar(hwnd);
5134     return TRUE;
5135 }
5136
5137
5138 /* MSDN gives slightly wrong info on padding.
5139  * 1. It is not only used on buttons with the BTNS_AUTOSIZE style
5140  * 2. It is not used to create a blank area between the edge of the button
5141  *    and the text or image if TBSTYLE_LIST is set. It is used to control
5142  *    the gap between the image and text. 
5143  * 3. It is not applied to both sides. If TBSTYLE_LIST is set it is used 
5144  *    to control the bottom and right borders [with the border being
5145  *    szPadding.cx - (GetSystemMetrics(SM_CXEDGE)+1)], otherwise the padding
5146  *    is shared evenly on both sides of the button.
5147  * See blueprints in comments above TOOLBAR_MeasureButton for more info.
5148  */
5149 static LRESULT
5150 TOOLBAR_SetPadding (HWND hwnd, WPARAM wParam, LPARAM lParam)
5151 {
5152     TOOLBAR_INFO *infoPtr = TOOLBAR_GetInfoPtr (hwnd);
5153     DWORD  oldPad;
5154
5155     oldPad = MAKELONG(infoPtr->szPadding.cx, infoPtr->szPadding.cy);
5156     infoPtr->szPadding.cx = min(LOWORD((DWORD)lParam), GetSystemMetrics(SM_CXEDGE));
5157     infoPtr->szPadding.cy = min(HIWORD((DWORD)lParam), GetSystemMetrics(SM_CYEDGE));
5158     TRACE("cx=%ld, cy=%ld\n",
5159           infoPtr->szPadding.cx, infoPtr->szPadding.cy);
5160     return (LRESULT) oldPad;
5161 }
5162
5163
5164 static LRESULT
5165 TOOLBAR_SetParent (HWND hwnd, WPARAM wParam, LPARAM lParam)
5166 {
5167     TOOLBAR_INFO *infoPtr = TOOLBAR_GetInfoPtr (hwnd);
5168     HWND hwndOldNotify;
5169
5170     TRACE("\n");
5171
5172     hwndOldNotify = infoPtr->hwndNotify;
5173     infoPtr->hwndNotify = (HWND)wParam;
5174
5175     return (LRESULT)hwndOldNotify;
5176 }
5177
5178
5179 static LRESULT
5180 TOOLBAR_SetRows (HWND hwnd, WPARAM wParam, LPARAM lParam)
5181 {
5182     TOOLBAR_INFO *infoPtr = TOOLBAR_GetInfoPtr (hwnd);
5183     LPRECT lprc = (LPRECT)lParam;
5184
5185     TRACE("\n");
5186
5187     if (LOWORD(wParam) > 1) {
5188         FIXME("multiple rows not supported!\n");
5189     }
5190
5191     if(infoPtr->nRows != LOWORD(wParam))
5192     {
5193         infoPtr->nRows = LOWORD(wParam);
5194
5195         /* recalculate toolbar */
5196         TOOLBAR_CalcToolbar (hwnd);
5197
5198         /* repaint toolbar */
5199         InvalidateRect(hwnd, NULL, TRUE);
5200     }
5201
5202     /* return bounding rectangle */
5203     if (lprc) {
5204         lprc->left   = infoPtr->rcBound.left;
5205         lprc->right  = infoPtr->rcBound.right;
5206         lprc->top    = infoPtr->rcBound.top;
5207         lprc->bottom = infoPtr->rcBound.bottom;
5208     }
5209
5210     return 0;
5211 }
5212
5213
5214 static LRESULT
5215 TOOLBAR_SetState (HWND hwnd, WPARAM wParam, LPARAM lParam)
5216 {
5217     TOOLBAR_INFO *infoPtr = TOOLBAR_GetInfoPtr (hwnd);
5218     TBUTTON_INFO *btnPtr;
5219     INT nIndex;
5220
5221     nIndex = TOOLBAR_GetButtonIndex (infoPtr, (INT)wParam, FALSE);
5222     if (nIndex == -1)
5223         return FALSE;
5224
5225     btnPtr = &infoPtr->buttons[nIndex];
5226
5227     /* if hidden state has changed the invalidate entire window and recalc */
5228     if ((btnPtr->fsState & TBSTATE_HIDDEN) != (LOWORD(lParam) & TBSTATE_HIDDEN)) {
5229         btnPtr->fsState = LOWORD(lParam);
5230         TOOLBAR_CalcToolbar (hwnd);
5231         InvalidateRect(hwnd, 0, TRUE);
5232         return TRUE;
5233     }
5234
5235     /* process state changing if current state doesn't match new state */
5236     if(btnPtr->fsState != LOWORD(lParam))
5237     {
5238         btnPtr->fsState = LOWORD(lParam);
5239         InvalidateRect(hwnd, &btnPtr->rect, TRUE);
5240     }
5241
5242     return TRUE;
5243 }
5244
5245
5246 static LRESULT
5247 TOOLBAR_SetStyle (HWND hwnd, WPARAM wParam, LPARAM lParam)
5248 {
5249     SetWindowLongW(hwnd, GWL_STYLE, lParam);
5250
5251     return TRUE;
5252 }
5253
5254
5255 inline static LRESULT
5256 TOOLBAR_SetToolTips (HWND hwnd, WPARAM wParam, LPARAM lParam)
5257 {
5258     TOOLBAR_INFO *infoPtr = TOOLBAR_GetInfoPtr (hwnd);
5259
5260     TRACE("hwnd=%p, hwndTooltip=%p, lParam=0x%lx\n", hwnd, (HWND)wParam, lParam);
5261
5262     infoPtr->hwndToolTip = (HWND)wParam;
5263     return 0;
5264 }
5265
5266
5267 static LRESULT
5268 TOOLBAR_SetUnicodeFormat (HWND hwnd, WPARAM wParam, LPARAM lParam)
5269 {
5270     TOOLBAR_INFO *infoPtr = TOOLBAR_GetInfoPtr (hwnd);
5271     BOOL bTemp;
5272
5273     TRACE("%s hwnd=%p\n",
5274            ((BOOL)wParam) ? "TRUE" : "FALSE", hwnd);
5275
5276     bTemp = infoPtr->bUnicode;
5277     infoPtr->bUnicode = (BOOL)wParam;
5278
5279     return bTemp;
5280 }
5281
5282
5283 static LRESULT
5284 TOOLBAR_GetColorScheme (HWND hwnd, LPCOLORSCHEME lParam)
5285 {
5286     TOOLBAR_INFO *infoPtr = TOOLBAR_GetInfoPtr (hwnd);
5287
5288     lParam->clrBtnHighlight = (infoPtr->clrBtnHighlight == CLR_DEFAULT) ?
5289                                comctl32_color.clrBtnHighlight :
5290                                infoPtr->clrBtnHighlight;
5291     lParam->clrBtnShadow = (infoPtr->clrBtnShadow == CLR_DEFAULT) ?
5292                            comctl32_color.clrBtnShadow : infoPtr->clrBtnShadow;
5293     return 1;
5294 }
5295
5296
5297 static LRESULT
5298 TOOLBAR_SetColorScheme (HWND hwnd, LPCOLORSCHEME lParam)
5299 {
5300     TOOLBAR_INFO *infoPtr = TOOLBAR_GetInfoPtr (hwnd);
5301
5302     TRACE("new colors Hl=%lx Shd=%lx, old colors Hl=%lx Shd=%lx\n",
5303           lParam->clrBtnHighlight, lParam->clrBtnShadow,
5304           infoPtr->clrBtnHighlight, infoPtr->clrBtnShadow);
5305
5306     infoPtr->clrBtnHighlight = lParam->clrBtnHighlight;
5307     infoPtr->clrBtnShadow = lParam->clrBtnShadow;
5308     InvalidateRect(hwnd, NULL, TRUE);
5309     return 0;
5310 }
5311
5312
5313 static LRESULT
5314 TOOLBAR_SetVersion (HWND hwnd, INT iVersion)
5315 {
5316     TOOLBAR_INFO *infoPtr = TOOLBAR_GetInfoPtr (hwnd);
5317     INT iOldVersion = infoPtr->iVersion;
5318
5319     infoPtr->iVersion = iVersion;
5320
5321     if (infoPtr->iVersion >= 5)
5322         TOOLBAR_SetUnicodeFormat(hwnd, (WPARAM)TRUE, (LPARAM)0);
5323
5324     return iOldVersion;
5325 }
5326
5327
5328 static LRESULT
5329 TOOLBAR_GetStringA (HWND hwnd, WPARAM wParam, LPARAM lParam)
5330 {
5331     TOOLBAR_INFO *infoPtr = TOOLBAR_GetInfoPtr(hwnd);
5332     WORD iString = HIWORD(wParam);
5333     WORD buffersize = LOWORD(wParam);
5334     LPSTR str = (LPSTR)lParam;
5335     LRESULT ret = -1;
5336
5337     TRACE("hwnd=%p, iString=%d, buffersize=%d, string=%p\n", hwnd, iString, buffersize, str);
5338
5339     if (iString < infoPtr->nNumStrings)
5340     {
5341         ret = WideCharToMultiByte(CP_ACP, 0, infoPtr->strings[iString], -1, str, buffersize, NULL, NULL);
5342
5343         TRACE("returning %s\n", debugstr_a(str));
5344     }
5345     else
5346         ERR("String index %d out of range (largest is %d)\n", iString, infoPtr->nNumStrings - 1);
5347
5348     return ret;
5349 }
5350
5351
5352 static LRESULT
5353 TOOLBAR_GetStringW (HWND hwnd, WPARAM wParam, LPARAM lParam)
5354 {
5355     TOOLBAR_INFO *infoPtr = TOOLBAR_GetInfoPtr(hwnd);
5356     WORD iString = HIWORD(wParam);
5357     WORD len = LOWORD(wParam)/sizeof(WCHAR) - 1;
5358     LPWSTR str = (LPWSTR)lParam;
5359     LRESULT ret = -1;
5360
5361     TRACE("hwnd=%p, iString=%d, buffersize=%d, string=%p\n", hwnd, iString, LOWORD(wParam), str);
5362
5363     if (iString < infoPtr->nNumStrings)
5364     {
5365         len = min(len, strlenW(infoPtr->strings[iString]));
5366         ret = (len+1)*sizeof(WCHAR);
5367         memcpy(str, infoPtr->strings[iString], ret);
5368         str[len] = '\0';
5369
5370         TRACE("returning %s\n", debugstr_w(str));
5371     }
5372     else
5373         ERR("String index %d out of range (largest is %d)\n", iString, infoPtr->nNumStrings - 1);
5374
5375     return ret;
5376 }
5377
5378 /* UNDOCUMENTED MESSAGE: This appears to set some kind of size. Perhaps it
5379  * is the maximum size of the toolbar? */
5380 static LRESULT TOOLBAR_Unkwn45D(HWND hwnd, WPARAM wParam, LPARAM lParam)
5381 {
5382     SIZE * pSize = (SIZE*)lParam;
5383     FIXME("hwnd=%p, wParam=0x%08x, size.cx=%ld, size.cy=%ld stub!\n", hwnd, wParam, pSize->cx, pSize->cy);
5384     return 0;
5385 }
5386
5387
5388 /* UNDOCUMENTED MESSAGE: This is an extended version of the
5389  * TB_SETHOTITEM message. It allows the caller to specify a reason why the
5390  * hot item changed (rather than just the HICF_OTHER that TB_SETHOTITEM
5391  * sends). */
5392 static LRESULT
5393 TOOLBAR_Unkwn45E (HWND hwnd, WPARAM wParam, LPARAM lParam)
5394 {
5395     TOOLBAR_INFO *infoPtr = TOOLBAR_GetInfoPtr(hwnd);
5396     INT nOldHotItem = infoPtr->nHotItem;
5397
5398     TRACE("old item=%d, new item=%d, flags=%08lx\n",
5399           nOldHotItem, infoPtr->nHotItem, (DWORD)lParam);
5400
5401     if ((INT) wParam < 0 || (INT)wParam > infoPtr->nNumButtons)
5402         wParam = -1;
5403
5404     /* NOTE: an application can still remove the hot item even if anchor
5405      * highlighting is enabled */
5406
5407     TOOLBAR_SetHotItemEx(infoPtr, wParam, lParam);
5408
5409     GetFocus();
5410
5411     return (nOldHotItem < 0) ? -1 : (LRESULT)nOldHotItem;
5412 }
5413
5414 /* UNDOCUMENTED MESSAGE: This sets the toolbar global iListGap parameter
5415  * which controls the amount of spacing between the image and the text
5416  * of buttons for TBSTYLE_LIST toolbars. */
5417 static LRESULT TOOLBAR_Unkwn460(HWND hwnd, WPARAM wParam, LPARAM lParam)
5418 {
5419     TOOLBAR_INFO *infoPtr = TOOLBAR_GetInfoPtr(hwnd);
5420
5421     TRACE("hwnd=%p iListGap=%d\n", hwnd, wParam);
5422     
5423     if (lParam != 0)
5424         FIXME("lParam = 0x%08lx. Please report\n", lParam);
5425     
5426     infoPtr->iListGap = (INT)wParam;
5427
5428     InvalidateRect(hwnd, NULL, TRUE);
5429
5430     return 0;
5431 }
5432
5433 /* UNDOCUMENTED MESSAGE: This returns the number of maximum number
5434  * of image lists associated with the various states. */
5435 static LRESULT TOOLBAR_Unkwn462(HWND hwnd, WPARAM wParam, LPARAM lParam)
5436 {
5437     TOOLBAR_INFO *infoPtr = TOOLBAR_GetInfoPtr(hwnd);
5438
5439     TRACE("hwnd=%p wParam %08x lParam %08lx\n", hwnd, wParam, lParam);
5440
5441     return max(infoPtr->cimlDef, max(infoPtr->cimlHot, infoPtr->cimlDis));
5442 }
5443
5444 static LRESULT
5445 TOOLBAR_Unkwn463 (HWND hwnd, WPARAM wParam, LPARAM lParam)
5446 {
5447     TOOLBAR_INFO *infoPtr = TOOLBAR_GetInfoPtr (hwnd);
5448     LPSIZE lpsize = (LPSIZE)lParam;
5449
5450     if (lpsize == NULL)
5451         return FALSE;
5452
5453     /*
5454      * Testing shows the following:
5455      *   wParam    = 0 adjust cx value
5456      *             = 1 set cy value to max size.
5457      *   lParam    pointer to SIZE structure
5458      *
5459      */
5460     TRACE("[0463] wParam %d, lParam 0x%08lx -> 0x%08lx 0x%08lx\n",
5461           wParam, lParam, lpsize->cx, lpsize->cy);
5462
5463     switch(wParam) {
5464     case 0:
5465         if (lpsize->cx == -1) {
5466             /* **** this is wrong, native measures each button and sets it */
5467             lpsize->cx = infoPtr->rcBound.right - infoPtr->rcBound.left;
5468         }
5469         else if(HIWORD(lpsize->cx)) {
5470             RECT rc;
5471             HWND hwndParent = GetParent(hwnd);
5472
5473             GetWindowRect(hwnd, &rc);
5474             MapWindowPoints(0, hwndParent, (LPPOINT)&rc, 2);
5475             TRACE("mapped to (%ld,%ld)-(%ld,%ld)\n",
5476                 rc.left, rc.top, rc.right, rc.bottom);
5477             lpsize->cx = max(rc.right-rc.left,
5478                              infoPtr->rcBound.right - infoPtr->rcBound.left);
5479         }
5480         else {
5481             lpsize->cx = infoPtr->rcBound.right - infoPtr->rcBound.left;
5482         }
5483         break;
5484     case 1:
5485         lpsize->cy = infoPtr->rcBound.bottom - infoPtr->rcBound.top;
5486         break;
5487     default:
5488         ERR("Unknown wParam %d for Toolbar message [0463]. Please report\n",
5489             wParam);
5490         return 0;
5491     }
5492     TRACE("[0463] set to -> 0x%08lx 0x%08lx\n",
5493           lpsize->cx, lpsize->cy);
5494     return 1;
5495 }
5496
5497 static LRESULT TOOLBAR_Unkwn464(HWND hwnd, WPARAM wParam, LPARAM lParam)
5498 {
5499     FIXME("hwnd=%p wParam %08x lParam %08lx\n", hwnd, wParam, lParam);
5500
5501     InvalidateRect(hwnd, NULL, TRUE);
5502     return 1;
5503 }
5504
5505
5506 static LRESULT
5507 TOOLBAR_Create (HWND hwnd, WPARAM wParam, LPARAM lParam)
5508 {
5509     TOOLBAR_INFO *infoPtr = TOOLBAR_GetInfoPtr (hwnd);
5510     DWORD dwStyle = GetWindowLongW (hwnd, GWL_STYLE);
5511     LOGFONTW logFont;
5512
5513     TRACE("hwnd = %p\n", hwnd);
5514
5515     /* initialize info structure */
5516     infoPtr->nButtonHeight = 22;
5517     infoPtr->nButtonWidth = 24;
5518     infoPtr->nBitmapHeight = 15;
5519     infoPtr->nBitmapWidth = 16;
5520
5521     infoPtr->nMaxTextRows = 1;
5522     infoPtr->cxMin = -1;
5523     infoPtr->cxMax = -1;
5524     infoPtr->nNumBitmaps = 0;
5525     infoPtr->nNumStrings = 0;
5526
5527     infoPtr->bCaptured = FALSE;
5528     infoPtr->nButtonDown = -1;
5529     infoPtr->nButtonDrag = -1;
5530     infoPtr->nOldHit = -1;
5531     infoPtr->nHotItem = -1;
5532     infoPtr->hwndNotify = ((LPCREATESTRUCTW)lParam)->hwndParent;
5533     infoPtr->dwDTFlags = (dwStyle & TBSTYLE_LIST) ? DT_LEFT | DT_VCENTER | DT_SINGLELINE | DT_END_ELLIPSIS: DT_CENTER | DT_END_ELLIPSIS;
5534     infoPtr->bAnchor = FALSE; /* no anchor highlighting */
5535     infoPtr->bDragOutSent = FALSE;
5536     infoPtr->iVersion = 0;
5537     infoPtr->hwndSelf = hwnd;
5538     infoPtr->bDoRedraw = TRUE;
5539     infoPtr->clrBtnHighlight = CLR_DEFAULT;
5540     infoPtr->clrBtnShadow = CLR_DEFAULT;
5541     infoPtr->szPadding.cx = DEFPAD_CX;
5542     infoPtr->szPadding.cy = DEFPAD_CY;
5543     infoPtr->iListGap = DEFLISTGAP;
5544     infoPtr->dwStyle = dwStyle;
5545     infoPtr->tbim.iButton = -1;
5546     GetClientRect(hwnd, &infoPtr->client_rect);
5547     infoPtr->bUnicode = infoPtr->hwndNotify && 
5548         (NFR_UNICODE == SendMessageW(hwnd, WM_NOTIFYFORMAT, (WPARAM)hwnd, (LPARAM)NF_REQUERY));
5549
5550     SystemParametersInfoW (SPI_GETICONTITLELOGFONT, 0, &logFont, 0);
5551     infoPtr->hFont = infoPtr->hDefaultFont = CreateFontIndirectW (&logFont);
5552
5553     if (dwStyle & TBSTYLE_TOOLTIPS) {
5554         /* Create tooltip control */
5555         infoPtr->hwndToolTip =
5556             CreateWindowExW (0, TOOLTIPS_CLASSW, NULL, 0,
5557                                CW_USEDEFAULT, CW_USEDEFAULT,
5558                                CW_USEDEFAULT, CW_USEDEFAULT,
5559                                hwnd, 0, 0, 0);
5560
5561         /* Send NM_TOOLTIPSCREATED notification */
5562         if (infoPtr->hwndToolTip)
5563         {
5564             NMTOOLTIPSCREATED nmttc;
5565
5566             nmttc.hwndToolTips = infoPtr->hwndToolTip;
5567
5568             TOOLBAR_SendNotify (&nmttc.hdr, infoPtr, NM_TOOLTIPSCREATED);
5569         }
5570     }
5571     
5572     OpenThemeData (hwnd, themeClass);
5573
5574     TOOLBAR_CheckStyle (hwnd, dwStyle);
5575
5576     TOOLBAR_CalcToolbar(hwnd);
5577
5578     return 0;
5579 }
5580
5581
5582 static LRESULT
5583 TOOLBAR_Destroy (HWND hwnd, WPARAM wParam, LPARAM lParam)
5584 {
5585     TOOLBAR_INFO *infoPtr = TOOLBAR_GetInfoPtr (hwnd);
5586
5587     /* delete tooltip control */
5588     if (infoPtr->hwndToolTip)
5589         DestroyWindow (infoPtr->hwndToolTip);
5590
5591     /* delete temporary buffer for tooltip text */
5592     Free (infoPtr->pszTooltipText);
5593     Free (infoPtr->bitmaps);            /* bitmaps list */
5594
5595     /* delete button data */
5596     if (infoPtr->buttons)
5597         Free (infoPtr->buttons);
5598
5599     /* delete strings */
5600     if (infoPtr->strings) {
5601         INT i;
5602         for (i = 0; i < infoPtr->nNumStrings; i++)
5603             if (infoPtr->strings[i])
5604                 Free (infoPtr->strings[i]);
5605
5606         Free (infoPtr->strings);
5607     }
5608
5609     /* destroy internal image list */
5610     if (infoPtr->himlInt)
5611         ImageList_Destroy (infoPtr->himlInt);
5612
5613         TOOLBAR_DeleteImageList(&infoPtr->himlDef, &infoPtr->cimlDef);
5614         TOOLBAR_DeleteImageList(&infoPtr->himlDis, &infoPtr->cimlDis);
5615         TOOLBAR_DeleteImageList(&infoPtr->himlHot, &infoPtr->cimlHot);
5616
5617     /* delete default font */
5618     if (infoPtr->hFont)
5619         DeleteObject (infoPtr->hDefaultFont);
5620         
5621     CloseThemeData (GetWindowTheme (hwnd));
5622
5623     /* free toolbar info data */
5624     Free (infoPtr);
5625     SetWindowLongPtrW (hwnd, 0, 0);
5626
5627     return 0;
5628 }
5629
5630
5631 static LRESULT
5632 TOOLBAR_EraseBackground (HWND hwnd, WPARAM wParam, LPARAM lParam)
5633 {
5634     TOOLBAR_INFO *infoPtr = TOOLBAR_GetInfoPtr (hwnd);
5635     NMTBCUSTOMDRAW tbcd;
5636     INT ret = FALSE;
5637     DWORD ntfret;
5638     HTHEME theme = GetWindowTheme (hwnd);
5639
5640     /* the app has told us not to redraw the toolbar */
5641     if (!infoPtr->bDoRedraw)
5642         return FALSE;
5643
5644     if (infoPtr->dwStyle & TBSTYLE_CUSTOMERASE) {
5645         ZeroMemory (&tbcd, sizeof(NMTBCUSTOMDRAW));
5646         tbcd.nmcd.dwDrawStage = CDDS_PREERASE;
5647         tbcd.nmcd.hdc = (HDC)wParam;
5648         ntfret = TOOLBAR_SendNotify (&tbcd.nmcd.hdr, infoPtr, NM_CUSTOMDRAW);
5649         infoPtr->dwBaseCustDraw = ntfret & 0xffff;
5650
5651         /* FIXME: in general the return flags *can* be or'ed together */
5652         switch (infoPtr->dwBaseCustDraw)
5653             {
5654             case CDRF_DODEFAULT:
5655                 break;
5656             case CDRF_SKIPDEFAULT:
5657                 return TRUE;
5658             default:
5659                 FIXME("[%p] response %ld not handled to NM_CUSTOMDRAW (CDDS_PREERASE)\n",
5660                       hwnd, ntfret);
5661             }
5662     }
5663
5664     /* If the toolbar is "transparent" then pass the WM_ERASEBKGND up
5665      * to my parent for processing.
5666      */
5667     if (theme || (infoPtr->dwStyle & TBSTYLE_TRANSPARENT)) {
5668         POINT pt, ptorig;
5669         HDC hdc = (HDC)wParam;
5670         HWND parent;
5671
5672         pt.x = 0;
5673         pt.y = 0;
5674         parent = GetParent(hwnd);
5675         MapWindowPoints(hwnd, parent, &pt, 1);
5676         OffsetWindowOrgEx (hdc, pt.x, pt.y, &ptorig);
5677         ret = SendMessageW (parent, WM_ERASEBKGND, wParam, lParam);
5678         SetWindowOrgEx (hdc, ptorig.x, ptorig.y, 0);
5679     }
5680     if (!ret)
5681         ret = DefWindowProcW (hwnd, WM_ERASEBKGND, wParam, lParam);
5682
5683     if ((infoPtr->dwStyle & TBSTYLE_CUSTOMERASE) &&
5684         (infoPtr->dwBaseCustDraw & CDRF_NOTIFYPOSTERASE)) {
5685         ZeroMemory (&tbcd, sizeof(NMTBCUSTOMDRAW));
5686         tbcd.nmcd.dwDrawStage = CDDS_POSTERASE;
5687         tbcd.nmcd.hdc = (HDC)wParam;
5688         ntfret = TOOLBAR_SendNotify (&tbcd.nmcd.hdr, infoPtr, NM_CUSTOMDRAW);
5689         infoPtr->dwBaseCustDraw = ntfret & 0xffff;
5690         switch (infoPtr->dwBaseCustDraw)
5691             {
5692             case CDRF_DODEFAULT:
5693                 break;
5694             case CDRF_SKIPDEFAULT:
5695                 return TRUE;
5696             default:
5697                 FIXME("[%p] response %ld not handled to NM_CUSTOMDRAW (CDDS_POSTERASE)\n",
5698                       hwnd, ntfret);
5699             }
5700     }
5701     return ret;
5702 }
5703
5704
5705 static LRESULT
5706 TOOLBAR_GetFont (HWND hwnd, WPARAM wParam, LPARAM lParam)
5707 {
5708     TOOLBAR_INFO *infoPtr = TOOLBAR_GetInfoPtr (hwnd);
5709
5710     return (LRESULT)infoPtr->hFont;
5711 }
5712
5713
5714 static void
5715 TOOLBAR_SetRelativeHotItem(TOOLBAR_INFO *infoPtr, INT iDirection, DWORD dwReason)
5716 {
5717     INT i;
5718     INT nNewHotItem = infoPtr->nHotItem;
5719
5720     for (i = 0; i < infoPtr->nNumButtons; i++)
5721     {
5722         /* did we wrap? */
5723         if ((nNewHotItem + iDirection < 0) ||
5724             (nNewHotItem + iDirection >= infoPtr->nNumButtons))
5725         {
5726             NMTBWRAPHOTITEM nmtbwhi;
5727             nmtbwhi.idNew = infoPtr->buttons[nNewHotItem].idCommand;
5728             nmtbwhi.iDirection = iDirection;
5729             nmtbwhi.dwReason = dwReason;
5730     
5731             if (TOOLBAR_SendNotify(&nmtbwhi.hdr, infoPtr, TBN_WRAPHOTITEM))
5732                 return;
5733         }
5734
5735         nNewHotItem += iDirection;
5736         nNewHotItem = (nNewHotItem + infoPtr->nNumButtons) % infoPtr->nNumButtons;
5737
5738         if ((infoPtr->buttons[nNewHotItem].fsState & TBSTATE_ENABLED) &&
5739             !(infoPtr->buttons[nNewHotItem].fsStyle & BTNS_SEP))
5740         {
5741             TOOLBAR_SetHotItemEx(infoPtr, nNewHotItem, dwReason);
5742             break;
5743         }
5744     }
5745 }
5746
5747 static LRESULT
5748 TOOLBAR_KeyDown (HWND hwnd, WPARAM wParam, LPARAM lParam)
5749 {
5750     TOOLBAR_INFO *infoPtr = TOOLBAR_GetInfoPtr (hwnd);
5751     NMKEY nmkey;
5752
5753     nmkey.nVKey = (UINT)wParam;
5754     nmkey.uFlags = HIWORD(lParam);
5755
5756     if (TOOLBAR_SendNotify(&nmkey.hdr, infoPtr, NM_KEYDOWN))
5757         return DefWindowProcW(hwnd, WM_KEYDOWN, wParam, lParam);
5758
5759     switch ((UINT)wParam)
5760     {
5761     case VK_LEFT:
5762     case VK_UP:
5763         TOOLBAR_SetRelativeHotItem(infoPtr, -1, HICF_ARROWKEYS);
5764         break;
5765     case VK_RIGHT:
5766     case VK_DOWN:
5767         TOOLBAR_SetRelativeHotItem(infoPtr, 1, HICF_ARROWKEYS);
5768         break;
5769     case VK_SPACE:
5770     case VK_RETURN:
5771         if ((infoPtr->nHotItem >= 0) &&
5772             (infoPtr->buttons[infoPtr->nHotItem].fsState & TBSTATE_ENABLED))
5773         {
5774             SendMessageW (infoPtr->hwndNotify, WM_COMMAND,
5775                 MAKEWPARAM(infoPtr->buttons[infoPtr->nHotItem].idCommand, BN_CLICKED),
5776                 (LPARAM)hwnd);
5777         }
5778         break;
5779     }
5780
5781     return 0;
5782 }
5783
5784
5785 static LRESULT
5786 TOOLBAR_LButtonDblClk (HWND hwnd, WPARAM wParam, LPARAM lParam)
5787 {
5788     POINT pt;
5789     INT   nHit;
5790
5791     pt.x = (INT)LOWORD(lParam);
5792     pt.y = (INT)HIWORD(lParam);
5793     nHit = TOOLBAR_InternalHitTest (hwnd, &pt);
5794
5795     if (nHit >= 0)
5796         TOOLBAR_LButtonDown (hwnd, wParam, lParam);
5797     else if (GetWindowLongW (hwnd, GWL_STYLE) & CCS_ADJUSTABLE)
5798         TOOLBAR_Customize (hwnd);
5799
5800     return 0;
5801 }
5802
5803
5804 static LRESULT
5805 TOOLBAR_LButtonDown (HWND hwnd, WPARAM wParam, LPARAM lParam)
5806 {
5807     TOOLBAR_INFO *infoPtr = TOOLBAR_GetInfoPtr (hwnd);
5808     TBUTTON_INFO *btnPtr;
5809     POINT pt;
5810     INT   nHit;
5811     NMTOOLBARA nmtb;
5812     NMMOUSE nmmouse;
5813     BOOL bDragKeyPressed;
5814
5815     TRACE("\n");
5816
5817     if (infoPtr->dwStyle & TBSTYLE_ALTDRAG)
5818         bDragKeyPressed = (GetKeyState(VK_MENU) < 0);
5819     else
5820         bDragKeyPressed = (wParam & MK_SHIFT);
5821
5822     if (infoPtr->hwndToolTip)
5823         TOOLBAR_RelayEvent (infoPtr->hwndToolTip, hwnd,
5824                             WM_LBUTTONDOWN, wParam, lParam);
5825
5826     pt.x = (INT)LOWORD(lParam);
5827     pt.y = (INT)HIWORD(lParam);
5828     nHit = TOOLBAR_InternalHitTest (hwnd, &pt);
5829
5830     btnPtr = &infoPtr->buttons[nHit];
5831
5832     if ((nHit >= 0) && bDragKeyPressed && (infoPtr->dwStyle & CCS_ADJUSTABLE))
5833     {
5834         infoPtr->nButtonDrag = nHit;
5835         SetCapture (hwnd);
5836         
5837         /* If drag cursor has not been loaded, load it.
5838          * Note: it doesn't need to be freed */
5839         if (!hCursorDrag)
5840             hCursorDrag = LoadCursorW(COMCTL32_hModule, (LPCWSTR)IDC_MOVEBUTTON);
5841         SetCursor(hCursorDrag);
5842     }
5843     else if (nHit >= 0)
5844     {
5845         RECT arrowRect;
5846         infoPtr->nOldHit = nHit;
5847
5848         CopyRect(&arrowRect, &btnPtr->rect);
5849         arrowRect.left = max(btnPtr->rect.left, btnPtr->rect.right - DDARROW_WIDTH);
5850
5851         /* for EX_DRAWDDARROWS style,  click must be in the drop-down arrow rect */
5852         if ((btnPtr->fsState & TBSTATE_ENABLED) && 
5853              ((btnPtr->fsStyle & BTNS_WHOLEDROPDOWN) ||
5854               ((btnPtr->fsStyle & BTNS_DROPDOWN) &&
5855                ((TOOLBAR_HasDropDownArrows(infoPtr->dwExStyle) && PtInRect(&arrowRect, pt)) ||
5856                (!TOOLBAR_HasDropDownArrows(infoPtr->dwExStyle))))))
5857         {
5858             LRESULT res;
5859
5860             /* draw in pressed state */
5861             if (btnPtr->fsStyle & BTNS_WHOLEDROPDOWN)
5862                 btnPtr->fsState |= TBSTATE_PRESSED;
5863             else
5864                 btnPtr->bDropDownPressed = TRUE;
5865             RedrawWindow(hwnd,&btnPtr->rect,0,
5866                         RDW_ERASE|RDW_INVALIDATE|RDW_UPDATENOW);
5867
5868             memset(&nmtb, 0, sizeof(nmtb));
5869             nmtb.iItem = btnPtr->idCommand;
5870             nmtb.rcButton = btnPtr->rect;
5871             res = TOOLBAR_SendNotify ((NMHDR *) &nmtb, infoPtr,
5872                                   TBN_DROPDOWN);
5873             TRACE("TBN_DROPDOWN responded with %ld\n", res);
5874
5875             if (res != TBDDRET_TREATPRESSED)
5876             {
5877                 MSG msg;
5878
5879                 /* redraw button in unpressed state */
5880                 if (btnPtr->fsStyle & BTNS_WHOLEDROPDOWN)
5881                     btnPtr->fsState &= ~TBSTATE_PRESSED;
5882                 else
5883                     btnPtr->bDropDownPressed = FALSE;
5884                 InvalidateRect(hwnd, &btnPtr->rect, TRUE);
5885
5886                 /* find and set hot item
5887                  * NOTE: native doesn't do this, but that is a bug */
5888                 GetCursorPos(&pt);
5889                 ScreenToClient(hwnd, &pt);
5890                 nHit = TOOLBAR_InternalHitTest(hwnd, &pt);
5891                 if (!infoPtr->bAnchor || (nHit >= 0))
5892                     TOOLBAR_SetHotItemEx(infoPtr, nHit, HICF_MOUSE | HICF_LMOUSE);
5893                 
5894                 /* remove any left mouse button down or double-click messages
5895                  * so that we can get a toggle effect on the button */
5896                 while (PeekMessageW(&msg, hwnd, WM_LBUTTONDOWN, WM_LBUTTONDOWN, PM_REMOVE) ||
5897                        PeekMessageW(&msg, hwnd, WM_LBUTTONDBLCLK, WM_LBUTTONDBLCLK, PM_REMOVE))
5898                     ;
5899
5900                 return 0;
5901             }
5902             /* otherwise drop through and process as pushed */
5903         }
5904         infoPtr->bCaptured = TRUE;
5905         infoPtr->nButtonDown = nHit;
5906         infoPtr->bDragOutSent = FALSE;
5907
5908         btnPtr->fsState |= TBSTATE_PRESSED;
5909
5910         TOOLBAR_SetHotItemEx(infoPtr, nHit, HICF_MOUSE | HICF_LMOUSE);
5911
5912         if (btnPtr->fsState & TBSTATE_ENABLED)
5913             InvalidateRect(hwnd, &btnPtr->rect, TRUE);
5914         UpdateWindow(hwnd);
5915         SetCapture (hwnd);
5916     }
5917
5918     if (nHit >=0)
5919     {
5920         memset(&nmtb, 0, sizeof(nmtb));
5921         nmtb.iItem = btnPtr->idCommand;
5922         TOOLBAR_SendNotify((NMHDR *)&nmtb, infoPtr, TBN_BEGINDRAG);
5923     }
5924
5925     nmmouse.dwHitInfo = nHit;
5926
5927     /* !!! Undocumented - sends NM_LDOWN with the NMMOUSE structure. */
5928     if (nHit < 0)
5929         nmmouse.dwItemSpec = -1;
5930     else
5931     {
5932         nmmouse.dwItemSpec = infoPtr->buttons[nmmouse.dwHitInfo].idCommand;
5933         nmmouse.dwItemData = infoPtr->buttons[nmmouse.dwHitInfo].dwData;
5934     }
5935
5936     ClientToScreen(hwnd, &pt); 
5937     nmmouse.pt = pt;
5938
5939     if (!TOOLBAR_SendNotify(&nmmouse.hdr, infoPtr, NM_LDOWN))
5940         return DefWindowProcW(hwnd, WM_LBUTTONDOWN, wParam, lParam);
5941
5942     return 0;
5943 }
5944
5945 static LRESULT
5946 TOOLBAR_LButtonUp (HWND hwnd, WPARAM wParam, LPARAM lParam)
5947 {
5948     TOOLBAR_INFO *infoPtr = TOOLBAR_GetInfoPtr (hwnd);
5949     TBUTTON_INFO *btnPtr;
5950     POINT pt;
5951     INT   nHit;
5952     INT   nOldIndex = -1;
5953     BOOL  bSendMessage = TRUE;
5954     NMHDR hdr;
5955     NMMOUSE nmmouse;
5956     NMTOOLBARA nmtb;
5957
5958     if (infoPtr->hwndToolTip)
5959         TOOLBAR_RelayEvent (infoPtr->hwndToolTip, hwnd,
5960                             WM_LBUTTONUP, wParam, lParam);
5961
5962     pt.x = (INT)LOWORD(lParam);
5963     pt.y = (INT)HIWORD(lParam);
5964     nHit = TOOLBAR_InternalHitTest (hwnd, &pt);
5965
5966     if (!infoPtr->bAnchor || (nHit >= 0))
5967         TOOLBAR_SetHotItemEx(infoPtr, nHit, HICF_MOUSE | HICF_LMOUSE);
5968
5969     if (infoPtr->nButtonDrag >= 0) {
5970         RECT rcClient;
5971         NMHDR hdr;
5972
5973         btnPtr = &infoPtr->buttons[infoPtr->nButtonDrag];
5974         ReleaseCapture();
5975         /* reset cursor */
5976         SetCursor(LoadCursorW(NULL, (LPCWSTR)IDC_ARROW));
5977
5978         GetClientRect(hwnd, &rcClient);
5979         if (PtInRect(&rcClient, pt))
5980         {
5981             INT nButton = -1;
5982             if (nHit >= 0)
5983                 nButton = nHit;
5984             else if (nHit < -1)
5985                 nButton = -nHit;
5986             else if ((nHit == -1) && PtInRect(&infoPtr->buttons[-nHit].rect, pt))
5987                 nButton = -nHit;
5988
5989             if (nButton == infoPtr->nButtonDrag)
5990             {
5991                 /* if the button is moved sightly left and we have a
5992                  * separator there then remove it */
5993                 if (pt.x < (btnPtr->rect.left + (btnPtr->rect.right - btnPtr->rect.left)/2))
5994                 {
5995                     if ((nButton > 0) && (infoPtr->buttons[nButton-1].fsStyle & BTNS_SEP))
5996                         TOOLBAR_DeleteButton(hwnd, nButton - 1, 0);
5997                 }
5998                 else /* else insert a separator before the dragged button */
5999                 {
6000                     TBBUTTON tbb;
6001                     memset(&tbb, 0, sizeof(tbb));
6002                     tbb.fsStyle = BTNS_SEP;
6003                     tbb.iString = -1;
6004                     TOOLBAR_InsertButtonW(hwnd, nButton, (LPARAM)&tbb);
6005                 }
6006             }
6007             else
6008             {
6009                 if (nButton == -1)
6010                 {
6011                     if ((infoPtr->nNumButtons > 0) && (pt.x < infoPtr->buttons[0].rect.left))
6012                         TOOLBAR_MoveButton(hwnd, infoPtr->nButtonDrag, 0);
6013                     else
6014                         TOOLBAR_MoveButton(hwnd, infoPtr->nButtonDrag, infoPtr->nNumButtons);
6015                 }
6016                 else
6017                     TOOLBAR_MoveButton(hwnd, infoPtr->nButtonDrag, nButton);
6018             }
6019         }
6020         else
6021         {
6022             TRACE("button %d dragged out of toolbar\n", infoPtr->nButtonDrag);
6023             TOOLBAR_DeleteButton(hwnd, (WPARAM)infoPtr->nButtonDrag, 0);
6024         }
6025
6026         /* button under cursor changed so need to re-set hot item */
6027         TOOLBAR_SetHotItemEx(infoPtr, nHit, HICF_MOUSE | HICF_LMOUSE);
6028         infoPtr->nButtonDrag = -1;
6029
6030         TOOLBAR_SendNotify(&hdr, infoPtr, TBN_TOOLBARCHANGE);
6031     }
6032     else if (infoPtr->nButtonDown >= 0) {
6033         btnPtr = &infoPtr->buttons[infoPtr->nButtonDown];
6034         btnPtr->fsState &= ~TBSTATE_PRESSED;
6035
6036         if (btnPtr->fsStyle & BTNS_CHECK) {
6037                 if (btnPtr->fsStyle & BTNS_GROUP) {
6038                     nOldIndex = TOOLBAR_GetCheckedGroupButtonIndex (infoPtr,
6039                         nHit);
6040                     if (nOldIndex == nHit)
6041                         bSendMessage = FALSE;
6042                     if ((nOldIndex != nHit) &&
6043                         (nOldIndex != -1))
6044                         infoPtr->buttons[nOldIndex].fsState &= ~TBSTATE_CHECKED;
6045                     btnPtr->fsState |= TBSTATE_CHECKED;
6046                 }
6047                 else {
6048                     if (btnPtr->fsState & TBSTATE_CHECKED)
6049                         btnPtr->fsState &= ~TBSTATE_CHECKED;
6050                     else
6051                         btnPtr->fsState |= TBSTATE_CHECKED;
6052                 }
6053         }
6054
6055         if (nOldIndex != -1)
6056             InvalidateRect(hwnd, &infoPtr->buttons[nOldIndex].rect, TRUE);
6057
6058         /*
6059          * now we can ReleaseCapture, which triggers CAPTURECHANGED msg,
6060          * that resets bCaptured and btn TBSTATE_PRESSED flags,
6061          * and obliterates nButtonDown and nOldHit (see TOOLBAR_CaptureChanged)
6062          */
6063         if ((infoPtr->bCaptured) && (infoPtr->nButtonDown >= 0))
6064             ReleaseCapture ();
6065         infoPtr->nButtonDown = -1;
6066
6067         /* Issue NM_RELEASEDCAPTURE to parent to let him know it is released */
6068         TOOLBAR_SendNotify ((NMHDR *) &hdr, infoPtr,
6069                         NM_RELEASEDCAPTURE);
6070
6071         /* native issues TBN_ENDDRAG here, if _LBUTTONDOWN issued the
6072          * TBN_BEGINDRAG
6073          */
6074         memset(&nmtb, 0, sizeof(nmtb));
6075         nmtb.iItem = btnPtr->idCommand;
6076         TOOLBAR_SendNotify ((NMHDR *) &nmtb, infoPtr,
6077                         TBN_ENDDRAG);
6078
6079         if (btnPtr->fsState & TBSTATE_ENABLED)
6080         {
6081             SendMessageW (infoPtr->hwndNotify, WM_COMMAND,
6082               MAKEWPARAM(infoPtr->buttons[nHit].idCommand, BN_CLICKED), (LPARAM)hwnd);
6083         }
6084     }
6085
6086     /* !!! Undocumented - toolbar at 4.71 level and above sends
6087     * NM_CLICK with the NMMOUSE structure. */
6088     nmmouse.dwHitInfo = nHit;
6089
6090     if (nHit < 0)
6091         nmmouse.dwItemSpec = -1;
6092     else
6093     {
6094         nmmouse.dwItemSpec = infoPtr->buttons[nmmouse.dwHitInfo].idCommand;
6095         nmmouse.dwItemData = infoPtr->buttons[nmmouse.dwHitInfo].dwData;
6096     }
6097
6098     ClientToScreen(hwnd, &pt); 
6099     nmmouse.pt = pt;
6100
6101     if (!TOOLBAR_SendNotify((LPNMHDR)&nmmouse, infoPtr, NM_CLICK))
6102         return DefWindowProcW(hwnd, WM_LBUTTONUP, wParam, lParam);
6103
6104     return 0;
6105 }
6106
6107 static LRESULT
6108 TOOLBAR_RButtonUp( HWND hwnd, WPARAM wParam, LPARAM lParam)
6109 {
6110     TOOLBAR_INFO *infoPtr = TOOLBAR_GetInfoPtr (hwnd);
6111     INT nHit;
6112     NMMOUSE nmmouse;
6113     POINT pt;
6114
6115     pt.x = LOWORD(lParam);
6116     pt.y = HIWORD(lParam);
6117
6118     nHit = TOOLBAR_InternalHitTest(hwnd, &pt);
6119     nmmouse.dwHitInfo = nHit;
6120
6121     if (nHit < 0) {
6122         nmmouse.dwItemSpec = -1;
6123     } else {
6124         nmmouse.dwItemSpec = infoPtr->buttons[nmmouse.dwHitInfo].idCommand;
6125         nmmouse.dwItemData = infoPtr->buttons[nmmouse.dwHitInfo].dwData;
6126     }
6127
6128     ClientToScreen(hwnd, &pt); 
6129     nmmouse.pt = pt;
6130
6131     if (!TOOLBAR_SendNotify((LPNMHDR)&nmmouse, infoPtr, NM_RCLICK))
6132         return DefWindowProcW(hwnd, WM_RBUTTONUP, wParam, lParam);
6133
6134     return 0;
6135 }
6136
6137 static LRESULT
6138 TOOLBAR_RButtonDblClk( HWND hwnd, WPARAM wParam, LPARAM lParam)
6139 {
6140     TOOLBAR_INFO *infoPtr = TOOLBAR_GetInfoPtr (hwnd);
6141     NMHDR nmhdr;
6142
6143     if (!TOOLBAR_SendNotify(&nmhdr, infoPtr, NM_RDBLCLK))
6144         return DefWindowProcW(hwnd, WM_RBUTTONDBLCLK, wParam, lParam);
6145
6146     return 0;
6147 }
6148
6149 static LRESULT
6150 TOOLBAR_CaptureChanged(HWND hwnd)
6151 {
6152     TOOLBAR_INFO *infoPtr = TOOLBAR_GetInfoPtr (hwnd);
6153     TBUTTON_INFO *btnPtr;
6154
6155     infoPtr->bCaptured = FALSE;
6156
6157     if (infoPtr->nButtonDown >= 0)
6158     {
6159         btnPtr = &infoPtr->buttons[infoPtr->nButtonDown];
6160         btnPtr->fsState &= ~TBSTATE_PRESSED;
6161
6162         infoPtr->nOldHit = -1;
6163
6164         if (btnPtr->fsState & TBSTATE_ENABLED)
6165             InvalidateRect(hwnd, &btnPtr->rect, TRUE);
6166     }
6167     return 0;
6168 }
6169
6170 static LRESULT
6171 TOOLBAR_MouseLeave (HWND hwnd, WPARAM wParam, LPARAM lParam)
6172 {
6173     TOOLBAR_INFO *infoPtr = TOOLBAR_GetInfoPtr (hwnd);
6174     TBUTTON_INFO *hotBtnPtr;
6175
6176     hotBtnPtr = &infoPtr->buttons[infoPtr->nOldHit];
6177
6178     /* don't remove hot effects when in anchor highlighting mode or when a
6179      * drop-down button is pressed */
6180     if (!infoPtr->bAnchor && (infoPtr->nOldHit < 0 || !hotBtnPtr->bDropDownPressed))
6181         TOOLBAR_SetHotItemEx(infoPtr, TOOLBAR_NOWHERE, HICF_MOUSE);
6182
6183     if (infoPtr->nOldHit < 0)
6184       return TRUE;
6185
6186     /* If the last button we were over is depressed then make it not */
6187     /* depressed and redraw it */
6188     if(infoPtr->nOldHit == infoPtr->nButtonDown)
6189     {
6190       TBUTTON_INFO *btnPtr;
6191       RECT rc1;
6192
6193       btnPtr = &infoPtr->buttons[infoPtr->nButtonDown];
6194
6195       btnPtr->fsState &= ~TBSTATE_PRESSED;
6196
6197       rc1 = hotBtnPtr->rect;
6198       InflateRect (&rc1, 1, 1);
6199       InvalidateRect (hwnd, &rc1, TRUE);
6200     }
6201
6202     if (infoPtr->bCaptured && !infoPtr->bDragOutSent)
6203     {
6204         NMTOOLBARW nmt;
6205         ZeroMemory(&nmt, sizeof(nmt));
6206         nmt.iItem = infoPtr->buttons[infoPtr->nButtonDown].idCommand;
6207         TOOLBAR_SendNotify(&nmt.hdr, infoPtr, TBN_DRAGOUT);
6208         infoPtr->bDragOutSent = TRUE;
6209     }
6210
6211     infoPtr->nOldHit = -1; /* reset the old hit index as we've left the toolbar */
6212
6213     return TRUE;
6214 }
6215
6216 static LRESULT
6217 TOOLBAR_MouseMove (HWND hwnd, WPARAM wParam, LPARAM lParam)
6218 {
6219     TOOLBAR_INFO *infoPtr = TOOLBAR_GetInfoPtr (hwnd);
6220     POINT pt;
6221     TRACKMOUSEEVENT trackinfo;
6222     INT   nHit;
6223     TBUTTON_INFO *btnPtr;
6224     
6225     if ((infoPtr->dwStyle & TBSTYLE_FLAT) || GetWindowTheme (infoPtr->hwndSelf)) {
6226         /* fill in the TRACKMOUSEEVENT struct */
6227         trackinfo.cbSize = sizeof(TRACKMOUSEEVENT);
6228         trackinfo.dwFlags = TME_QUERY;
6229
6230         /* call _TrackMouseEvent to see if we are currently tracking for this hwnd */
6231         _TrackMouseEvent(&trackinfo);
6232
6233         /* Make sure tracking is enabled so we receive a WM_MOUSELEAVE message */
6234         if(trackinfo.hwndTrack != hwnd || !(trackinfo.dwFlags & TME_LEAVE)) {
6235             trackinfo.dwFlags = TME_LEAVE; /* notify upon leaving */
6236             trackinfo.hwndTrack = hwnd;
6237
6238             /* call TRACKMOUSEEVENT so we receive a WM_MOUSELEAVE message */
6239             /* and can properly deactivate the hot toolbar button */
6240             _TrackMouseEvent(&trackinfo);
6241        }
6242     }
6243
6244     if (infoPtr->hwndToolTip)
6245         TOOLBAR_RelayEvent (infoPtr->hwndToolTip, hwnd,
6246                             WM_MOUSEMOVE, wParam, lParam);
6247
6248     pt.x = (INT)LOWORD(lParam);
6249     pt.y = (INT)HIWORD(lParam);
6250
6251     nHit = TOOLBAR_InternalHitTest (hwnd, &pt);
6252
6253     if (((infoPtr->dwStyle & TBSTYLE_FLAT) || GetWindowTheme (infoPtr->hwndSelf)) 
6254         && (!infoPtr->bAnchor || (nHit >= 0)))
6255         TOOLBAR_SetHotItemEx(infoPtr, nHit, HICF_MOUSE);
6256
6257     if (infoPtr->nOldHit != nHit)
6258     {
6259         if (infoPtr->bCaptured)
6260         {
6261             if (!infoPtr->bDragOutSent)
6262             {
6263                 NMTOOLBARW nmt;
6264                 ZeroMemory(&nmt, sizeof(nmt));
6265                 nmt.iItem = infoPtr->buttons[infoPtr->nButtonDown].idCommand;
6266                 TOOLBAR_SendNotify(&nmt.hdr, infoPtr, TBN_DRAGOUT);
6267                 infoPtr->bDragOutSent = TRUE;
6268             }
6269
6270             btnPtr = &infoPtr->buttons[infoPtr->nButtonDown];
6271             if (infoPtr->nOldHit == infoPtr->nButtonDown) {
6272                 btnPtr->fsState &= ~TBSTATE_PRESSED;
6273                 InvalidateRect(hwnd, &btnPtr->rect, TRUE);
6274             }
6275             else if (nHit == infoPtr->nButtonDown) {
6276                 btnPtr->fsState |= TBSTATE_PRESSED;
6277                 InvalidateRect(hwnd, &btnPtr->rect, TRUE);
6278             }
6279             infoPtr->nOldHit = nHit;
6280         }
6281     }
6282
6283     return 0;
6284 }
6285
6286
6287 inline static LRESULT
6288 TOOLBAR_NCActivate (HWND hwnd, WPARAM wParam, LPARAM lParam)
6289 {
6290 /*    if (wndPtr->dwStyle & CCS_NODIVIDER) */
6291         return DefWindowProcW (hwnd, WM_NCACTIVATE, wParam, lParam);
6292 /*    else */
6293 /*      return TOOLBAR_NCPaint (wndPtr, wParam, lParam); */
6294 }
6295
6296
6297 inline static LRESULT
6298 TOOLBAR_NCCalcSize (HWND hwnd, WPARAM wParam, LPARAM lParam)
6299 {
6300     if (!(GetWindowLongW(hwnd, GWL_STYLE) & CCS_NODIVIDER))
6301         ((LPRECT)lParam)->top += GetSystemMetrics(SM_CYEDGE);
6302
6303     return DefWindowProcW (hwnd, WM_NCCALCSIZE, wParam, lParam);
6304 }
6305
6306
6307 static LRESULT
6308 TOOLBAR_NCCreate (HWND hwnd, WPARAM wParam, LPARAM lParam)
6309 {
6310     TOOLBAR_INFO *infoPtr;
6311     LPCREATESTRUCTA cs = (LPCREATESTRUCTA)lParam;
6312     DWORD styleadd = 0;
6313
6314     /* allocate memory for info structure */
6315     infoPtr = (TOOLBAR_INFO *)Alloc (sizeof(TOOLBAR_INFO));
6316     SetWindowLongPtrW (hwnd, 0, (LONG_PTR)infoPtr);
6317
6318     /* paranoid!! */
6319     infoPtr->dwStructSize = sizeof(TBBUTTON);
6320     infoPtr->nRows = 1;
6321     infoPtr->nWidth = 0;
6322
6323     /* fix instance handle, if the toolbar was created by CreateToolbarEx() */
6324     if (!GetWindowLongPtrW (hwnd, GWLP_HINSTANCE)) {
6325         HINSTANCE hInst = (HINSTANCE)GetWindowLongPtrW (GetParent (hwnd), GWLP_HINSTANCE);
6326         SetWindowLongPtrW (hwnd, GWLP_HINSTANCE, (LONG_PTR)hInst);
6327     }
6328
6329     /* native control does:
6330      *    Get a lot of colors and brushes
6331      *    WM_NOTIFYFORMAT
6332      *    SystemParametersInfoW(0x1f, 0x3c, adr1, 0)
6333      *    CreateFontIndirectW(adr1)
6334      *    CreateBitmap(0x27, 0x24, 1, 1, 0)
6335      *    hdc = GetDC(toolbar)
6336      *    GetSystemMetrics(0x48)
6337      *    fnt2=CreateFontW(0xe, 0, 0, 0, 0x190, 0, 0, 0, 0, 2,
6338      *                     0, 0, 0, 0, "MARLETT")
6339      *    oldfnt = SelectObject(hdc, fnt2)
6340      *    GetCharWidthW(hdc, 0x36, 0x36, adr2)
6341      *    GetTextMetricsW(hdc, adr3)
6342      *    SelectObject(hdc, oldfnt)
6343      *    DeleteObject(fnt2)
6344      *    ReleaseDC(hdc)
6345      *    InvalidateRect(toolbar, 0, 1)
6346      *    SetWindowLongW(toolbar, 0, addr)
6347      *    SetWindowLongW(toolbar, -16, xxx)  **sometimes**
6348      *                                          WM_STYLECHANGING
6349      *                             CallWinEx   old         new
6350      *                       ie 1  0x56000a4c  0x46000a4c  0x56008a4d
6351      *                       ie 2  0x4600094c  0x4600094c  0x4600894d
6352      *                       ie 3  0x56000b4c  0x46000b4c  0x56008b4d
6353      *                      rebar  0x50008844  0x40008844  0x50008845
6354      *                      pager  0x50000844  0x40000844  0x50008845
6355      *                    IC35mgr  0x5400084e  **nochange**
6356      *           on entry to _NCCREATE         0x5400084e
6357      *                    rowlist  0x5400004e  **nochange**
6358      *           on entry to _NCCREATE         0x5400004e
6359      *
6360      */
6361
6362     /* I think the code below is a bug, but it is the way that the native
6363      * controls seem to work. The effect is that if the user of TBSTYLE_FLAT
6364      * forgets to specify TBSTYLE_TRANSPARENT but does specify either
6365      * CCS_TOP or CCS_BOTTOM (_NOMOVEY and _TOP), then the control
6366      * does *not* set TBSTYLE_TRANSPARENT even though it should!!!!
6367      * Somehow, the only cases of this seem to be MFC programs.
6368      *
6369      * Note also that the addition of _TRANSPARENT occurs *only* here. It
6370      * does not occur in the WM_STYLECHANGING routine.
6371      *    (Guy Albertelli   9/2001)
6372      *
6373      */
6374     if (((infoPtr->dwStyle & TBSTYLE_FLAT) || GetWindowTheme (infoPtr->hwndSelf)) 
6375         && !(cs->style & TBSTYLE_TRANSPARENT))
6376         styleadd |= TBSTYLE_TRANSPARENT;
6377     if (!(cs->style & (CCS_TOP | CCS_NOMOVEY))) {
6378         styleadd |= CCS_TOP;   /* default to top */
6379         SetWindowLongW (hwnd, GWL_STYLE, cs->style | styleadd);
6380     }
6381
6382     return DefWindowProcW (hwnd, WM_NCCREATE, wParam, lParam);
6383 }
6384
6385
6386 static LRESULT
6387 TOOLBAR_NCPaint (HWND hwnd, WPARAM wParam, LPARAM lParam)
6388 {
6389     DWORD dwStyle = GetWindowLongW(hwnd, GWL_STYLE);
6390     RECT rcWindow;
6391     HDC hdc;
6392
6393     if (dwStyle & WS_MINIMIZE)
6394         return 0; /* Nothing to do */
6395
6396     DefWindowProcW (hwnd, WM_NCPAINT, wParam, lParam);
6397
6398     if (!(hdc = GetDCEx (hwnd, 0, DCX_USESTYLE | DCX_WINDOW)))
6399         return 0;
6400
6401     if (!(dwStyle & CCS_NODIVIDER))
6402     {
6403         GetWindowRect (hwnd, &rcWindow);
6404         OffsetRect (&rcWindow, -rcWindow.left, -rcWindow.top);
6405         if( dwStyle & WS_BORDER )
6406             OffsetRect (&rcWindow, 1, 1);
6407         DrawEdge (hdc, &rcWindow, EDGE_ETCHED, BF_TOP);
6408     }
6409
6410     ReleaseDC( hwnd, hdc );
6411
6412     return 0;
6413 }
6414
6415
6416 /* handles requests from the tooltip control on what text to display */
6417 static LRESULT TOOLBAR_TTGetDispInfo (TOOLBAR_INFO *infoPtr, NMTTDISPINFOW *lpnmtdi)
6418 {
6419     int index = TOOLBAR_GetButtonIndex(infoPtr, lpnmtdi->hdr.idFrom, FALSE);
6420
6421     TRACE("button index = %d\n", index);
6422
6423     Free (infoPtr->pszTooltipText);
6424     infoPtr->pszTooltipText = NULL;
6425
6426     if (index < 0)
6427         return 0;
6428
6429     if (infoPtr->bUnicode)
6430     {
6431         WCHAR wszBuffer[INFOTIPSIZE+1];
6432         NMTBGETINFOTIPW tbgit;
6433         unsigned int len; /* in chars */
6434
6435         wszBuffer[0] = '\0';
6436         wszBuffer[INFOTIPSIZE] = '\0';
6437
6438         tbgit.pszText = wszBuffer;
6439         tbgit.cchTextMax = INFOTIPSIZE;
6440         tbgit.iItem = lpnmtdi->hdr.idFrom;
6441         tbgit.lParam = infoPtr->buttons[index].dwData;
6442
6443         TOOLBAR_SendNotify(&tbgit.hdr, infoPtr, TBN_GETINFOTIPW);
6444
6445         TRACE("TBN_GETINFOTIPW - got string %s\n", debugstr_w(tbgit.pszText));
6446
6447         len = strlenW(tbgit.pszText);
6448         if (len > sizeof(lpnmtdi->szText)/sizeof(lpnmtdi->szText[0])-1)
6449         {
6450             /* need to allocate temporary buffer in infoPtr as there
6451              * isn't enough space in buffer passed to us by the
6452              * tooltip control */
6453             infoPtr->pszTooltipText = Alloc((len+1)*sizeof(WCHAR));
6454             if (infoPtr->pszTooltipText)
6455             {
6456                 memcpy(infoPtr->pszTooltipText, tbgit.pszText, (len+1)*sizeof(WCHAR));
6457                 lpnmtdi->lpszText = infoPtr->pszTooltipText;
6458                 return 0;
6459             }
6460         }
6461         else if (len > 0)
6462         {
6463             memcpy(lpnmtdi->lpszText, tbgit.pszText, (len+1)*sizeof(WCHAR));
6464             return 0;
6465         }
6466     }
6467     else
6468     {
6469         CHAR szBuffer[INFOTIPSIZE+1];
6470         NMTBGETINFOTIPA tbgit;
6471         unsigned int len; /* in chars */
6472
6473         szBuffer[0] = '\0';
6474         szBuffer[INFOTIPSIZE] = '\0';
6475
6476         tbgit.pszText = szBuffer;
6477         tbgit.cchTextMax = INFOTIPSIZE;
6478         tbgit.iItem = lpnmtdi->hdr.idFrom;
6479         tbgit.lParam = infoPtr->buttons[index].dwData;
6480
6481         TOOLBAR_SendNotify(&tbgit.hdr, infoPtr, TBN_GETINFOTIPA);
6482
6483         TRACE("TBN_GETINFOTIPA - got string %s\n", debugstr_a(tbgit.pszText));
6484
6485         len = MultiByteToWideChar(CP_ACP, 0, tbgit.pszText, -1, NULL, 0);
6486         if (len > sizeof(lpnmtdi->szText)/sizeof(lpnmtdi->szText[0]))
6487         {
6488             /* need to allocate temporary buffer in infoPtr as there
6489              * isn't enough space in buffer passed to us by the
6490              * tooltip control */
6491             infoPtr->pszTooltipText = Alloc(len*sizeof(WCHAR));
6492             if (infoPtr->pszTooltipText)
6493             {
6494                 MultiByteToWideChar(CP_ACP, 0, tbgit.pszText, -1, infoPtr->pszTooltipText, len);
6495                 lpnmtdi->lpszText = infoPtr->pszTooltipText;
6496                 return 0;
6497             }
6498         }
6499         else if (len > 0)
6500         {
6501             MultiByteToWideChar(CP_ACP, 0, tbgit.pszText, -1,
6502                                 lpnmtdi->lpszText, sizeof(lpnmtdi->szText)/sizeof(lpnmtdi->szText[0]));
6503             return 0;
6504         }
6505     }
6506
6507     /* if button has text, but it is not shown then automatically
6508      * use that text as tooltip */
6509     if ((infoPtr->dwExStyle & TBSTYLE_EX_MIXEDBUTTONS) &&
6510         !(infoPtr->buttons[index].fsStyle & BTNS_SHOWTEXT))
6511     {
6512         LPWSTR pszText = TOOLBAR_GetText(infoPtr, &infoPtr->buttons[index]);
6513         unsigned int len = pszText ? strlenW(pszText) : 0;
6514
6515         TRACE("using button hidden text %s\n", debugstr_w(pszText));
6516
6517         if (len > sizeof(lpnmtdi->szText)/sizeof(lpnmtdi->szText[0])-1)
6518         {
6519             /* need to allocate temporary buffer in infoPtr as there
6520              * isn't enough space in buffer passed to us by the
6521              * tooltip control */
6522             infoPtr->pszTooltipText = Alloc((len+1)*sizeof(WCHAR));
6523             if (infoPtr->pszTooltipText)
6524             {
6525                 memcpy(infoPtr->pszTooltipText, pszText, (len+1)*sizeof(WCHAR));
6526                 lpnmtdi->lpszText = infoPtr->pszTooltipText;
6527                 return 0;
6528             }
6529         }
6530         else if (len > 0)
6531         {
6532             memcpy(lpnmtdi->lpszText, pszText, (len+1)*sizeof(WCHAR));
6533             return 0;
6534         }
6535     }
6536
6537     TRACE("Sending tooltip notification to %p\n", infoPtr->hwndNotify);
6538
6539     /* last resort: send notification on to app */
6540     /* FIXME: find out what is really used here */
6541     return SendMessageW(infoPtr->hwndNotify, WM_NOTIFY, 0, (LPARAM)lpnmtdi);
6542 }
6543
6544
6545 inline static LRESULT
6546 TOOLBAR_Notify (HWND hwnd, WPARAM wParam, LPARAM lParam)
6547 {
6548     TOOLBAR_INFO *infoPtr = TOOLBAR_GetInfoPtr (hwnd);
6549     LPNMHDR lpnmh = (LPNMHDR)lParam;
6550
6551     switch (lpnmh->code)
6552     {
6553     case PGN_CALCSIZE:
6554     {
6555         LPNMPGCALCSIZE lppgc = (LPNMPGCALCSIZE)lParam;
6556
6557         if (lppgc->dwFlag == PGF_CALCWIDTH) {
6558             lppgc->iWidth = infoPtr->rcBound.right - infoPtr->rcBound.left;
6559             TRACE("processed PGN_CALCSIZE, returning horz size = %d\n",
6560                   lppgc->iWidth);
6561         }
6562         else {
6563             lppgc->iHeight = infoPtr->rcBound.bottom - infoPtr->rcBound.top;
6564             TRACE("processed PGN_CALCSIZE, returning vert size = %d\n",
6565                   lppgc->iHeight);
6566         }
6567         return 0;
6568     }
6569
6570     case PGN_SCROLL:
6571     {
6572         LPNMPGSCROLL lppgs = (LPNMPGSCROLL)lParam;
6573
6574         lppgs->iScroll = (lppgs->iDir & (PGF_SCROLLLEFT | PGF_SCROLLRIGHT)) ?
6575                           infoPtr->nButtonWidth : infoPtr->nButtonHeight;
6576         TRACE("processed PGN_SCROLL, returning scroll=%d, dir=%d\n",
6577               lppgs->iScroll, lppgs->iDir);
6578         return 0;
6579     }
6580
6581     case TTN_GETDISPINFOW:
6582         return TOOLBAR_TTGetDispInfo(infoPtr, (LPNMTTDISPINFOW)lParam);
6583
6584     case TTN_GETDISPINFOA:
6585         FIXME("TTN_GETDISPINFOA - should not be received; please report\n");
6586         return 0;
6587
6588     default:
6589         return 0;
6590     }
6591 }
6592
6593
6594 static LRESULT
6595 TOOLBAR_NotifyFormat(TOOLBAR_INFO *infoPtr, WPARAM wParam, LPARAM lParam)
6596 {
6597     LRESULT format;
6598
6599     TRACE("wParam = 0x%x, lParam = 0x%08lx\n", wParam, lParam);
6600
6601     if (lParam == NF_QUERY)
6602         return NFR_UNICODE;
6603
6604     if (lParam == NF_REQUERY) {
6605         format = SendMessageW(infoPtr->hwndNotify,
6606                          WM_NOTIFYFORMAT, (WPARAM)infoPtr->hwndSelf, NF_QUERY);
6607         if ((format != NFR_ANSI) && (format != NFR_UNICODE)) {
6608             ERR("wrong response to WM_NOTIFYFORMAT (%ld), assuming ANSI\n",
6609                 format);
6610             format = NFR_ANSI;
6611         }
6612         return format;
6613     }
6614     return 0;
6615 }
6616
6617
6618 static LRESULT
6619 TOOLBAR_Paint (HWND hwnd, WPARAM wParam)
6620 {
6621     TOOLBAR_INFO *infoPtr = TOOLBAR_GetInfoPtr(hwnd);
6622     HDC hdc;
6623     PAINTSTRUCT ps;
6624
6625     /* fill ps.rcPaint with a default rect */
6626     memcpy(&(ps.rcPaint), &(infoPtr->rcBound), sizeof(infoPtr->rcBound));
6627
6628     hdc = wParam==0 ? BeginPaint(hwnd, &ps) : (HDC)wParam;
6629
6630     TRACE("psrect=(%ld,%ld)-(%ld,%ld)\n",
6631           ps.rcPaint.left, ps.rcPaint.top,
6632           ps.rcPaint.right, ps.rcPaint.bottom);
6633
6634     TOOLBAR_Refresh (hwnd, hdc, &ps);
6635     if (!wParam) EndPaint (hwnd, &ps);
6636
6637     return 0;
6638 }
6639
6640
6641 static LRESULT
6642 TOOLBAR_SetFocus (HWND hwnd, WPARAM wParam)
6643 {
6644     TOOLBAR_INFO *infoPtr = TOOLBAR_GetInfoPtr (hwnd);
6645
6646     TRACE("nHotItem = %d\n", infoPtr->nHotItem);
6647
6648     /* make first item hot */
6649     if (infoPtr->nNumButtons > 0)
6650         TOOLBAR_SetHotItemEx(infoPtr, 0, HICF_OTHER);
6651
6652     return 0;
6653 }
6654
6655
6656 static LRESULT
6657 TOOLBAR_SetRedraw (HWND hwnd, WPARAM wParam, LPARAM lParam)
6658      /*****************************************************
6659       *
6660       * Function;
6661       *  Handles the WM_SETREDRAW message.
6662       *
6663       * Documentation:
6664       *  According to testing V4.71 of COMCTL32 returns the
6665       *  *previous* status of the redraw flag (either 0 or 1)
6666       *  instead of the MSDN documented value of 0 if handled.
6667       *  (For laughs see the "consistency" with same function
6668       *   in rebar.)
6669       *
6670       *****************************************************/
6671 {
6672     TOOLBAR_INFO *infoPtr = TOOLBAR_GetInfoPtr (hwnd);
6673     BOOL oldredraw = infoPtr->bDoRedraw;
6674
6675     TRACE("set to %s\n",
6676           (wParam) ? "TRUE" : "FALSE");
6677     infoPtr->bDoRedraw = (BOOL) wParam;
6678     if (wParam) {
6679         InvalidateRect (infoPtr->hwndSelf, 0, TRUE);
6680     }
6681     return (oldredraw) ? 1 : 0;
6682 }
6683
6684
6685 static LRESULT
6686 TOOLBAR_Size (HWND hwnd, WPARAM wParam, LPARAM lParam)
6687 {
6688     TOOLBAR_INFO *infoPtr = TOOLBAR_GetInfoPtr (hwnd);
6689
6690     TRACE("sizing toolbar!\n");
6691
6692     if (infoPtr->dwExStyle & TBSTYLE_EX_HIDECLIPPEDBUTTONS)
6693     {
6694         RECT delta_width, delta_height, client, dummy;
6695         DWORD min_x, max_x, min_y, max_y;
6696         TBUTTON_INFO *btnPtr;
6697         INT i;
6698
6699         GetClientRect(hwnd, &client);
6700         if(client.right > infoPtr->client_rect.right)
6701         {
6702             min_x = infoPtr->client_rect.right;
6703             max_x = client.right;
6704         }
6705         else
6706         {
6707             max_x = infoPtr->client_rect.right;
6708             min_x = client.right;
6709         }
6710         if(client.bottom > infoPtr->client_rect.bottom)
6711         {
6712             min_y = infoPtr->client_rect.bottom;
6713             max_y = client.bottom;
6714         }
6715         else
6716         {
6717             max_y = infoPtr->client_rect.bottom;
6718             min_y = client.bottom;
6719         }
6720
6721         SetRect(&delta_width, min_x, 0, max_x, min_y);
6722         SetRect(&delta_height, 0, min_y, max_x, max_y);
6723
6724         TRACE("delta_width %s delta_height %s\n", wine_dbgstr_rect(&delta_width), wine_dbgstr_rect(&delta_height));
6725         btnPtr = infoPtr->buttons;
6726         for (i = 0; i < infoPtr->nNumButtons; i++, btnPtr++)
6727             if(IntersectRect(&dummy, &delta_width, &btnPtr->rect) ||
6728                 IntersectRect(&dummy, &delta_height, &btnPtr->rect))
6729                 InvalidateRect(hwnd, &btnPtr->rect, TRUE);
6730     }
6731     GetClientRect(hwnd, &infoPtr->client_rect);
6732     TOOLBAR_AutoSize(hwnd);
6733     return 0;
6734 }
6735
6736
6737 static LRESULT
6738 TOOLBAR_StyleChanged (HWND hwnd, INT nType, LPSTYLESTRUCT lpStyle)
6739 {
6740     TOOLBAR_INFO *infoPtr = TOOLBAR_GetInfoPtr (hwnd);
6741
6742     if (nType == GWL_STYLE)
6743     {
6744         if (lpStyle->styleNew & TBSTYLE_LIST)
6745             infoPtr->dwDTFlags = DT_LEFT | DT_VCENTER | DT_SINGLELINE | DT_END_ELLIPSIS;
6746         else
6747             infoPtr->dwDTFlags = DT_CENTER | DT_END_ELLIPSIS;
6748
6749         TOOLBAR_CheckStyle (hwnd, lpStyle->styleNew);
6750
6751         TRACE("new style 0x%08lx\n", lpStyle->styleNew);
6752
6753         infoPtr->dwStyle = lpStyle->styleNew;
6754
6755         /* only resize if one of the CCS_* styles was changed */
6756         if ((infoPtr->dwStyle ^ lpStyle->styleNew) & COMMON_STYLES)
6757         {
6758             TOOLBAR_AutoSize (hwnd);
6759     
6760             InvalidateRect(hwnd, NULL, TRUE);
6761         }
6762     }
6763
6764     return 0;
6765 }
6766
6767
6768 static LRESULT
6769 TOOLBAR_SysColorChange (HWND hwnd)
6770 {
6771     COMCTL32_RefreshSysColors();
6772
6773     return 0;
6774 }
6775
6776
6777 /* update theme after a WM_THEMECHANGED message */
6778 static LRESULT theme_changed (HWND hwnd)
6779 {
6780     HTHEME theme = GetWindowTheme (hwnd);
6781     CloseThemeData (theme);
6782     OpenThemeData (hwnd, themeClass);
6783     return 0;
6784 }
6785
6786
6787 static LRESULT WINAPI
6788 ToolbarWindowProc (HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
6789 {
6790     TOOLBAR_INFO *infoPtr = TOOLBAR_GetInfoPtr (hwnd);
6791
6792     TRACE("hwnd=%p msg=%x wparam=%x lparam=%lx\n",
6793           hwnd, uMsg, /* SPY_GetMsgName(uMsg), */ wParam, lParam);
6794
6795     if (!infoPtr && (uMsg != WM_NCCREATE))
6796         return DefWindowProcW( hwnd, uMsg, wParam, lParam );
6797
6798     switch (uMsg)
6799     {
6800         case TB_ADDBITMAP:
6801             return TOOLBAR_AddBitmap (hwnd, wParam, lParam);
6802
6803         case TB_ADDBUTTONSA:
6804             return TOOLBAR_AddButtonsA (hwnd, wParam, lParam);
6805
6806         case TB_ADDBUTTONSW:
6807             return TOOLBAR_AddButtonsW (hwnd, wParam, lParam);
6808
6809         case TB_ADDSTRINGA:
6810             return TOOLBAR_AddStringA (hwnd, wParam, lParam);
6811
6812         case TB_ADDSTRINGW:
6813             return TOOLBAR_AddStringW (hwnd, wParam, lParam);
6814
6815         case TB_AUTOSIZE:
6816             return TOOLBAR_AutoSize (hwnd);
6817
6818         case TB_BUTTONCOUNT:
6819             return TOOLBAR_ButtonCount (hwnd, wParam, lParam);
6820
6821         case TB_BUTTONSTRUCTSIZE:
6822             return TOOLBAR_ButtonStructSize (hwnd, wParam, lParam);
6823
6824         case TB_CHANGEBITMAP:
6825             return TOOLBAR_ChangeBitmap (hwnd, wParam, lParam);
6826
6827         case TB_CHECKBUTTON:
6828             return TOOLBAR_CheckButton (hwnd, wParam, lParam);
6829
6830         case TB_COMMANDTOINDEX:
6831             return TOOLBAR_CommandToIndex (hwnd, wParam, lParam);
6832
6833         case TB_CUSTOMIZE:
6834             return TOOLBAR_Customize (hwnd);
6835
6836         case TB_DELETEBUTTON:
6837             return TOOLBAR_DeleteButton (hwnd, wParam, lParam);
6838
6839         case TB_ENABLEBUTTON:
6840             return TOOLBAR_EnableButton (hwnd, wParam, lParam);
6841
6842         case TB_GETANCHORHIGHLIGHT:
6843             return TOOLBAR_GetAnchorHighlight (hwnd);
6844
6845         case TB_GETBITMAP:
6846             return TOOLBAR_GetBitmap (hwnd, wParam, lParam);
6847
6848         case TB_GETBITMAPFLAGS:
6849             return TOOLBAR_GetBitmapFlags (hwnd, wParam, lParam);
6850
6851         case TB_GETBUTTON:
6852             return TOOLBAR_GetButton (hwnd, wParam, lParam);
6853
6854         case TB_GETBUTTONINFOA:
6855             return TOOLBAR_GetButtonInfoA (hwnd, wParam, lParam);
6856
6857         case TB_GETBUTTONINFOW:
6858             return TOOLBAR_GetButtonInfoW (hwnd, wParam, lParam);
6859
6860         case TB_GETBUTTONSIZE:
6861             return TOOLBAR_GetButtonSize (hwnd);
6862
6863         case TB_GETBUTTONTEXTA:
6864             return TOOLBAR_GetButtonTextA (hwnd, wParam, lParam);
6865
6866         case TB_GETBUTTONTEXTW:
6867             return TOOLBAR_GetButtonTextW (hwnd, wParam, lParam);
6868
6869         case TB_GETDISABLEDIMAGELIST:
6870             return TOOLBAR_GetDisabledImageList (hwnd, wParam, lParam);
6871
6872         case TB_GETEXTENDEDSTYLE:
6873             return TOOLBAR_GetExtendedStyle (hwnd);
6874
6875         case TB_GETHOTIMAGELIST:
6876             return TOOLBAR_GetHotImageList (hwnd, wParam, lParam);
6877
6878         case TB_GETHOTITEM:
6879             return TOOLBAR_GetHotItem (hwnd);
6880
6881         case TB_GETIMAGELIST:
6882             return TOOLBAR_GetDefImageList (hwnd, wParam, lParam);
6883
6884         case TB_GETINSERTMARK:
6885             return TOOLBAR_GetInsertMark (hwnd, wParam, lParam);
6886
6887         case TB_GETINSERTMARKCOLOR:
6888             return TOOLBAR_GetInsertMarkColor (hwnd, wParam, lParam);
6889
6890         case TB_GETITEMRECT:
6891             return TOOLBAR_GetItemRect (hwnd, wParam, lParam);
6892
6893         case TB_GETMAXSIZE:
6894             return TOOLBAR_GetMaxSize (hwnd, wParam, lParam);
6895
6896 /*      case TB_GETOBJECT:                      */ /* 4.71 */
6897
6898         case TB_GETPADDING:
6899             return TOOLBAR_GetPadding (hwnd);
6900
6901         case TB_GETRECT:
6902             return TOOLBAR_GetRect (hwnd, wParam, lParam);
6903
6904         case TB_GETROWS:
6905             return TOOLBAR_GetRows (hwnd, wParam, lParam);
6906
6907         case TB_GETSTATE:
6908             return TOOLBAR_GetState (hwnd, wParam, lParam);
6909
6910         case TB_GETSTRINGA:
6911         return TOOLBAR_GetStringA (hwnd, wParam, lParam);
6912
6913         case TB_GETSTRINGW:
6914             return TOOLBAR_GetStringW (hwnd, wParam, lParam);
6915
6916         case TB_GETSTYLE:
6917             return TOOLBAR_GetStyle (hwnd, wParam, lParam);
6918
6919         case TB_GETTEXTROWS:
6920             return TOOLBAR_GetTextRows (hwnd, wParam, lParam);
6921
6922         case TB_GETTOOLTIPS:
6923             return TOOLBAR_GetToolTips (hwnd, wParam, lParam);
6924
6925         case TB_GETUNICODEFORMAT:
6926             return TOOLBAR_GetUnicodeFormat (hwnd, wParam, lParam);
6927
6928         case TB_HIDEBUTTON:
6929             return TOOLBAR_HideButton (hwnd, wParam, lParam);
6930
6931         case TB_HITTEST:
6932             return TOOLBAR_HitTest (hwnd, wParam, lParam);
6933
6934         case TB_INDETERMINATE:
6935             return TOOLBAR_Indeterminate (hwnd, wParam, lParam);
6936
6937         case TB_INSERTBUTTONA:
6938             return TOOLBAR_InsertButtonA (hwnd, wParam, lParam);
6939
6940         case TB_INSERTBUTTONW:
6941             return TOOLBAR_InsertButtonW (hwnd, wParam, lParam);
6942
6943 /*      case TB_INSERTMARKHITTEST:              */ /* 4.71 */
6944
6945         case TB_ISBUTTONCHECKED:
6946             return TOOLBAR_IsButtonChecked (hwnd, wParam, lParam);
6947
6948         case TB_ISBUTTONENABLED:
6949             return TOOLBAR_IsButtonEnabled (hwnd, wParam, lParam);
6950
6951         case TB_ISBUTTONHIDDEN:
6952             return TOOLBAR_IsButtonHidden (hwnd, wParam, lParam);
6953
6954         case TB_ISBUTTONHIGHLIGHTED:
6955             return TOOLBAR_IsButtonHighlighted (hwnd, wParam, lParam);
6956
6957         case TB_ISBUTTONINDETERMINATE:
6958             return TOOLBAR_IsButtonIndeterminate (hwnd, wParam, lParam);
6959
6960         case TB_ISBUTTONPRESSED:
6961             return TOOLBAR_IsButtonPressed (hwnd, wParam, lParam);
6962
6963         case TB_LOADIMAGES:
6964             return TOOLBAR_LoadImages (hwnd, wParam, lParam);
6965
6966         case TB_MAPACCELERATORA:
6967         case TB_MAPACCELERATORW:
6968             return TOOLBAR_MapAccelerator (hwnd, wParam, lParam);
6969
6970         case TB_MARKBUTTON:
6971             return TOOLBAR_MarkButton (hwnd, wParam, lParam);
6972
6973         case TB_MOVEBUTTON:
6974             return TOOLBAR_MoveButton (hwnd, wParam, lParam);
6975
6976         case TB_PRESSBUTTON:
6977             return TOOLBAR_PressButton (hwnd, wParam, lParam);
6978
6979         case TB_REPLACEBITMAP:
6980             return TOOLBAR_ReplaceBitmap (hwnd, wParam, lParam);
6981
6982         case TB_SAVERESTOREA:
6983             return TOOLBAR_SaveRestoreA (hwnd, wParam, (LPTBSAVEPARAMSA)lParam);
6984
6985         case TB_SAVERESTOREW:
6986             return TOOLBAR_SaveRestoreW (hwnd, wParam, (LPTBSAVEPARAMSW)lParam);
6987
6988         case TB_SETANCHORHIGHLIGHT:
6989             return TOOLBAR_SetAnchorHighlight (hwnd, wParam);
6990
6991         case TB_SETBITMAPSIZE:
6992             return TOOLBAR_SetBitmapSize (hwnd, wParam, lParam);
6993
6994         case TB_SETBUTTONINFOA:
6995             return TOOLBAR_SetButtonInfoA (hwnd, wParam, lParam);
6996
6997         case TB_SETBUTTONINFOW:
6998             return TOOLBAR_SetButtonInfoW (hwnd, wParam, lParam);
6999
7000         case TB_SETBUTTONSIZE:
7001             return TOOLBAR_SetButtonSize (hwnd, wParam, lParam);
7002
7003         case TB_SETBUTTONWIDTH:
7004             return TOOLBAR_SetButtonWidth (hwnd, wParam, lParam);
7005
7006         case TB_SETCMDID:
7007             return TOOLBAR_SetCmdId (hwnd, wParam, lParam);
7008
7009         case TB_SETDISABLEDIMAGELIST:
7010             return TOOLBAR_SetDisabledImageList (hwnd, wParam, lParam);
7011
7012         case TB_SETDRAWTEXTFLAGS:
7013             return TOOLBAR_SetDrawTextFlags (hwnd, wParam, lParam);
7014
7015         case TB_SETEXTENDEDSTYLE:
7016             return TOOLBAR_SetExtendedStyle (hwnd, wParam, lParam);
7017
7018         case TB_SETHOTIMAGELIST:
7019             return TOOLBAR_SetHotImageList (hwnd, wParam, lParam);
7020
7021         case TB_SETHOTITEM:
7022             return TOOLBAR_SetHotItem (hwnd, wParam);
7023
7024         case TB_SETIMAGELIST:
7025             return TOOLBAR_SetImageList (hwnd, wParam, lParam);
7026
7027         case TB_SETINDENT:
7028             return TOOLBAR_SetIndent (hwnd, wParam, lParam);
7029
7030         case TB_SETINSERTMARK:
7031             return TOOLBAR_SetInsertMark (hwnd, wParam, lParam);
7032
7033         case TB_SETINSERTMARKCOLOR:
7034             return TOOLBAR_SetInsertMarkColor (hwnd, wParam, lParam);
7035
7036         case TB_SETMAXTEXTROWS:
7037             return TOOLBAR_SetMaxTextRows (hwnd, wParam, lParam);
7038
7039         case TB_SETPADDING:
7040             return TOOLBAR_SetPadding (hwnd, wParam, lParam);
7041
7042         case TB_SETPARENT:
7043             return TOOLBAR_SetParent (hwnd, wParam, lParam);
7044
7045         case TB_SETROWS:
7046             return TOOLBAR_SetRows (hwnd, wParam, lParam);
7047
7048         case TB_SETSTATE:
7049             return TOOLBAR_SetState (hwnd, wParam, lParam);
7050
7051         case TB_SETSTYLE:
7052             return TOOLBAR_SetStyle (hwnd, wParam, lParam);
7053
7054         case TB_SETTOOLTIPS:
7055             return TOOLBAR_SetToolTips (hwnd, wParam, lParam);
7056
7057         case TB_SETUNICODEFORMAT:
7058             return TOOLBAR_SetUnicodeFormat (hwnd, wParam, lParam);
7059
7060         case TB_UNKWN45D:
7061             return TOOLBAR_Unkwn45D(hwnd, wParam, lParam);
7062
7063         case TB_UNKWN45E:
7064             return TOOLBAR_Unkwn45E (hwnd, wParam, lParam);
7065
7066         case TB_UNKWN460:
7067             return TOOLBAR_Unkwn460(hwnd, wParam, lParam);
7068
7069         case TB_UNKWN462:
7070             return TOOLBAR_Unkwn462(hwnd, wParam, lParam);
7071
7072         case TB_UNKWN463:
7073             return TOOLBAR_Unkwn463 (hwnd, wParam, lParam);
7074
7075         case TB_UNKWN464:
7076             return TOOLBAR_Unkwn464(hwnd, wParam, lParam);
7077
7078 /* Common Control Messages */
7079
7080 /*      case TB_GETCOLORSCHEME:                 */ /* identical to CCM_ */
7081         case CCM_GETCOLORSCHEME:
7082             return TOOLBAR_GetColorScheme (hwnd, (LPCOLORSCHEME)lParam);
7083
7084 /*      case TB_SETCOLORSCHEME:                 */ /* identical to CCM_ */
7085         case CCM_SETCOLORSCHEME:
7086             return TOOLBAR_SetColorScheme (hwnd, (LPCOLORSCHEME)lParam);
7087
7088         case CCM_GETVERSION:
7089             return TOOLBAR_GetVersion (hwnd);
7090
7091         case CCM_SETVERSION:
7092             return TOOLBAR_SetVersion (hwnd, (INT)wParam);
7093
7094
7095 /*      case WM_CHAR: */
7096
7097         case WM_CREATE:
7098             return TOOLBAR_Create (hwnd, wParam, lParam);
7099
7100         case WM_DESTROY:
7101           return TOOLBAR_Destroy (hwnd, wParam, lParam);
7102
7103         case WM_ERASEBKGND:
7104             return TOOLBAR_EraseBackground (hwnd, wParam, lParam);
7105
7106         case WM_GETFONT:
7107                 return TOOLBAR_GetFont (hwnd, wParam, lParam);
7108
7109         case WM_KEYDOWN:
7110             return TOOLBAR_KeyDown (hwnd, wParam, lParam);
7111
7112 /*      case WM_KILLFOCUS: */
7113
7114         case WM_LBUTTONDBLCLK:
7115             return TOOLBAR_LButtonDblClk (hwnd, wParam, lParam);
7116
7117         case WM_LBUTTONDOWN:
7118             return TOOLBAR_LButtonDown (hwnd, wParam, lParam);
7119
7120         case WM_LBUTTONUP:
7121             return TOOLBAR_LButtonUp (hwnd, wParam, lParam);
7122
7123         case WM_RBUTTONUP:
7124             return TOOLBAR_RButtonUp (hwnd, wParam, lParam);
7125
7126         case WM_RBUTTONDBLCLK:
7127             return TOOLBAR_RButtonDblClk (hwnd, wParam, lParam);
7128
7129         case WM_MOUSEMOVE:
7130             return TOOLBAR_MouseMove (hwnd, wParam, lParam);
7131
7132         case WM_MOUSELEAVE:
7133             return TOOLBAR_MouseLeave (hwnd, wParam, lParam);
7134
7135         case WM_CAPTURECHANGED:
7136             return TOOLBAR_CaptureChanged(hwnd);
7137
7138         case WM_NCACTIVATE:
7139             return TOOLBAR_NCActivate (hwnd, wParam, lParam);
7140
7141         case WM_NCCALCSIZE:
7142             return TOOLBAR_NCCalcSize (hwnd, wParam, lParam);
7143
7144         case WM_NCCREATE:
7145             return TOOLBAR_NCCreate (hwnd, wParam, lParam);
7146
7147         case WM_NCPAINT:
7148             return TOOLBAR_NCPaint (hwnd, wParam, lParam);
7149
7150         case WM_NOTIFY:
7151             return TOOLBAR_Notify (hwnd, wParam, lParam);
7152
7153         case WM_NOTIFYFORMAT:
7154             return TOOLBAR_NotifyFormat (infoPtr, wParam, lParam);
7155
7156         case WM_PRINTCLIENT:
7157         case WM_PAINT:
7158             return TOOLBAR_Paint (hwnd, wParam);
7159
7160         case WM_SETFOCUS:
7161             return TOOLBAR_SetFocus (hwnd, wParam);
7162
7163         case WM_SETREDRAW:
7164             return TOOLBAR_SetRedraw (hwnd, wParam, lParam);
7165
7166         case WM_SIZE:
7167             return TOOLBAR_Size (hwnd, wParam, lParam);
7168
7169         case WM_STYLECHANGED:
7170             return TOOLBAR_StyleChanged (hwnd, (INT)wParam, (LPSTYLESTRUCT)lParam);
7171
7172         case WM_SYSCOLORCHANGE:
7173             return TOOLBAR_SysColorChange (hwnd);
7174             
7175         case WM_THEMECHANGED:
7176             return theme_changed (hwnd);
7177
7178 /*      case WM_WININICHANGE: */
7179
7180         case WM_CHARTOITEM:
7181         case WM_COMMAND:
7182         case WM_DRAWITEM:
7183         case WM_MEASUREITEM:
7184         case WM_VKEYTOITEM:
7185             return SendMessageW (infoPtr->hwndNotify, uMsg, wParam, lParam);
7186
7187         /* We see this in Outlook Express 5.x and just does DefWindowProc */
7188         case PGM_FORWARDMOUSE:
7189             return DefWindowProcW (hwnd, uMsg, wParam, lParam);
7190
7191         default:
7192             if ((uMsg >= WM_USER) && (uMsg < WM_APP))
7193                 ERR("unknown msg %04x wp=%08x lp=%08lx\n",
7194                      uMsg, wParam, lParam);
7195             return DefWindowProcW (hwnd, uMsg, wParam, lParam);
7196     }
7197 }
7198
7199
7200 VOID
7201 TOOLBAR_Register (void)
7202 {
7203     WNDCLASSW wndClass;
7204
7205     ZeroMemory (&wndClass, sizeof(WNDCLASSW));
7206     wndClass.style         = CS_GLOBALCLASS | CS_DBLCLKS;
7207     wndClass.lpfnWndProc   = ToolbarWindowProc;
7208     wndClass.cbClsExtra    = 0;
7209     wndClass.cbWndExtra    = sizeof(TOOLBAR_INFO *);
7210     wndClass.hCursor       = LoadCursorW (0, (LPWSTR)IDC_ARROW);
7211     wndClass.hbrBackground = (HBRUSH)(COLOR_BTNFACE + 1);
7212     wndClass.lpszClassName = TOOLBARCLASSNAMEW;
7213
7214     RegisterClassW (&wndClass);
7215 }
7216
7217
7218 VOID
7219 TOOLBAR_Unregister (void)
7220 {
7221     UnregisterClassW (TOOLBARCLASSNAMEW, NULL);
7222 }
7223
7224 static HIMAGELIST TOOLBAR_InsertImageList(PIMLENTRY **pies, INT *cies, HIMAGELIST himl, INT id)
7225 {
7226     HIMAGELIST himlold;
7227     PIMLENTRY c = NULL;
7228
7229     /* Check if the entry already exists */
7230     c = TOOLBAR_GetImageListEntry(*pies, *cies, id);
7231
7232     /* If this is a new entry we must create it and insert into the array */
7233     if (!c)
7234     {
7235         PIMLENTRY *pnies;
7236
7237         c = (PIMLENTRY) Alloc(sizeof(IMLENTRY));
7238         c->id = id;
7239
7240         pnies = Alloc((*cies + 1) * sizeof(PIMLENTRY));
7241         memcpy(pnies, *pies, ((*cies) * sizeof(PIMLENTRY)));
7242         pnies[*cies] = c;
7243         (*cies)++;
7244
7245         Free(*pies);
7246         *pies = pnies;
7247     }
7248
7249     himlold = c->himl;
7250     c->himl = himl;
7251
7252     return himlold;
7253 }
7254
7255
7256 static VOID TOOLBAR_DeleteImageList(PIMLENTRY **pies, INT *cies)
7257 {
7258     int i;
7259
7260     for (i = 0; i < *cies; i++)
7261         Free((*pies)[i]);
7262
7263     Free(*pies);
7264
7265     *cies = 0;
7266     *pies = NULL;
7267 }
7268
7269
7270 static PIMLENTRY TOOLBAR_GetImageListEntry(PIMLENTRY *pies, INT cies, INT id)
7271 {
7272     PIMLENTRY c = NULL;
7273
7274     if (pies != NULL)
7275     {
7276         int i;
7277
7278         for (i = 0; i < cies; i++)
7279         {
7280             if (pies[i]->id == id)
7281             {
7282                 c = pies[i];
7283                 break;
7284             }
7285         }
7286     }
7287
7288     return c;
7289 }
7290
7291
7292 static HIMAGELIST TOOLBAR_GetImageList(PIMLENTRY *pies, INT cies, INT id)
7293 {
7294     HIMAGELIST himlDef = 0;
7295     PIMLENTRY pie = TOOLBAR_GetImageListEntry(pies, cies, id);
7296
7297     if (pie)
7298         himlDef = pie->himl;
7299
7300     return himlDef;
7301 }
7302
7303
7304 static BOOL TOOLBAR_GetButtonInfo(TOOLBAR_INFO *infoPtr, NMTOOLBARW *nmtb)
7305 {
7306     if (infoPtr->bUnicode)
7307         return TOOLBAR_SendNotify(&nmtb->hdr, infoPtr, TBN_GETBUTTONINFOW);
7308     else
7309     {
7310         CHAR Buffer[256];
7311         NMTOOLBARA nmtba;
7312         BOOL bRet = FALSE;
7313
7314         nmtba.iItem = nmtb->iItem;
7315         nmtba.pszText = Buffer;
7316         nmtba.cchText = 256;
7317         ZeroMemory(nmtba.pszText, nmtba.cchText);
7318
7319         if (TOOLBAR_SendNotify(&nmtba.hdr, infoPtr, TBN_GETBUTTONINFOA))
7320         {
7321             int ccht = strlen(nmtba.pszText);
7322             if (ccht)
7323                MultiByteToWideChar(CP_ACP, 0, (LPCSTR)nmtba.pszText, -1, 
7324                   nmtb->pszText, nmtb->cchText);
7325
7326             memcpy(&nmtb->tbButton, &nmtba.tbButton, sizeof(TBBUTTON));
7327             bRet = TRUE;
7328         }
7329
7330         return bRet;
7331     }
7332 }
7333
7334
7335 static BOOL TOOLBAR_IsButtonRemovable(TOOLBAR_INFO *infoPtr,
7336         int iItem, PCUSTOMBUTTON btnInfo)
7337 {
7338     NMTOOLBARW nmtb;
7339
7340     /* MSDN states that iItem is the index of the button, rather than the
7341      * command ID as used by every other NMTOOLBAR notification */
7342     nmtb.iItem = iItem;
7343     memcpy(&nmtb.tbButton, &btnInfo->btn, sizeof(TBBUTTON));
7344
7345     return TOOLBAR_SendNotify(&nmtb.hdr, infoPtr, TBN_QUERYDELETE);
7346 }