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