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