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