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