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