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