Added the ability to use multiline tab controls to wine.

This commit is contained in:
Aric Stewart 2000-05-09 22:33:48 +00:00 committed by Alexandre Julliard
parent b7ed6df279
commit 8ee3144a77
2 changed files with 220 additions and 49 deletions

View File

@ -174,14 +174,15 @@ static BOOL TAB_InternalGetItemRect(
RECT* itemRect,
RECT* selectedRect)
{
RECT tmpItemRect;
RECT tmpItemRect,clientRect;
LONG lStyle = GetWindowLongA(hwnd, GWL_STYLE);
/*
* Perform a sanity check and a trivial visibility check.
*/
if ( (infoPtr->uNumItem <=0) ||
(itemIndex >= infoPtr->uNumItem) ||
(itemIndex < infoPtr->leftmostVisible) )
(!(lStyle &TCS_MULTILINE) && (itemIndex < infoPtr->leftmostVisible)) )
return FALSE;
/*
@ -196,6 +197,31 @@ static BOOL TAB_InternalGetItemRect(
*/
*itemRect = infoPtr->items[itemIndex].rect;
/*
* calculate the times bottom and top based on the row
*/
GetClientRect(hwnd, &clientRect);
if (lStyle & TCS_BOTTOM)
{
itemRect->bottom = clientRect.bottom -
SELECTED_TAB_OFFSET -
itemRect->top * (infoPtr->tabHeight - 2);
itemRect->top = clientRect.bottom -
infoPtr->tabHeight -
itemRect->top * ( infoPtr->tabHeight - 2);
}
else
{
itemRect->bottom = clientRect.top +
infoPtr->tabHeight +
itemRect->top * (infoPtr->tabHeight - 2);
itemRect->top = clientRect.top +
SELECTED_TAB_OFFSET+
itemRect->top * (infoPtr->tabHeight - 2);
}
/*
* "scroll" it to make sure the item at the very left of the
* tab control is the leftmost visible tab.
@ -463,9 +489,9 @@ static LRESULT TAB_AdjustRect(
* Add the height of the tabs.
*/
if (GetWindowLongA(hwnd, GWL_STYLE) & TCS_BOTTOM)
prc->bottom += infoPtr->tabHeight;
prc->bottom += (infoPtr->tabHeight - 2) * (infoPtr->uNumRows + 1) + 2;
else
prc->top -= infoPtr->tabHeight;
prc->top -= (infoPtr->tabHeight - 2) * (infoPtr->uNumRows + 1) + 2;
/*
* Inflate the rectangle for the padding
@ -497,9 +523,9 @@ static LRESULT TAB_AdjustRect(
* Remove the height of the tabs.
*/
if (GetWindowLongA(hwnd, GWL_STYLE) & TCS_BOTTOM)
prc->bottom -= infoPtr->tabHeight;
prc->bottom -= (infoPtr->tabHeight - 2) * (infoPtr->uNumRows + 1) + 2;
else
prc->top += infoPtr->tabHeight;
prc->top += (infoPtr->tabHeight - 2) * (infoPtr->uNumRows + 1) + 2;
}
@ -575,10 +601,6 @@ static void TAB_SetupScrolling(
*/
if (infoPtr->hwndUpDown==0)
{
/*
* I use a scrollbar since it seems to be more stable than the Updown
* control.
*/
infoPtr->hwndUpDown = CreateWindowA("msctls_updown32",
"",
WS_VISIBLE | WS_CHILD | UDS_HORZ,
@ -651,6 +673,7 @@ static void TAB_SetItemBounds (HWND hwnd)
TEXTMETRICA fontMetrics;
INT curItem;
INT curItemLeftPos;
INT curItemRowCount;
HFONT hFont, hOldFont;
HDC hdc;
RECT clientRect;
@ -675,6 +698,7 @@ static void TAB_SetItemBounds (HWND hwnd)
* The leftmost item will be "0" aligned
*/
curItemLeftPos = 0;
curItemRowCount = 0;
if ( !(lStyle & TCS_FIXEDWIDTH) && !((lStyle & TCS_OWNERDRAWFIXED) && infoPtr->fSizeSet) )
{
@ -710,24 +734,6 @@ static void TAB_SetItemBounds (HWND hwnd)
for (curItem = 0; curItem < infoPtr->uNumItem; curItem++)
{
/*
* Calculate the vertical position of the tab
*/
if (lStyle & TCS_BOTTOM)
{
infoPtr->items[curItem].rect.bottom = clientRect.bottom -
SELECTED_TAB_OFFSET;
infoPtr->items[curItem].rect.top = clientRect.bottom -
infoPtr->tabHeight;
}
else
{
infoPtr->items[curItem].rect.top = clientRect.top +
SELECTED_TAB_OFFSET;
infoPtr->items[curItem].rect.bottom = clientRect.top +
infoPtr->tabHeight;
}
/*
* Set the leftmost position of the tab.
*/
@ -764,6 +770,27 @@ static void TAB_SetItemBounds (HWND hwnd)
num*HORIZONTAL_ITEM_PADDING;
}
/*
* Check if this is a multiline tab control and if so
* check to see if we should wrap the tabs
*
* Because we are going to arange all these tabs evenly
* really we are basically just counting rows at this point
*
*/
if ((lStyle & TCS_MULTILINE)&&
(infoPtr->items[curItem].rect.right > clientRect.right))
{
infoPtr->items[curItem].rect.right -=
infoPtr->items[curItem].rect.left;
infoPtr->items[curItem].rect.left = 0;
curItemRowCount ++;
}
infoPtr->items[curItem].rect.bottom = 0;
infoPtr->items[curItem].rect.top = curItemRowCount;
TRACE("TextSize: %i\n ", size.cx);
TRACE("Rect: T %i, L %i, B %i, R %i\n",
infoPtr->items[curItem].rect.top,
@ -781,18 +808,113 @@ static void TAB_SetItemBounds (HWND hwnd)
curItemLeftPos = infoPtr->items[curItem].rect.right;
}
if (!(lStyle & TCS_MULTILINE))
{
/*
* Check if we need a scrolling control.
*/
infoPtr->needsScrolling = (curItemLeftPos + (2*SELECTED_TAB_OFFSET) >
clientRect.right);
TAB_SetupScrolling(hwnd, infoPtr, &clientRect);
}
/*
* Check if we need a scrolling control.
* Set the number of rows
*/
infoPtr->needsScrolling = (curItemLeftPos + (2*SELECTED_TAB_OFFSET) >
clientRect.right);
/* Don't need scrolling, then update infoPtr->leftmostVisible */
if(!infoPtr->needsScrolling)
infoPtr->leftmostVisible = 0;
infoPtr->uNumRows = curItemRowCount;
TAB_SetupScrolling(hwnd, infoPtr, &clientRect);
if ((lStyle & TCS_MULTILINE)&&(infoPtr->uNumItem > 0))
{
INT widthDiff,remainder;
INT tabPerRow,remTab;
INT iRow,iItm;
INT iIndexStart=0,iIndexEnd=0, iCount=0;
/*
* Ok Microsoft trys to even out the rows. place the same
* number of tabs in each row. So lets give that a shot
*
*/
tabPerRow = infoPtr->uNumItem / (infoPtr->uNumRows + 1);
remTab = infoPtr->uNumItem % (infoPtr->uNumRows + 1);
for (iItm=0,iRow=0,iCount=0,curItemLeftPos=0;
iItm<infoPtr->uNumItem;
iItm++,iCount++)
{
if (iCount >= ((iRow<remTab)?tabPerRow+1:tabPerRow))
{
iRow++;
curItemLeftPos = 0;
iCount = 0;
}
/*
* normalize the current rect
*/
infoPtr->items[iItm].rect.right -=
infoPtr->items[iItm].rect.left;
infoPtr->items[iItm].rect.left = 0;
infoPtr->items[iItm].rect.top = iRow;
infoPtr->items[iItm].rect.left +=curItemLeftPos;
infoPtr->items[iItm].rect.right +=curItemLeftPos;
if (lStyle & TCS_BUTTONS)
curItemLeftPos = infoPtr->items[iItm].rect.right +
BUTTON_SPACINGX;
else
curItemLeftPos = infoPtr->items[iItm].rect.right;
}
/*
* Justify the rows
*
*/
{
while(iIndexStart < infoPtr->uNumItem)
{
/*
* find the indexs of the row
*/
for (iIndexEnd=iIndexStart;
(iIndexEnd < infoPtr->uNumItem) &&
(infoPtr->items[iIndexEnd].rect.top ==
infoPtr->items[iIndexStart].rect.top) ;
iIndexEnd++)
/* intentionaly blank */;
/*
* we need to justify these tabs so they fill the whole given
* client area
*
*/
widthDiff = clientRect.right - (2*SELECTED_TAB_OFFSET) -
infoPtr->items[iIndexEnd-1].rect.right;
iCount = iIndexEnd-iIndexStart;
if (iCount)
{
INT iIndex;
remainder = widthDiff % iCount;
widthDiff = widthDiff / iCount;
for (iIndex=iIndexStart,iCount=0; iIndex < iIndexEnd;
iIndex++,iCount++)
{
infoPtr->items[iIndex].rect.left +=iCount*widthDiff;
infoPtr->items[iIndex].rect.right +=(iCount+1)*widthDiff;
}
infoPtr->items[iIndex-1].rect.right += remainder;
}
iIndexStart=iIndexEnd;
}
}
}
TAB_EnsureSelectionVisible(hwnd,infoPtr);
/*
* Cleanup
*/
@ -1044,7 +1166,14 @@ static void TAB_DrawItem(
/*
* Draw the text;
*/
DrawTextA(hdc,
if (lStyle & TCS_RIGHTJUSTIFY)
DrawTextA(hdc,
infoPtr->items[iItem].pszText,
lstrlenA(infoPtr->items[iItem].pszText),
&r,
DT_CENTER|DT_SINGLELINE|DT_VCENTER);
else
DrawTextA(hdc,
infoPtr->items[iItem].pszText,
lstrlenA(infoPtr->items[iItem].pszText),
&r,
@ -1101,11 +1230,11 @@ static void TAB_DrawBorder (HWND hwnd, HDC hdc)
*/
if (GetWindowLongA(hwnd, GWL_STYLE) & TCS_BOTTOM)
{
rect.bottom -= infoPtr->tabHeight;
rect.bottom -= (infoPtr->tabHeight - 2) * (infoPtr->uNumRows + 1) + 2;
}
else
{
rect.top += infoPtr->tabHeight;
rect.top += (infoPtr->tabHeight - 2) * (infoPtr->uNumRows + 1) + 2;
}
/*
@ -1185,8 +1314,8 @@ static void TAB_Refresh (HWND hwnd, HDC hdc)
* If we haven't set the current focus yet, set it now.
* Only happens when we first paint the tab controls.
*/
if (infoPtr->uFocus == -1)
TAB_SetCurFocus(hwnd, infoPtr->iSelected);
if (infoPtr->uFocus == -1)
TAB_SetCurFocus(hwnd, infoPtr->iSelected);
}
SelectObject (hdc, hOldFont);
@ -1236,6 +1365,41 @@ static void TAB_EnsureSelectionVisible(
{
INT iSelected = infoPtr->iSelected;
/*
* set the items row to the bottommost row or topmost row depending on
* style
*/
if (infoPtr->uNumRows > 0)
{
INT newselected=infoPtr->items[iSelected].rect.top;
INT iTargetRow;
LONG lStyle = GetWindowLongA(hwnd, GWL_STYLE);
if (lStyle & TCS_BOTTOM)
iTargetRow = 0;
else
iTargetRow = infoPtr->uNumRows;
if (newselected != iTargetRow)
{
INT i;
for (i=0; i < infoPtr->uNumItem; i++)
if (infoPtr->items[i].rect.top == newselected )
infoPtr->items[i].rect.top = iTargetRow;
else if (lStyle&TCS_BOTTOM)
{
if (infoPtr->items[i].rect.top < newselected)
infoPtr->items[i].rect.top+=1;
}
else
{
if (infoPtr->items[i].rect.top > newselected)
infoPtr->items[i].rect.top-=1;
}
}
}
/*
* Do the trivial cases first.
*/
@ -1301,11 +1465,13 @@ static void TAB_InvalidateTabArea(
if (GetWindowLongA(hwnd, GWL_STYLE) & TCS_BOTTOM)
{
clientRect.top = clientRect.bottom - (infoPtr->tabHeight + 3);
clientRect.top = clientRect.bottom - (infoPtr->tabHeight *
(infoPtr->uNumRows + 1) + 3);
}
else
{
clientRect.bottom = clientRect.top + (infoPtr->tabHeight + 1);
clientRect.bottom = clientRect.top + (infoPtr->tabHeight *
(infoPtr->uNumRows + 1) + 1);
}
InvalidateRect(hwnd, &clientRect, TRUE);
@ -1389,12 +1555,12 @@ TAB_InsertItem (HWND hwnd, WPARAM wParam, LPARAM lParam)
if (pti->mask & TCIF_PARAM)
infoPtr->items[iItem].lParam = pti->lParam;
TAB_SetItemBounds(hwnd);
TAB_InvalidateTabArea(hwnd, infoPtr);
TRACE("[%04x]: added item %d '%s'\n",
hwnd, iItem, infoPtr->items[iItem].pszText);
TAB_SetItemBounds(hwnd);
return iItem;
}
@ -1668,6 +1834,7 @@ TAB_Create (HWND hwnd, WPARAM wParam, LPARAM lParam)
SetWindowLongA(hwnd, 0, (DWORD)infoPtr);
infoPtr->uNumItem = 0;
infoPtr->uNumRows = 0;
infoPtr->hFont = 0;
infoPtr->items = 0;
infoPtr->hcurArrow = LoadCursorA (0, IDC_ARROWA);
@ -1938,7 +2105,7 @@ TAB_WindowProc (HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
default:
if (uMsg >= WM_USER)
WARN("unknown msg %04x wp=%08x lp=%08lx\n",
ERR("unknown msg %04x wp=%08x lp=%08lx\n",
uMsg, wParam, lParam);
return DefWindowProcA (hwnd, uMsg, wParam, lParam);
}

View File

@ -20,12 +20,16 @@ typedef struct tagTAB_ITEM
LPARAM lParam;
RECT rect; /* bounding rectangle of the item relative to the
* leftmost item (the leftmost item, 0, would have a
* "left" member of 0 in this rectangle) */
* "left" member of 0 in this rectangle)
*
* additionally the top member hold the row number
* and bottom is unused and should be 0 */
} TAB_ITEM;
typedef struct tagTAB_INFO
{
UINT uNumItem; /* number of tab items */
UINT uNumRows; /* number of tab rows */
INT tabHeight; /* height of the tab row */
INT tabWidth; /* width of tabs */
HFONT hFont; /* handle to the current font */