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