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