4 * Copyright 1998 Anders Carlsson
5 * Copyright 1999 Alex Priem <alexp@sci.kun.nl>
6 * Copyright 1999 Francis Beaudet
19 #include "debugtools.h"
23 DEFAULT_DEBUG_CHANNEL(tab)
25 /******************************************************************************
26 * Positioning constants
28 #define SELECTED_TAB_OFFSET 2
29 #define HORIZONTAL_ITEM_PADDING 5
30 #define VERTICAL_ITEM_PADDING 3
31 #define ROUND_CORNER_SIZE 2
32 #define FOCUS_RECT_HOFFSET 2
33 #define FOCUS_RECT_VOFFSET 1
34 #define DISPLAY_AREA_PADDINGX 2
35 #define DISPLAY_AREA_PADDINGY 2
36 #define CONTROL_BORDER_SIZEX 2
37 #define CONTROL_BORDER_SIZEY 2
38 #define BUTTON_SPACINGX 10
39 #define DEFAULT_TAB_WIDTH 96
41 #define TAB_GetInfoPtr(hwnd) ((TAB_INFO *)GetWindowLongA(hwnd,0))
43 /******************************************************************************
46 static void TAB_Refresh (HWND hwnd, HDC hdc);
47 static void TAB_InvalidateTabArea(HWND hwnd, TAB_INFO* infoPtr);
48 static void TAB_EnsureSelectionVisible(HWND hwnd, TAB_INFO* infoPtr);
51 TAB_SendSimpleNotify (HWND hwnd, UINT code)
55 nmhdr.hwndFrom = hwnd;
56 nmhdr.idFrom = GetWindowLongA(hwnd, GWL_ID);
59 return (BOOL) SendMessageA (GetParent (hwnd), WM_NOTIFY,
60 (WPARAM) nmhdr.idFrom, (LPARAM) &nmhdr);
65 TAB_RelayEvent (HWND hwndTip, HWND hwndMsg, UINT uMsg,
66 WPARAM wParam, LPARAM lParam)
74 msg.time = GetMessageTime ();
75 msg.pt.x = LOWORD(GetMessagePos ());
76 msg.pt.y = HIWORD(GetMessagePos ());
78 SendMessageA (hwndTip, TTM_RELAYEVENT, 0, (LPARAM)&msg);
84 TAB_GetCurSel (HWND hwnd)
86 TAB_INFO *infoPtr = TAB_GetInfoPtr(hwnd);
88 return infoPtr->iSelected;
92 TAB_GetCurFocus (HWND hwnd)
94 TAB_INFO *infoPtr = TAB_GetInfoPtr(hwnd);
96 return infoPtr->uFocus;
100 TAB_GetToolTips (HWND hwnd, WPARAM wParam, LPARAM lParam)
102 TAB_INFO *infoPtr = TAB_GetInfoPtr(hwnd);
104 if (infoPtr == NULL) return 0;
105 return infoPtr->hwndToolTip;
110 TAB_SetCurSel (HWND hwnd,WPARAM wParam)
112 TAB_INFO *infoPtr = TAB_GetInfoPtr(hwnd);
113 INT iItem=(INT) wParam;
117 if ((iItem >= 0) && (iItem < infoPtr->uNumItem)) {
118 prevItem=infoPtr->iSelected;
119 infoPtr->iSelected=iItem;
120 TAB_EnsureSelectionVisible(hwnd, infoPtr);
121 TAB_InvalidateTabArea(hwnd, infoPtr);
127 TAB_SetCurFocus (HWND hwnd,WPARAM wParam)
129 TAB_INFO *infoPtr = TAB_GetInfoPtr(hwnd);
130 INT iItem=(INT) wParam;
132 if ((iItem < 0) || (iItem >= infoPtr->uNumItem)) return 0;
134 infoPtr->uFocus=iItem;
135 if (GetWindowLongA(hwnd, GWL_STYLE) & TCS_BUTTONS) {
136 FIXME("Should set input focus\n");
138 if (infoPtr->iSelected != iItem) {
139 if (TAB_SendSimpleNotify(hwnd, TCN_SELCHANGING)!=TRUE) {
140 infoPtr->iSelected = iItem;
141 TAB_SendSimpleNotify(hwnd, TCN_SELCHANGE);
143 TAB_EnsureSelectionVisible(hwnd, infoPtr);
144 TAB_InvalidateTabArea(hwnd, infoPtr);
152 TAB_SetToolTips (HWND hwnd, WPARAM wParam, LPARAM lParam)
154 TAB_INFO *infoPtr = TAB_GetInfoPtr(hwnd);
156 if (infoPtr == NULL) return 0;
157 infoPtr->hwndToolTip = (HWND)wParam;
161 /******************************************************************************
162 * TAB_InternalGetItemRect
164 * This method will calculate the rectangle representing a given tab item in
165 * client coordinates. This method takes scrolling into account.
167 * This method returns TRUE if the item is visible in the window and FALSE
168 * if it is completely outside the client area.
170 static BOOL TAB_InternalGetItemRect(
180 * Perform a sanity check and a trivial visibility check.
182 if ( (infoPtr->uNumItem <=0) ||
183 (itemIndex >= infoPtr->uNumItem) ||
184 (itemIndex < infoPtr->leftmostVisible) )
188 * Avoid special cases in this procedure by assigning the "out"
189 * parameters if the caller didn't supply them
192 itemRect = &tmpItemRect;
195 * Retrieve the unmodified item rect.
197 *itemRect = infoPtr->items[itemIndex].rect;
200 * "scroll" it to make sure the item at the very left of the
201 * tab control is the leftmost visible tab.
204 -infoPtr->items[infoPtr->leftmostVisible].rect.left,
208 * Move the rectangle so the first item is slightly offset from
209 * the left of the tab control.
217 * Now, calculate the position of the item as if it were selected.
219 if (selectedRect!=NULL)
221 CopyRect(selectedRect, itemRect);
224 * The rectangle of a selected item is a bit wider.
226 InflateRect(selectedRect, SELECTED_TAB_OFFSET, 0);
229 * If it also a bit higher.
231 if (GetWindowLongA(hwnd, GWL_STYLE) & TCS_BOTTOM)
233 selectedRect->top -=2; /* the border is thicker on the bottom */
234 selectedRect->bottom +=SELECTED_TAB_OFFSET;
238 selectedRect->top -=SELECTED_TAB_OFFSET;
239 selectedRect->bottom+=1;
246 static BOOL TAB_GetItemRect(HWND hwnd, WPARAM wParam, LPARAM lParam)
248 return TAB_InternalGetItemRect(hwnd, TAB_GetInfoPtr(hwnd), (INT)wParam,
249 (LPRECT)lParam, (LPRECT)NULL);
252 /******************************************************************************
255 * This method is called to handle keyboard input
257 static LRESULT TAB_KeyUp(
261 TAB_INFO* infoPtr = TAB_GetInfoPtr(hwnd);
267 newItem = infoPtr->uFocus-1;
270 newItem = infoPtr->uFocus+1;
275 * If we changed to a valid item, change the selection
277 if ( (newItem >= 0) &&
278 (newItem < infoPtr->uNumItem) &&
279 (infoPtr->uFocus != newItem) )
281 if (!TAB_SendSimpleNotify(hwnd, TCN_SELCHANGING))
283 infoPtr->iSelected = newItem;
284 infoPtr->uFocus = newItem;
285 TAB_SendSimpleNotify(hwnd, TCN_SELCHANGE);
287 TAB_EnsureSelectionVisible(hwnd, infoPtr);
288 TAB_InvalidateTabArea(hwnd, infoPtr);
295 /******************************************************************************
298 * This method is called whenever the focus goes in or out of this control
299 * it is used to update the visual state of the control.
301 static LRESULT TAB_FocusChanging(
307 TAB_INFO *infoPtr = TAB_GetInfoPtr(hwnd);
312 * Get the rectangle for the item.
314 isVisible = TAB_InternalGetItemRect(hwnd,
321 * If the rectangle is not completely invisible, invalidate that
322 * portion of the window.
326 InvalidateRect(hwnd, &selectedRect, TRUE);
330 * Don't otherwise disturb normal behavior.
332 return DefWindowProcA (hwnd, uMsg, wParam, lParam);
335 static HWND TAB_InternalHitTest (
345 for (iCount = 0; iCount < infoPtr->uNumItem; iCount++)
347 TAB_InternalGetItemRect(hwnd,
353 if (PtInRect (&rect, pt))
355 *flags = TCHT_ONITEM;
365 TAB_HitTest (HWND hwnd, WPARAM wParam, LPARAM lParam)
367 TAB_INFO *infoPtr = TAB_GetInfoPtr(hwnd);
368 LPTCHITTESTINFO lptest=(LPTCHITTESTINFO) lParam;
370 return TAB_InternalHitTest (hwnd, infoPtr,lptest->pt,&lptest->flags);
375 TAB_LButtonDown (HWND hwnd, WPARAM wParam, LPARAM lParam)
377 TAB_INFO *infoPtr = TAB_GetInfoPtr(hwnd);
381 if (infoPtr->hwndToolTip)
382 TAB_RelayEvent (infoPtr->hwndToolTip, hwnd,
383 WM_LBUTTONDOWN, wParam, lParam);
385 if (GetWindowLongA(hwnd, GWL_STYLE) & TCS_FOCUSONBUTTONDOWN ) {
389 if (infoPtr->hwndToolTip)
390 TAB_RelayEvent (infoPtr->hwndToolTip, hwnd,
391 WM_LBUTTONDOWN, wParam, lParam);
393 pt.x = (INT)LOWORD(lParam);
394 pt.y = (INT)HIWORD(lParam);
396 newItem=TAB_InternalHitTest (hwnd, infoPtr,pt,&dummy);
398 TRACE("On Tab, item %d\n", newItem);
400 if ( (newItem!=-1) &&
401 (infoPtr->iSelected != newItem) )
403 if (TAB_SendSimpleNotify(hwnd, TCN_SELCHANGING)!=TRUE)
405 infoPtr->iSelected = newItem;
406 infoPtr->uFocus = newItem;
407 TAB_SendSimpleNotify(hwnd, TCN_SELCHANGE);
409 TAB_EnsureSelectionVisible(hwnd, infoPtr);
411 TAB_InvalidateTabArea(hwnd, infoPtr);
418 TAB_LButtonUp (HWND hwnd, WPARAM wParam, LPARAM lParam)
420 TAB_SendSimpleNotify(hwnd, NM_CLICK);
426 TAB_RButtonDown (HWND hwnd, WPARAM wParam, LPARAM lParam)
428 TAB_SendSimpleNotify(hwnd, NM_RCLICK);
433 TAB_MouseMove (HWND hwnd, WPARAM wParam, LPARAM lParam)
435 TAB_INFO *infoPtr = TAB_GetInfoPtr(hwnd);
437 if (infoPtr->hwndToolTip)
438 TAB_RelayEvent (infoPtr->hwndToolTip, hwnd,
439 WM_LBUTTONDOWN, wParam, lParam);
443 /******************************************************************************
446 * Calculates the tab control's display area given the windows rectangle or
447 * the window rectangle given the requested display rectangle.
449 static LRESULT TAB_AdjustRect(
454 TAB_INFO *infoPtr = TAB_GetInfoPtr(hwnd);
459 * Go from display rectangle
463 * Add the height of the tabs.
465 if (GetWindowLongA(hwnd, GWL_STYLE) & TCS_BOTTOM)
466 prc->bottom += infoPtr->tabHeight;
468 prc->top -= infoPtr->tabHeight;
471 * Inflate the rectangle for the padding
473 InflateRect(prc, DISPLAY_AREA_PADDINGX, DISPLAY_AREA_PADDINGY);
476 * Inflate for the border
478 InflateRect(prc, CONTROL_BORDER_SIZEX, CONTROL_BORDER_SIZEX);
483 * Go from window rectangle.
487 * Deflate the rectangle for the border
489 InflateRect(prc, -CONTROL_BORDER_SIZEX, -CONTROL_BORDER_SIZEX);
492 * Deflate the rectangle for the padding
494 InflateRect(prc, -DISPLAY_AREA_PADDINGX, -DISPLAY_AREA_PADDINGY);
497 * Remove the height of the tabs.
499 if (GetWindowLongA(hwnd, GWL_STYLE) & TCS_BOTTOM)
500 prc->bottom -= infoPtr->tabHeight;
502 prc->top += infoPtr->tabHeight;
509 /******************************************************************************
512 * This method will handle the notification from the scroll control and
513 * perform the scrolling operation on the tab control.
515 static LRESULT TAB_OnHScroll(
521 TAB_INFO *infoPtr = TAB_GetInfoPtr(hwnd);
523 if(nScrollCode == SB_THUMBPOSITION && nPos != infoPtr->leftmostVisible)
525 if(nPos < infoPtr->leftmostVisible)
526 infoPtr->leftmostVisible--;
528 infoPtr->leftmostVisible++;
530 TAB_InvalidateTabArea(hwnd, infoPtr);
531 SendMessageA(infoPtr->hwndUpDown, UDM_SETPOS, 0,
532 MAKELONG(infoPtr->leftmostVisible, 0));
538 /******************************************************************************
541 * This method will check the current scrolling state and make sure the
542 * scrolling control is displayed (or not).
544 static void TAB_SetupScrolling(
547 const RECT* clientRect)
550 if (infoPtr->needsScrolling)
556 * Calculate the position of the scroll control.
558 controlPos.right = clientRect->right;
559 controlPos.left = controlPos.right - 2*GetSystemMetrics(SM_CXHSCROLL);
561 if (GetWindowLongA(hwnd, GWL_STYLE) & TCS_BOTTOM)
563 controlPos.top = clientRect->bottom - infoPtr->tabHeight;
564 controlPos.bottom = controlPos.top + GetSystemMetrics(SM_CYHSCROLL);
568 controlPos.bottom = clientRect->top + infoPtr->tabHeight;
569 controlPos.top = controlPos.bottom - GetSystemMetrics(SM_CYHSCROLL);
573 * If we don't have a scroll control yet, we want to create one.
574 * If we have one, we want to make sure it's positioned right.
576 if (infoPtr->hwndUpDown==0)
578 infoPtr->hwndUpDown = CreateWindowA("msctls_updown32",
580 WS_VISIBLE | WS_CHILD | UDS_HORZ,
581 controlPos.left, controlPos.top,
582 controlPos.right - controlPos.left,
583 controlPos.bottom - controlPos.top,
591 SetWindowPos(infoPtr->hwndUpDown,
593 controlPos.left, controlPos.top,
594 controlPos.right - controlPos.left,
595 controlPos.bottom - controlPos.top,
596 SWP_SHOWWINDOW | SWP_NOZORDER);
599 /* Now calculate upper limit of the updown control range.
600 * We do this by calculating how many tabs will be offscreen when the
601 * last tab is visible.
603 if(infoPtr->uNumItem)
605 vsize = clientRect->right - (controlPos.right - controlPos.left + 1);
606 maxRange = infoPtr->uNumItem;
607 tabwidth = infoPtr->items[maxRange-1].rect.right;
609 for(; maxRange > 0; maxRange--)
611 if(tabwidth - infoPtr->items[maxRange - 1].rect.left > vsize)
615 if(maxRange == infoPtr->uNumItem)
622 * If we once had a scroll control... hide it.
624 if (infoPtr->hwndUpDown!=0)
626 ShowWindow(infoPtr->hwndUpDown, SW_HIDE);
629 if (infoPtr->hwndUpDown)
630 SendMessageA(infoPtr->hwndUpDown, UDM_SETRANGE32, 0, maxRange);
633 /******************************************************************************
636 * This method will calculate the position rectangles of all the items in the
637 * control. The rectangle calculated starts at 0 for the first item in the
638 * list and ignores scrolling and selection.
639 * It also uses the current font to determine the height of the tab row and
640 * it checks if all the tabs fit in the client area of the window. If they
641 * dont, a scrolling control is added.
643 static void TAB_SetItemBounds (HWND hwnd)
645 TAB_INFO* infoPtr = TAB_GetInfoPtr(hwnd);
646 LONG lStyle = GetWindowLongA(hwnd, GWL_STYLE);
647 TEXTMETRICA fontMetrics;
650 HFONT hFont, hOldFont;
656 * We need to get text information so we need a DC and we need to select
661 hFont = infoPtr->hFont ? infoPtr->hFont : GetStockObject (SYSTEM_FONT);
662 hOldFont = SelectObject (hdc, hFont);
665 * We will base the rectangle calculations on the client rectangle
668 GetClientRect(hwnd, &clientRect);
671 * The leftmost item will be "0" aligned
675 if ( !(lStyle & TCS_FIXEDWIDTH) && !((lStyle & TCS_OWNERDRAWFIXED) && infoPtr->fSizeSet) )
681 * Use the current font to determine the height of a tab.
683 GetTextMetricsA(hdc, &fontMetrics);
686 * Get the icon height
689 ImageList_GetIconSize(infoPtr->himl, 0, &icon_height);
692 * Take the highest between font or icon
694 if (fontMetrics.tmHeight > icon_height)
695 item_height = fontMetrics.tmHeight;
697 item_height = icon_height;
700 * Make sure there is enough space for the letters + icon + growing the
701 * selected item + extra space for the selected item.
703 infoPtr->tabHeight = item_height + 2*VERTICAL_ITEM_PADDING +
707 for (curItem = 0; curItem < infoPtr->uNumItem; curItem++)
710 * Calculate the vertical position of the tab
712 if (lStyle & TCS_BOTTOM)
714 infoPtr->items[curItem].rect.bottom = clientRect.bottom -
716 infoPtr->items[curItem].rect.top = clientRect.bottom -
721 infoPtr->items[curItem].rect.top = clientRect.top +
723 infoPtr->items[curItem].rect.bottom = clientRect.top +
728 * Set the leftmost position of the tab.
730 infoPtr->items[curItem].rect.left = curItemLeftPos;
732 if ( (lStyle & TCS_FIXEDWIDTH) || ((lStyle & TCS_OWNERDRAWFIXED) && infoPtr->fSizeSet))
734 infoPtr->items[curItem].rect.right = infoPtr->items[curItem].rect.left +
736 2*HORIZONTAL_ITEM_PADDING;
744 * Calculate how wide the tab is depending on the text it contains
746 GetTextExtentPoint32A(hdc, infoPtr->items[curItem].pszText,
747 lstrlenA(infoPtr->items[curItem].pszText), &size);
754 ImageList_GetIconSize(infoPtr->himl, &icon_width, 0);
758 infoPtr->items[curItem].rect.right = infoPtr->items[curItem].rect.left +
759 size.cx + icon_width +
760 num*HORIZONTAL_ITEM_PADDING;
763 TRACE("TextSize: %i\n ", size.cx);
764 TRACE("Rect: T %i, L %i, B %i, R %i\n",
765 infoPtr->items[curItem].rect.top,
766 infoPtr->items[curItem].rect.left,
767 infoPtr->items[curItem].rect.bottom,
768 infoPtr->items[curItem].rect.right);
771 * The leftmost position of the next item is the rightmost position
774 if (lStyle & TCS_BUTTONS)
775 curItemLeftPos = infoPtr->items[curItem].rect.right + BUTTON_SPACINGX;
777 curItemLeftPos = infoPtr->items[curItem].rect.right;
781 * Check if we need a scrolling control.
783 infoPtr->needsScrolling = (curItemLeftPos + (2*SELECTED_TAB_OFFSET) >
786 TAB_SetupScrolling(hwnd, infoPtr, &clientRect);
791 SelectObject (hdc, hOldFont);
792 ReleaseDC (hwnd, hdc);
795 /******************************************************************************
798 * This method is used to draw a single tab into the tab control.
800 static void TAB_DrawItem(
805 TAB_INFO *infoPtr = TAB_GetInfoPtr(hwnd);
806 LONG lStyle = GetWindowLongA(hwnd, GWL_STYLE);
813 * Get the rectangle for the item.
815 isVisible = TAB_InternalGetItemRect(hwnd,
823 HBRUSH hbr = CreateSolidBrush (GetSysColor(COLOR_BTNFACE));
824 HPEN hwPen = GetSysColorPen (COLOR_3DHILIGHT);
825 HPEN hbPen = GetSysColorPen (COLOR_BTNSHADOW);
826 HPEN hsdPen = GetSysColorPen (COLOR_BTNTEXT);
827 HPEN hfocusPen = CreatePen(PS_DOT, 1, GetSysColor(COLOR_BTNTEXT));
831 BOOL deleteBrush = TRUE;
833 if (lStyle & TCS_BUTTONS)
836 * Get item rectangle.
840 holdPen = SelectObject (hdc, hwPen);
842 if (iItem == infoPtr->iSelected)
847 if (!((lStyle & TCS_OWNERDRAWFIXED) && infoPtr->fSizeSet))
849 COLORREF bk = GetSysColor(COLOR_3DHILIGHT);
851 hbr = GetSysColorBrush(COLOR_SCROLLBAR);
852 SetTextColor(hdc, GetSysColor(COLOR_3DFACE));
855 /* if COLOR_WINDOW happens to be the same as COLOR_3DHILIGHT
856 * we better use 0x55aa bitmap brush to make scrollbar's background
857 * look different from the window background.
859 if (bk == GetSysColor(COLOR_WINDOW))
860 hbr = CACHE_GetPattern55AABrush();
866 * Erase the background.
868 FillRect(hdc, &r, hbr);
872 * The rectangles calculated exclude the right and bottom
873 * borders of the rectangle. To simply the following code, those
874 * borders are shaved-off beforehand.
880 MoveToEx (hdc, r.left, r.bottom, NULL);
881 LineTo (hdc, r.right, r.bottom);
882 LineTo (hdc, r.right, r.top);
885 SelectObject(hdc, hbPen);
886 LineTo (hdc, r.left, r.top);
887 LineTo (hdc, r.left, r.bottom);
892 * Erase the background.
894 FillRect(hdc, &r, hbr);
897 MoveToEx (hdc, r.left, r.bottom, NULL);
898 LineTo (hdc, r.left, r.top);
899 LineTo (hdc, r.right, r.top);
902 SelectObject(hdc, hbPen);
903 LineTo (hdc, r.right, r.bottom);
904 LineTo (hdc, r.left, r.bottom);
913 hbr = CreateSolidBrush(GetSysColor(COLOR_BTNFACE));
916 * We draw a rectangle of different sizes depending on the selection
919 if (iItem == infoPtr->iSelected)
925 * Erase the background.
926 * This is necessary when drawing the selected item since it is larger
927 * than the others, it might overlap with stuff already drawn by the
930 FillRect(hdc, &r, hbr);
934 * The rectangles calculated exclude the right and bottom
935 * borders of the rectangle. To simply the following code, those
936 * borders are shaved-off beforehand.
941 holdPen = SelectObject (hdc, hwPen);
943 if (lStyle & TCS_BOTTOM)
946 MoveToEx (hdc, r.left, r.top, NULL);
947 LineTo (hdc, r.left, r.bottom - ROUND_CORNER_SIZE);
948 LineTo (hdc, r.left + ROUND_CORNER_SIZE, r.bottom);
951 SelectObject(hdc, hbPen);
952 LineTo (hdc, r.right - ROUND_CORNER_SIZE, r.bottom);
953 LineTo (hdc, r.right, r.bottom - ROUND_CORNER_SIZE);
954 LineTo (hdc, r.right, r.top);
959 MoveToEx (hdc, r.left, r.bottom, NULL);
960 LineTo (hdc, r.left, r.top + ROUND_CORNER_SIZE);
961 LineTo (hdc, r.left + ROUND_CORNER_SIZE, r.top);
962 LineTo (hdc, r.right - ROUND_CORNER_SIZE, r.top);
965 SelectObject(hdc, hbPen);
966 LineTo (hdc, r.right, r.top + ROUND_CORNER_SIZE);
967 LineTo (hdc, r.right, r.bottom);
974 SelectObject(hdc, hsdPen);
976 oldBkMode = SetBkMode(hdc, TRANSPARENT);
977 SetTextColor (hdc, COLOR_BTNTEXT);
980 * Deflate the rectangle to acount for the padding
982 InflateRect(&r, -HORIZONTAL_ITEM_PADDING, -VERTICAL_ITEM_PADDING);
985 * if owner draw, tell the owner to draw
987 if ( (lStyle & TCS_OWNERDRAWFIXED) && GetParent(hwnd) )
996 pwndPtr = WIN_FindWndPtr( hwnd );
997 id = pwndPtr->wIDmenu;
998 WIN_ReleaseWndPtr(pwndPtr);
1001 * put together the DRAWITEMSTRUCT
1003 dis.CtlType = ODT_TAB;
1006 dis.itemAction = ODA_DRAWENTIRE;
1007 if ( iItem == infoPtr->iSelected )
1008 dis.itemState = ODS_SELECTED;
1011 dis.hwndItem = hwnd; /* */
1013 dis.rcItem = r; /* */
1014 dis.itemData = infoPtr->items[iItem].lParam;
1017 * send the draw message
1019 SendMessageA( GetParent(hwnd), WM_DRAWITEM, (WPARAM)id, (LPARAM)&dis );
1024 * If not owner draw, then do the drawing ourselves.
1028 if (infoPtr->himl && (infoPtr->items[iItem].mask & TCIF_IMAGE) )
1030 ImageList_Draw (infoPtr->himl, infoPtr->items[iItem].iImage, hdc,
1031 r.left, r.top+1, ILD_NORMAL);
1032 ImageList_GetIconSize (infoPtr->himl, &cx, &cy);
1033 r.left+=(cx + HORIZONTAL_ITEM_PADDING);
1040 infoPtr->items[iItem].pszText,
1041 lstrlenA(infoPtr->items[iItem].pszText),
1043 DT_LEFT|DT_SINGLELINE|DT_VCENTER);
1047 * Draw the focus rectangle
1049 if (((lStyle & TCS_FOCUSNEVER) == 0) &&
1050 (GetFocus() == hwnd) &&
1051 (iItem == infoPtr->uFocus) )
1053 InflateRect(&r, FOCUS_RECT_HOFFSET, FOCUS_RECT_VOFFSET);
1055 SelectObject(hdc, hfocusPen);
1057 MoveToEx (hdc, r.left, r.top, NULL);
1058 LineTo (hdc, r.right-1, r.top);
1059 LineTo (hdc, r.right-1, r.bottom -1);
1060 LineTo (hdc, r.left, r.bottom -1);
1061 LineTo (hdc, r.left, r.top);
1067 SetBkMode(hdc, oldBkMode);
1068 SelectObject(hdc, holdPen);
1069 DeleteObject(hfocusPen);
1070 if (deleteBrush) DeleteObject(hbr);
1074 /******************************************************************************
1077 * This method is used to draw the raised border around the tab control
1080 static void TAB_DrawBorder (HWND hwnd, HDC hdc)
1082 TAB_INFO *infoPtr = TAB_GetInfoPtr(hwnd);
1084 HPEN hwPen = GetSysColorPen (COLOR_3DHILIGHT);
1085 HPEN hbPen = GetSysColorPen (COLOR_3DDKSHADOW);
1086 HPEN hShade = GetSysColorPen (COLOR_BTNSHADOW);
1089 GetClientRect (hwnd, &rect);
1092 * Adjust for the style
1094 if (GetWindowLongA(hwnd, GWL_STYLE) & TCS_BOTTOM)
1096 rect.bottom -= infoPtr->tabHeight;
1100 rect.top += infoPtr->tabHeight;
1104 * Shave-off the right and bottom margins (exluded in the
1111 htmPen = SelectObject (hdc, hwPen);
1113 MoveToEx (hdc, rect.left, rect.bottom, NULL);
1114 LineTo (hdc, rect.left, rect.top);
1115 LineTo (hdc, rect.right, rect.top);
1118 SelectObject (hdc, hbPen);
1119 LineTo (hdc, rect.right, rect.bottom );
1120 LineTo (hdc, rect.left, rect.bottom);
1123 SelectObject (hdc, hShade );
1124 MoveToEx (hdc, rect.right-1, rect.top, NULL);
1125 LineTo (hdc, rect.right-1, rect.bottom-1);
1126 LineTo (hdc, rect.left, rect.bottom-1);
1128 SelectObject(hdc, htmPen);
1131 /******************************************************************************
1134 * This method repaints the tab control..
1136 static void TAB_Refresh (HWND hwnd, HDC hdc)
1138 TAB_INFO *infoPtr = TAB_GetInfoPtr(hwnd);
1142 if (!infoPtr->DoRedraw)
1145 hOldFont = SelectObject (hdc, infoPtr->hFont);
1147 if (GetWindowLongA(hwnd, GWL_STYLE) & TCS_BUTTONS)
1149 for (i = 0; i < infoPtr->uNumItem; i++)
1151 TAB_DrawItem (hwnd, hdc, i);
1157 * Draw all the non selected item first.
1159 for (i = 0; i < infoPtr->uNumItem; i++)
1161 if (i != infoPtr->iSelected)
1162 TAB_DrawItem (hwnd, hdc, i);
1166 * Now, draw the border, draw it before the selected item
1167 * since the selected item overwrites part of the border.
1169 TAB_DrawBorder (hwnd, hdc);
1172 * Then, draw the selected item
1174 TAB_DrawItem (hwnd, hdc, infoPtr->iSelected);
1177 SelectObject (hdc, hOldFont);
1181 TAB_SetRedraw (HWND hwnd, WPARAM wParam)
1183 TAB_INFO *infoPtr = TAB_GetInfoPtr(hwnd);
1185 infoPtr->DoRedraw=(BOOL) wParam;
1189 static LRESULT TAB_EraseBackground(
1196 HBRUSH brush = CreateSolidBrush(GetSysColor(COLOR_BTNFACE));
1198 hdc = givenDC ? givenDC : GetDC(hwnd);
1200 GetClientRect(hwnd, &clientRect);
1202 FillRect(hdc, &clientRect, brush);
1205 ReleaseDC(hwnd, hdc);
1207 DeleteObject(brush);
1212 /******************************************************************************
1213 * TAB_EnsureSelectionVisible
1215 * This method will make sure that the current selection is completely
1216 * visible by scrolling until it is.
1218 static void TAB_EnsureSelectionVisible(
1222 INT iSelected = infoPtr->iSelected;
1225 * Do the trivial cases first.
1227 if ( (!infoPtr->needsScrolling) ||
1228 (infoPtr->hwndUpDown==0) )
1231 if (infoPtr->leftmostVisible >= iSelected)
1233 infoPtr->leftmostVisible = iSelected;
1240 * Calculate the part of the client area that is visible.
1242 GetClientRect(hwnd, &r);
1245 GetClientRect(infoPtr->hwndUpDown, &r);
1248 if ((infoPtr->items[iSelected].rect.right -
1249 infoPtr->items[iSelected].rect.left) >= width )
1251 /* Special case: width of selected item is greater than visible
1254 infoPtr->leftmostVisible = iSelected;
1258 for (i = infoPtr->leftmostVisible; i < infoPtr->uNumItem; i++)
1260 if ((infoPtr->items[iSelected].rect.right -
1261 infoPtr->items[i].rect.left) < width)
1264 infoPtr->leftmostVisible = i;
1268 SendMessageA(infoPtr->hwndUpDown, UDM_SETPOS, 0,
1269 MAKELONG(infoPtr->leftmostVisible, 0));
1272 /******************************************************************************
1273 * TAB_InvalidateTabArea
1275 * This method will invalidate the portion of the control that contains the
1276 * tabs. It is called when the state of the control changes and needs
1279 static void TAB_InvalidateTabArea(
1285 GetClientRect(hwnd, &clientRect);
1287 if (GetWindowLongA(hwnd, GWL_STYLE) & TCS_BOTTOM)
1289 clientRect.top = clientRect.bottom - (infoPtr->tabHeight + 3);
1293 clientRect.bottom = clientRect.top + (infoPtr->tabHeight + 1);
1296 InvalidateRect(hwnd, &clientRect, TRUE);
1300 TAB_Paint (HWND hwnd, WPARAM wParam)
1305 hdc = wParam== 0 ? BeginPaint (hwnd, &ps) : (HDC)wParam;
1306 TAB_Refresh (hwnd, hdc);
1309 EndPaint (hwnd, &ps);
1315 TAB_InsertItem (HWND hwnd, WPARAM wParam, LPARAM lParam)
1317 TAB_INFO *infoPtr = TAB_GetInfoPtr(hwnd);
1322 GetClientRect (hwnd, &rect);
1323 TRACE("Rect: %x T %i, L %i, B %i, R %i\n", hwnd,
1324 rect.top, rect.left, rect.bottom, rect.right);
1326 pti = (TCITEMA *)lParam;
1327 iItem = (INT)wParam;
1329 if (iItem < 0) return -1;
1330 if (iItem > infoPtr->uNumItem)
1331 iItem = infoPtr->uNumItem;
1333 if (infoPtr->uNumItem == 0) {
1334 infoPtr->items = COMCTL32_Alloc (sizeof (TAB_ITEM));
1335 infoPtr->uNumItem++;
1336 infoPtr->iSelected = 0;
1339 TAB_ITEM *oldItems = infoPtr->items;
1341 infoPtr->uNumItem++;
1342 infoPtr->items = COMCTL32_Alloc (sizeof (TAB_ITEM) * infoPtr->uNumItem);
1344 /* pre insert copy */
1346 memcpy (&infoPtr->items[0], &oldItems[0],
1347 iItem * sizeof(TAB_ITEM));
1350 /* post insert copy */
1351 if (iItem < infoPtr->uNumItem - 1) {
1352 memcpy (&infoPtr->items[iItem+1], &oldItems[iItem],
1353 (infoPtr->uNumItem - iItem - 1) * sizeof(TAB_ITEM));
1357 if (iItem <= infoPtr->iSelected)
1358 infoPtr->iSelected++;
1360 COMCTL32_Free (oldItems);
1363 infoPtr->items[iItem].mask = pti->mask;
1364 if (pti->mask & TCIF_TEXT) {
1365 len = lstrlenA (pti->pszText);
1366 infoPtr->items[iItem].pszText = COMCTL32_Alloc (len+1);
1367 lstrcpyA (infoPtr->items[iItem].pszText, pti->pszText);
1368 infoPtr->items[iItem].cchTextMax = pti->cchTextMax;
1371 if (pti->mask & TCIF_IMAGE)
1372 infoPtr->items[iItem].iImage = pti->iImage;
1374 if (pti->mask & TCIF_PARAM)
1375 infoPtr->items[iItem].lParam = pti->lParam;
1377 TAB_InvalidateTabArea(hwnd, infoPtr);
1379 TRACE("[%04x]: added item %d '%s'\n",
1380 hwnd, iItem, infoPtr->items[iItem].pszText);
1382 TAB_SetItemBounds(hwnd);
1387 TAB_SetItemSize (HWND hwnd, WPARAM wParam, LPARAM lParam)
1389 TAB_INFO *infoPtr = TAB_GetInfoPtr(hwnd);
1390 LONG lStyle = GetWindowLongA(hwnd, GWL_STYLE);
1393 if ((lStyle & TCS_FIXEDWIDTH) || (lStyle & TCS_OWNERDRAWFIXED))
1395 lResult = MAKELONG(infoPtr->tabWidth, infoPtr->tabHeight);
1396 infoPtr->tabWidth = (INT)LOWORD(lParam);
1397 infoPtr->tabHeight = (INT)HIWORD(lParam);
1399 infoPtr->fSizeSet = TRUE;
1405 TAB_SetItemA (HWND hwnd, WPARAM wParam, LPARAM lParam)
1407 TAB_INFO *infoPtr = TAB_GetInfoPtr(hwnd);
1413 tabItem=(LPTCITEMA ) lParam;
1414 TRACE("%d %p\n",iItem, tabItem);
1415 if ((iItem<0) || (iItem>=infoPtr->uNumItem)) return FALSE;
1417 wineItem=& infoPtr->items[iItem];
1419 if (tabItem->mask & TCIF_IMAGE)
1420 wineItem->iImage=tabItem->iImage;
1422 if (tabItem->mask & TCIF_PARAM)
1423 wineItem->lParam=tabItem->lParam;
1425 if (tabItem->mask & TCIF_RTLREADING)
1426 FIXME("TCIF_RTLREADING\n");
1428 if (tabItem->mask & TCIF_STATE)
1429 wineItem->dwState=tabItem->dwState;
1431 if (tabItem->mask & TCIF_TEXT) {
1432 len=lstrlenA (tabItem->pszText);
1433 if (len>wineItem->cchTextMax)
1434 wineItem->pszText= COMCTL32_ReAlloc (wineItem->pszText, len+1);
1435 lstrcpyA (wineItem->pszText, tabItem->pszText);
1439 * Update and repaint tabs.
1441 TAB_SetItemBounds(hwnd);
1442 TAB_InvalidateTabArea(hwnd,infoPtr);
1448 TAB_GetItemCount (HWND hwnd, WPARAM wParam, LPARAM lParam)
1450 TAB_INFO *infoPtr = TAB_GetInfoPtr(hwnd);
1452 return infoPtr->uNumItem;
1457 TAB_GetItemA (HWND hwnd, WPARAM wParam, LPARAM lParam)
1459 TAB_INFO *infoPtr = TAB_GetInfoPtr(hwnd);
1465 tabItem=(LPTCITEMA) lParam;
1467 if ((iItem<0) || (iItem>=infoPtr->uNumItem)) return FALSE;
1469 wineItem=& infoPtr->items[iItem];
1471 if (tabItem->mask & TCIF_IMAGE)
1472 tabItem->iImage=wineItem->iImage;
1474 if (tabItem->mask & TCIF_PARAM)
1475 tabItem->lParam=wineItem->lParam;
1477 if (tabItem->mask & TCIF_RTLREADING)
1478 FIXME("TCIF_RTLREADING\n");
1480 if (tabItem->mask & TCIF_STATE)
1481 tabItem->dwState=wineItem->dwState;
1483 if (tabItem->mask & TCIF_TEXT)
1484 lstrcpynA (tabItem->pszText, wineItem->pszText, tabItem->cchTextMax);
1490 TAB_DeleteItem (HWND hwnd, WPARAM wParam, LPARAM lParam)
1492 TAB_INFO *infoPtr = TAB_GetInfoPtr(hwnd);
1493 INT iItem = (INT) wParam;
1494 BOOL bResult = FALSE;
1496 if ((iItem >= 0) && (iItem < infoPtr->uNumItem))
1498 TAB_ITEM *oldItems = infoPtr->items;
1500 infoPtr->uNumItem--;
1501 infoPtr->items = COMCTL32_Alloc(sizeof (TAB_ITEM) * infoPtr->uNumItem);
1504 memcpy(&infoPtr->items[0], &oldItems[0], iItem * sizeof(TAB_ITEM));
1506 if (iItem < infoPtr->uNumItem)
1507 memcpy(&infoPtr->items[iItem], &oldItems[iItem + 1],
1508 (infoPtr->uNumItem - iItem) * sizeof(TAB_ITEM));
1510 COMCTL32_Free (oldItems);
1513 * Readjust the selected index.
1515 if ((iItem == infoPtr->iSelected) && (iItem > 0))
1516 infoPtr->iSelected--;
1518 if (iItem < infoPtr->iSelected)
1519 infoPtr->iSelected--;
1521 if (infoPtr->uNumItem == 0)
1522 infoPtr->iSelected = -1;
1525 * Reposition and repaint tabs.
1527 TAB_SetItemBounds(hwnd);
1528 TAB_InvalidateTabArea(hwnd,infoPtr);
1537 TAB_DeleteAllItems (HWND hwnd, WPARAM wParam, LPARAM lParam)
1539 TAB_INFO *infoPtr = TAB_GetInfoPtr(hwnd);
1541 COMCTL32_Free (infoPtr->items);
1542 infoPtr->uNumItem = 0;
1543 infoPtr->iSelected = -1;
1545 TAB_SetItemBounds(hwnd);
1546 TAB_InvalidateTabArea(hwnd,infoPtr);
1552 TAB_GetFont (HWND hwnd, WPARAM wParam, LPARAM lParam)
1554 TAB_INFO *infoPtr = TAB_GetInfoPtr(hwnd);
1557 return (LRESULT)infoPtr->hFont;
1561 TAB_SetFont (HWND hwnd, WPARAM wParam, LPARAM lParam)
1564 TAB_INFO *infoPtr = TAB_GetInfoPtr(hwnd);
1566 TRACE("%x %lx\n",wParam, lParam);
1568 infoPtr->hFont = (HFONT)wParam;
1570 TAB_SetItemBounds(hwnd);
1572 TAB_InvalidateTabArea(hwnd, infoPtr);
1579 TAB_GetImageList (HWND hwnd, WPARAM wParam, LPARAM lParam)
1581 TAB_INFO *infoPtr = TAB_GetInfoPtr(hwnd);
1584 return (LRESULT)infoPtr->himl;
1588 TAB_SetImageList (HWND hwnd, WPARAM wParam, LPARAM lParam)
1590 TAB_INFO *infoPtr = TAB_GetInfoPtr(hwnd);
1591 HIMAGELIST himlPrev;
1594 himlPrev = infoPtr->himl;
1595 infoPtr->himl= (HIMAGELIST)lParam;
1596 return (LRESULT)himlPrev;
1601 TAB_Size (HWND hwnd, WPARAM wParam, LPARAM lParam)
1604 /* I'm not really sure what the following code was meant to do.
1605 This is what it is doing:
1606 When WM_SIZE is sent with SIZE_RESTORED, the control
1607 gets positioned in the top left corner.
1611 UINT uPosFlags,cx,cy;
1615 parent = GetParent (hwnd);
1616 GetClientRect(parent, &parent_rect);
1619 if (GetWindowLongA(hwnd, GWL_STYLE) & CCS_NORESIZE)
1620 uPosFlags |= (SWP_NOSIZE | SWP_NOMOVE);
1622 SetWindowPos (hwnd, 0, parent_rect.left, parent_rect.top,
1623 cx, cy, uPosFlags | SWP_NOZORDER);
1625 FIXME (tab,"WM_SIZE flag %x %lx not handled\n", wParam, lParam);
1629 * Recompute the size/position of the tabs.
1631 TAB_SetItemBounds (hwnd);
1634 * Force a repaint of the control.
1636 InvalidateRect(hwnd, NULL, TRUE);
1643 TAB_Create (HWND hwnd, WPARAM wParam, LPARAM lParam)
1646 TEXTMETRICA fontMetrics;
1651 infoPtr = (TAB_INFO *)COMCTL32_Alloc (sizeof(TAB_INFO));
1653 SetWindowLongA(hwnd, 0, (DWORD)infoPtr);
1655 infoPtr->uNumItem = 0;
1658 infoPtr->hcurArrow = LoadCursorA (0, IDC_ARROWA);
1659 infoPtr->iSelected = -1;
1660 infoPtr->uFocus = 0;
1661 infoPtr->hwndToolTip = 0;
1662 infoPtr->DoRedraw = TRUE;
1663 infoPtr->needsScrolling = FALSE;
1664 infoPtr->hwndUpDown = 0;
1665 infoPtr->leftmostVisible = 0;
1666 infoPtr->fSizeSet = FALSE;
1668 TRACE("Created tab control, hwnd [%04x]\n", hwnd);
1670 /* The tab control always has the WS_CLIPSIBLINGS style. Even
1671 if you don't specify in CreateWindow. This is necesary in
1672 order for paint to work correctly. This follows windows behaviour. */
1673 dwStyle = GetWindowLongA(hwnd, GWL_STYLE);
1674 SetWindowLongA(hwnd, GWL_STYLE, dwStyle|WS_CLIPSIBLINGS);
1676 if (dwStyle & TCS_TOOLTIPS) {
1677 /* Create tooltip control */
1678 infoPtr->hwndToolTip =
1679 CreateWindowExA (0, TOOLTIPS_CLASSA, NULL, 0,
1680 CW_USEDEFAULT, CW_USEDEFAULT,
1681 CW_USEDEFAULT, CW_USEDEFAULT,
1684 /* Send NM_TOOLTIPSCREATED notification */
1685 if (infoPtr->hwndToolTip) {
1686 NMTOOLTIPSCREATED nmttc;
1688 nmttc.hdr.hwndFrom = hwnd;
1689 nmttc.hdr.idFrom = GetWindowLongA(hwnd, GWL_ID);
1690 nmttc.hdr.code = NM_TOOLTIPSCREATED;
1691 nmttc.hwndToolTips = infoPtr->hwndToolTip;
1693 SendMessageA (GetParent (hwnd), WM_NOTIFY,
1694 (WPARAM)GetWindowLongA(hwnd, GWL_ID), (LPARAM)&nmttc);
1699 * We need to get text information so we need a DC and we need to select
1703 hOldFont = SelectObject (hdc, GetStockObject (SYSTEM_FONT));
1706 * Use the system font to determine the initial height of a tab.
1708 GetTextMetricsA(hdc, &fontMetrics);
1711 * Make sure there is enough space for the letters + growing the
1712 * selected item + extra space for the selected item.
1714 infoPtr->tabHeight = fontMetrics.tmHeight + 2*VERTICAL_ITEM_PADDING +
1715 SELECTED_TAB_OFFSET;
1718 * Initialize the width of a tab.
1720 infoPtr->tabWidth = DEFAULT_TAB_WIDTH;
1722 SelectObject (hdc, hOldFont);
1723 ReleaseDC(hwnd, hdc);
1729 TAB_Destroy (HWND hwnd, WPARAM wParam, LPARAM lParam)
1731 TAB_INFO *infoPtr = TAB_GetInfoPtr(hwnd);
1737 if (infoPtr->items) {
1738 for (iItem = 0; iItem < infoPtr->uNumItem; iItem++) {
1739 if (infoPtr->items[iItem].pszText)
1740 COMCTL32_Free (infoPtr->items[iItem].pszText);
1742 COMCTL32_Free (infoPtr->items);
1745 if (infoPtr->hwndToolTip)
1746 DestroyWindow (infoPtr->hwndToolTip);
1748 if (infoPtr->hwndUpDown)
1749 DestroyWindow(infoPtr->hwndUpDown);
1751 COMCTL32_Free (infoPtr);
1755 static LRESULT WINAPI
1756 TAB_WindowProc (HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
1760 case TCM_GETIMAGELIST:
1761 return TAB_GetImageList (hwnd, wParam, lParam);
1763 case TCM_SETIMAGELIST:
1764 return TAB_SetImageList (hwnd, wParam, lParam);
1766 case TCM_GETITEMCOUNT:
1767 return TAB_GetItemCount (hwnd, wParam, lParam);
1770 return TAB_GetItemA (hwnd, wParam, lParam);
1773 FIXME("Unimplemented msg TCM_GETITEMW\n");
1777 return TAB_SetItemA (hwnd, wParam, lParam);
1780 FIXME("Unimplemented msg TCM_SETITEMW\n");
1783 case TCM_DELETEITEM:
1784 return TAB_DeleteItem (hwnd, wParam, lParam);
1786 case TCM_DELETEALLITEMS:
1787 return TAB_DeleteAllItems (hwnd, wParam, lParam);
1789 case TCM_GETITEMRECT:
1790 return TAB_GetItemRect (hwnd, wParam, lParam);
1793 return TAB_GetCurSel (hwnd);
1796 return TAB_HitTest (hwnd, wParam, lParam);
1799 return TAB_SetCurSel (hwnd, wParam);
1801 case TCM_INSERTITEMA:
1802 return TAB_InsertItem (hwnd, wParam, lParam);
1804 case TCM_INSERTITEMW:
1805 FIXME("Unimplemented msg TCM_INSERTITEMW\n");
1808 case TCM_SETITEMEXTRA:
1809 FIXME("Unimplemented msg TCM_SETITEMEXTRA\n");
1812 case TCM_ADJUSTRECT:
1813 return TAB_AdjustRect (hwnd, (BOOL)wParam, (LPRECT)lParam);
1815 case TCM_SETITEMSIZE:
1816 return TAB_SetItemSize (hwnd, wParam, lParam);
1818 case TCM_REMOVEIMAGE:
1819 FIXME("Unimplemented msg TCM_REMOVEIMAGE\n");
1822 case TCM_SETPADDING:
1823 FIXME("Unimplemented msg TCM_SETPADDING\n");
1826 case TCM_GETROWCOUNT:
1827 FIXME("Unimplemented msg TCM_GETROWCOUNT\n");
1830 case TCM_GETUNICODEFORMAT:
1831 FIXME("Unimplemented msg TCM_GETUNICODEFORMAT\n");
1834 case TCM_SETUNICODEFORMAT:
1835 FIXME("Unimplemented msg TCM_SETUNICODEFORMAT\n");
1838 case TCM_HIGHLIGHTITEM:
1839 FIXME("Unimplemented msg TCM_HIGHLIGHTITEM\n");
1842 case TCM_GETTOOLTIPS:
1843 return TAB_GetToolTips (hwnd, wParam, lParam);
1845 case TCM_SETTOOLTIPS:
1846 return TAB_SetToolTips (hwnd, wParam, lParam);
1848 case TCM_GETCURFOCUS:
1849 return TAB_GetCurFocus (hwnd);
1851 case TCM_SETCURFOCUS:
1852 return TAB_SetCurFocus (hwnd, wParam);
1854 case TCM_SETMINTABWIDTH:
1855 FIXME("Unimplemented msg TCM_SETMINTABWIDTH\n");
1858 case TCM_DESELECTALL:
1859 FIXME("Unimplemented msg TCM_DESELECTALL\n");
1862 case TCM_GETEXTENDEDSTYLE:
1863 FIXME("Unimplemented msg TCM_GETEXTENDEDSTYLE\n");
1866 case TCM_SETEXTENDEDSTYLE:
1867 FIXME("Unimplemented msg TCM_SETEXTENDEDSTYLE\n");
1871 return TAB_GetFont (hwnd, wParam, lParam);
1874 return TAB_SetFont (hwnd, wParam, lParam);
1877 return TAB_Create (hwnd, wParam, lParam);
1880 return TAB_Destroy (hwnd, wParam, lParam);
1883 return DLGC_WANTARROWS | DLGC_WANTCHARS;
1885 case WM_LBUTTONDOWN:
1886 return TAB_LButtonDown (hwnd, wParam, lParam);
1889 return TAB_LButtonUp (hwnd, wParam, lParam);
1891 case WM_RBUTTONDOWN:
1892 return TAB_RButtonDown (hwnd, wParam, lParam);
1895 return TAB_MouseMove (hwnd, wParam, lParam);
1898 return TAB_EraseBackground (hwnd, (HDC)wParam);
1901 return TAB_Paint (hwnd, wParam);
1904 return TAB_Size (hwnd, wParam, lParam);
1907 return TAB_SetRedraw (hwnd, wParam);
1910 return TAB_OnHScroll(hwnd, (int)LOWORD(wParam), (int)HIWORD(wParam), (HWND)lParam);
1912 case WM_STYLECHANGED:
1913 TAB_SetItemBounds (hwnd);
1914 InvalidateRect(hwnd, NULL, TRUE);
1919 return TAB_FocusChanging(hwnd, uMsg, wParam, lParam);
1922 return TAB_KeyUp(hwnd, wParam);
1925 if (uMsg >= WM_USER)
1926 ERR("unknown msg %04x wp=%08x lp=%08lx\n",
1927 uMsg, wParam, lParam);
1928 return DefWindowProcA (hwnd, uMsg, wParam, lParam);
1940 ZeroMemory (&wndClass, sizeof(WNDCLASSA));
1941 wndClass.style = CS_GLOBALCLASS | CS_DBLCLKS | CS_HREDRAW | CS_VREDRAW;
1942 wndClass.lpfnWndProc = (WNDPROC)TAB_WindowProc;
1943 wndClass.cbClsExtra = 0;
1944 wndClass.cbWndExtra = sizeof(TAB_INFO *);
1945 wndClass.hCursor = LoadCursorA (0, IDC_ARROWA);
1946 wndClass.hbrBackground = (HBRUSH)NULL;
1947 wndClass.lpszClassName = WC_TABCONTROLA;
1949 RegisterClassA (&wndClass);
1954 TAB_Unregister (void)
1956 UnregisterClassA (WC_TABCONTROLA, (HINSTANCE)NULL);