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