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