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