*
* 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
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
*
* NOTES
*
* TODO:
*
* Styles:
- * TCS_MULTISELECT
+ * TCS_MULTISELECT - implement for VK_SPACE selection
* TCS_RIGHT
* TCS_RIGHTJUSTIFY
* TCS_SCROLLOPPOSITE
* TCIF_RTLREADING
*
* Extended Styles:
- * TCS_EX_FLATSEPARATORS
* TCS_EX_REGISTERDROP
*
- * States:
- * TCIS_BUTTONPRESSED
- *
* Notifications:
* NM_RELEASEDCAPTURE
* TCN_FOCUSCHANGE
* TCN_GETOBJECT
* TCN_KEYDOWN
*
- * Messages:
- * TCM_REMOVEIMAGE
- * TCM_DESELECTALL
- * TCM_GETEXTENDEDSTYLE
- * TCM_SETEXTENDEDSTYLE
- *
* Macros:
* TabCtrl_AdjustRect
*
typedef struct
{
- UINT mask;
DWORD dwState;
LPWSTR pszText;
INT iImage;
} TAB_ITEM;
/* The size of a tab item depends on how much extra data is requested */
-#define TAB_ITEM_SIZE(infoPtr) (sizeof(TAB_ITEM) - sizeof(BYTE) + infoPtr->cbInfo)
+#define TAB_ITEM_SIZE(infoPtr) (FIELD_OFFSET(TAB_ITEM, extra[(infoPtr)->cbInfo]))
typedef struct
{
BOOL bUnicode; /* Unicode control? */
HWND hwndUpDown; /* Updown control used for scrolling */
INT cbInfo; /* Number of bytes of caller supplied info per tab */
+
+ DWORD exStyle; /* Extended style used, currently:
+ TCS_EX_FLATSEPARATORS, TCS_EX_REGISTERDROP */
} TAB_INFO;
/******************************************************************************
#define BUTTON_SPACINGY 3
#define FLAT_BTN_SPACINGX 8
#define DEFAULT_MIN_TAB_WIDTH 54
-#define DEFAULT_TAB_WIDTH_FIXED 96
#define DEFAULT_PADDING_X 6
#define EXTRA_ICON_PADDING 3
/******************************************************************************
* Prototypes
*/
-static void TAB_InvalidateTabArea(TAB_INFO *);
+static void TAB_InvalidateTabArea(const TAB_INFO *);
static void TAB_EnsureSelectionVisible(TAB_INFO *);
-static void TAB_DrawItemInterior(TAB_INFO *, HDC, INT, RECT*);
+static void TAB_DrawItemInterior(const TAB_INFO *, HDC, INT, RECT*);
+static LRESULT TAB_DeselectAll(TAB_INFO *, BOOL);
static BOOL
TAB_SendSimpleNotify (const TAB_INFO *infoPtr, UINT code)
nmhdr.code = code;
return (BOOL) SendMessageW (infoPtr->hwndNotify, WM_NOTIFY,
- (WPARAM) nmhdr.idFrom, (LPARAM) &nmhdr);
+ nmhdr.idFrom, (LPARAM) &nmhdr);
}
static void
msg.wParam = wParam;
msg.lParam = lParam;
msg.time = GetMessageTime ();
- msg.pt.x = LOWORD(GetMessagePos ());
- msg.pt.y = HIWORD(GetMessagePos ());
+ msg.pt.x = (short)LOWORD(GetMessagePos ());
+ msg.pt.y = (short)HIWORD(GetMessagePos ());
SendMessageW (hwndTip, TTM_RELAYEVENT, 0, (LPARAM)&msg);
}
static void
-TAB_DumpItemExternalT(TCITEMW *pti, UINT iItem, BOOL isW)
+TAB_DumpItemExternalT(const TCITEMW *pti, UINT iItem, BOOL isW)
{
if (TRACE_ON(tab)) {
- TRACE("external tab %d, mask=0x%08x, dwState=0x%08lx, dwStateMask=0x%08lx, cchTextMax=0x%08x\n",
+ TRACE("external tab %d, mask=0x%08x, dwState=0x%08x, dwStateMask=0x%08x, cchTextMax=0x%08x\n",
iItem, pti->mask, pti->dwState, pti->dwStateMask, pti->cchTextMax);
TRACE("external tab %d, iImage=%d, lParam=0x%08lx, pszTextW=%s\n",
iItem, pti->iImage, pti->lParam, isW ? debugstr_w(pti->pszText) : debugstr_a((LPSTR)pti->pszText));
}
static void
-TAB_DumpItemInternal(TAB_INFO *infoPtr, UINT iItem)
+TAB_DumpItemInternal(const TAB_INFO *infoPtr, UINT iItem)
{
if (TRACE_ON(tab)) {
TAB_ITEM *ti;
ti = TAB_GetItem(infoPtr, iItem);
- TRACE("tab %d, mask=0x%08x, dwState=0x%08lx, pszText=%s, iImage=%d\n",
- iItem, ti->mask, ti->dwState, debugstr_w(ti->pszText),
- ti->iImage);
- TRACE("tab %d, rect.left=%ld, rect.top(row)=%ld\n",
+ 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",
iItem, ti->rect.left, ti->rect.top);
}
}
}
/* RETURNS
- * the index of the tab item that has the focus
- * NOTE
- * we have not to return negative value
- * TODO
- * test for windows */
+ * the index of the tab item that has the focus. */
static inline LRESULT
TAB_GetCurFocus (const TAB_INFO *infoPtr)
{
- if (infoPtr->uFocus<0)
- {
- FIXME("we have not to return negative value");
- return 0;
- }
return infoPtr->uFocus;
}
static inline LRESULT TAB_SetCurSel (TAB_INFO *infoPtr, INT iItem)
{
- INT prevItem = -1;
+ INT prevItem = infoPtr->iSelected;
- if (iItem >= 0 && iItem < infoPtr->uNumItem) {
- prevItem=infoPtr->iSelected;
- infoPtr->iSelected=iItem;
- TAB_EnsureSelectionVisible(infoPtr);
- TAB_InvalidateTabArea(infoPtr);
+ if (iItem < 0)
+ infoPtr->iSelected=-1;
+ else if (iItem >= infoPtr->uNumItem)
+ return -1;
+ else {
+ if (infoPtr->iSelected != iItem) {
+ TAB_GetItem(infoPtr, prevItem)->dwState &= ~TCIS_BUTTONPRESSED;
+ TAB_GetItem(infoPtr, iItem)->dwState |= TCIS_BUTTONPRESSED;
+
+ infoPtr->iSelected=iItem;
+ infoPtr->uFocus=iItem;
+ TAB_EnsureSelectionVisible(infoPtr);
+ TAB_InvalidateTabArea(infoPtr);
+ }
}
return prevItem;
}
static LRESULT TAB_SetCurFocus (TAB_INFO *infoPtr, INT iItem)
{
- if (iItem < 0 || iItem >= infoPtr->uNumItem) return 0;
-
- if (GetWindowLongW(infoPtr->hwnd, GWL_STYLE) & TCS_BUTTONS) {
- FIXME("Should set input focus\n");
- } else {
- int oldFocus = infoPtr->uFocus;
- if (infoPtr->iSelected != iItem || oldFocus == -1 ) {
- infoPtr->uFocus = iItem;
- if (oldFocus != -1) {
- if (!TAB_SendSimpleNotify(infoPtr, TCN_SELCHANGING)) {
- infoPtr->iSelected = iItem;
- TAB_SendSimpleNotify(infoPtr, TCN_SELCHANGE);
+ if (iItem < 0)
+ infoPtr->uFocus = -1;
+ else if (iItem < infoPtr->uNumItem) {
+ if (GetWindowLongW(infoPtr->hwnd, GWL_STYLE) & TCS_BUTTONS) {
+ FIXME("Should set input focus\n");
+ } else {
+ int oldFocus = infoPtr->uFocus;
+ if (infoPtr->iSelected != iItem || oldFocus == -1 ) {
+ infoPtr->uFocus = iItem;
+ if (oldFocus != -1) {
+ if (!TAB_SendSimpleNotify(infoPtr, TCN_SELCHANGING)) {
+ infoPtr->iSelected = iItem;
+ TAB_SendSimpleNotify(infoPtr, TCN_SELCHANGE);
+ }
+ else
+ infoPtr->iSelected = iItem;
+ TAB_EnsureSelectionVisible(infoPtr);
+ TAB_InvalidateTabArea(infoPtr);
}
- else
- infoPtr->iSelected = iItem;
- TAB_EnsureSelectionVisible(infoPtr);
- TAB_InvalidateTabArea(infoPtr);
}
}
}
SELECTED_TAB_OFFSET,
0);
}
- TRACE("item %d tab h=%d, rect=(%ld,%ld)-(%ld,%ld)\n",
- itemIndex, infoPtr->tabHeight,
- itemRect->left, itemRect->top, itemRect->right, itemRect->bottom);
+ TRACE("item %d tab h=%d, rect=(%s)\n",
+ itemIndex, infoPtr->tabHeight, wine_dbgstr_rect(itemRect));
/* Now, calculate the position of the item as if it were selected. */
if (selectedRect!=NULL)
}
static inline BOOL
-TAB_GetItemRect(TAB_INFO *infoPtr, WPARAM wParam, LPARAM lParam)
+TAB_GetItemRect(const TAB_INFO *infoPtr, WPARAM wParam, LPARAM lParam)
{
- return TAB_InternalGetItemRect(infoPtr, (INT)wParam, (LPRECT)lParam, (LPRECT)NULL);
+ return TAB_InternalGetItemRect(infoPtr, wParam, (LPRECT)lParam, NULL);
}
/******************************************************************************
{
if (!TAB_SendSimpleNotify(infoPtr, TCN_SELCHANGING))
{
- infoPtr->iSelected = newItem;
- infoPtr->uFocus = newItem;
+ TAB_SetCurSel(infoPtr, newItem);
TAB_SendSimpleNotify(infoPtr, TCN_SELCHANGE);
-
- TAB_EnsureSelectionVisible(infoPtr);
- TAB_InvalidateTabArea(infoPtr);
}
}
*/
if (isVisible)
{
- TRACE("invalidate (%ld,%ld)-(%ld,%ld)\n",
- selectedRect.left,selectedRect.top,
- selectedRect.right,selectedRect.bottom);
+ TRACE("invalidate (%s)\n", wine_dbgstr_rect(&selectedRect));
InvalidateRect(infoPtr->hwnd, &selectedRect, TRUE);
}
}
-static INT TAB_InternalHitTest (
- TAB_INFO* infoPtr,
- POINT pt,
- UINT* flags)
-
+static INT TAB_InternalHitTest (const TAB_INFO *infoPtr, POINT pt, UINT *flags)
{
RECT rect;
INT iCount;
}
static inline LRESULT
-TAB_HitTest (TAB_INFO *infoPtr, LPTCHITTESTINFO lptest)
+TAB_HitTest (const TAB_INFO *infoPtr, LPTCHITTESTINFO lptest)
{
return TAB_InternalHitTest (infoPtr, lptest->pt, &lptest->flags);
}
* doesn't do it that way. Maybe depends on tab control styles ?
*/
static inline LRESULT
-TAB_NCHitTest (TAB_INFO *infoPtr, LPARAM lParam)
+TAB_NCHitTest (const TAB_INFO *infoPtr, LPARAM lParam)
{
POINT pt;
UINT dummyflag;
- pt.x = LOWORD(lParam);
- pt.y = HIWORD(lParam);
+ pt.x = (short)LOWORD(lParam);
+ pt.y = (short)HIWORD(lParam);
ScreenToClient(infoPtr->hwnd, &pt);
if (TAB_InternalHitTest(infoPtr, pt, &dummyflag) == -1)
POINT pt;
INT newItem;
UINT dummy;
+ LONG lStyle = GetWindowLongW(infoPtr->hwnd, GWL_STYLE);
if (infoPtr->hwndToolTip)
TAB_RelayEvent (infoPtr->hwndToolTip, infoPtr->hwnd,
TAB_RelayEvent (infoPtr->hwndToolTip, infoPtr->hwnd,
WM_LBUTTONDOWN, wParam, lParam);
- pt.x = (INT)LOWORD(lParam);
- pt.y = (INT)HIWORD(lParam);
+ pt.x = (short)LOWORD(lParam);
+ pt.y = (short)HIWORD(lParam);
newItem = TAB_InternalHitTest (infoPtr, pt, &dummy);
TRACE("On Tab, item %d\n", newItem);
- if (newItem != -1 && infoPtr->iSelected != newItem)
+ if ((newItem != -1) && (infoPtr->iSelected != newItem))
{
- if (!TAB_SendSimpleNotify(infoPtr, TCN_SELCHANGING))
+ if ((lStyle & TCS_BUTTONS) && (lStyle & TCS_MULTISELECT) &&
+ (wParam & MK_CONTROL))
{
- infoPtr->iSelected = newItem;
- infoPtr->uFocus = newItem;
- TAB_SendSimpleNotify(infoPtr, TCN_SELCHANGE);
+ RECT r;
- TAB_EnsureSelectionVisible(infoPtr);
+ /* toggle multiselection */
+ TAB_GetItem(infoPtr, newItem)->dwState ^= TCIS_BUTTONPRESSED;
+ if (TAB_InternalGetItemRect (infoPtr, newItem, &r, NULL))
+ InvalidateRect (infoPtr->hwnd, &r, TRUE);
+ }
+ else
+ {
+ INT i;
+ BOOL pressed = FALSE;
- TAB_InvalidateTabArea(infoPtr);
+ /* any button pressed ? */
+ for (i = 0; i < infoPtr->uNumItem; i++)
+ if ((TAB_GetItem (infoPtr, i)->dwState & TCIS_BUTTONPRESSED) &&
+ (infoPtr->iSelected != i))
+ {
+ pressed = TRUE;
+ break;
+ }
+
+ TAB_SendSimpleNotify(infoPtr, TCN_SELCHANGING);
+
+ if (pressed)
+ TAB_DeselectAll (infoPtr, FALSE);
+ else
+ TAB_SetCurSel(infoPtr, newItem);
+
+ TAB_SendSimpleNotify(infoPtr, TCN_SELCHANGE);
}
}
+
return 0;
}
* only calls TAB_DrawItemInterior for the single specified item.
*/
static void
-TAB_DrawLoneItemInterior(TAB_INFO* infoPtr, int iItem)
+TAB_DrawLoneItemInterior(const TAB_INFO* infoPtr, int iItem)
{
HDC hdc = GetDC(infoPtr->hwnd);
RECT r, rC;
/* update a tab after hottracking - invalidate it or just redraw the interior,
* based on whether theming is used or not */
-static inline void hottrack_refresh (TAB_INFO* infoPtr, int tabIndex)
+static inline void hottrack_refresh(const TAB_INFO *infoPtr, int tabIndex)
{
if (tabIndex == -1) return;
}
else
{
- pt.x = LOWORD(*pos);
- pt.y = HIWORD(*pos);
+ pt.x = (short)LOWORD(*pos);
+ pt.y = (short)HIWORD(*pos);
}
item = TAB_InternalHitTest(infoPtr, pt, &flags);
* Calculates the tab control's display area given the window rectangle or
* the window rectangle given the requested display rectangle.
*/
-static LRESULT TAB_AdjustRect(
- TAB_INFO *infoPtr,
- WPARAM fLarger,
- LPRECT prc)
+static LRESULT TAB_AdjustRect(const TAB_INFO *infoPtr, WPARAM fLarger, LPRECT prc)
{
DWORD lStyle = GetWindowLongW(infoPtr->hwnd, GWL_STYLE);
LONG *iRightBottom, *iLeftTop;
- TRACE ("hwnd=%p fLarger=%d (%ld,%ld)-(%ld,%ld)\n", infoPtr->hwnd, fLarger, prc->left, prc->top, prc->right, prc->bottom);
+ TRACE ("hwnd=%p fLarger=%ld (%s)\n", infoPtr->hwnd, fLarger,
+ wine_dbgstr_rect(prc));
+
+ if (!prc) return -1;
if(lStyle & TCS_VERTICAL)
{
* This method will handle the notification from the scroll control and
* perform the scrolling operation on the tab control.
*/
-static LRESULT TAB_OnHScroll(
- TAB_INFO *infoPtr,
- int nScrollCode,
- int nPos,
- HWND hwndScroll)
+static LRESULT TAB_OnHScroll(TAB_INFO *infoPtr, int nScrollCode, int nPos)
{
if(nScrollCode == SB_THUMBPOSITION && nPos != infoPtr->leftmostVisible)
{
((lStyle & TCS_BUTTONS) ? 2 : 1) *
infoPtr->uVItemPadding;
- TRACE("tabH=%d, tmH=%ld, iconh=%d\n",
+ TRACE("tabH=%d, tmH=%d, iconh=%d\n",
infoPtr->tabHeight, fontMetrics.tmHeight, icon_height);
}
- TRACE("client right=%ld\n", clientRect.right);
+ TRACE("client right=%d\n", clientRect.right);
/* Get the icon width */
if (infoPtr->himl)
tabwidth = max(tabwidth, infoPtr->tabMinWidth);
curr->rect.right = curr->rect.left + tabwidth;
- TRACE("for <%s>, l,r=%ld,%ld\n",
+ TRACE("for <%s>, l,r=%d,%d\n",
debugstr_w(curr->pszText), curr->rect.left, curr->rect.right);
}
curr->rect.left = 0;
curItemRowCount++;
- TRACE("wrapping <%s>, l,r=%ld,%ld\n", debugstr_w(curr->pszText),
+ TRACE("wrapping <%s>, l,r=%d,%d\n", debugstr_w(curr->pszText),
curr->rect.left, curr->rect.right);
}
curr->rect.bottom = 0;
curr->rect.top = curItemRowCount - 1;
- TRACE("Rect: T %li, L %li, B %li, R %li\n", curr->rect.top,
- curr->rect.left, curr->rect.bottom, curr->rect.right);
+ TRACE("Rect: %s\n", wine_dbgstr_rect(&curr->rect));
/*
* The leftmost position of the next item is the rightmost position
curr->rect.right -= curr->rect.left;
curr->rect.left = 0;
- TRACE("r=%ld, cl=%d, cl.r=%ld, iCount=%d, iRow=%d, uNumRows=%d, remTab=%d, tabPerRow=%d\n",
+ TRACE("r=%d, cl=%d, cl.r=%d, iCount=%d, iRow=%d, uNumRows=%d, remTab=%d, tabPerRow=%d\n",
curr->rect.right, curItemLeftPos, clientRect.right,
iCount, iRow, infoPtr->uNumRows, remTab, tabPerRow);
else
curItemLeftPos = curr->rect.right;
- TRACE("arranging <%s>, l,r=%ld,%ld, row=%ld\n",
+ TRACE("arranging <%s>, l,r=%d,%d, row=%d\n",
debugstr_w(curr->pszText), curr->rect.left,
curr->rect.right, curr->rect.top);
}
item->rect.left += iCount * widthDiff;
item->rect.right += (iCount + 1) * widthDiff;
- TRACE("adjusting 1 <%s>, l,r=%ld,%ld\n",
+ TRACE("adjusting 1 <%s>, l,r=%d,%d\n",
debugstr_w(item->pszText),
item->rect.left, item->rect.right);
start->rect.left = clientRect.left;
start->rect.right = clientRect.right - 4;
- TRACE("adjusting 2 <%s>, l,r=%ld,%ld\n",
+ TRACE("adjusting 2 <%s>, l,r=%d,%d\n",
debugstr_w(start->pszText),
start->rect.left, start->rect.right);
static void
-TAB_EraseTabInterior
- (
- TAB_INFO* infoPtr,
- HDC hdc,
- INT iItem,
- RECT* drawRect
- )
+TAB_EraseTabInterior(const TAB_INFO *infoPtr, HDC hdc, INT iItem, const RECT *drawRect)
{
LONG lStyle = GetWindowLongW(infoPtr->hwnd, GWL_STYLE);
HBRUSH hbr = CreateSolidBrush (comctl32_color.clrBtnFace);
BOOL deleteBrush = TRUE;
RECT rTemp = *drawRect;
- InflateRect(&rTemp, -2, -2);
if (lStyle & TCS_BUTTONS)
{
if (iItem == infoPtr->iSelected)
{
if (lStyle & TCS_FLATBUTTONS)
{
- FillRect(hdc, drawRect, hbr);
+ InflateRect(&rTemp, 2, 2);
+ FillRect(hdc, &rTemp, hbr);
if (iItem == infoPtr->iHotTracked)
- DrawEdge(hdc, drawRect, EDGE_RAISED, BF_SOFT|BF_RECT);
+ DrawEdge(hdc, &rTemp, BDR_RAISEDINNER, BF_RECT);
}
else
FillRect(hdc, &rTemp, hbr);
}
else /* !TCS_BUTTONS */
{
+ InflateRect(&rTemp, -2, -2);
if (!GetWindowTheme (infoPtr->hwnd))
FillRect(hdc, &rTemp, hbr);
}
+ /* highlighting is drawn on top of previous fills */
+ if (TAB_GetItem(infoPtr, iItem)->dwState & TCIS_HIGHLIGHTED)
+ {
+ if (deleteBrush)
+ {
+ DeleteObject(hbr);
+ deleteBrush = FALSE;
+ }
+ hbr = GetSysColorBrush(COLOR_HIGHLIGHT);
+ FillRect(hdc, &rTemp, hbr);
+ }
+
/* Cleanup */
if (deleteBrush) DeleteObject(hbr);
}
* into the tab control.
*/
static void
-TAB_DrawItemInterior
- (
- TAB_INFO* infoPtr,
- HDC hdc,
- INT iItem,
- RECT* drawRect
- )
+TAB_DrawItemInterior(const TAB_INFO *infoPtr, HDC hdc, INT iItem, RECT *drawRect)
{
LONG lStyle = GetWindowLongW(infoPtr->hwnd, GWL_STYLE);
drawRect->left += 4;
drawRect->top += 4;
drawRect->right -= 4;
- drawRect->bottom -= 1;
+
+ if (lStyle & TCS_VERTICAL)
+ {
+ if (!(lStyle & TCS_BOTTOM)) drawRect->right += 1;
+ drawRect->bottom -= 4;
+ }
+ else
+ {
+ if (lStyle & TCS_BOTTOM)
+ {
+ drawRect->top -= 2;
+ drawRect->bottom -= 4;
+ }
+ else
+ drawRect->bottom -= 1;
+ }
}
else
{
}
}
}
- TRACE("drawRect=(%ld,%ld)-(%ld,%ld)\n",
- drawRect->left, drawRect->top, drawRect->right, drawRect->bottom);
+ TRACE("drawRect=(%s)\n", wine_dbgstr_rect(drawRect));
/* Clear interior */
TAB_EraseTabInterior (infoPtr, hdc, iItem, drawRect);
/*
* Text pen
*/
- htextPen = CreatePen( PS_SOLID, 1, GetSysColor(COLOR_BTNTEXT) );
+ htextPen = CreatePen( PS_SOLID, 1, comctl32_color.clrBtnText );
holdPen = SelectObject(hdc, htextPen);
hOldFont = SelectObject(hdc, infoPtr->hFont);
*/
oldBkMode = SetBkMode(hdc, TRANSPARENT);
if (!GetWindowTheme (infoPtr->hwnd) || (lStyle & TCS_BUTTONS))
- SetTextColor(hdc, (((lStyle & TCS_HOTTRACK) && (iItem == infoPtr->iHotTracked)
- && !(lStyle & TCS_FLATBUTTONS))
- | (TAB_GetItem(infoPtr, iItem)->dwState & TCIS_HIGHLIGHTED)) ?
- comctl32_color.clrHighlight : comctl32_color.clrBtnText);
+ {
+ if ((lStyle & TCS_HOTTRACK) && (iItem == infoPtr->iHotTracked) &&
+ !(lStyle & TCS_FLATBUTTONS))
+ SetTextColor(hdc, comctl32_color.clrHighlight);
+ else if (TAB_GetItem(infoPtr, iItem)->dwState & TCIS_HIGHLIGHTED)
+ SetTextColor(hdc, comctl32_color.clrHighlightText);
+ else
+ SetTextColor(hdc, comctl32_color.clrBtnText);
+ }
/*
* if owner draw, tell the owner to draw
*
* Draw the icon.
*/
- if (infoPtr->himl && (item->mask & TCIF_IMAGE))
+ if (infoPtr->himl && item->iImage != -1)
{
INT cx;
INT cy;
if(lStyle & TCS_VERTICAL)
{
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;
+ center_offset_v = ((drawRect->right - drawRect->left) - cx) / 2;
}
else
{
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;
+ center_offset_v = ((drawRect->bottom - drawRect->top) - cy) / 2;
}
+ /* if an item is selected, the icon is shifted up instead of down */
+ if (iItem == infoPtr->iSelected)
+ center_offset_v -= infoPtr->uVItemPadding / 2;
+ else
+ center_offset_v += infoPtr->uVItemPadding / 2;
+
if (lStyle & TCS_FIXEDWIDTH && lStyle & (TCS_FORCELABELLEFT | TCS_FORCEICONLEFT))
center_offset_h = infoPtr->uHItemPadding;
if (center_offset_v < 0)
center_offset_v = 0;
- TRACE("for <%s>, c_o_h=%d, c_o_v=%d, draw=(%ld,%ld)-(%ld,%ld), textlen=%ld\n",
+ 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,
- drawRect->left, drawRect->top, drawRect->right, drawRect->bottom,
- (rcText.right-rcText.left));
+ wine_dbgstr_rect(drawRect), (rcText.right-rcText.left));
if((lStyle & TCS_VERTICAL) && (lStyle & TCS_BOTTOM))
{
drawRect->left += cx + infoPtr->uHItemPadding;
}
- TRACE("drawing image=%d, left=%ld, top=%ld\n",
+ TRACE("drawing image=%d, left=%d, top=%d\n",
item->iImage, rcImage.left, rcImage.top-1);
ImageList_Draw
(
}
else
{
- TRACE("for <%s>, c_o_h=%d, c_o_v=%d, draw=(%ld,%ld)-(%ld,%ld), textlen=%ld\n",
+ 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,
- drawRect->left, drawRect->top, drawRect->right, drawRect->bottom,
- (rcText.right-rcText.left));
+ wine_dbgstr_rect(drawRect), (rcText.right-rcText.left));
if (item->pszText)
{
DrawTextW
*
* This method is used to draw a single tab into the tab control.
*/
-static void TAB_DrawItem(
- TAB_INFO *infoPtr,
- HDC hdc,
- INT iItem)
+static void TAB_DrawItem(const TAB_INFO *infoPtr, HDC hdc, INT iItem)
{
LONG lStyle = GetWindowLongW(infoPtr->hwnd, GWL_STYLE);
RECT itemRect;
r = itemRect;
/* Separators between flat buttons */
- if (lStyle & TCS_FLATBUTTONS)
+ if ((lStyle & TCS_FLATBUTTONS) && (infoPtr->exStyle & TCS_EX_FLATSEPARATORS))
{
r1 = r;
r1.right += (FLAT_BTN_SPACINGX -2);
}
else /* ! selected */
{
- if (!(lStyle & TCS_FLATBUTTONS))
- DrawEdge(hdc, &r, EDGE_RAISED, BF_SOFT|BF_RECT);
+ DWORD state = TAB_GetItem(infoPtr, iItem)->dwState;
+
+ if (state & TCIS_BUTTONPRESSED)
+ DrawEdge(hdc, &r, EDGE_SUNKEN, BF_SOFT|BF_RECT);
+ else
+ if (!(lStyle & TCS_FLATBUTTONS))
+ DrawEdge(hdc, &r, EDGE_RAISED, BF_SOFT|BF_RECT);
}
}
else /* !TCS_BUTTONS */
{
/* These are for adjusting the drawing of a Selected tab */
/* The initial values are for the normal case of non-Selected */
- int ZZ = 1; /* Do not strech if selected */
+ int ZZ = 1; /* Do not stretch if selected */
if (iItem == infoPtr->iSelected) {
ZZ = 0;
/* Adjust both rectangles to match native */
r.left += (1-ZZ);
- TRACE("<right> item=%d, fill=(%ld,%ld)-(%ld,%ld), edge=(%ld,%ld)-(%ld,%ld)\n",
- iItem,
- fillRect.left,fillRect.top,fillRect.right,fillRect.bottom,
- r.left,r.top,r.right,r.bottom);
+ TRACE("<right> item=%d, fill=(%s), edge=(%s)\n",
+ iItem, wine_dbgstr_rect(&fillRect), wine_dbgstr_rect(&r));
/* Clear interior */
SetBkColor(hdc, bkgnd);
}
else
{
- TRACE("<left> item=%d, fill=(%ld,%ld)-(%ld,%ld), edge=(%ld,%ld)-(%ld,%ld)\n",
- iItem,
- fillRect.left,fillRect.top,fillRect.right,fillRect.bottom,
- r.left,r.top,r.right,r.bottom);
+ TRACE("<left> item=%d, fill=(%s), edge=(%s)\n",
+ iItem, wine_dbgstr_rect(&fillRect), wine_dbgstr_rect(&r));
/* Clear interior */
SetBkColor(hdc, bkgnd);
r.top -= 1;
}
- TRACE("<bottom> item=%d, fill=(%ld,%ld)-(%ld,%ld), edge=(%ld,%ld)-(%ld,%ld)\n",
- iItem,
- fillRect.left,fillRect.top,fillRect.right,fillRect.bottom,
- r.left,r.top,r.right,r.bottom);
+ TRACE("<bottom> item=%d, fill=(%s), edge=(%s)\n",
+ iItem, wine_dbgstr_rect(&fillRect), wine_dbgstr_rect(&r));
/* Clear interior */
SetBkColor(hdc, bkgnd);
r.bottom += 2;
}
- TRACE("<top> item=%d, fill=(%ld,%ld)-(%ld,%ld), edge=(%ld,%ld)-(%ld,%ld)\n",
- iItem,
- fillRect.left,fillRect.top,fillRect.right,fillRect.bottom,
- r.left,r.top,r.right,r.bottom);
+ TRACE("<top> item=%d, fill=(%s), edge=(%s)\n",
+ iItem, wine_dbgstr_rect(&fillRect), wine_dbgstr_rect(&r));
/* Clear interior */
SetBkColor(hdc, bkgnd);
* This method is used to draw the raised border around the tab control
* "content" area.
*/
-static void TAB_DrawBorder (TAB_INFO *infoPtr, HDC hdc)
+static void TAB_DrawBorder(const TAB_INFO *infoPtr, HDC hdc)
{
RECT rect;
DWORD lStyle = GetWindowLongW(infoPtr->hwnd, GWL_STYLE);
rect.top += infoPtr->tabHeight * infoPtr->uNumRows + CONTROL_BORDER_SIZEX;
}
- TRACE("border=(%ld,%ld)-(%ld,%ld)\n",
- rect.left, rect.top, rect.right, rect.bottom);
+ TRACE("border=(%s)\n", wine_dbgstr_rect(&rect));
if (theme)
DrawThemeBackground (theme, hdc, TABP_PANE, 0, &rect, NULL);
/* Then, draw the selected item */
TAB_DrawItem (infoPtr, hdc, infoPtr->iSelected);
-
- /* 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(infoPtr, infoPtr->iSelected);
}
SelectObject (hdc, hOldFont);
* tabs. It is called when the state of the control changes and needs
* to be redisplayed
*/
-static void TAB_InvalidateTabArea(TAB_INFO* infoPtr)
+static void TAB_InvalidateTabArea(const TAB_INFO *infoPtr)
{
RECT clientRect, rInvalidate, rAdjClient;
DWORD lStyle = GetWindowLongW(infoPtr->hwnd, GWL_STYLE);
else
rInvalidate.right = clientRect.right - r.left;
}
-
- TRACE("invalidate (%ld,%ld)-(%ld,%ld)\n",
- rInvalidate.left, rInvalidate.top,
- rInvalidate.right, rInvalidate.bottom);
-
+
+ TRACE("invalidate (%s)\n", wine_dbgstr_rect(&rInvalidate));
+
InvalidateRect(infoPtr->hwnd, &rInvalidate, TRUE);
}
else
{
hdc = BeginPaint (infoPtr->hwnd, &ps);
- TRACE("erase %d, rect=(%ld,%ld)-(%ld,%ld)\n",
- ps.fErase,
- ps.rcPaint.left,ps.rcPaint.top,ps.rcPaint.right,ps.rcPaint.bottom);
+ TRACE("erase %d, rect=(%s)\n", ps.fErase, wine_dbgstr_rect(&ps.rcPaint));
}
TAB_Refresh (infoPtr, hdc);
RECT rect;
GetClientRect (infoPtr->hwnd, &rect);
- TRACE("Rect: %p T %li, L %li, B %li, R %li\n", infoPtr->hwnd,
- rect.top, rect.left, rect.bottom, rect.right);
+ TRACE("Rect: %p %s\n", infoPtr->hwnd, wine_dbgstr_rect(&rect));
pti = (TCITEMW *)lParam;
iItem = (INT)wParam;
item = TAB_GetItem(infoPtr, iItem);
- item->mask = pti->mask;
item->pszText = NULL;
if (pti->mask & TCIF_TEXT)
TRACE("[%p]: added item %d %s\n",
infoPtr->hwnd, iItem, debugstr_w(item->pszText));
+ /* If we haven't set the current focus yet, set it now. */
+ if (infoPtr->uFocus == -1)
+ TAB_SetCurFocus(infoPtr, iItem);
+
return iItem;
}
TRACE("(%p,%d)\n", infoPtr, cx);
- if (infoPtr) {
+ if (infoPtr->tabMinWidth < 0)
+ oldcx = DEFAULT_MIN_TAB_WIDTH;
+ else
oldcx = infoPtr->tabMinWidth;
- infoPtr->tabMinWidth = cx;
- }
+ infoPtr->tabMinWidth = cx;
TAB_SetItemBounds(infoPtr);
-
return oldcx;
}
TAB_HighlightItem (TAB_INFO *infoPtr, INT iItem, BOOL fHighlight)
{
LPDWORD lpState;
+ DWORD oldState;
+ RECT r;
TRACE("(%p,%d,%s)\n", infoPtr, iItem, fHighlight ? "true" : "false");
return FALSE;
lpState = &TAB_GetItem(infoPtr, iItem)->dwState;
+ oldState = *lpState;
if (fHighlight)
*lpState |= TCIS_HIGHLIGHTED;
else
*lpState &= ~TCIS_HIGHLIGHTED;
+ if ((oldState != *lpState) && TAB_InternalGetItemRect (infoPtr, iItem, &r, NULL))
+ InvalidateRect (infoPtr->hwnd, &r, TRUE);
+
return TRUE;
}
FIXME("TCIF_RTLREADING\n");
if (tabItem->mask & TCIF_STATE)
- wineItem->dwState = tabItem->dwState;
+ wineItem->dwState = (wineItem->dwState & ~tabItem->dwStateMask) |
+ ( tabItem->dwState & tabItem->dwStateMask);
if (tabItem->mask & TCIF_TEXT)
{
- if (wineItem->pszText)
- {
- Free(wineItem->pszText);
- wineItem->pszText = NULL;
- }
+ Free(wineItem->pszText);
+ wineItem->pszText = NULL;
if (bUnicode)
Str_SetPtrW(&wineItem->pszText, tabItem->pszText);
else
FIXME("TCIF_RTLREADING\n");
if (tabItem->mask & TCIF_STATE)
- tabItem->dwState = wineItem->dwState;
+ tabItem->dwState = wineItem->dwState & tabItem->dwStateMask;
if (tabItem->mask & TCIF_TEXT)
{
{
TAB_ITEM *item = TAB_GetItem(infoPtr, iItem);
LPBYTE oldItems = (LPBYTE)infoPtr->items;
-
- TAB_InvalidateTabArea(infoPtr);
-
- if ((item->mask & TCIF_TEXT) && item->pszText)
- Free(item->pszText);
+ TAB_InvalidateTabArea(infoPtr);
+ Free(item->pszText);
infoPtr->uNumItem--;
if (!infoPtr->uNumItem)
if (iItem <= infoPtr->iHotTracked)
{
/* When tabs move left/up, the hot track item may change */
- FIXME("Recalc hot track");
+ FIXME("Recalc hot track\n");
}
}
Free(oldItems);
HIMAGELIST himlPrev = infoPtr->himl;
TRACE("\n");
infoPtr->himl = himlNew;
+ TAB_SetItemBounds(infoPtr);
+ InvalidateRect(infoPtr->hwnd, NULL, TRUE);
return (LRESULT)himlPrev;
}
}
-static LRESULT TAB_Create (HWND hwnd, WPARAM wParam, LPARAM lParam)
+static LRESULT TAB_Create (HWND hwnd, LPARAM lParam)
{
TAB_INFO *infoPtr;
TEXTMETRICW fontMetrics;
HFONT hOldFont;
DWORD dwStyle;
- infoPtr = (TAB_INFO *)Alloc (sizeof(TAB_INFO));
+ infoPtr = Alloc (sizeof(TAB_INFO));
SetWindowLongPtrW(hwnd, 0, (DWORD_PTR)infoPtr);
dwStyle = GetWindowLongW(hwnd, GWL_STYLE);
SetWindowLongW(hwnd, GWL_STYLE, dwStyle|WS_CLIPSIBLINGS);
+ infoPtr->exStyle = (dwStyle & TCS_FLATBUTTONS) ? TCS_EX_FLATSEPARATORS : 0;
+
if (dwStyle & TCS_TOOLTIPS) {
/* Create tooltip control */
infoPtr->hwndToolTip =
- CreateWindowExW (0, TOOLTIPS_CLASSW, NULL, 0,
+ CreateWindowExW (0, TOOLTIPS_CLASSW, NULL, WS_POPUP,
CW_USEDEFAULT, CW_USEDEFAULT,
CW_USEDEFAULT, CW_USEDEFAULT,
hwnd, 0, 0, 0);
/* Initialize the width of a tab. */
if (dwStyle & TCS_FIXEDWIDTH)
- infoPtr->tabWidth = DEFAULT_TAB_WIDTH_FIXED;
+ infoPtr->tabWidth = GetDeviceCaps(hdc, LOGPIXELSX);
infoPtr->tabMinWidth = -1;
if (infoPtr->items) {
for (iItem = 0; iItem < infoPtr->uNumItem; iItem++) {
- if (TAB_GetItem(infoPtr, iItem)->pszText)
- Free (TAB_GetItem(infoPtr, iItem)->pszText);
+ Free (TAB_GetItem(infoPtr, iItem)->pszText);
}
Free (infoPtr->items);
}
}
/* update theme after a WM_THEMECHANGED message */
-static LRESULT theme_changed (TAB_INFO* infoPtr)
+static LRESULT theme_changed(const TAB_INFO *infoPtr)
{
HTHEME theme = GetWindowTheme (infoPtr->hwnd);
CloseThemeData (theme);
return 0;
}
-static LRESULT TAB_NCCalcSize(HWND hwnd, WPARAM wParam, LPARAM lParam)
+static LRESULT TAB_NCCalcSize(WPARAM wParam)
{
if (!wParam)
return 0;
return TRUE;
}
+static LRESULT TAB_RemoveImage (TAB_INFO *infoPtr, INT image)
+{
+ if (!infoPtr)
+ return 0;
+
+ if (ImageList_Remove (infoPtr->himl, image))
+ {
+ INT i, *idx;
+ RECT r;
+
+ /* shift indices, repaint items if needed */
+ for (i = 0; i < infoPtr->uNumItem; i++)
+ {
+ idx = &TAB_GetItem(infoPtr, i)->iImage;
+ if (*idx >= image)
+ {
+ if (*idx == image)
+ *idx = -1;
+ else
+ (*idx)--;
+
+ /* repaint item */
+ if (TAB_InternalGetItemRect (infoPtr, i, &r, NULL))
+ InvalidateRect (infoPtr->hwnd, &r, TRUE);
+ }
+ }
+ }
+
+ return 0;
+}
+
+static LRESULT
+TAB_SetExtendedStyle (TAB_INFO *infoPtr, DWORD exMask, DWORD exStyle)
+{
+ DWORD prevstyle = infoPtr->exStyle;
+
+ /* zero mask means all styles */
+ if (exMask == 0) exMask = ~0;
+
+ if (exMask & TCS_EX_REGISTERDROP)
+ {
+ FIXME("TCS_EX_REGISTERDROP style unimplemented\n");
+ exMask &= ~TCS_EX_REGISTERDROP;
+ exStyle &= ~TCS_EX_REGISTERDROP;
+ }
+
+ if (exMask & TCS_EX_FLATSEPARATORS)
+ {
+ if ((prevstyle ^ exStyle) & TCS_EX_FLATSEPARATORS)
+ {
+ infoPtr->exStyle ^= TCS_EX_FLATSEPARATORS;
+ TAB_InvalidateTabArea(infoPtr);
+ }
+ }
+
+ return prevstyle;
+}
+
+static inline LRESULT
+TAB_GetExtendedStyle (const TAB_INFO *infoPtr)
+{
+ return infoPtr->exStyle;
+}
+
+static LRESULT
+TAB_DeselectAll (TAB_INFO *infoPtr, BOOL excludesel)
+{
+ LONG style = GetWindowLongW(infoPtr->hwnd, GWL_STYLE);
+ BOOL paint = FALSE;
+ INT i, selected = infoPtr->iSelected;
+
+ if (!(style & TCS_BUTTONS))
+ return 0;
+
+ for (i = 0; i < infoPtr->uNumItem; i++)
+ {
+ if ((TAB_GetItem(infoPtr, i)->dwState & TCIS_BUTTONPRESSED) &&
+ (selected != i))
+ {
+ TAB_GetItem(infoPtr, i)->dwState &= ~TCIS_BUTTONPRESSED;
+ paint = TRUE;
+ }
+ }
+
+ if (!excludesel && (selected != -1))
+ {
+ TAB_GetItem(infoPtr, selected)->dwState &= ~TCIS_BUTTONPRESSED;
+ infoPtr->iSelected = -1;
+ paint = TRUE;
+ }
+
+ if (paint)
+ TAB_InvalidateTabArea (infoPtr);
+
+ return 0;
+}
+
static LRESULT WINAPI
TAB_WindowProc (HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
TAB_INFO *infoPtr = TAB_GetInfoPtr(hwnd);
- TRACE("hwnd=%p msg=%x wParam=%x lParam=%lx\n", hwnd, uMsg, wParam, lParam);
+ TRACE("hwnd=%p msg=%x wParam=%lx lParam=%lx\n", hwnd, uMsg, wParam, lParam);
if (!infoPtr && (uMsg != WM_CREATE))
return DefWindowProcW (hwnd, uMsg, wParam, lParam);
return TAB_SetItemSize (infoPtr, lParam);
case TCM_REMOVEIMAGE:
- FIXME("Unimplemented msg TCM_REMOVEIMAGE\n");
- return 0;
+ return TAB_RemoveImage (infoPtr, wParam);
case TCM_SETPADDING:
return TAB_SetPadding (infoPtr, lParam);
return TAB_SetMinTabWidth(infoPtr, (INT)lParam);
case TCM_DESELECTALL:
- FIXME("Unimplemented msg TCM_DESELECTALL\n");
- return 0;
+ return TAB_DeselectAll (infoPtr, (BOOL)wParam);
case TCM_GETEXTENDEDSTYLE:
- FIXME("Unimplemented msg TCM_GETEXTENDEDSTYLE\n");
- return 0;
+ return TAB_GetExtendedStyle (infoPtr);
case TCM_SETEXTENDEDSTYLE:
- FIXME("Unimplemented msg TCM_SETEXTENDEDSTYLE\n");
- return 0;
+ return TAB_SetExtendedStyle (infoPtr, wParam, lParam);
case WM_GETFONT:
return TAB_GetFont (infoPtr);
return TAB_SetFont (infoPtr, (HFONT)wParam);
case WM_CREATE:
- return TAB_Create (hwnd, wParam, lParam);
+ return TAB_Create (hwnd, lParam);
case WM_NCDESTROY:
return TAB_Destroy (infoPtr);
case WM_MOUSEMOVE:
return TAB_MouseMove (infoPtr, wParam, lParam);
+ case WM_PRINTCLIENT:
case WM_PAINT:
return TAB_Paint (infoPtr, (HDC)wParam);
return TAB_SetRedraw (infoPtr, (BOOL)wParam);
case WM_HSCROLL:
- return TAB_OnHScroll(infoPtr, (int)LOWORD(wParam), (int)HIWORD(wParam), (HWND)lParam);
+ return TAB_OnHScroll(infoPtr, (int)LOWORD(wParam), (int)HIWORD(wParam));
case WM_STYLECHANGED:
TAB_SetItemBounds (infoPtr);
return TAB_NCHitTest(infoPtr, lParam);
case WM_NCCALCSIZE:
- return TAB_NCCalcSize(hwnd, wParam, lParam);
+ return TAB_NCCalcSize(wParam);
default:
- if (uMsg >= WM_USER && uMsg < WM_APP)
- WARN("unknown msg %04x wp=%08x lp=%08lx\n",
+ if (uMsg >= WM_USER && uMsg < WM_APP && !COMCTL32_IsReflectedMessage(uMsg))
+ WARN("unknown msg %04x wp=%08lx lp=%08lx\n",
uMsg, wParam, lParam);
break;
}