Sync to Wine-20050628:
[reactos.git] / reactos / lib / comctl32 / toolbar.c
index b740673..53f1884 100644 (file)
@@ -211,12 +211,13 @@ typedef enum
 \r
 #define DEFPAD_CX 7\r
 #define DEFPAD_CY 6\r
+#define DEFLISTGAP 4\r
+\r
+/* vertical padding used in list mode when image is present */\r
+#define LISTPAD_CY 9\r
 \r
-/* gap between border of button and text/image */\r
-#define OFFSET_X 1\r
-#define OFFSET_Y 1\r
 /* how wide to treat the bitmap if it isn't present */\r
-#define LIST_IMAGE_ABSENT_WIDTH 2\r
+#define NONLIST_NOTEXT_OFFSET 2\r
 \r
 #define TOOLBAR_NOWHERE (-1)\r
 \r
@@ -224,11 +225,6 @@ typedef enum
 #define TOOLBAR_HasText(x, y) (TOOLBAR_GetText(x, y) ? TRUE : FALSE)\r
 #define TOOLBAR_HasDropDownArrows(exStyle) ((exStyle & TBSTYLE_EX_DRAWDDARROWS) ? TRUE : FALSE)\r
 \r
-static inline int TOOLBAR_GetListTextOffset(TOOLBAR_INFO *infoPtr, INT iListGap)\r
-{\r
-    return GetSystemMetrics(SM_CXEDGE) + iListGap - infoPtr->szPadding.cx/2;\r
-}\r
-\r
 /* Used to find undocumented extended styles */\r
 #define TBSTYLE_EX_ALL (TBSTYLE_EX_DRAWDDARROWS | \\r
                         TBSTYLE_EX_UNDOC1 | \\r
@@ -396,6 +392,14 @@ TOOLBAR_IsValidBitmapIndex(TOOLBAR_INFO *infoPtr, INT index)
 }\r
 \r
 \r
