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