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