*
*/
-#include <stdarg.h>
-#include <string.h>
-
-#include "windef.h"
-#include "winbase.h"
-#include "wingdi.h"
-#include "winuser.h"
-#include "winnls.h"
-#include "commctrl.h"
#include "comctl32.h"
-#include "uxtheme.h"
-#include "tmschema.h"
-#include "wine/debug.h"
-#include <math.h>
WINE_DEFAULT_DEBUG_CHANNEL(tab);
INT iSelected; /* the currently selected item */
INT iHotTracked; /* the highlighted item under the mouse */
INT uFocus; /* item which has the focus */
- TAB_ITEM* items; /* pointer to an array of TAB_ITEM's */
BOOL DoRedraw; /* flag for redrawing when tab contents is changed*/
BOOL needsScrolling; /* TRUE if the size of the tabs is greater than
* the size of the control */
DWORD exStyle; /* Extended style used, currently:
TCS_EX_FLATSEPARATORS, TCS_EX_REGISTERDROP */
DWORD dwStyle; /* the cached window GWL_STYLE */
+
+ HDPA items; /* dynamic array of TAB_ITEM* pointers */
} TAB_INFO;
/******************************************************************************
#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_MIN_TAB_WIDTH(infoPtr) (DEFAULT_MIN_TAB_WIDTH - (DEFAULT_PADDING_X - (infoPtr)->uHItemPadding) * 2)
static const WCHAR themeClass[] = { 'T','a','b',0 };
+static inline TAB_ITEM* TAB_GetItem(const TAB_INFO *infoPtr, INT i)
+{
+ assert(i >= 0 && i < infoPtr->uNumItem);
+ return DPA_GetPtr(infoPtr->items, i);
+}
+
/******************************************************************************
* Prototypes
*/
TAB_DumpItemInternal(const TAB_INFO *infoPtr, UINT iItem)
{
if (TRACE_ON(tab)) {
- TAB_ITEM *ti;
+ TAB_ITEM *ti = TAB_GetItem(infoPtr, iItem);
- ti = TAB_GetItem(infoPtr, iItem);
TRACE("tab %d, dwState=0x%08x, pszText=%s, iImage=%d\n",
iItem, ti->dwState, debugstr_w(ti->pszText), ti->iImage);
TRACE("tab %d, rect.left=%d, rect.top(row)=%d\n",
TRACE("(%p %d)\n", infoPtr, iItem);
- if (iItem < 0)
- infoPtr->iSelected = -1;
- else if (iItem >= infoPtr->uNumItem)
+ if (iItem >= (INT)infoPtr->uNumItem)
return -1;
- else {
- if (prevItem != iItem) {
- if (prevItem != -1)
- TAB_GetItem(infoPtr, prevItem)->dwState &= ~TCIS_BUTTONPRESSED;
- TAB_GetItem(infoPtr, iItem)->dwState |= TCIS_BUTTONPRESSED;
+ if (prevItem != iItem) {
+ if (prevItem != -1)
+ TAB_GetItem(infoPtr, prevItem)->dwState &= ~TCIS_BUTTONPRESSED;
+
+ if (iItem >= 0)
+ {
+ TAB_GetItem(infoPtr, iItem)->dwState |= TCIS_BUTTONPRESSED;
infoPtr->iSelected = iItem;
infoPtr->uFocus = iItem;
- TAB_EnsureSelectionVisible(infoPtr);
- TAB_InvalidateTabArea(infoPtr);
}
+ else
+ {
+ infoPtr->iSelected = -1;
+ infoPtr->uFocus = -1;
+ }
+
+ TAB_EnsureSelectionVisible(infoPtr);
+ TAB_InvalidateTabArea(infoPtr);
}
+
return prevItem;
}
(itemIndex < infoPtr->leftmostVisible)))
{
TRACE("Not Visible\n");
- /* need to initialize these to empty rects */
- if (itemRect)
- {
- memset(itemRect,0,sizeof(RECT));
- itemRect->bottom = infoPtr->tabHeight;
- }
- if (selectedRect)
- memset(selectedRect,0,sizeof(RECT));
+ SetRect(itemRect, 0, 0, 0, infoPtr->tabHeight);
+ SetRectEmpty(selectedRect);
return FALSE;
}
/* Now, calculate the position of the item as if it were selected. */
if (selectedRect!=NULL)
{
- CopyRect(selectedRect, itemRect);
+ *selectedRect = *itemRect;
/* The rectangle of a selected item is a bit wider. */
if(infoPtr->dwStyle & TCS_VERTICAL)
break;
}
- TAB_SendSimpleNotify(infoPtr, TCN_SELCHANGING);
+ if (TAB_SendSimpleNotify(infoPtr, TCN_SELCHANGING))
+ return 0;
if (pressed)
TAB_DeselectAll (infoPtr, FALSE);
return 0;
}
-static inline LRESULT
-TAB_RButtonDown (const TAB_INFO *infoPtr)
+static inline void
+TAB_RButtonUp (const TAB_INFO *infoPtr)
{
TAB_SendSimpleNotify(infoPtr, NM_RCLICK);
- return 0;
}
/******************************************************************************
/*
* Calculate the position of the scroll control.
*/
- if(infoPtr->dwStyle & TCS_VERTICAL)
- {
- controlPos.right = clientRect->right;
- controlPos.left = controlPos.right - 2 * GetSystemMetrics(SM_CXHSCROLL);
+ controlPos.right = clientRect->right;
+ controlPos.left = controlPos.right - 2 * GetSystemMetrics(SM_CXHSCROLL);
- if (infoPtr->dwStyle & TCS_BOTTOM)
- {
- controlPos.top = clientRect->bottom - infoPtr->tabHeight;
- controlPos.bottom = controlPos.top + GetSystemMetrics(SM_CYHSCROLL);
- }
- else
- {
- controlPos.bottom = clientRect->top + infoPtr->tabHeight;
- controlPos.top = controlPos.bottom - GetSystemMetrics(SM_CYHSCROLL);
- }
+ if (infoPtr->dwStyle & TCS_BOTTOM)
+ {
+ controlPos.top = clientRect->bottom - infoPtr->tabHeight;
+ controlPos.bottom = controlPos.top + GetSystemMetrics(SM_CYHSCROLL);
}
else
{
- controlPos.right = clientRect->right;
- controlPos.left = controlPos.right - 2 * GetSystemMetrics(SM_CXHSCROLL);
-
- if (infoPtr->dwStyle & TCS_BOTTOM)
- {
- controlPos.top = clientRect->bottom - infoPtr->tabHeight;
- controlPos.bottom = controlPos.top + GetSystemMetrics(SM_CYHSCROLL);
- }
- else
- {
- controlPos.bottom = clientRect->top + infoPtr->tabHeight;
- controlPos.top = controlPos.bottom - GetSystemMetrics(SM_CYHSCROLL);
- }
+ controlPos.bottom = clientRect->top + infoPtr->tabHeight;
+ controlPos.top = controlPos.bottom - GetSystemMetrics(SM_CYHSCROLL);
}
/*
tabwidth = max(tabwidth, infoPtr->tabMinWidth);
curr->rect.right = curr->rect.left + tabwidth;
- TRACE("for <%s>, l,r=%d,%d\n",
- debugstr_w(curr->pszText), curr->rect.left, curr->rect.right);
+ TRACE("for <%s>, rect %s\n", debugstr_w(curr->pszText), wine_dbgstr_rect(&curr->rect));
}
/*
curr->rect.left = 0;
curItemRowCount++;
- TRACE("wrapping <%s>, l,r=%d,%d\n", debugstr_w(curr->pszText),
- curr->rect.left, curr->rect.right);
+ TRACE("wrapping <%s>, rect %s\n", debugstr_w(curr->pszText), wine_dbgstr_rect(&curr->rect));
}
curr->rect.bottom = 0;
else
curItemLeftPos = curr->rect.right;
- TRACE("arranging <%s>, l,r=%d,%d, row=%d\n",
- debugstr_w(curr->pszText), curr->rect.left,
- curr->rect.right, curr->rect.top);
+ TRACE("arranging <%s>, rect %s\n", debugstr_w(curr->pszText), wine_dbgstr_rect(&curr->rect));
}
/*
item->rect.left += iCount * widthDiff;
item->rect.right += (iCount + 1) * widthDiff;
- TRACE("adjusting 1 <%s>, l,r=%d,%d\n",
- debugstr_w(item->pszText),
- item->rect.left, item->rect.right);
+ TRACE("adjusting 1 <%s>, rect %s\n", debugstr_w(item->pszText), wine_dbgstr_rect(&item->rect));
}
TAB_GetItem(infoPtr, iIndex - 1)->rect.right += remainder;
start->rect.left = clientRect.left;
start->rect.right = clientRect.right - 4;
- TRACE("adjusting 2 <%s>, l,r=%d,%d\n",
- debugstr_w(start->pszText),
- start->rect.left, start->rect.right);
-
+ TRACE("adjusting 2 <%s>, rect %s\n", debugstr_w(start->pszText), wine_dbgstr_rect(&start->rect));
}
-
iIndexStart = iIndexEnd;
}
}
HPEN holdPen;
INT oldBkMode;
HFONT hOldFont;
+#ifdef __REACTOS__
+HTHEME theme = GetWindowTheme (infoPtr->hwnd);
+#endif
/* if (drawRect == NULL) */
{
}
}
else
- {
- drawRect->left += 2;
- drawRect->top += 2;
- drawRect->right -= 2;
- drawRect->bottom -= 2;
- }
+ InflateRect(drawRect, -2, -2);
}
else
{
if (iItem != infoPtr->iSelected)
{
drawRect->left += 2;
- drawRect->top += 2;
- drawRect->bottom -= 2;
+ InflateRect(drawRect, 0, -2);
}
}
else if (infoPtr->dwStyle & TCS_VERTICAL)
}
else
{
- drawRect->top += 2;
drawRect->right -= 2;
- drawRect->bottom -= 2;
+ InflateRect(drawRect, 0, -2);
}
}
else if (infoPtr->dwStyle & TCS_BOTTOM)
drawRect->top += 2;
drawRect->right -= 1;
if ( iItem == infoPtr->iSelected )
- {
- drawRect->right -= 1;
- drawRect->left += 1;
- }
+ InflateRect(drawRect, -1, 0);
id = (UINT)GetWindowLongPtrW( infoPtr->hwnd, GWLP_ID );
dis.itemState |= ODS_FOCUS;
dis.hwndItem = infoPtr->hwnd;
dis.hDC = hdc;
- CopyRect(&dis.rcItem,drawRect);
+ dis.rcItem = *drawRect;
/* when extra data fits ULONG_PTR, store it directly */
if (infoPtr->cbInfo > sizeof(LPARAM))
{
/* this could be considered broken on 64 bit, but that's how it works -
only first 4 bytes are copied */
+ dis.itemData = 0;
memcpy(&dis.itemData, (ULONG_PTR*)TAB_GetItem(infoPtr, iItem)->extra, 4);
}
rcImage = *drawRect;
rcTemp = *drawRect;
-
- rcText.left = rcText.top = rcText.right = rcText.bottom = 0;
+ SetRectEmpty(&rcText);
/* get the rectangle that the text fits in */
if (item->pszText)
/* Draw the text */
if(infoPtr->dwStyle & TCS_VERTICAL) /* if we are vertical rotate the text and each character */
{
- static const WCHAR ArialW[] = { 'A','r','i','a','l',0 };
LOGFONTW logfont;
- HFONT hFont = 0;
+ HFONT hFont;
INT nEscapement = 900;
INT nOrientation = 900;
}
/* to get a font with the escapement and orientation we are looking for, we need to */
- /* call CreateFontIndirectA, which requires us to set the values of the logfont we pass in */
- if (!GetObjectW((infoPtr->hFont) ?
- infoPtr->hFont : GetStockObject(SYSTEM_FONT),
- sizeof(LOGFONTW),&logfont))
- {
- INT iPointSize = 9;
-
- lstrcpyW(logfont.lfFaceName, ArialW);
- logfont.lfHeight = -MulDiv(iPointSize, GetDeviceCaps(hdc, LOGPIXELSY),
- 72);
- logfont.lfWeight = FW_NORMAL;
- logfont.lfItalic = 0;
- logfont.lfUnderline = 0;
- logfont.lfStrikeOut = 0;
- }
+ /* call CreateFontIndirect, which requires us to set the values of the logfont we pass in */
+ if (!GetObjectW(infoPtr->hFont, sizeof(logfont), &logfont))
+ GetObjectW(GetStockObject(DEFAULT_GUI_FONT), sizeof(logfont), &logfont);
logfont.lfEscapement = nEscapement;
logfont.lfOrientation = nOrientation;
TRACE("for <%s>, c_o_h=%d, c_o_v=%d, draw=(%s), textlen=%d\n",
debugstr_w(item->pszText), center_offset_h, center_offset_v,
wine_dbgstr_rect(drawRect), (rcText.right-rcText.left));
+#ifdef __REACTOS__
+ if (theme && item->pszText)
+ {
+ int partIndex = iItem == infoPtr->iSelected ? TABP_TABITEM : TABP_TOPTABITEM;
+ int stateId = TIS_NORMAL;
+
+ if (iItem == infoPtr->iSelected)
+ stateId = TIS_SELECTED;
+ else if (iItem == infoPtr->iHotTracked)
+ stateId = TIS_HOT;
+ else if (iItem == infoPtr->uFocus)
+ stateId = TIS_FOCUSED;
+
+ DrawThemeText(theme,
+ hdc,
+ partIndex,
+ stateId,
+ item->pszText,
+ lstrlenW(item->pszText),
+ DT_LEFT | DT_SINGLELINE, 0, drawRect);
+ }
+ else
+#endif
if (item->pszText)
{
DrawTextW
partIndex += 4;
/* The part also differs on the position of a tab on a line.
* "Visually" determining the position works well enough. */
+ GetClientRect(infoPtr->hwnd, &r1);
if(selectedRect.left == 0)
partIndex += 1;
- if(selectedRect.right == clRight)
+ if(selectedRect.right == r1.right)
partIndex += 2;
if (iItem == infoPtr->iSelected)
INT iSelected = infoPtr->iSelected;
INT iOrigLeftmostVisible = infoPtr->leftmostVisible;
+ if (iSelected < 0)
+ return;
+
/* set the items row to the bottommost row or topmost row depending on
* style */
if ((infoPtr->uNumRows > 1) && !(infoPtr->dwStyle & TCS_BUTTONS))
TAB_DumpItemExternalT(pti, iItem, bUnicode);
-
- if (infoPtr->uNumItem == 0) {
- infoPtr->items = Alloc (TAB_ITEM_SIZE(infoPtr));
- infoPtr->uNumItem++;
- infoPtr->iSelected = 0;
+ if (!(item = Alloc(TAB_ITEM_SIZE(infoPtr)))) return FALSE;
+ if (DPA_InsertPtr(infoPtr->items, iItem, item) == -1)
+ {
+ Free(item);
+ return FALSE;
}
- else {
- LPBYTE oldItems = (LPBYTE)infoPtr->items;
-
- infoPtr->uNumItem++;
- infoPtr->items = Alloc (TAB_ITEM_SIZE(infoPtr) * infoPtr->uNumItem);
-
- /* pre insert copy */
- if (iItem > 0) {
- memcpy (infoPtr->items, oldItems,
- iItem * TAB_ITEM_SIZE(infoPtr));
- }
-
- /* post insert copy */
- if (iItem < infoPtr->uNumItem - 1) {
- memcpy (TAB_GetItem(infoPtr, iItem + 1),
- oldItems + iItem * TAB_ITEM_SIZE(infoPtr),
- (infoPtr->uNumItem - iItem - 1) * TAB_ITEM_SIZE(infoPtr));
-
- }
- if (iItem <= infoPtr->iSelected)
+ if (infoPtr->uNumItem == 0)
+ infoPtr->iSelected = 0;
+ else if (iItem <= infoPtr->iSelected)
infoPtr->iSelected++;
- Free (oldItems);
- }
-
- item = TAB_GetItem(infoPtr, iItem);
+ infoPtr->uNumItem++;
item->pszText = NULL;
-
if (pti->mask & TCIF_TEXT)
{
if (bUnicode)
static LRESULT TAB_DeleteItem (TAB_INFO *infoPtr, INT iItem)
{
- BOOL bResult = FALSE;
+ TAB_ITEM *item;
TRACE("(%p, %d)\n", infoPtr, iItem);
- if ((iItem >= 0) && (iItem < infoPtr->uNumItem))
- {
- TAB_ITEM *item = TAB_GetItem(infoPtr, iItem);
- LPBYTE oldItems = (LPBYTE)infoPtr->items;
+ if (iItem < 0 || iItem >= infoPtr->uNumItem) return FALSE;
- TAB_InvalidateTabArea(infoPtr);
- Free(item->pszText);
- infoPtr->uNumItem--;
+ TAB_InvalidateTabArea(infoPtr);
+ item = TAB_GetItem(infoPtr, iItem);
+ Free(item->pszText);
+ Free(item);
+ infoPtr->uNumItem--;
+ DPA_DeletePtr(infoPtr->items, iItem);
- if (!infoPtr->uNumItem)
+ if (infoPtr->uNumItem == 0)
+ {
+ if (infoPtr->iHotTracked >= 0)
{
- infoPtr->items = NULL;
- if (infoPtr->iHotTracked >= 0)
- {
- KillTimer(infoPtr->hwnd, TAB_HOTTRACK_TIMER);
- infoPtr->iHotTracked = -1;
- }
+ KillTimer(infoPtr->hwnd, TAB_HOTTRACK_TIMER);
+ infoPtr->iHotTracked = -1;
}
- else
- {
- infoPtr->items = Alloc(TAB_ITEM_SIZE(infoPtr) * infoPtr->uNumItem);
-
- if (iItem > 0)
- memcpy(infoPtr->items, oldItems, iItem * TAB_ITEM_SIZE(infoPtr));
-
- if (iItem < infoPtr->uNumItem)
- memcpy(TAB_GetItem(infoPtr, iItem),
- oldItems + (iItem + 1) * TAB_ITEM_SIZE(infoPtr),
- (infoPtr->uNumItem - iItem) * TAB_ITEM_SIZE(infoPtr));
-
- if (iItem <= infoPtr->iHotTracked)
- {
- /* When tabs move left/up, the hot track item may change */
- FIXME("Recalc hot track\n");
- }
- }
- Free(oldItems);
-
- /* Readjust the selected index */
- if (iItem == infoPtr->iSelected)
- infoPtr->iSelected = -1;
- else if (iItem < infoPtr->iSelected)
- infoPtr->iSelected--;
- if (infoPtr->uNumItem == 0)
- infoPtr->iSelected = -1;
+ infoPtr->iSelected = -1;
+ }
+ else
+ {
+ if (iItem <= infoPtr->iHotTracked)
+ {
+ /* When tabs move left/up, the hot track item may change */
+ FIXME("Recalc hot track\n");
+ }
+ }
- /* Reposition and repaint tabs */
- TAB_SetItemBounds(infoPtr);
+ /* adjust the selected index */
+ if (iItem == infoPtr->iSelected)
+ infoPtr->iSelected = -1;
+ else if (iItem < infoPtr->iSelected)
+ infoPtr->iSelected--;
- bResult = TRUE;
- }
+ /* reposition and repaint tabs */
+ TAB_SetItemBounds(infoPtr);
- return bResult;
+ return TRUE;
}
static inline LRESULT TAB_DeleteAllItems (TAB_INFO *infoPtr)
TEXTMETRICW fontMetrics;
HDC hdc;
HFONT hOldFont;
- DWORD dwStyle;
+ DWORD style;
infoPtr = Alloc (sizeof(TAB_INFO));
infoPtr->uHItemPadding_s = 6;
infoPtr->uVItemPadding_s = 3;
infoPtr->hFont = 0;
- infoPtr->items = 0;
+ infoPtr->items = DPA_Create(8);
infoPtr->hcurArrow = LoadCursorW (0, (LPWSTR)IDC_ARROW);
infoPtr->iSelected = -1;
infoPtr->iHotTracked = -1;
/* The tab control always has the WS_CLIPSIBLINGS style. Even
if you don't specify it in CreateWindow. This is necessary in
order for paint to work correctly. This follows windows behaviour. */
- dwStyle = GetWindowLongW(hwnd, GWL_STYLE);
- SetWindowLongW(hwnd, GWL_STYLE, dwStyle|WS_CLIPSIBLINGS);
+ style = GetWindowLongW(hwnd, GWL_STYLE);
+ if (style & TCS_VERTICAL) style |= TCS_MULTILINE;
+ style |= WS_CLIPSIBLINGS;
+ SetWindowLongW(hwnd, GWL_STYLE, style);
- infoPtr->dwStyle = dwStyle | WS_CLIPSIBLINGS;
- infoPtr->exStyle = (dwStyle & TCS_FLATBUTTONS) ? TCS_EX_FLATSEPARATORS : 0;
+ infoPtr->dwStyle = style;
+ infoPtr->exStyle = (style & TCS_FLATBUTTONS) ? TCS_EX_FLATSEPARATORS : 0;
if (infoPtr->dwStyle & TCS_TOOLTIPS) {
/* Create tooltip control */
static LRESULT
TAB_Destroy (TAB_INFO *infoPtr)
{
- UINT iItem;
+ INT iItem;
SetWindowLongPtrW(infoPtr->hwnd, 0, 0);
- if (infoPtr->items) {
- for (iItem = 0; iItem < infoPtr->uNumItem; iItem++) {
- Free (TAB_GetItem(infoPtr, iItem)->pszText);
- }
- Free (infoPtr->items);
+ for (iItem = infoPtr->uNumItem - 1; iItem >= 0; iItem--)
+ {
+ TAB_ITEM *tab = TAB_GetItem(infoPtr, iItem);
+
+ DPA_DeletePtr(infoPtr->items, iItem);
+ infoPtr->uNumItem--;
+
+ Free(tab->pszText);
+ Free(tab);
}
+ DPA_Destroy(infoPtr->items);
+ infoPtr->items = NULL;
if (infoPtr->hwndToolTip)
DestroyWindow (infoPtr->hwndToolTip);
case WM_NOTIFY:
return SendMessageW(infoPtr->hwndNotify, WM_NOTIFY, wParam, lParam);
- case WM_RBUTTONDOWN:
- return TAB_RButtonDown (infoPtr);
+ case WM_RBUTTONUP:
+ TAB_RButtonUp (infoPtr);
+ return DefWindowProcW (hwnd, uMsg, wParam, lParam);
case WM_MOUSEMOVE:
return TAB_MouseMove (infoPtr, wParam, lParam);