comctl32: Tab - fix handling of minimum tab width, add more tests
Vitaliy Margolen
wine-patch at kievinfo.com
Sun Aug 14 15:49:26 CDT 2005
Fixed version.
Vitaliy Margolen
Sunday, August 14, 2005, 11:27:50, Vitaliy Margolen wrote:
> It looks like there are lots of magic around handling of minimum tab width in
> native comctl32. This magic tested on win98 & win2k.
> I also changed test somewhat to make results easier to read.
> Vitaliy Margolen
> changelog:
> dlls/comctl32/tab.c
> dlls/comctl32/test/tab.c
> Fix handling of minimum tab width
> Add more tests to test it
-------------- next part --------------
Index: dlls/comctl32/tab.c
===================================================================
RCS file: /home/wine/wine/dlls/comctl32/tab.c,v
retrieving revision 1.114
diff -u -p -r1.114 tab.c
--- dlls/comctl32/tab.c 11 Aug 2005 18:35:00 -0000 1.114
+++ dlls/comctl32/tab.c 14 Aug 2005 17:15:16 -0000
@@ -142,12 +142,16 @@ typedef struct
#define BUTTON_SPACINGX 3
#define BUTTON_SPACINGY 3
#define FLAT_BTN_SPACINGX 8
-#define DEFAULT_TAB_WIDTH 96
+#define DEFAULT_MIN_TAB_WIDTH 54
+#define DEFAULT_TAB_WIDTH_FIXED 96
+#define DEFAULT_PADDING_X 6
+#define EXTRA_ICON_PADDING 3
#define TAB_GetInfoPtr(hwnd) ((TAB_INFO *)GetWindowLongPtrW(hwnd,0))
/* Since items are variable sized, cannot directly access them */
#define TAB_GetItem(info,i) \
((TAB_ITEM*)((LPBYTE)info->items + (i) * TAB_ITEM_SIZE(info)))
+#define get_default_mintabwidth (DEFAULT_MIN_TAB_WIDTH - (DEFAULT_PADDING_X - infoPtr->uHItemPadding) * 2)
/******************************************************************************
* Hot-tracking timer constants
@@ -1152,23 +1156,43 @@ static void TAB_SetItemBounds (TAB_INFO
/* Set the leftmost position of the tab. */
curr->rect.left = curItemLeftPos;
- if ((lStyle & TCS_FIXEDWIDTH) || !curr->pszText)
+ if (lStyle & TCS_FIXEDWIDTH)
{
curr->rect.right = curr->rect.left +
max(infoPtr->tabWidth, icon_width);
}
- else
+ else if (!curr->pszText)
{
- int num = 2;
+ /* If no text use minimum tab width including padding. */
+ if (infoPtr->tabMinWidth < 0)
+ curr->rect.right = curr->rect.left + get_default_mintabwidth;
+ else
+ {
+ curr->rect.right = curr->rect.left + infoPtr->tabMinWidth;
+ /* Add extra padding if icon is present */
+ if (infoPtr->himl && infoPtr->tabMinWidth > 0 && infoPtr->tabMinWidth < DEFAULT_MIN_TAB_WIDTH
+ && infoPtr->uHItemPadding > 1)
+ curr->rect.right += EXTRA_ICON_PADDING * (infoPtr->uHItemPadding-1);
+ }
+ }
+ else
+ {
+ int tabwidth;
/* Calculate how wide the tab is depending on the text it contains */
GetTextExtentPoint32W(hdc, curr->pszText,
lstrlenW(curr->pszText), &size);
- curr->rect.right = curr->rect.left + size.cx + icon_width +
- num * infoPtr->uHItemPadding;
- TRACE("for <%s>, l,r=%ld,%ld, num=%d\n",
- debugstr_w(curr->pszText), curr->rect.left, curr->rect.right, num);
+ tabwidth = size.cx + icon_width + 2 * infoPtr->uHItemPadding;
+
+ if (infoPtr->tabMinWidth < 0)
+ tabwidth = max(tabwidth, get_default_mintabwidth);
+ else
+ tabwidth = max(tabwidth, infoPtr->tabMinWidth);
+
+ curr->rect.right = curr->rect.left + tabwidth;
+ TRACE("for <%s>, l,r=%ld,%ld\n",
+ debugstr_w(curr->pszText), curr->rect.left, curr->rect.right);
}
/*
@@ -2637,7 +2689,7 @@ TAB_SetItemSize (TAB_INFO *infoPtr, LPAR
/* UNDOCUMENTED: If requested Width or Height is 0 this means that program wants to use auto size. */
if (lStyle & TCS_FIXEDWIDTH && (infoPtr->tabWidth != (INT)LOWORD(lParam)))
{
- infoPtr->tabWidth = max((INT)LOWORD(lParam), infoPtr->tabMinWidth);
+ infoPtr->tabWidth = (INT)LOWORD(lParam);
bNeedPaint = TRUE;
}
@@ -2669,8 +2721,9 @@ static inline LRESULT TAB_SetMinTabWidth
if (infoPtr) {
oldcx = infoPtr->tabMinWidth;
- infoPtr->tabMinWidth = (cx==-1)?DEFAULT_TAB_WIDTH:cx;
+ infoPtr->tabMinWidth = cx;
}
+ TAB_SetItemBounds(infoPtr);
return oldcx;
}
@@ -3030,8 +3083,10 @@ static LRESULT TAB_Create (HWND hwnd, WP
infoPtr->uVItemPadding;
/* Initialize the width of a tab. */
- infoPtr->tabWidth = DEFAULT_TAB_WIDTH;
- infoPtr->tabMinWidth = 0;
+ if (dwStyle & TCS_FIXEDWIDTH)
+ infoPtr->tabWidth = DEFAULT_TAB_WIDTH_FIXED;
+
+ infoPtr->tabMinWidth = -1;
TRACE("tabH=%d, tabW=%d\n", infoPtr->tabHeight, infoPtr->tabWidth);
Index: dlls/comctl32/tests/tab.c
===================================================================
RCS file: /home/wine/wine/dlls/comctl32/tests/tab.c,v
retrieving revision 1.5
diff -u -p -r1.5 tab.c
--- dlls/comctl32/tests/tab.c 9 Jun 2005 09:50:56 -0000 1.5
+++ dlls/comctl32/tests/tab.c 14 Aug 2005 17:15:24 -0000
@@ -23,24 +23,37 @@
#include "wine/test.h"
-#undef VISIBLE
-
+#define DEFAULT_MIN_TAB_WIDTH 54
#define TAB_DEFAULT_WIDTH 96
-#define TAB_PADDING_X 2
-#define TAB_PADDING_Y 2
+#define TAB_PADDING_X 6
+#define EXTRA_ICON_PADDING 3
+
+#define TabWidthPadded(padd_x, num) (DEFAULT_MIN_TAB_WIDTH - (TAB_PADDING_X - (padd_x)) * num)
-#ifdef VISIBLE
-#define WAIT Sleep (1000)
-#define REDRAW(hwnd) RedrawWindow (hwnd, NULL, 0, RDW_UPDATENOW)
-#define trace_tab(str) trace(str)
-#else
-#define WAIT
-#define REDRAW(hwnd)
-#define trace_tab(str)
-#endif
+#define TabCheckSetSize(hwnd, SetWidth, SetHeight, ExpWidth, ExpHeight, Msg)\
+ SendMessage (hwnd, TCM_SETITEMSIZE, 0,\
+ (LPARAM) MAKELPARAM((SetWidth >= 0) ? SetWidth:0, (SetHeight >= 0) ? SetHeight:0));\
+ if (winetest_interactive) RedrawWindow (hwnd, NULL, 0, RDW_UPDATENOW);\
+ CheckSize(hwnd, ExpWidth, ExpHeight, Msg);
+
+#define CheckSize(hwnd,width,height,msg)\
+ SendMessage (hwnd, TCM_GETITEMRECT, 0, (LPARAM) &rTab);\
+ if ((width >= 0) && (height < 0))\
+ ok (width == rTab.right - rTab.left, "%s: Expected width [%d] got [%ld]\n",\
+ msg, (int)width, rTab.right - rTab.left);\
+ else if ((height >= 0) && (width < 0))\
+ ok (height == rTab.bottom - rTab.top, "%s: Expected height [%d] got [%ld]\n",\
+ msg, (int)height, rTab.bottom - rTab.top);\
+ else\
+ ok ((width == rTab.right - rTab.left) &&\
+ (height == rTab.bottom - rTab.top ),\
+ "%s: Expected [%d,%d] got [%ld,%ld]\n", msg, (int)width, (int)height,\
+ rTab.right - rTab.left, rTab.bottom - rTab.top);
-static HWND
-create_tabcontrol (DWORD style)
+HFONT hFont = 0;
+
+HWND
+create_tabcontrol (DWORD style, DWORD mask)
{
HWND handle;
TCITEM tcNewTab;
@@ -53,10 +66,11 @@ create_tabcontrol (DWORD style)
NULL, NULL, NULL, 0);
assert (handle);
-
+
SetWindowLong(handle, GWL_STYLE, WS_CLIPSIBLINGS | WS_CLIPCHILDREN | TCS_FOCUSNEVER | style);
+ SendMessage (handle, WM_SETFONT, 0, (LPARAM) hFont);
- tcNewTab.mask = TCIF_TEXT | TCIF_IMAGE;
+ tcNewTab.mask = mask;
tcNewTab.pszText = "Tab 1";
tcNewTab.iImage = 0;
SendMessage (handle, TCM_INSERTITEM, 0, (LPARAM) &tcNewTab);
@@ -67,131 +81,166 @@ create_tabcontrol (DWORD style)
tcNewTab.iImage = 2;
SendMessage (handle, TCM_INSERTITEM, 2, (LPARAM) &tcNewTab);
-#ifdef VISIBLE
- ShowWindow (handle, SW_SHOW);
-#endif
- REDRAW(handle);
- WAIT;
+ if (winetest_interactive)
+ {
+ ShowWindow (handle, SW_SHOW);
+ RedrawWindow (handle, NULL, 0, RDW_UPDATENOW);
+ Sleep (1000);
+ }
return handle;
}
-static void CheckSize(HWND hwnd, INT width, INT height)
-{
- RECT rTab, r1;
-
- r1.left=r1.top=r1.right=r1.bottom=0;
- SendMessage (hwnd, TCM_GETITEMRECT, 0, (LPARAM) &rTab);
- SendMessage (hwnd, TCM_ADJUSTRECT, FALSE, (LPARAM) &r1);
- /* trace ("Got (%ld,%ld)-(%ld,%ld)\n", rTab.left, rTab.top, rTab.right, rTab.bottom); */
- trace (" (%ld,%ld)-(%ld,%ld)\n", r1.left, r1.top, r1.right, r1.bottom);
- if ((width >= 0) && (height < 0))
- ok (width == rTab.right - rTab.left, "Expected [%d] got [%ld]\n", width, rTab.right - rTab.left);
- else if ((height >= 0) && (width < 0))
- ok (height == rTab.bottom - rTab.top, "Expected [%d] got [%ld]\n", height, rTab.bottom - rTab.top);
- else
- ok ((width == rTab.right - rTab.left) &&
- (height == rTab.bottom - rTab.top ),
- "Expected [%d,%d] got [%ld,%ld]\n", width, height, rTab.right - rTab.left, rTab.bottom - rTab.top);
-}
-
-static void TabCheckSetSize(HWND hwnd, INT SetWidth, INT SetHeight, INT ExpWidth, INT ExpHeight)
-{
- SendMessage (hwnd, TCM_SETITEMSIZE, 0,
- (LPARAM) MAKELPARAM((SetWidth >= 0) ? SetWidth:0, (SetHeight >= 0) ? SetHeight:0));
- REDRAW(hwnd);
- CheckSize(hwnd, ExpWidth, ExpHeight);
- WAIT;
-}
-
-START_TEST(tab)
+static void test_tab(INT nMinTabWidth)
{
HWND hwTab;
+ RECT rTab;
HIMAGELIST himl = ImageList_Create(21, 21, ILC_COLOR, 3, 4);
+ SIZE size;
+ HDC hdc;
+ HFONT hOldFont;
+ INT i;
+
+ hwTab = create_tabcontrol(TCS_FIXEDWIDTH, TCIF_TEXT|TCIF_IMAGE);
+ SendMessage(hwTab, TCM_SETMINTABWIDTH, 0, nMinTabWidth);
+
+ hdc = GetDC(hwTab);
+ hOldFont = SelectObject(hdc, (HFONT)SendMessage(hwTab, WM_GETFONT, 0, 0));
+ GetTextExtentPoint32A(hdc, "Tab 1", strlen("Tab 1"), &size);
+ trace("Tab1 text size: size.cx=%ld size.cy=%ld\n", size.cx, size.cy);
+ SelectObject(hdc, hOldFont);
+ ReleaseDC(hwTab, hdc);
+
+ trace (" TCS_FIXEDWIDTH tabs no icon...\n");
+ CheckSize(hwTab, TAB_DEFAULT_WIDTH, -1, "default width");
+ TabCheckSetSize(hwTab, 50, 20, 50, 20, "set size");
+ TabCheckSetSize(hwTab, 0, 1, 0, 1, "min size");
- InitCommonControls();
+ SendMessage(hwTab, TCM_SETIMAGELIST, 0, (LPARAM)himl);
+ trace (" TCS_FIXEDWIDTH tabs with icon...\n");
+ TabCheckSetSize(hwTab, 50, 30, 50, 30, "set size > icon");
+ TabCheckSetSize(hwTab, 20, 20, 25, 20, "set size < icon");
+ TabCheckSetSize(hwTab, 0, 1, 25, 1, "min size");
+
+ DestroyWindow (hwTab);
- hwTab = create_tabcontrol(TCS_FIXEDWIDTH);
+ hwTab = create_tabcontrol(TCS_FIXEDWIDTH | TCS_BUTTONS, TCIF_TEXT|TCIF_IMAGE);
+ SendMessage(hwTab, TCM_SETMINTABWIDTH, 0, nMinTabWidth);
- trace_tab ("Testing TCS_FIXEDWIDTH tabs no icon...\n");
- trace_tab (" default width...\n");
- CheckSize(hwTab, TAB_DEFAULT_WIDTH, -1);
- trace_tab (" set size...\n");
- TabCheckSetSize(hwTab, 50, 20, 50, 20);
- WAIT;
- trace_tab (" min size...\n");
- TabCheckSetSize(hwTab, 0, 1, 0, 1);
- WAIT;
+ trace (" TCS_FIXEDWIDTH buttons no icon...\n");
+ CheckSize(hwTab, TAB_DEFAULT_WIDTH, -1, "default width");
+ TabCheckSetSize(hwTab, 20, 20, 20, 20, "set size 1");
+ TabCheckSetSize(hwTab, 10, 50, 10, 50, "set size 2");
+ TabCheckSetSize(hwTab, 0, 1, 0, 1, "min size");
SendMessage(hwTab, TCM_SETIMAGELIST, 0, (LPARAM)himl);
- trace_tab ("Testing TCS_FIXEDWIDTH tabs with icon...\n");
- trace_tab (" set size > icon...\n");
- TabCheckSetSize(hwTab, 50, 30, 50, 30);
- trace_tab (" set size < icon...\n");
- TabCheckSetSize(hwTab, 20, 20, 25, 20);
- trace_tab (" min size...\n");
- TabCheckSetSize(hwTab, 0, 1, 25, 1);
+ trace (" TCS_FIXEDWIDTH buttons with icon...\n");
+ TabCheckSetSize(hwTab, 50, 30, 50, 30, "set size > icon");
+ TabCheckSetSize(hwTab, 20, 20, 25, 20, "set size < icon");
+ TabCheckSetSize(hwTab, 0, 1, 25, 1, "min size");
+ SendMessage(hwTab, TCM_SETPADDING, 0, MAKELPARAM(4,4));
+ TabCheckSetSize(hwTab, 0, 1, 25, 1, "set padding, min size");
DestroyWindow (hwTab);
- trace_tab ("Testing TCS_FIXEDWIDTH buttons no icon...\n");
- hwTab = create_tabcontrol(TCS_FIXEDWIDTH | TCS_BUTTONS);
+ hwTab = create_tabcontrol(TCS_FIXEDWIDTH | TCS_BOTTOM, TCIF_TEXT|TCIF_IMAGE);
+ SendMessage(hwTab, TCM_SETMINTABWIDTH, 0, nMinTabWidth);
+
+ trace (" TCS_FIXEDWIDTH | TCS_BOTTOM tabs...\n");
+ CheckSize(hwTab, TAB_DEFAULT_WIDTH, -1, "no icon, default width");
- trace_tab (" default width...\n");
- CheckSize(hwTab, TAB_DEFAULT_WIDTH, -1);
- trace_tab (" set size 1...\n");
- TabCheckSetSize(hwTab, 20, 20, 20, 20);
- trace_tab (" set size 2...\n");
- TabCheckSetSize(hwTab, 10, 50, 10, 50);
- trace_tab (" min size...\n");
- TabCheckSetSize(hwTab, 0, 1, 0, 1);
+ TabCheckSetSize(hwTab, 20, 20, 20, 20, "no icon, set size 1");
+ TabCheckSetSize(hwTab, 10, 50, 10, 50, "no icon, set size 2");
+ TabCheckSetSize(hwTab, 0, 1, 0, 1, "no icon, min size");
SendMessage(hwTab, TCM_SETIMAGELIST, 0, (LPARAM)himl);
- trace_tab ("Testing TCS_FIXEDWIDTH buttons with icon...\n");
- trace_tab (" set size > icon...\n");
- TabCheckSetSize(hwTab, 50, 30, 50, 30);
- trace_tab (" set size < icon...\n");
- TabCheckSetSize(hwTab, 20, 20, 25, 20);
- trace_tab (" min size...\n");
- TabCheckSetSize(hwTab, 0, 1, 25, 1);
- trace_tab (" Add padding...\n");
+ TabCheckSetSize(hwTab, 50, 30, 50, 30, "with icon, set size > icon");
+ TabCheckSetSize(hwTab, 20, 20, 25, 20, "with icon, set size < icon");
+ TabCheckSetSize(hwTab, 0, 1, 25, 1, "with icon, min size");
SendMessage(hwTab, TCM_SETPADDING, 0, MAKELPARAM(4,4));
- trace_tab (" min size...\n");
- TabCheckSetSize(hwTab, 0, 1, 25, 1);
+ TabCheckSetSize(hwTab, 0, 1, 25, 1, "set padding, min size");
DestroyWindow (hwTab);
- hwTab = create_tabcontrol(TCS_FIXEDWIDTH | TCS_BOTTOM);
- trace_tab ("Testing TCS_FIXEDWIDTH | TCS_BOTTOM tabs no icon...\n");
+ hwTab = create_tabcontrol(0, TCIF_TEXT|TCIF_IMAGE);
+ SendMessage(hwTab, TCM_SETMINTABWIDTH, 0, nMinTabWidth);
- trace_tab (" default width...\n");
- CheckSize(hwTab, TAB_DEFAULT_WIDTH, -1);
- trace_tab (" set size 1...\n");
- TabCheckSetSize(hwTab, 20, 20, 20, 20);
- trace_tab (" set size 2...\n");
- TabCheckSetSize(hwTab, 10, 50, 10, 50);
- trace_tab (" min size...\n");
- TabCheckSetSize(hwTab, 0, 1, 0, 1);
+ trace (" non fixed width, with text...\n");
+ CheckSize(hwTab, max(size.cx +TAB_PADDING_X*2, (nMinTabWidth < 0) ? DEFAULT_MIN_TAB_WIDTH : nMinTabWidth), -1,
+ "no icon, default width");
+ for (i=0; i<8; i++)
+ {
+ INT nTabWidth = (nMinTabWidth < 0) ? TabWidthPadded(i, 2) : nMinTabWidth;
+
+ SendMessage(hwTab, TCM_SETIMAGELIST, 0, 0);
+ SendMessage(hwTab, TCM_SETPADDING, 0, MAKELPARAM(i,i));
+
+ TabCheckSetSize(hwTab, 50, 20, max(size.cx + i*2, nTabWidth), 20, "no icon, set size");
+ TabCheckSetSize(hwTab, 0, 1, max(size.cx + i*2, nTabWidth), 1, "no icon, min size");
+
+ SendMessage(hwTab, TCM_SETIMAGELIST, 0, (LPARAM)himl);
+ nTabWidth = (nMinTabWidth < 0) ? TabWidthPadded(i, 3) : nMinTabWidth;
+
+ TabCheckSetSize(hwTab, 50, 30, max(size.cx + 21 + i*3, nTabWidth), 30, "with icon, set size > icon");
+ TabCheckSetSize(hwTab, 20, 20, max(size.cx + 21 + i*3, nTabWidth), 20, "with icon, set size < icon");
+ TabCheckSetSize(hwTab, 0, 1, max(size.cx + 21 + i*3, nTabWidth), 1, "with icon, min size");
+ }
+ DestroyWindow (hwTab);
- SendMessage(hwTab, TCM_SETIMAGELIST, 0, (LPARAM)himl);
-
- trace_tab ("Testing TCS_FIXEDWIDTH | TCS_BOTTOM tabs with icon...\n");
- trace_tab (" set size > icon...\n");
- TabCheckSetSize(hwTab, 50, 30, 50, 30);
- trace_tab (" set size < icon...\n");
- TabCheckSetSize(hwTab, 20, 20, 25, 20);
- trace_tab (" min size...\n");
- TabCheckSetSize(hwTab, 0, 1, 25, 1);
- trace_tab (" Add padding...\n");
- SendMessage(hwTab, TCM_SETPADDING, 0, MAKELPARAM(4,4));
- trace_tab (" min size...\n");
- TabCheckSetSize(hwTab, 0, 1, 25, 1);
+ hwTab = create_tabcontrol(0, TCIF_IMAGE);
+ SendMessage(hwTab, TCM_SETMINTABWIDTH, 0, nMinTabWidth);
- DestroyWindow (hwTab);
+ trace (" non fixed width, no text...\n");
+ CheckSize(hwTab, (nMinTabWidth < 0) ? DEFAULT_MIN_TAB_WIDTH : nMinTabWidth, -1, "no icon, default width");
+ for (i=0; i<8; i++)
+ {
+ INT nTabWidth = (nMinTabWidth < 0) ? TabWidthPadded(i, 2) : nMinTabWidth;
+
+ SendMessage(hwTab, TCM_SETIMAGELIST, 0, 0);
+ SendMessage(hwTab, TCM_SETPADDING, 0, MAKELPARAM(i,i));
+
+ TabCheckSetSize(hwTab, 50, 20, nTabWidth, 20, "no icon, set size");
+ TabCheckSetSize(hwTab, 0, 1, nTabWidth, 1, "no icon, min size");
+
+ SendMessage(hwTab, TCM_SETIMAGELIST, 0, (LPARAM)himl);
+ if (i > 1 && nMinTabWidth > 0 && nMinTabWidth < DEFAULT_MIN_TAB_WIDTH)
+ nTabWidth += EXTRA_ICON_PADDING *(i-1);
+
+ TabCheckSetSize(hwTab, 50, 30, nTabWidth, 30, "with icon, set size > icon");
+ TabCheckSetSize(hwTab, 20, 20, nTabWidth, 20, "with icon, set size < icon");
+ TabCheckSetSize(hwTab, 0, 1, nTabWidth, 1, "with icon, min size");
+ }
+ DestroyWindow (hwTab);
ImageList_Destroy(himl);
+ DeleteObject(hFont);
+}
+
+START_TEST(tab)
+{
+ LOGFONTA logfont;
+
+ lstrcpyA(logfont.lfFaceName, "Arial");
+ memset(&logfont, 0, sizeof(logfont));
+ logfont.lfHeight = -12;
+ logfont.lfWeight = FW_NORMAL;
+ logfont.lfCharSet = ANSI_CHARSET;
+ hFont = CreateFontIndirectA(&logfont);
+
+ InitCommonControls();
+
+ trace ("Testing with default MinWidth\n");
+ test_tab(-1);
+ trace ("Testing with MinWidth set to -3\n");
+ test_tab(-3);
+ trace ("Testing with MinWidth set to 24\n");
+ test_tab(24);
+ trace ("Testing with MinWidth set to 54\n");
+ test_tab(54);
+ trace ("Testing with MinWidth set to 94\n");
+ test_tab(94);
}
More information about the wine-patches
mailing list