- 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.
This commit is contained in:
Vitaliy Margolen 2003-10-31 00:06:42 +00:00 committed by Alexandre Julliard
parent 0b37bf74b9
commit 785bae8aae
4 changed files with 241 additions and 51 deletions

View File

@ -93,7 +93,7 @@ typedef struct
#define DISPLAY_AREA_PADDINGY 2 #define DISPLAY_AREA_PADDINGY 2
#define CONTROL_BORDER_SIZEX 2 #define CONTROL_BORDER_SIZEX 2
#define CONTROL_BORDER_SIZEY 2 #define CONTROL_BORDER_SIZEY 2
#define BUTTON_SPACINGX 4 #define BUTTON_SPACINGX 3
#define BUTTON_SPACINGY 4 #define BUTTON_SPACINGY 4
#define FLAT_BTN_SPACINGX 8 #define FLAT_BTN_SPACINGX 8
#define DEFAULT_TAB_WIDTH 96 #define DEFAULT_TAB_WIDTH 96
@ -344,11 +344,10 @@ static BOOL TAB_InternalGetItemRect(
itemRect->bottom = clientRect.top + itemRect->bottom = clientRect.top +
infoPtr->tabHeight + infoPtr->tabHeight +
itemRect->top * (infoPtr->tabHeight - 2) + 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 + itemRect->top = clientRect.top +
SELECTED_TAB_OFFSET +
itemRect->top * (infoPtr->tabHeight - 2) + 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; INT iTemp;
RECT* rcItem; RECT* rcItem;
INT iIndex; INT iIndex;
INT icon_width = 0;
/* /*
* We need to get text information so we need a DC and we need to select * 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); 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++) for (curItem = 0; curItem < infoPtr->uNumItem; curItem++)
{ {
/* Set the leftmost position of the tab. */ /* Set the leftmost position of the tab. */
infoPtr->items[curItem].rect.left = curItemLeftPos; 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->items[curItem].rect.right = infoPtr->items[curItem].rect.left +
infoPtr->tabWidth + max(infoPtr->tabWidth, icon_width);
2 * infoPtr->uHItemPadding;
} }
else else
{ {
int icon_width = 0;
int num = 2; int num = 2;
/* Calculate how wide the tab is depending on the text it contains */ /* Calculate how wide the tab is depending on the text it contains */
GetTextExtentPoint32W(hdc, infoPtr->items[curItem].pszText, GetTextExtentPoint32W(hdc, infoPtr->items[curItem].pszText,
lstrlenW(infoPtr->items[curItem].pszText), &size); 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 + infoPtr->items[curItem].rect.right = infoPtr->items[curItem].rect.left +
size.cx + icon_width + size.cx + icon_width +
num * infoPtr->uHItemPadding; num * infoPtr->uHItemPadding;
@ -1215,7 +1213,7 @@ static void TAB_SetItemBounds (HWND hwnd)
*/ */
if (lStyle & TCS_BUTTONS) if (lStyle & TCS_BUTTONS)
{ {
curItemLeftPos = infoPtr->items[curItem].rect.right + 1; curItemLeftPos = infoPtr->items[curItem].rect.right + BUTTON_SPACINGX;
if (lStyle & TCS_FLATBUTTONS) if (lStyle & TCS_FLATBUTTONS)
curItemLeftPos += FLAT_BTN_SPACINGX; curItemLeftPos += FLAT_BTN_SPACINGX;
} }
@ -1547,7 +1545,7 @@ TAB_DrawItemInterior
/* used to center the icon and text in the tab */ /* used to center the icon and text in the tab */
RECT rcText; RECT rcText;
INT center_offset; INT center_offset_h, center_offset_v;
/* /*
* Deflate the rectangle to acount for the padding * Deflate the rectangle to acount for the padding
@ -1585,34 +1583,46 @@ TAB_DrawItemInterior
ImageList_GetIconSize(infoPtr->himl, &cx, &cy); ImageList_GetIconSize(infoPtr->himl, &cx, &cy);
if(lStyle & TCS_VERTICAL) 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 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", 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, drawRect->left, drawRect->top, drawRect->right, drawRect->bottom,
(rcText.right-rcText.left)); (rcText.right-rcText.left));
if((lStyle & TCS_VERTICAL) && (lStyle & TCS_BOTTOM)) if((lStyle & TCS_VERTICAL) && (lStyle & TCS_BOTTOM))
{ {
rcImage.top = drawRect->top + center_offset; rcImage.top = drawRect->top + center_offset_h;
rcImage.left = drawRect->right - cx; /* if tab is TCS_VERTICAL and TCS_BOTTOM, the text is drawn from the */ /* 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 */ /* 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 */ /* 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); drawRect->top = rcImage.top + (cx + infoPtr->uHItemPadding);
} }
else if(lStyle & TCS_VERTICAL) else if(lStyle & TCS_VERTICAL)
{ {
rcImage.top = drawRect->bottom - cy - center_offset; rcImage.top = drawRect->bottom - cy - center_offset_h;
rcImage.left--; rcImage.left = drawRect->left + center_offset_v;
drawRect->bottom = rcImage.top - infoPtr->uHItemPadding; drawRect->bottom = rcImage.top - infoPtr->uHItemPadding;
} }
else /* normal style, whether TCS_BOTTOM or not */ 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; 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", TRACE("drawing image=%d, left=%ld, top=%ld\n",
@ -1626,33 +1636,47 @@ TAB_DrawItemInterior
rcImage.top, rcImage.top,
ILD_NORMAL 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) if(lStyle & TCS_VERTICAL)
{ {
center_offset = 0; center_offset_h = 0;
/* /*
currently the rcText rect is flawed because the rotated font does not currently the rcText rect is flawed because the rotated font does not
often match the horizontal font. So leave this as 0 often match the horizontal font. So leave this as 0
((drawRect->bottom - drawRect->top) - (rcText.right - rcText.left)) / 2; ((drawRect->bottom - drawRect->top) - (rcText.right - rcText.left)) / 2;
*/ */
if(lStyle & TCS_BOTTOM) if(lStyle & TCS_BOTTOM)
drawRect->top+=center_offset; drawRect->top+=center_offset_h;
else else
drawRect->bottom-=center_offset; drawRect->bottom-=center_offset_h;
} }
else else
{ {
center_offset = ((drawRect->right - drawRect->left) - (rcText.right - rcText.left)) / 2; center_offset_h = ((drawRect->right - drawRect->left) - (rcText.right - rcText.left)) / 2;
drawRect->left+=center_offset; drawRect->left+=center_offset_h;
} }
} }
/* Draw the text */ if(lStyle & TCS_VERTICAL)
if (lStyle & TCS_RIGHTJUSTIFY) {
uHorizAlign = DT_CENTER; center_offset_v = ((drawRect->right - drawRect->left) - ((rcText.bottom - rcText.top) + infoPtr->uVItemPadding)) / 2;
drawRect->left += center_offset_v;
}
else 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; uHorizAlign = DT_LEFT;
else
uHorizAlign = DT_CENTER;
if(lStyle & TCS_VERTICAL) /* if we are vertical rotate the text and each character */ 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); lResult = MAKELONG(infoPtr->tabWidth, infoPtr->tabHeight);
/* UNDOCUMENTED: If requested Width or Height is 0 this means that program wants to use auto size. */ /* UNDOCUMENTED: If requested Width or Height is 0 this means that program wants to use auto size. */
if ((lStyle & (TCS_FIXEDWIDTH | TCS_OWNERDRAWFIXED)) && if (lStyle & TCS_FIXEDWIDTH && (infoPtr->tabWidth != (INT)LOWORD(lParam)))
(infoPtr->tabWidth != (INT)LOWORD(lParam)))
{ {
infoPtr->tabWidth = max((INT)LOWORD(lParam), infoPtr->tabMinWidth); infoPtr->tabWidth = max((INT)LOWORD(lParam), infoPtr->tabMinWidth);
bNeedPaint = TRUE; bNeedPaint = TRUE;
@ -2583,8 +2606,6 @@ TAB_SetItemSize (HWND hwnd, WPARAM wParam, LPARAM lParam)
{ {
if ((infoPtr->fHeightSet = ((INT)HIWORD(lParam) != 0))) if ((infoPtr->fHeightSet = ((INT)HIWORD(lParam) != 0)))
infoPtr->tabHeight = (INT)HIWORD(lParam); infoPtr->tabHeight = (INT)HIWORD(lParam);
else
TAB_SetItemBounds(hwnd);
bNeedPaint = TRUE; bNeedPaint = TRUE;
} }
@ -2593,7 +2614,10 @@ TAB_SetItemSize (HWND hwnd, WPARAM wParam, LPARAM lParam)
infoPtr->tabHeight, infoPtr->tabWidth); infoPtr->tabHeight, infoPtr->tabWidth);
if (bNeedPaint) if (bNeedPaint)
{
TAB_SetItemBounds(hwnd);
RedrawWindow(hwnd, NULL, NULL, RDW_ERASE | RDW_INVALIDATE | RDW_UPDATENOW); RedrawWindow(hwnd, NULL, NULL, RDW_ERASE | RDW_INVALIDATE | RDW_UPDATENOW);
}
return lResult; return lResult;
} }
@ -3045,8 +3069,7 @@ TAB_Create (HWND hwnd, WPARAM wParam, LPARAM lParam)
/* Initialize the width of a tab. */ /* Initialize the width of a tab. */
infoPtr->tabWidth = DEFAULT_TAB_WIDTH; infoPtr->tabWidth = DEFAULT_TAB_WIDTH;
/* The minimum width is the default width at creation */ infoPtr->tabMinWidth = 0;
infoPtr->tabMinWidth = DEFAULT_TAB_WIDTH;
TRACE("tabH=%d, tabW=%d\n", infoPtr->tabHeight, infoPtr->tabWidth); TRACE("tabH=%d, tabW=%d\n", infoPtr->tabHeight, infoPtr->tabWidth);

View File

@ -1,4 +1,5 @@
Makefile Makefile
comctl32_test.exe.spec.c comctl32_test.exe.spec.c
dpa.ok dpa.ok
tab.ok
testlist.c testlist.c

View File

@ -3,10 +3,11 @@ TOPOBJDIR = ../../..
SRCDIR = @srcdir@ SRCDIR = @srcdir@
VPATH = @srcdir@ VPATH = @srcdir@
TESTDLL = comctl32.dll TESTDLL = comctl32.dll
IMPORTS = comctl32 IMPORTS = comctl32 user32
CTESTS = \ CTESTS = \
dpa.c dpa.c \
tab.c
@MAKE_TEST_RULES@ @MAKE_TEST_RULES@

165
dlls/comctl32/tests/tab.c Normal file
View File

@ -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 <assert.h>
#include <windows.h>
#include <commctrl.h>
#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);
}