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