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