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