From 785bae8aaee6c5991670084101d6aad5aa7ac1d4 Mon Sep 17 00:00:00 2001 From: Vitaliy Margolen Date: Fri, 31 Oct 2003 00:06:42 +0000 Subject: [PATCH] - Fix tab size for TCS_OWNERDRAWFIXED style. - Correct size recalculation after setting tab width. - Fix button sizes to match native. - Center both vertically and horizontally tab text & icon. - Use correct left/center alignment flags. --- dlls/comctl32/tab.c | 121 +++++++++++++---------- dlls/comctl32/tests/.cvsignore | 1 + dlls/comctl32/tests/Makefile.in | 5 +- dlls/comctl32/tests/tab.c | 165 ++++++++++++++++++++++++++++++++ 4 files changed, 241 insertions(+), 51 deletions(-) create mode 100644 dlls/comctl32/tests/tab.c diff --git a/dlls/comctl32/tab.c b/dlls/comctl32/tab.c index ab2ebbf7f32..eacef5f985f 100644 --- a/dlls/comctl32/tab.c +++ b/dlls/comctl32/tab.c @@ -93,7 +93,7 @@ typedef struct #define DISPLAY_AREA_PADDINGY 2 #define CONTROL_BORDER_SIZEX 2 #define CONTROL_BORDER_SIZEY 2 -#define BUTTON_SPACINGX 4 +#define BUTTON_SPACINGX 3 #define BUTTON_SPACINGY 4 #define FLAT_BTN_SPACINGX 8 #define DEFAULT_TAB_WIDTH 96 @@ -344,11 +344,10 @@ static BOOL TAB_InternalGetItemRect( itemRect->bottom = clientRect.top + infoPtr->tabHeight + itemRect->top * (infoPtr->tabHeight - 2) + - ((lStyle & TCS_BUTTONS) ? itemRect->top * BUTTON_SPACINGY : 0); + ((lStyle & TCS_BUTTONS) ? itemRect->top * BUTTON_SPACINGY : SELECTED_TAB_OFFSET); itemRect->top = clientRect.top + - SELECTED_TAB_OFFSET + itemRect->top * (infoPtr->tabHeight - 2) + - ((lStyle & TCS_BUTTONS) ? itemRect->top * BUTTON_SPACINGY : 0); + ((lStyle & TCS_BUTTONS) ? itemRect->top * BUTTON_SPACINGY : SELECTED_TAB_OFFSET); } /* @@ -1072,6 +1071,7 @@ static void TAB_SetItemBounds (HWND hwnd) INT iTemp; RECT* rcItem; INT iIndex; + INT icon_width = 0; /* * We need to get text information so we need a DC and we need to select @@ -1134,38 +1134,36 @@ static void TAB_SetItemBounds (HWND hwnd) TRACE("client right=%ld\n", clientRect.right); + /* Get the icon width */ + if (infoPtr->himl) + { + ImageList_GetIconSize(infoPtr->himl, &icon_width, 0); + + if (lStyle & TCS_FIXEDWIDTH) + icon_width += 4; + else + /* Add padding if icon is present */ + icon_width += infoPtr->uHItemPadding; + } + for (curItem = 0; curItem < infoPtr->uNumItem; curItem++) { /* Set the leftmost position of the tab. */ infoPtr->items[curItem].rect.left = curItemLeftPos; - if ( lStyle & (TCS_FIXEDWIDTH | TCS_OWNERDRAWFIXED) ) + if (lStyle & TCS_FIXEDWIDTH) { infoPtr->items[curItem].rect.right = infoPtr->items[curItem].rect.left + - infoPtr->tabWidth + - 2 * infoPtr->uHItemPadding; + max(infoPtr->tabWidth, icon_width); } else { - int icon_width = 0; int num = 2; /* Calculate how wide the tab is depending on the text it contains */ GetTextExtentPoint32W(hdc, infoPtr->items[curItem].pszText, lstrlenW(infoPtr->items[curItem].pszText), &size); - /* under Windows, there seems to be a minimum width of 2x the height - * for button style tabs */ - if (lStyle & TCS_BUTTONS) - size.cx = max(size.cx, 2 * (infoPtr->tabHeight - 2)); - - /* Add the icon width */ - if (infoPtr->himl) - { - ImageList_GetIconSize(infoPtr->himl, &icon_width, 0); - num++; - } - infoPtr->items[curItem].rect.right = infoPtr->items[curItem].rect.left + size.cx + icon_width + num * infoPtr->uHItemPadding; @@ -1215,7 +1213,7 @@ static void TAB_SetItemBounds (HWND hwnd) */ if (lStyle & TCS_BUTTONS) { - curItemLeftPos = infoPtr->items[curItem].rect.right + 1; + curItemLeftPos = infoPtr->items[curItem].rect.right + BUTTON_SPACINGX; if (lStyle & TCS_FLATBUTTONS) curItemLeftPos += FLAT_BTN_SPACINGX; } @@ -1547,7 +1545,7 @@ TAB_DrawItemInterior /* used to center the icon and text in the tab */ RECT rcText; - INT center_offset; + INT center_offset_h, center_offset_v; /* * Deflate the rectangle to acount for the padding @@ -1585,34 +1583,46 @@ TAB_DrawItemInterior ImageList_GetIconSize(infoPtr->himl, &cx, &cy); if(lStyle & TCS_VERTICAL) - center_offset = ((drawRect->bottom - drawRect->top) - (cy + infoPtr->uHItemPadding + (rcText.right - rcText.left))) / 2; + { + center_offset_h = ((drawRect->bottom - drawRect->top) - (cy + infoPtr->uHItemPadding + (rcText.right - rcText.left))) / 2; + center_offset_v = ((drawRect->right - drawRect->left) - (cx + infoPtr->uVItemPadding)) / 2; + } else - center_offset = ((drawRect->right - drawRect->left) - (cx + infoPtr->uHItemPadding + (rcText.right - rcText.left))) / 2; + { + center_offset_h = ((drawRect->right - drawRect->left) - (cx + infoPtr->uHItemPadding + (rcText.right - rcText.left))) / 2; + center_offset_v = ((drawRect->bottom - drawRect->top) - (cy + infoPtr->uVItemPadding)) / 2; + } + + if ((lStyle & TCS_FIXEDWIDTH && + lStyle & (TCS_FORCELABELLEFT | TCS_FORCEICONLEFT)) || + (center_offset_h < 0)) + center_offset_h = 0; TRACE("for <%s>, c_o=%d, draw=(%ld,%ld)-(%ld,%ld), textlen=%ld\n", - debugstr_w(infoPtr->items[iItem].pszText), center_offset, + debugstr_w(infoPtr->items[iItem].pszText), center_offset_h, drawRect->left, drawRect->top, drawRect->right, drawRect->bottom, (rcText.right-rcText.left)); if((lStyle & TCS_VERTICAL) && (lStyle & TCS_BOTTOM)) { - rcImage.top = drawRect->top + center_offset; - rcImage.left = drawRect->right - cx; /* if tab is TCS_VERTICAL and TCS_BOTTOM, the text is drawn from the */ - /* right side of the tab, but the image still uses the left as its x position */ - /* this keeps the image always drawn off of the same side of the tab */ + rcImage.top = drawRect->top + center_offset_h; + /* if tab is TCS_VERTICAL and TCS_BOTTOM, the text is drawn from the */ + /* right side of the tab, but the image still uses the left as its x position */ + /* this keeps the image always drawn off of the same side of the tab */ + rcImage.left = drawRect->right - cx - center_offset_v; drawRect->top = rcImage.top + (cx + infoPtr->uHItemPadding); } else if(lStyle & TCS_VERTICAL) { - rcImage.top = drawRect->bottom - cy - center_offset; - rcImage.left--; + rcImage.top = drawRect->bottom - cy - center_offset_h; + rcImage.left = drawRect->left + center_offset_v; drawRect->bottom = rcImage.top - infoPtr->uHItemPadding; } else /* normal style, whether TCS_BOTTOM or not */ { - rcImage.left = drawRect->left + center_offset + 3; + rcImage.left = drawRect->left + center_offset_h + 3; drawRect->left = rcImage.left + cx + infoPtr->uHItemPadding; - rcImage.top -= (lStyle & TCS_BOTTOM) ? 2 : 1; + rcImage.top = drawRect->top + center_offset_v; } TRACE("drawing image=%d, left=%ld, top=%ld\n", @@ -1626,33 +1636,47 @@ TAB_DrawItemInterior rcImage.top, ILD_NORMAL ); - } else /* no image, so just shift the drawRect borders around */ + } + else /* no image, so just shift the drawRect borders around */ { if(lStyle & TCS_VERTICAL) { - center_offset = 0; + center_offset_h = 0; /* currently the rcText rect is flawed because the rotated font does not often match the horizontal font. So leave this as 0 ((drawRect->bottom - drawRect->top) - (rcText.right - rcText.left)) / 2; */ if(lStyle & TCS_BOTTOM) - drawRect->top+=center_offset; + drawRect->top+=center_offset_h; else - drawRect->bottom-=center_offset; + drawRect->bottom-=center_offset_h; } else { - center_offset = ((drawRect->right - drawRect->left) - (rcText.right - rcText.left)) / 2; - drawRect->left+=center_offset; + center_offset_h = ((drawRect->right - drawRect->left) - (rcText.right - rcText.left)) / 2; + drawRect->left+=center_offset_h; } } - /* Draw the text */ - if (lStyle & TCS_RIGHTJUSTIFY) - uHorizAlign = DT_CENTER; + if(lStyle & TCS_VERTICAL) + { + center_offset_v = ((drawRect->right - drawRect->left) - ((rcText.bottom - rcText.top) + infoPtr->uVItemPadding)) / 2; + drawRect->left += center_offset_v; + } else + { + center_offset_v = ((drawRect->bottom - drawRect->top) - ((rcText.bottom - rcText.top) + infoPtr->uVItemPadding)) / 2; + drawRect->top += center_offset_v; + } + + + /* Draw the text */ + if ((lStyle & TCS_FIXEDWIDTH && lStyle & TCS_FORCELABELLEFT) || + !center_offset_h) uHorizAlign = DT_LEFT; + else + uHorizAlign = DT_CENTER; if(lStyle & TCS_VERTICAL) /* if we are vertical rotate the text and each character */ { @@ -2572,8 +2596,7 @@ TAB_SetItemSize (HWND hwnd, WPARAM wParam, LPARAM lParam) lResult = MAKELONG(infoPtr->tabWidth, infoPtr->tabHeight); /* UNDOCUMENTED: If requested Width or Height is 0 this means that program wants to use auto size. */ - if ((lStyle & (TCS_FIXEDWIDTH | TCS_OWNERDRAWFIXED)) && - (infoPtr->tabWidth != (INT)LOWORD(lParam))) + if (lStyle & TCS_FIXEDWIDTH && (infoPtr->tabWidth != (INT)LOWORD(lParam))) { infoPtr->tabWidth = max((INT)LOWORD(lParam), infoPtr->tabMinWidth); bNeedPaint = TRUE; @@ -2583,8 +2606,6 @@ TAB_SetItemSize (HWND hwnd, WPARAM wParam, LPARAM lParam) { if ((infoPtr->fHeightSet = ((INT)HIWORD(lParam) != 0))) infoPtr->tabHeight = (INT)HIWORD(lParam); - else - TAB_SetItemBounds(hwnd); bNeedPaint = TRUE; } @@ -2593,7 +2614,10 @@ TAB_SetItemSize (HWND hwnd, WPARAM wParam, LPARAM lParam) infoPtr->tabHeight, infoPtr->tabWidth); if (bNeedPaint) + { + TAB_SetItemBounds(hwnd); RedrawWindow(hwnd, NULL, NULL, RDW_ERASE | RDW_INVALIDATE | RDW_UPDATENOW); + } return lResult; } @@ -2992,7 +3016,7 @@ TAB_Create (HWND hwnd, WPARAM wParam, LPARAM lParam) infoPtr->needsScrolling = FALSE; infoPtr->hwndUpDown = 0; infoPtr->leftmostVisible = 0; - infoPtr->fHeightSet = FALSE; + infoPtr->fHeightSet = FALSE; infoPtr->bUnicode = IsWindowUnicode (hwnd); TRACE("Created tab control, hwnd [%p]\n", hwnd); @@ -3045,8 +3069,7 @@ TAB_Create (HWND hwnd, WPARAM wParam, LPARAM lParam) /* Initialize the width of a tab. */ infoPtr->tabWidth = DEFAULT_TAB_WIDTH; - /* The minimum width is the default width at creation */ - infoPtr->tabMinWidth = DEFAULT_TAB_WIDTH; + infoPtr->tabMinWidth = 0; TRACE("tabH=%d, tabW=%d\n", infoPtr->tabHeight, infoPtr->tabWidth); diff --git a/dlls/comctl32/tests/.cvsignore b/dlls/comctl32/tests/.cvsignore index 9c7aece378c..e2292bb5def 100644 --- a/dlls/comctl32/tests/.cvsignore +++ b/dlls/comctl32/tests/.cvsignore @@ -1,4 +1,5 @@ Makefile comctl32_test.exe.spec.c dpa.ok +tab.ok testlist.c diff --git a/dlls/comctl32/tests/Makefile.in b/dlls/comctl32/tests/Makefile.in index fc11d1a703d..574b32fb0b8 100644 --- a/dlls/comctl32/tests/Makefile.in +++ b/dlls/comctl32/tests/Makefile.in @@ -3,10 +3,11 @@ TOPOBJDIR = ../../.. SRCDIR = @srcdir@ VPATH = @srcdir@ TESTDLL = comctl32.dll -IMPORTS = comctl32 +IMPORTS = comctl32 user32 CTESTS = \ - dpa.c + dpa.c \ + tab.c @MAKE_TEST_RULES@ diff --git a/dlls/comctl32/tests/tab.c b/dlls/comctl32/tests/tab.c new file mode 100644 index 00000000000..3be0a9edfee --- /dev/null +++ b/dlls/comctl32/tests/tab.c @@ -0,0 +1,165 @@ +/* Unit test suite for tab control. + * + * Copyright 2003 Vitaliy Margolen + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include +#include +#include + +#include "wine/test.h" + +#undef VISIBLE + +#define TAB_DEFAULT_WIDTH 96 +#define TAB_PADDING_X 2 +#define TAB_PADDING_Y 2 + +#ifdef VISIBLE +#define WAIT Sleep (1000) +#define REDRAW(hwnd) RedrawWindow (hwnd, NULL, 0, RDW_UPDATENOW) +#else +#define WAIT +#define REDRAW(hwnd) +#endif + +HWND +create_tabcontrol (DWORD style) +{ + HWND handle; + TCITEM tcNewTab; + + handle = CreateWindow ( + WC_TABCONTROLA, + "TestTab", + WS_CLIPSIBLINGS | WS_CLIPCHILDREN | TCS_FOCUSNEVER | style, + 0, 0, 300, 100, + NULL, NULL, NULL, 0); + + assert (handle); + + tcNewTab.mask = TCIF_TEXT | TCIF_IMAGE; + tcNewTab.pszText = "Tab 1"; + tcNewTab.iImage = 0; + SendMessage (handle, TCM_INSERTITEM, 0, (LPARAM) &tcNewTab); + tcNewTab.pszText = "Wide Tab 2"; + tcNewTab.iImage = 1; + SendMessage (handle, TCM_INSERTITEM, 1, (LPARAM) &tcNewTab); + tcNewTab.pszText = "T 3"; + tcNewTab.iImage = 2; + SendMessage (handle, TCM_INSERTITEM, 2, (LPARAM) &tcNewTab); + +#ifdef VISIBLE + ShowWindow (handle, SW_SHOW); +#endif + REDRAW(handle); + WAIT; + + return handle; +} + +void CheckSize(HWND hwnd, INT width, INT height) +{ + RECT rTab; + + SendMessage (hwnd, TCM_GETITEMRECT, 1, (LPARAM) &rTab); + /*trace ("Got (%ld,%ld)-(%ld,%ld)\n", rTab.left, rTab.top, rTab.right, rTab.bottom);*/ + if ((width >= 0) && (height < 0)) + ok (width == rTab.right - rTab.left, "Expected [%d] got [%ld]", width, rTab.right - rTab.left); + else if ((height >= 0) && (width < 0)) + ok (height == rTab.bottom - rTab.top, "Expected [%d] got [%ld]", height, rTab.bottom - rTab.top); + else + ok ((width == rTab.right - rTab.left) && + (height == rTab.bottom - rTab.top ), + "Expected [%d,%d] got [%ld,%ld]", width, height, rTab.right - rTab.left, rTab.bottom - rTab.top); +} + +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) +{ + HWND hwTab; + HIMAGELIST himl = ImageList_Create(21, 21, ILC_COLOR, 3, 4); + + InitCommonControls(); + + + hwTab = create_tabcontrol(TCS_FIXEDWIDTH); + + trace ("Testing TCS_FIXEDWIDTH tabs no icon...\n"); + trace (" default width...\n"); + CheckSize(hwTab, TAB_DEFAULT_WIDTH, -1); + trace (" set size...\n"); + TabCheckSetSize(hwTab, 50, 20, 50, 20); + WAIT; + trace (" min size...\n"); + TabCheckSetSize(hwTab, 0, 1, 0, 1); + WAIT; + + SendMessage(hwTab, TCM_SETIMAGELIST, 0, (LPARAM)himl); + + trace ("Testing TCS_FIXEDWIDTH tabs with icon...\n"); + trace (" set size > icon...\n"); + TabCheckSetSize(hwTab, 50, 30, 50, 30); + WAIT; + trace (" set size < icon...\n"); + TabCheckSetSize(hwTab, 20, 20, 25, 20); + WAIT; + trace (" min size...\n"); + TabCheckSetSize(hwTab, 0, 1, 25, 1); + WAIT; + + DestroyWindow (hwTab); + + trace ("Testing TCS_FIXEDWIDTH buttons no icon...\n"); + hwTab = create_tabcontrol(TCS_FIXEDWIDTH | TCS_BUTTONS); + + trace (" default width...\n"); + CheckSize(hwTab, TAB_DEFAULT_WIDTH, -1); + trace (" set size 1...\n"); + TabCheckSetSize(hwTab, 20, 20, 20, 20); + trace (" set size 2...\n"); + TabCheckSetSize(hwTab, 10, 50, 10, 50); + trace (" min size...\n"); + TabCheckSetSize(hwTab, 0, 1, 0, 1); + + SendMessage(hwTab, TCM_SETIMAGELIST, 0, (LPARAM)himl); + + trace ("Testing TCS_FIXEDWIDTH buttons with icon...\n"); + trace (" set size > icon...\n"); + TabCheckSetSize(hwTab, 50, 30, 50, 30); + trace (" set size < icon...\n"); + TabCheckSetSize(hwTab, 20, 20, 25, 20); + trace (" min size...\n"); + TabCheckSetSize(hwTab, 0, 1, 25, 1); + + trace (" Add padding...\n"); + SendMessage(hwTab, TCM_SETPADDING, 0, MAKELPARAM(4,4)); + trace (" min size...\n"); + TabCheckSetSize(hwTab, 0, 1, 25, 1); + WAIT; + + DestroyWindow (hwTab); + ImageList_Destroy(himl); +}