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