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