+static inline BOOL\r
+TOOLBAR_IsValidImageList(TOOLBAR_INFO *infoPtr, INT index)\r
+{\r
+    HIMAGELIST himl = GETDEFIMAGELIST(infoPtr, GETHIMLID(infoPtr, index));\r
+    return (himl != NULL) && (ImageList_GetImageCount(himl) > 0);\r
+}\r
+\r
+\r
 /***********************************************************************\r
 *              TOOLBAR_GetImageListForDrawing\r
 *\r
@@ -445,37 +449,6 @@ TOOLBAR_GetImageListForDrawing (TOOLBAR_INFO *infoPtr, TBUTTON_INFO *btnPtr, IMA
 }\r
 \r
 \r
-/***********************************************************************\r
-*              TOOLBAR_TestImageExist\r
-*\r
-* This function is similar to TOOLBAR_GetImageListForDrawing, except it does not\r
-* return the image list. The I_IMAGECALLBACK functionality is implemented.\r
-*/\r
-static BOOL\r
-TOOLBAR_TestImageExist (TOOLBAR_INFO *infoPtr, TBUTTON_INFO *btnPtr, HIMAGELIST himl)\r
-{\r
-    INT index;\r
-\r
-    if (!himl) return FALSE;\r
-\r
-    if (!TOOLBAR_IsValidBitmapIndex(infoPtr,btnPtr->iBitmap)) {\r
-       if (btnPtr->iBitmap == I_IMAGENONE) return FALSE;\r
-       ERR("index %d is not valid, max %d\n",\r
-           btnPtr->iBitmap, infoPtr->nNumBitmaps);\r
-       return FALSE;\r
-    }\r
-\r
-    if ((index = TOOLBAR_GetBitmapIndex(infoPtr, btnPtr)) < 0) {\r
-       if ((index == I_IMAGECALLBACK) ||\r
-           (index == I_IMAGENONE)) return FALSE;\r
-       ERR("TBN_GETDISPINFO returned invalid index %d\n",\r
-           index);\r
-       return FALSE;\r
-    }\r
-    return TRUE;\r
-}\r
-\r
-\r
 static void\r
 TOOLBAR_DrawFlatSeparator (LPRECT lpRect, HDC hdc, TOOLBAR_INFO *infoPtr)\r
 {\r
@@ -755,7 +728,7 @@ TOOLBAR_DrawImage(TOOLBAR_INFO *infoPtr, TBUTTON_INFO *btnPtr, INT left, INT top
 \r
 /* draws a blank frame for a toolbar button */\r
 static void\r
-TOOLBAR_DrawFrame(const TOOLBAR_INFO *infoPtr, BOOL flat, const NMTBCUSTOMDRAW *tbcd)\r
+TOOLBAR_DrawFrame(const TOOLBAR_INFO *infoPtr, const NMTBCUSTOMDRAW *tbcd)\r
 {\r
     HDC hdc = tbcd->nmcd.hdc;\r
     RECT rc = tbcd->nmcd.rc;\r
@@ -771,7 +744,7 @@ TOOLBAR_DrawFrame(const TOOLBAR_INFO *infoPtr, BOOL flat, const NMTBCUSTOMDRAW *
     if (infoPtr->dwItemCDFlag & TBCDRF_NOEDGES)\r
         return;\r
 \r
-    if (flat)\r
+    if (infoPtr->dwStyle & TBSTYLE_FLAT)\r
     {\r
         if (pressed_look)\r
             DrawEdge (hdc, &rc, BDR_SUNKENOUTER, BF_RECT);\r
@@ -845,7 +818,6 @@ TOOLBAR_DrawButton (HWND hwnd, TBUTTON_INFO *btnPtr, HDC hdc)
 \r
     rc = btnPtr->rect;\r
     CopyRect (&rcArrow, &rc);\r
-    CopyRect(&rcBitmap, &rc);\r
 \r
     /* get a pointer to the text */\r
     lpText = TOOLBAR_GetText(infoPtr, btnPtr);\r
@@ -865,47 +837,51 @@ TOOLBAR_DrawButton (HWND hwnd, TBUTTON_INFO *btnPtr, HDC hdc)
         rcArrow.left = right;\r
     }\r
 \r
-    /* copy text rect after adjusting for drop-down arrow\r
-     * so that text is centred in the rectangle not containing\r
+    /* copy text & bitmap rects after adjusting for drop-down arrow\r
+     * so that text & bitmap is centred in the rectangle not containing\r
      * the arrow */\r
     CopyRect(&rcText, &rc);\r
+    CopyRect(&rcBitmap, &rc);\r
 \r
     /* Center the bitmap horizontally and vertically */\r
     if (dwStyle & TBSTYLE_LIST)\r
-        rcBitmap.left += GetSystemMetrics(SM_CXEDGE);\r
+    {\r
+        if (lpText &&\r
+            infoPtr->nMaxTextRows > 0 &&\r
+            (!(infoPtr->dwExStyle & TBSTYLE_EX_MIXEDBUTTONS) ||\r
+            (btnPtr->fsStyle & BTNS_SHOWTEXT)) )\r
+            rcBitmap.left += GetSystemMetrics(SM_CXEDGE) + infoPtr->szPadding.cx / 2;\r
+        else\r
+            rcBitmap.left += GetSystemMetrics(SM_CXEDGE) + infoPtr->iListGap / 2;\r
+    }\r
     else\r
-        rcBitmap.left+=(infoPtr->nButtonWidth - infoPtr->nBitmapWidth) / 2;\r
+        rcBitmap.left += (infoPtr->nButtonWidth - infoPtr->nBitmapWidth) / 2;\r
 \r
-    if(lpText)\r
-        rcBitmap.top+= GetSystemMetrics(SM_CYEDGE);\r
-    else\r
-        rcBitmap.top+=(infoPtr->nButtonHeight - infoPtr->nBitmapHeight) / 2;\r
+    rcBitmap.top += infoPtr->szPadding.cy / 2;\r
 \r
-    TRACE("iBitmap%d, start=(%ld,%ld) w=%d, h=%d\n",\r
+    TRACE("iBitmap=%d, start=(%ld,%ld) w=%d, h=%d\n",\r
       btnPtr->iBitmap, rcBitmap.left, rcBitmap.top,\r
       infoPtr->nBitmapWidth, infoPtr->nBitmapHeight);\r
-    TRACE ("iString: %x\n", btnPtr->iString);\r
-    TRACE ("Stringtext: %s\n", debugstr_w(lpText));\r
+    TRACE("Text=%s\n", debugstr_w(lpText));\r
+    TRACE("iListGap=%d, padding = { %ld, %ld }\n", infoPtr->iListGap, infoPtr->szPadding.cx, infoPtr->szPadding.cy);\r
 \r
-    /* draw text */\r
-    if (lpText) {\r
-        rcText.left += GetSystemMetrics(SM_CXEDGE) + OFFSET_X;\r
-        rcText.right -= GetSystemMetrics(SM_CXEDGE) + OFFSET_X;\r
-        if (GETDEFIMAGELIST(infoPtr, GETHIMLID(infoPtr,btnPtr->iBitmap)) &&\r
-            TOOLBAR_IsValidBitmapIndex(infoPtr,btnPtr->iBitmap))\r
+    /* calculate text position */\r
+    if (lpText)\r
+    {\r
+        rcText.left += GetSystemMetrics(SM_CXEDGE);\r
+        rcText.right -= GetSystemMetrics(SM_CXEDGE);\r
+        if (dwStyle & TBSTYLE_LIST)\r
         {\r
-            if (dwStyle & TBSTYLE_LIST)\r
-                rcText.left += infoPtr->nBitmapWidth + TOOLBAR_GetListTextOffset(infoPtr, infoPtr->iListGap);\r
-            else\r
-                rcText.top += GetSystemMetrics(SM_CYEDGE) + OFFSET_Y + infoPtr->nBitmapHeight + infoPtr->szPadding.cy/2;\r
+            if (TOOLBAR_IsValidBitmapIndex(infoPtr,btnPtr->iBitmap))\r
+                rcText.left += infoPtr->nBitmapWidth + infoPtr->iListGap + 2;\r
         }\r
         else\r
-            if (dwStyle & TBSTYLE_LIST)\r
-                rcText.left += LIST_IMAGE_ABSENT_WIDTH + TOOLBAR_GetListTextOffset(infoPtr, infoPtr->iListGap);\r
-\r
-        if (!(infoPtr->dwItemCDFlag & TBCDRF_NOOFFSET) &&\r
-          (btnPtr->fsState & (TBSTATE_PRESSED | TBSTATE_CHECKED)))\r
-            OffsetRect(&rcText, 1, 1);\r
+        {\r
+            if (ImageList_GetImageCount(GETDEFIMAGELIST(infoPtr, 0)) > 0)\r
+                rcText.top += infoPtr->szPadding.cy/2 + infoPtr->nBitmapHeight + 1;\r
+            else\r
+                rcText.top += infoPtr->szPadding.cy/2 + 2;\r
+        }\r
     }\r
 \r
     /* Initialize fields in all cases, because we use these later\r
@@ -980,6 +956,10 @@ TOOLBAR_DrawButton (HWND hwnd, TBUTTON_INFO *btnPtr, HDC hdc)
        goto FINALNOTIFY;\r
     }\r
 \r
+    if (!(infoPtr->dwItemCDFlag & TBCDRF_NOOFFSET) &&\r
+        (btnPtr->fsState & (TBSTATE_PRESSED | TBSTATE_CHECKED)))\r
+        OffsetRect(&rcText, 1, 1);\r
+\r
     if (!(tbcd.nmcd.uItemState & CDIS_HOT) && \r
         ((tbcd.nmcd.uItemState & CDIS_CHECKED) || (tbcd.nmcd.uItemState & CDIS_INDETERMINATE)))\r
         TOOLBAR_DrawPattern (&rc, &tbcd);\r
@@ -998,7 +978,7 @@ TOOLBAR_DrawButton (HWND hwnd, TBUTTON_INFO *btnPtr, HDC hdc)
         }\r
     }\r
 \r
-    TOOLBAR_DrawFrame(infoPtr, dwStyle & TBSTYLE_FLAT, &tbcd);\r
+    TOOLBAR_DrawFrame(infoPtr, &tbcd);\r
 \r
     if (drawSepDropDownArrow)\r
         TOOLBAR_DrawSepDDArrow(infoPtr, &tbcd, &rcArrow, btnPtr->bDropDownPressed);\r
@@ -1397,6 +1377,166 @@ TOOLBAR_WrapToolbar( HWND hwnd, DWORD dwStyle )
 }\r
 \r
 \r
+/***********************************************************************\r
+*              TOOLBAR_MeasureButton\r
+*\r
+* Calculates the width and height required for a button. Used in\r
+* TOOLBAR_CalcToolbar to set the all-button width and height and also for\r
+* the width of buttons that are autosized.\r
+*\r
+* Note that it would have been rather elegant to use one piece of code for\r
+* both the laying out of the toolbar and for controlling where button parts\r
+* are drawn, but the native control has inconsistencies between the two that\r
+* prevent this from being effectively. These inconsistencies can be seen as\r
+* artefacts where parts of the button appear outside of the bounding button\r
+* rectangle.\r
+*\r
+* There are several cases for the calculation of the button dimensions and\r
+* button part positioning:\r
+*\r
+* List\r
+* ====\r
+*\r
+* With Bitmap:\r
+*\r
+* +--------------------------------------------------------+ ^\r
+* |                    ^                     ^             | |\r
+* |                    | pad.cy / 2          | centred     | |\r
+* | pad.cx/2 + cxedge +--------------+     +------------+  | | DEFPAD_CY +\r
+* |<----------------->| nBitmapWidth |     | Text       |  | | max(nBitmapHeight, szText.cy)\r
+* |                   |<------------>|     |            |  | |\r
+* |                   +--------------+     +------------+  | |\r
+* |<-------------------------------------->|               | |\r
+* |  cxedge + iListGap + nBitmapWidth + 2  |<----------->  | |\r
+* |                                           szText.cx    | |\r
+* +--------------------------------------------------------+ -\r
+* <-------------------------------------------------------->\r
+*  2*cxedge + nBitmapWidth + iListGap + szText.cx + pad.cx\r
+*\r
+* Without Bitmap (I_IMAGENONE):\r
+*\r
+* +-----------------------------------+ ^\r
+* |                     ^             | |\r
+* |                     | centred     | | LISTPAD_CY +\r
+* |                   +------------+  | | szText.cy\r
+* |                   | Text       |  | |\r
+* |                   |            |  | |\r
+* |                   +------------+  | |\r
+* |<----------------->|               | |\r
+* |      cxedge       |<----------->  | |\r
+* |                      szText.cx    | |\r
+* +-----------------------------------+ -\r
+* <----------------------------------->\r
+*          szText.cx + pad.cx\r
+*\r
+* Without text:\r
+*\r
+* +--------------------------------------+ ^\r
+* |                       ^              | |\r
+* |                       | padding.cy/2 | | DEFPAD_CY +\r
+* |                     +------------+   | | nBitmapHeight\r
+* |                     | Bitmap     |   | |\r
+* |                     |            |   | |\r
+* |                     +------------+   | |\r
+* |<------------------->|                | |\r
+* | cxedge + iListGap/2 |<----------->   | |\r
+* |                       nBitmapWidth   | |\r
+* +--------------------------------------+ -\r
+* <-------------------------------------->\r
+*     2*cxedge + nBitmapWidth + iListGap\r
+*\r
+* Non-List\r
+* ========\r
+*\r
+* With bitmap:\r
+*\r
+* +-----------------------------------+ ^\r
+* |                     ^             | |\r
+* |                     | pad.cy / 2  | | nBitmapHeight +\r
+* |                     -             | | szText.cy +\r
+* |                   +------------+  | | DEFPAD_CY + 1\r
+* |    centred        |   Bitmap   |  | |\r
+* |<----------------->|            |  | |\r
+* |                   +------------+  | |\r
+* |                         ^         | |\r
+* |                       1 |         | |\r
+* |                         -         | |\r
+* |     centred     +---------------+ | |\r
+* |<--------------->|      Text     | | |\r
+* |                 +---------------+ | |\r
+* +-----------------------------------+ -\r
+* <----------------------------------->\r
+* pad.cx + max(nBitmapWidth, szText.cx)\r
+*\r
+* Without bitmaps (NULL imagelist or ImageList_GetImageCount() = 0):\r
+*\r
+* +---------------------------------------+ ^\r
+* |                     ^                 | |\r
+* |                     | 2 + pad.cy / 2  | |\r
+* |                     -                 | | szText.cy +\r
+* |    centred      +-----------------+   | | pad.cy + 2\r
+* |<--------------->|   Text          |   | |\r
+* |                 +-----------------+   | |\r
+* |                                       | |\r
+* +---------------------------------------+ -\r
+* <--------------------------------------->\r
+*          2*cxedge + pad.cx + szText.cx\r
+*\r
+* Without text:\r
+*   As for with bitmaps, but with szText.cx zero.\r
+*/\r
+static inline SIZE TOOLBAR_MeasureButton(TOOLBAR_INFO *infoPtr, SIZE sizeString, BOOL bHasBitmap, BOOL bValidImageList)\r
+{\r
+    SIZE sizeButton;\r
+    if (infoPtr->dwStyle & TBSTYLE_LIST)\r
+    {\r
+        /* set button height from bitmap / text height... */\r
+        sizeButton.cy = max((bHasBitmap ? infoPtr->nBitmapHeight : 0),\r
+            sizeString.cy);\r
+\r
+        /* ... add on the necessary padding */\r
+        if (bValidImageList)\r
+        {\r
+            if (bHasBitmap)\r
+                sizeButton.cy += DEFPAD_CY;\r
+            else\r
+                sizeButton.cy += LISTPAD_CY;\r
+        }\r
+        else\r
+            sizeButton.cy += infoPtr->szPadding.cy;\r
+\r
+        /* calculate button width */\r
+        if (bHasBitmap)\r
+        {\r
+            sizeButton.cx = 2*GetSystemMetrics(SM_CXEDGE) +\r
+                infoPtr->nBitmapWidth + infoPtr->iListGap;\r
+            if (sizeString.cx > 0)\r
+                sizeButton.cx += sizeString.cx + infoPtr->szPadding.cx;\r
+        }\r
+        else\r
+            sizeButton.cx = sizeString.cx + infoPtr->szPadding.cx;\r
+    }\r
+    else\r
+    {\r
+        if (bHasBitmap)\r
+        {\r
+            sizeButton.cy = infoPtr->nBitmapHeight + 1 +\r
+                sizeString.cy + DEFPAD_CY;\r
+            sizeButton.cx = infoPtr->szPadding.cx +\r
+                max(sizeString.cx, infoPtr->nBitmapWidth);\r
+        }\r
+        else\r
+        {\r
+            sizeButton.cy = sizeString.cy + infoPtr->szPadding.cy +\r
+                NONLIST_NOTEXT_OFFSET;\r
+            sizeButton.cx = 2*GetSystemMetrics(SM_CXEDGE) +\r
+                infoPtr->szPadding.cx + sizeString.cx;\r
+        }\r
+    }\r
+    return sizeButton;\r
+}\r
+\r
+\r
 /***********************************************************************\r
 *              TOOLBAR_CalcToolbar\r
 *\r
@@ -1407,7 +1547,6 @@ TOOLBAR_WrapToolbar( HWND hwnd, DWORD dwStyle )
 * the tooltip window if appropriate. Finally, it updates the rcBound\r
 * rect and calculates the new required toolbar window height.\r
 */\r
-\r
 static void\r
 TOOLBAR_CalcToolbar (HWND hwnd)\r
 {\r
@@ -1416,9 +1555,10 @@ TOOLBAR_CalcToolbar (HWND hwnd)
     TBUTTON_INFO *btnPtr;\r
     INT i, nRows, nSepRows;\r
     INT x, y, cx, cy;\r
-    SIZE  sizeString;\r
+    SIZE  sizeString, sizeButton;\r
     BOOL bWrap;\r
     BOOL usesBitmaps = FALSE;\r
+    BOOL validImageList = FALSE;\r
     BOOL hasDropDownArrows = TOOLBAR_HasDropDownArrows(infoPtr->dwExStyle);\r
 \r
     TOOLBAR_CalcStrings (hwnd, &sizeString);\r
@@ -1430,36 +1570,11 @@ TOOLBAR_CalcToolbar (HWND hwnd)
        if (TOOLBAR_IsValidBitmapIndex(infoPtr,infoPtr->buttons[i].iBitmap))\r
            usesBitmaps = TRUE;\r
     }\r
-    if (dwStyle & TBSTYLE_LIST)\r
-    {\r
-       infoPtr->nButtonHeight = max((usesBitmaps) ? infoPtr->nBitmapHeight :\r
-                                    0, sizeString.cy) + infoPtr->szPadding.cy;\r
-       infoPtr->nButtonWidth = ((usesBitmaps) ? infoPtr->nBitmapWidth :\r
-                                LIST_IMAGE_ABSENT_WIDTH) + sizeString.cx + infoPtr->szPadding.cx;\r
-        if (sizeString.cx > 0)\r
-            infoPtr->nButtonWidth += TOOLBAR_GetListTextOffset(infoPtr, infoPtr->iListGap) + infoPtr->szPadding.cx/2;\r
-       TRACE("LIST style, But w=%d h=%d, useBitmaps=%d, Bit w=%d h=%d\n",\r
-             infoPtr->nButtonWidth, infoPtr->nButtonHeight, usesBitmaps,\r
-             infoPtr->nBitmapWidth, infoPtr->nBitmapHeight);\r
-    }\r
-    else {\r
-        if (sizeString.cy > 0)\r
-        {\r
-            if (usesBitmaps)\r
-               infoPtr->nButtonHeight = sizeString.cy +\r
-                   infoPtr->szPadding.cy/2 + /* this is the space to separate text from bitmap */\r
-                  infoPtr->nBitmapHeight + infoPtr->szPadding.cy;\r
-            else\r
-                infoPtr->nButtonHeight = sizeString.cy + infoPtr->szPadding.cy;\r
-        }\r
-        else\r
-           infoPtr->nButtonHeight = infoPtr->nBitmapHeight + infoPtr->szPadding.cy;\r
-\r
-        if (sizeString.cx > infoPtr->nBitmapWidth)\r
-           infoPtr->nButtonWidth = sizeString.cx + infoPtr->szPadding.cx;\r
-        else\r
-            infoPtr->nButtonWidth = infoPtr->nBitmapWidth + infoPtr->szPadding.cx;\r
-    }\r
+    if (TOOLBAR_IsValidImageList(infoPtr, 0))\r
+        validImageList = TRUE;\r
+    sizeButton = TOOLBAR_MeasureButton(infoPtr, sizeString, usesBitmaps, validImageList);\r
+    infoPtr->nButtonWidth = sizeButton.cx;\r
+    infoPtr->nButtonHeight = sizeButton.cy;\r
 \r
     if ( infoPtr->cxMin >= 0 && infoPtr->nButtonWidth < infoPtr->cxMin )\r
         infoPtr->nButtonWidth = infoPtr->cxMin;\r
@@ -1474,9 +1589,7 @@ TOOLBAR_CalcToolbar (HWND hwnd)
     /* from above, minimum is a button, and possible text */\r
     cx = infoPtr->nButtonWidth;\r
 \r
-    /* cannot use just ButtonHeight, we may have no buttons! */\r
-    if (infoPtr->nNumButtons > 0)\r
-        infoPtr->nHeight = infoPtr->nButtonHeight;\r
+    infoPtr->nHeight = infoPtr->nButtonHeight;\r
 \r
     cy = infoPtr->nHeight;\r
 \r
@@ -1534,22 +1647,10 @@ TOOLBAR_CalcToolbar (HWND hwnd)
              SelectObject (hdc, hOldFont);\r
              ReleaseDC (hwnd, hdc);\r
 \r
-              /* add space on for button frame, etc */\r
-              cx = sz.cx + infoPtr->szPadding.cx;\r
-              \r
-              /* add list padding */\r
-              if ((dwStyle & TBSTYLE_LIST) && sz.cx > 0)\r
-                  cx += TOOLBAR_GetListTextOffset(infoPtr, infoPtr->iListGap) + infoPtr->szPadding.cx/2;\r
-\r
-              if (TOOLBAR_TestImageExist (infoPtr, btnPtr, GETDEFIMAGELIST(infoPtr,0)))\r
-              {\r
-                if (dwStyle & TBSTYLE_LIST)\r
-                  cx += infoPtr->nBitmapWidth;\r
-                else if (cx < (infoPtr->nBitmapWidth+infoPtr->szPadding.cx))\r
-                  cx = infoPtr->nBitmapWidth+infoPtr->szPadding.cx;\r
-              }\r
-              else if (dwStyle & TBSTYLE_LIST)\r
-                  cx += LIST_IMAGE_ABSENT_WIDTH;\r
+              sizeButton = TOOLBAR_MeasureButton(infoPtr, sz,\r
+                  TOOLBAR_IsValidBitmapIndex(infoPtr, infoPtr->buttons[i].iBitmap),\r
+                  validImageList);\r
+              cx = sizeButton.cx;\r
             }\r
             else\r
              cx = infoPtr->nButtonWidth;\r
@@ -4934,10 +5035,11 @@ TOOLBAR_SetHotItemEx (TOOLBAR_INFO *infoPtr, INT nHit, DWORD dwReason)
 \r
        no_highlight = TOOLBAR_SendNotify(&nmhotitem.hdr, infoPtr, TBN_HOTITEMCHANGE);\r
 \r
-       /* now invalidate the old and new buttons so they will be painted */\r
-       if (oldBtnPtr)\r
+       /* now invalidate the old and new buttons so they will be painted,\r
+        * but only if they are enabled - disabled buttons cannot become hot */\r
+       if (oldBtnPtr && (oldBtnPtr->fsState & TBSTATE_ENABLED))\r
            InvalidateRect(infoPtr->hwndSelf, &oldBtnPtr->rect, TRUE);\r
-       if (btnPtr && !no_highlight)\r
+       if (btnPtr && !no_highlight && (btnPtr->fsState & TBSTATE_ENABLED))\r
        {\r
             btnPtr->bHot = TRUE;\r
            InvalidateRect(infoPtr->hwndSelf, &btnPtr->rect, TRUE);\r
@@ -4990,8 +5092,8 @@ TOOLBAR_SetImageList (HWND hwnd, WPARAM wParam, LPARAM lParam)
     if (!ImageList_GetIconSize(himl, &infoPtr->nBitmapWidth,\r
             &infoPtr->nBitmapHeight))\r
     {\r
-        infoPtr->nBitmapWidth = 0;\r
-        infoPtr->nBitmapHeight = 0;\r
+        infoPtr->nBitmapWidth = 1;\r
+        infoPtr->nBitmapHeight = 1;\r
     }\r
 \r
     TRACE("hwnd %p, new himl=%p, id = %d, count=%d, bitmap w=%d, h=%d\n",\r
@@ -5089,6 +5191,7 @@ TOOLBAR_SetMaxTextRows (HWND hwnd, WPARAM wParam, LPARAM lParam)
  *    to control the bottom and right borders [with the border being\r
  *    szPadding.cx - (GetSystemMetrics(SM_CXEDGE)+1)], otherwise the padding\r
  *    is shared evenly on both sides of the button.\r
+ * See blueprints in comments above TOOLBAR_MeasureButton for more info.\r
  */\r
 static LRESULT\r
 TOOLBAR_SetPadding (HWND hwnd, WPARAM wParam, LPARAM lParam)\r
@@ -5097,8 +5200,8 @@ TOOLBAR_SetPadding (HWND hwnd, WPARAM wParam, LPARAM lParam)
     DWORD  oldPad;\r
 \r
     oldPad = MAKELONG(infoPtr->szPadding.cx, infoPtr->szPadding.cy);\r
-    infoPtr->szPadding.cx = LOWORD((DWORD)lParam);\r
-    infoPtr->szPadding.cy = HIWORD((DWORD)lParam);\r
+    infoPtr->szPadding.cx = min(LOWORD((DWORD)lParam), GetSystemMetrics(SM_CXEDGE));\r
+    infoPtr->szPadding.cy = min(HIWORD((DWORD)lParam), GetSystemMetrics(SM_CYEDGE));\r
     TRACE("cx=%ld, cy=%ld\n",\r
          infoPtr->szPadding.cx, infoPtr->szPadding.cy);\r
     return (LRESULT) oldPad;\r
@@ -5487,7 +5590,7 @@ TOOLBAR_Create (HWND hwnd, WPARAM wParam, LPARAM lParam)
     infoPtr->clrBtnShadow = CLR_DEFAULT;\r
     infoPtr->szPadding.cx = DEFPAD_CX;\r
     infoPtr->szPadding.cy = DEFPAD_CY;\r
-    infoPtr->iListGap = infoPtr->szPadding.cx / 2;\r
+    infoPtr->iListGap = DEFLISTGAP;\r
     infoPtr->dwStyle = dwStyle;\r
     infoPtr->tbim.iButton = -1;\r
     GetClientRect(hwnd, &infoPtr->client_rect);\r