4 * Copyright 1998 Anders Carlsson
5 * Copyright 1999 Alex Priem <alexp@sci.kun.nl>
6 * Copyright 1999 Francis Beaudet
21 DEFAULT_DEBUG_CHANNEL(tab
)
23 /******************************************************************************
24 * Positioning constants
26 #define SELECTED_TAB_OFFSET 2
27 #define HORIZONTAL_ITEM_PADDING 5
28 #define VERTICAL_ITEM_PADDING 3
29 #define ROUND_CORNER_SIZE 2
30 #define FOCUS_RECT_HOFFSET 2
31 #define FOCUS_RECT_VOFFSET 1
32 #define DISPLAY_AREA_PADDINGX 5
33 #define DISPLAY_AREA_PADDINGY 5
34 #define CONTROL_BORDER_SIZEX 2
35 #define CONTROL_BORDER_SIZEY 2
36 #define BUTTON_SPACINGX 10
37 #define DEFAULT_TAB_WIDTH 96
39 #define TAB_GetInfoPtr(hwnd) ((TAB_INFO *)GetWindowLongA(hwnd,0))
41 /******************************************************************************
44 static void TAB_Refresh (HWND hwnd
, HDC hdc
);
45 static void TAB_InvalidateTabArea(HWND hwnd
, TAB_INFO
* infoPtr
);
46 static void TAB_EnsureSelectionVisible(HWND hwnd
, TAB_INFO
* infoPtr
);
49 TAB_SendSimpleNotify (HWND hwnd
, UINT code
)
53 nmhdr
.hwndFrom
= hwnd
;
54 nmhdr
.idFrom
= GetWindowLongA(hwnd
, GWL_ID
);
57 return (BOOL
) SendMessageA (GetParent (hwnd
), WM_NOTIFY
,
58 (WPARAM
) nmhdr
.idFrom
, (LPARAM
) &nmhdr
);
63 TAB_RelayEvent (HWND hwndTip
, HWND hwndMsg
, UINT uMsg
,
64 WPARAM wParam
, LPARAM lParam
)
72 msg
.time
= GetMessageTime ();
73 msg
.pt
.x
= LOWORD(GetMessagePos ());
74 msg
.pt
.y
= HIWORD(GetMessagePos ());
76 SendMessageA (hwndTip
, TTM_RELAYEVENT
, 0, (LPARAM
)&msg
);
82 TAB_GetCurSel (HWND hwnd
)
84 TAB_INFO
*infoPtr
= TAB_GetInfoPtr(hwnd
);
86 return infoPtr
->iSelected
;
90 TAB_GetCurFocus (HWND hwnd
)
92 TAB_INFO
*infoPtr
= TAB_GetInfoPtr(hwnd
);
94 return infoPtr
->uFocus
;
98 TAB_GetToolTips (HWND hwnd
, WPARAM wParam
, LPARAM lParam
)
100 TAB_INFO
*infoPtr
= TAB_GetInfoPtr(hwnd
);
102 if (infoPtr
== NULL
) return 0;
103 return infoPtr
->hwndToolTip
;
108 TAB_SetCurSel (HWND hwnd
,WPARAM wParam
)
110 TAB_INFO
*infoPtr
= TAB_GetInfoPtr(hwnd
);
111 INT iItem
=(INT
) wParam
;
115 if ((iItem
>= 0) && (iItem
< infoPtr
->uNumItem
)) {
116 prevItem
=infoPtr
->iSelected
;
117 infoPtr
->iSelected
=iItem
;
123 TAB_SetCurFocus (HWND hwnd
,WPARAM wParam
)
125 TAB_INFO
*infoPtr
= TAB_GetInfoPtr(hwnd
);
126 INT iItem
=(INT
) wParam
;
128 if ((iItem
< 0) || (iItem
> infoPtr
->uNumItem
)) return 0;
130 infoPtr
->uFocus
=iItem
;
131 if (GetWindowLongA(hwnd
, GWL_STYLE
) & TCS_BUTTONS
) {
132 FIXME (tab
,"Should set input focus\n");
134 if (infoPtr
->iSelected
!= iItem
) {
135 if (TAB_SendSimpleNotify(hwnd
, TCN_SELCHANGING
)!=TRUE
) {
136 infoPtr
->iSelected
= iItem
;
137 TAB_SendSimpleNotify(hwnd
, TCN_SELCHANGE
);
139 TAB_EnsureSelectionVisible(hwnd
, infoPtr
);
140 TAB_InvalidateTabArea(hwnd
, infoPtr
);
148 TAB_SetToolTips (HWND hwnd
, WPARAM wParam
, LPARAM lParam
)
150 TAB_INFO
*infoPtr
= TAB_GetInfoPtr(hwnd
);
152 if (infoPtr
== NULL
) return 0;
153 infoPtr
->hwndToolTip
= (HWND
)wParam
;
157 /******************************************************************************
158 * TAB_InternalGetItemRect
160 * This method will calculate the rectangle representing a given tab item in
161 * client coordinates. This method takes scrolling into account.
163 * This method returns TRUE if the item is visible in the window and FALSE
164 * if it is completely outside the client area.
166 static BOOL
TAB_InternalGetItemRect(
176 * Perform a sanity check and a trivial visibility check.
178 if ( (infoPtr
->uNumItem
<=0) ||
179 (itemIndex
>= infoPtr
->uNumItem
) ||
180 (itemIndex
< infoPtr
->leftmostVisible
) )
184 * Avoid special cases in this procedure by assigning the "out"
185 * parameters if the caller didn't supply them
188 itemRect
= &tmpItemRect
;
191 * Retrieve the unmodified item rect.
193 *itemRect
= infoPtr
->items
[itemIndex
].rect
;
196 * "scroll" it to make sure the item at the very left of the
197 * tab control is the leftmost visible tab.
200 -infoPtr
->items
[infoPtr
->leftmostVisible
].rect
.left
,
204 * Move the rectangle so the first item is slightly offset from
205 * the left of the tab control.
213 * Now, calculate the position of the item as if it were selected.
215 if (selectedRect
!=NULL
)
217 CopyRect(selectedRect
, itemRect
);
220 * The rectangle of a selected item is a bit wider.
222 InflateRect(selectedRect
, SELECTED_TAB_OFFSET
, 0);
225 * If it also a bit higher.
227 if (GetWindowLongA(hwnd
, GWL_STYLE
) & TCS_BOTTOM
)
229 selectedRect
->top
-=2; /* the border is thicker on the bottom */
230 selectedRect
->bottom
+=SELECTED_TAB_OFFSET
;
234 selectedRect
->top
-=SELECTED_TAB_OFFSET
;
235 selectedRect
->bottom
+=1;
242 static BOOL
TAB_GetItemRect(HWND hwnd
, WPARAM wParam
, LPARAM lParam
)
244 return TAB_InternalGetItemRect(hwnd
, TAB_GetInfoPtr(hwnd
), (INT
)wParam
,
245 (LPRECT
)lParam
, (LPRECT
)NULL
);
248 /******************************************************************************
251 * This method is called to handle keyboard input
253 static LRESULT
TAB_KeyUp(
257 TAB_INFO
* infoPtr
= TAB_GetInfoPtr(hwnd
);
263 newItem
= infoPtr
->uFocus
-1;
266 newItem
= infoPtr
->uFocus
+1;
271 * If we changed to a valid item, change the selection
273 if ( (newItem
>= 0) &&
274 (newItem
< infoPtr
->uNumItem
) &&
275 (infoPtr
->uFocus
!= newItem
) )
277 if (!TAB_SendSimpleNotify(hwnd
, TCN_SELCHANGING
))
279 infoPtr
->iSelected
= newItem
;
280 infoPtr
->uFocus
= newItem
;
281 TAB_SendSimpleNotify(hwnd
, TCN_SELCHANGE
);
283 TAB_EnsureSelectionVisible(hwnd
, infoPtr
);
284 TAB_InvalidateTabArea(hwnd
, infoPtr
);
291 /******************************************************************************
294 * This method is called whenever the focus goes in or out of this control
295 * it is used to update the visual state of the control.
297 static LRESULT
TAB_FocusChanging(
303 TAB_INFO
*infoPtr
= TAB_GetInfoPtr(hwnd
);
308 * Get the rectangle for the item.
310 isVisible
= TAB_InternalGetItemRect(hwnd
,
317 * If the rectangle is not completely invisible, invalidate that
318 * portion of the window.
322 InvalidateRect(hwnd
, &selectedRect
, TRUE
);
326 * Don't otherwise disturb normal behavior.
328 return DefWindowProcA (hwnd
, uMsg
, wParam
, lParam
);
331 static HWND
TAB_InternalHitTest (
341 for (iCount
= 0; iCount
< infoPtr
->uNumItem
; iCount
++)
343 TAB_InternalGetItemRect(hwnd
,
349 if (PtInRect (&rect
, pt
))
351 *flags
= TCHT_ONITEM
;
361 TAB_HitTest (HWND hwnd
, WPARAM wParam
, LPARAM lParam
)
363 TAB_INFO
*infoPtr
= TAB_GetInfoPtr(hwnd
);
364 LPTCHITTESTINFO lptest
=(LPTCHITTESTINFO
) lParam
;
366 return TAB_InternalHitTest (hwnd
, infoPtr
,lptest
->pt
,&lptest
->flags
);
371 TAB_LButtonDown (HWND hwnd
, WPARAM wParam
, LPARAM lParam
)
373 TAB_INFO
*infoPtr
= TAB_GetInfoPtr(hwnd
);
375 if (infoPtr
->hwndToolTip
)
376 TAB_RelayEvent (infoPtr
->hwndToolTip
, hwnd
,
377 WM_LBUTTONDOWN
, wParam
, lParam
);
379 if (GetWindowLongA(hwnd
, GWL_STYLE
) & TCS_FOCUSONBUTTONDOWN
) {
386 TAB_LButtonUp (HWND hwnd
, WPARAM wParam
, LPARAM lParam
)
388 TAB_INFO
*infoPtr
= TAB_GetInfoPtr(hwnd
);
392 if (infoPtr
->hwndToolTip
)
393 TAB_RelayEvent (infoPtr
->hwndToolTip
, hwnd
,
394 WM_LBUTTONDOWN
, wParam
, lParam
);
396 pt
.x
= (INT
)LOWORD(lParam
);
397 pt
.y
= (INT
)HIWORD(lParam
);
399 newItem
=TAB_InternalHitTest (hwnd
, infoPtr
,pt
,&dummy
);
401 TRACE(tab
, "On Tab, item %d\n", newItem
);
403 if ( (newItem
!=-1) &&
404 (infoPtr
->iSelected
!= newItem
) )
406 if (TAB_SendSimpleNotify(hwnd
, TCN_SELCHANGING
)!=TRUE
)
408 infoPtr
->iSelected
= newItem
;
409 infoPtr
->uFocus
= newItem
;
410 TAB_SendSimpleNotify(hwnd
, TCN_SELCHANGE
);
412 TAB_EnsureSelectionVisible(hwnd
, infoPtr
);
414 TAB_InvalidateTabArea(hwnd
, infoPtr
);
417 TAB_SendSimpleNotify(hwnd
, NM_CLICK
);
423 TAB_RButtonDown (HWND hwnd
, WPARAM wParam
, LPARAM lParam
)
425 TAB_SendSimpleNotify(hwnd
, NM_RCLICK
);
430 TAB_MouseMove (HWND hwnd
, WPARAM wParam
, LPARAM lParam
)
432 TAB_INFO
*infoPtr
= TAB_GetInfoPtr(hwnd
);
434 if (infoPtr
->hwndToolTip
)
435 TAB_RelayEvent (infoPtr
->hwndToolTip
, hwnd
,
436 WM_LBUTTONDOWN
, wParam
, lParam
);
440 /******************************************************************************
443 * Calculates the tab control's display area given the windows rectangle or
444 * the window rectangle given the requested display rectangle.
446 static LRESULT
TAB_AdjustRect(
451 TAB_INFO
*infoPtr
= TAB_GetInfoPtr(hwnd
);
456 * Go from display rectangle
460 * Add the height of the tabs.
462 if (GetWindowLongA(hwnd
, GWL_STYLE
) & TCS_BOTTOM
)
463 prc
->bottom
+= infoPtr
->tabHeight
;
465 prc
->top
-= infoPtr
->tabHeight
;
468 * Inflate the rectangle for the padding
470 InflateRect(prc
, DISPLAY_AREA_PADDINGX
, DISPLAY_AREA_PADDINGY
);
473 * Inflate for the border
475 InflateRect(prc
, CONTROL_BORDER_SIZEX
, CONTROL_BORDER_SIZEX
);
480 * Go from window rectangle.
484 * Deflate the rectangle for the border
486 InflateRect(prc
, -CONTROL_BORDER_SIZEX
, -CONTROL_BORDER_SIZEX
);
489 * Deflate the rectangle for the padding
491 InflateRect(prc
, -DISPLAY_AREA_PADDINGX
, -DISPLAY_AREA_PADDINGY
);
494 * Remove the height of the tabs.
496 if (GetWindowLongA(hwnd
, GWL_STYLE
) & TCS_BOTTOM
)
497 prc
->bottom
-= infoPtr
->tabHeight
;
499 prc
->top
+= infoPtr
->tabHeight
;
506 /******************************************************************************
509 * This method will handle the notification from the scroll control and
510 * perform the scrolling operation on the tab control.
512 static LRESULT
TAB_OnHScroll(
518 TAB_INFO
*infoPtr
= TAB_GetInfoPtr(hwnd
);
520 if (nScrollCode
== SB_LINELEFT
)
522 if (infoPtr
->leftmostVisible
>0)
524 infoPtr
->leftmostVisible
--;
526 TAB_InvalidateTabArea(hwnd
, infoPtr
);
529 else if (nScrollCode
== SB_LINERIGHT
)
531 if (infoPtr
->leftmostVisible
< (infoPtr
->uNumItem
-1))
533 infoPtr
->leftmostVisible
++;
535 TAB_InvalidateTabArea(hwnd
, infoPtr
);
542 /******************************************************************************
545 * This method will check the current scrolling state and make sure the
546 * scrolling control is displayed (or not).
548 static void TAB_SetupScrolling(
551 const RECT
* clientRect
)
553 if (infoPtr
->needsScrolling
)
558 * Calculate the position of the scroll control.
560 controlPos
.right
= clientRect
->right
;
561 controlPos
.left
= controlPos
.right
- 2*GetSystemMetrics(SM_CXHSCROLL
);
563 if (GetWindowLongA(hwnd
, GWL_STYLE
) & TCS_BOTTOM
)
565 controlPos
.top
= clientRect
->bottom
- infoPtr
->tabHeight
;
566 controlPos
.bottom
= controlPos
.top
+ GetSystemMetrics(SM_CYHSCROLL
);
570 controlPos
.bottom
= clientRect
->top
+ infoPtr
->tabHeight
;
571 controlPos
.top
= controlPos
.bottom
- GetSystemMetrics(SM_CYHSCROLL
);
575 * If we don't have a scroll control yet, we want to create one.
576 * If we have one, we want to make sure it's positioned right.
578 if (infoPtr
->hwndUpDown
==0)
581 * I use a scrollbar since it seems to be more stable than the Updown
584 infoPtr
->hwndUpDown
= CreateWindowA("ScrollBar",
586 WS_VISIBLE
| WS_CHILD
| WS_OVERLAPPED
| SBS_HORZ
,
587 controlPos
.left
, controlPos
.top
,
588 controlPos
.right
- controlPos
.left
,
589 controlPos
.bottom
- controlPos
.top
,
597 SetWindowPos(infoPtr
->hwndUpDown
,
599 controlPos
.left
, controlPos
.top
,
600 controlPos
.right
- controlPos
.left
,
601 controlPos
.bottom
- controlPos
.top
,
602 SWP_SHOWWINDOW
| SWP_NOZORDER
);
608 * If we once had a scroll control... hide it.
610 if (infoPtr
->hwndUpDown
!=0)
612 ShowWindow(infoPtr
->hwndUpDown
, SW_HIDE
);
617 /******************************************************************************
620 * This method will calculate the position rectangles of all the items in the
621 * control. The rectangle calculated starts at 0 for the first item in the
622 * list and ignores scrolling and selection.
623 * It also uses the current font to determine the height of the tab row and
624 * it checks if all the tabs fit in the client area of the window. If they
625 * dont, a scrolling control is added.
627 static void TAB_SetItemBounds (HWND hwnd
)
629 TAB_INFO
* infoPtr
= TAB_GetInfoPtr(hwnd
);
630 LONG lStyle
= GetWindowLongA(hwnd
, GWL_STYLE
);
631 TEXTMETRICA fontMetrics
;
634 HFONT hFont
, hOldFont
;
640 * We need to get text information so we need a DC and we need to select
645 hFont
= infoPtr
->hFont
? infoPtr
->hFont
: GetStockObject (SYSTEM_FONT
);
646 hOldFont
= SelectObject (hdc
, hFont
);
649 * We will base the rectangle calculations on the client rectangle
652 GetClientRect(hwnd
, &clientRect
);
655 * The leftmost item will be "0" aligned
659 if (!((lStyle
& TCS_FIXEDWIDTH
) || (lStyle
& TCS_OWNERDRAWFIXED
)))
662 * Use the current font to determine the height of a tab.
664 GetTextMetricsA(hdc
, &fontMetrics
);
667 * Make sure there is enough space for the letters + growing the
668 * selected item + extra space for the selected item.
670 infoPtr
->tabHeight
= fontMetrics
.tmHeight
+ 2*VERTICAL_ITEM_PADDING
+
674 for (curItem
= 0; curItem
< infoPtr
->uNumItem
; curItem
++)
677 * Calculate the vertical position of the tab
679 if (lStyle
& TCS_BOTTOM
)
681 infoPtr
->items
[curItem
].rect
.bottom
= clientRect
.bottom
-
683 infoPtr
->items
[curItem
].rect
.top
= clientRect
.bottom
-
688 infoPtr
->items
[curItem
].rect
.top
= clientRect
.top
+
690 infoPtr
->items
[curItem
].rect
.bottom
= clientRect
.top
+
695 * Set the leftmost position of the tab.
697 infoPtr
->items
[curItem
].rect
.left
= curItemLeftPos
;
699 if ((lStyle
& TCS_FIXEDWIDTH
) || (lStyle
& TCS_OWNERDRAWFIXED
))
701 infoPtr
->items
[curItem
].rect
.right
= infoPtr
->items
[curItem
].rect
.left
+
703 2*HORIZONTAL_ITEM_PADDING
;
708 * Calculate how wide the tab is depending on the text it contains
710 GetTextExtentPoint32A(hdc
, infoPtr
->items
[curItem
].pszText
,
711 lstrlenA(infoPtr
->items
[curItem
].pszText
), &size
);
713 infoPtr
->items
[curItem
].rect
.right
= infoPtr
->items
[curItem
].rect
.left
+
714 size
.cx
+ 2*HORIZONTAL_ITEM_PADDING
;
717 TRACE(tab
, "TextSize: %i\n ", size
.cx
);
718 TRACE(tab
, "Rect: T %i, L %i, B %i, R %i\n",
719 infoPtr
->items
[curItem
].rect
.top
,
720 infoPtr
->items
[curItem
].rect
.left
,
721 infoPtr
->items
[curItem
].rect
.bottom
,
722 infoPtr
->items
[curItem
].rect
.right
);
725 * The leftmost position of the next item is the rightmost position
728 if (lStyle
& TCS_BUTTONS
)
729 curItemLeftPos
= infoPtr
->items
[curItem
].rect
.right
+ BUTTON_SPACINGX
;
731 curItemLeftPos
= infoPtr
->items
[curItem
].rect
.right
;
735 * Check if we need a scrolling control.
737 infoPtr
->needsScrolling
= (curItemLeftPos
+ (2*SELECTED_TAB_OFFSET
) >
740 TAB_SetupScrolling(hwnd
, infoPtr
, &clientRect
);
745 SelectObject (hdc
, hOldFont
);
746 ReleaseDC (hwnd
, hdc
);
749 /******************************************************************************
752 * This method is used to draw a single tab into the tab control.
754 static void TAB_DrawItem(
759 TAB_INFO
*infoPtr
= TAB_GetInfoPtr(hwnd
);
760 LONG lStyle
= GetWindowLongA(hwnd
, GWL_STYLE
);
767 * Get the rectangle for the item.
769 isVisible
= TAB_InternalGetItemRect(hwnd
,
777 HBRUSH hbr
= CreateSolidBrush (GetSysColor(COLOR_BACKGROUND
));
778 HPEN hwPen
= GetSysColorPen (COLOR_3DHILIGHT
);
779 HPEN hbPen
= GetSysColorPen (COLOR_BTNSHADOW
);
780 HPEN hsdPen
= GetSysColorPen (COLOR_BTNTEXT
);
781 HPEN hfocusPen
= CreatePen(PS_DOT
, 1, GetSysColor(COLOR_BTNTEXT
));
786 if (lStyle
& TCS_BUTTONS
)
789 * Get item rectangle.
793 holdPen
= SelectObject (hdc
, hwPen
);
795 if (iItem
== infoPtr
->iSelected
)
800 if (!(lStyle
& TCS_OWNERDRAWFIXED
))
801 hbr
= CreateSolidBrush(GetSysColor(COLOR_3DHILIGHT
));
804 * Erase the background.
806 FillRect(hdc
, &r
, hbr
);
810 * The rectangles calculated exclude the right and bottom
811 * borders of the rectangle. To simply the following code, those
812 * borders are shaved-off beforehand.
818 MoveToEx (hdc
, r
.left
, r
.bottom
, NULL
);
819 LineTo (hdc
, r
.right
, r
.bottom
);
820 LineTo (hdc
, r
.right
, r
.top
);
823 SelectObject(hdc
, hbPen
);
824 LineTo (hdc
, r
.left
, r
.top
);
825 LineTo (hdc
, r
.left
, r
.bottom
);
830 * Erase the background.
832 FillRect(hdc
, &r
, hbr
);
835 MoveToEx (hdc
, r
.left
, r
.bottom
, NULL
);
836 LineTo (hdc
, r
.left
, r
.top
);
837 LineTo (hdc
, r
.right
, r
.top
);
840 SelectObject(hdc
, hbPen
);
841 LineTo (hdc
, r
.right
, r
.bottom
);
842 LineTo (hdc
, r
.left
, r
.bottom
);
850 hbr
= CreateSolidBrush(GetSysColor(COLOR_BACKGROUND
));
853 * We draw a rectangle of different sizes depending on the selection
856 if (iItem
== infoPtr
->iSelected
)
862 * Erase the background.
863 * This is necessary when drawing the selected item since it is larger
864 * than the others, it might overlap with stuff already drawn by the
867 FillRect(hdc
, &r
, hbr
);
871 * The rectangles calculated exclude the right and bottom
872 * borders of the rectangle. To simply the following code, those
873 * borders are shaved-off beforehand.
878 holdPen
= SelectObject (hdc
, hwPen
);
880 if (lStyle
& TCS_BOTTOM
)
883 MoveToEx (hdc
, r
.left
, r
.top
, NULL
);
884 LineTo (hdc
, r
.left
, r
.bottom
- ROUND_CORNER_SIZE
);
885 LineTo (hdc
, r
.left
+ ROUND_CORNER_SIZE
, r
.bottom
);
888 SelectObject(hdc
, hbPen
);
889 LineTo (hdc
, r
.right
- ROUND_CORNER_SIZE
, r
.bottom
);
890 LineTo (hdc
, r
.right
, r
.bottom
- ROUND_CORNER_SIZE
);
891 LineTo (hdc
, r
.right
, r
.top
);
896 MoveToEx (hdc
, r
.left
, r
.bottom
, NULL
);
897 LineTo (hdc
, r
.left
, r
.top
+ ROUND_CORNER_SIZE
);
898 LineTo (hdc
, r
.left
+ ROUND_CORNER_SIZE
, r
.top
);
899 LineTo (hdc
, r
.right
- ROUND_CORNER_SIZE
, r
.top
);
902 SelectObject(hdc
, hbPen
);
903 LineTo (hdc
, r
.right
, r
.top
+ ROUND_CORNER_SIZE
);
904 LineTo (hdc
, r
.right
, r
.bottom
);
911 SelectObject(hdc
, hsdPen
);
913 oldBkMode
= SetBkMode(hdc
, TRANSPARENT
);
914 SetTextColor (hdc
, COLOR_BTNTEXT
);
917 * Deflate the rectangle to acount for the padding
919 InflateRect(&r
, -HORIZONTAL_ITEM_PADDING
, -VERTICAL_ITEM_PADDING
);
926 ImageList_Draw (infoPtr
->himl
, iItem
, hdc
,
927 r
.left
, r
.top
+1, ILD_NORMAL
);
928 ImageList_GetIconSize (infoPtr
->himl
, &cx
, &cy
);
936 infoPtr
->items
[iItem
].pszText
,
937 lstrlenA(infoPtr
->items
[iItem
].pszText
),
939 DT_LEFT
|DT_SINGLELINE
|DT_VCENTER
);
942 * Draw the focus rectangle
944 if (((lStyle
& TCS_FOCUSNEVER
) == 0) &&
945 (GetFocus() == hwnd
) &&
946 (iItem
== infoPtr
->uFocus
) )
948 InflateRect(&r
, FOCUS_RECT_HOFFSET
, FOCUS_RECT_VOFFSET
);
950 SelectObject(hdc
, hfocusPen
);
952 MoveToEx (hdc
, r
.left
, r
.top
, NULL
);
953 LineTo (hdc
, r
.right
-1, r
.top
);
954 LineTo (hdc
, r
.right
-1, r
.bottom
-1);
955 LineTo (hdc
, r
.left
, r
.bottom
-1);
956 LineTo (hdc
, r
.left
, r
.top
);
962 SetBkMode(hdc
, oldBkMode
);
963 SelectObject(hdc
, holdPen
);
967 /******************************************************************************
970 * This method is used to draw the raised border around the tab control
973 static void TAB_DrawBorder (HWND hwnd
, HDC hdc
)
975 TAB_INFO
*infoPtr
= TAB_GetInfoPtr(hwnd
);
977 HPEN hwPen
= GetSysColorPen (COLOR_3DHILIGHT
);
978 HPEN hbPen
= GetSysColorPen (COLOR_3DDKSHADOW
);
979 HPEN hShade
= GetSysColorPen (COLOR_BTNSHADOW
);
982 GetClientRect (hwnd
, &rect
);
985 * Adjust for the style
987 if (GetWindowLongA(hwnd
, GWL_STYLE
) & TCS_BOTTOM
)
989 rect
.bottom
-= infoPtr
->tabHeight
;
993 rect
.top
+= infoPtr
->tabHeight
;
997 * Shave-off the right and bottom margins (exluded in the
1004 htmPen
= SelectObject (hdc
, hwPen
);
1006 MoveToEx (hdc
, rect
.left
, rect
.bottom
, NULL
);
1007 LineTo (hdc
, rect
.left
, rect
.top
);
1008 LineTo (hdc
, rect
.right
, rect
.top
);
1011 SelectObject (hdc
, hbPen
);
1012 LineTo (hdc
, rect
.right
, rect
.bottom
);
1013 LineTo (hdc
, rect
.left
, rect
.bottom
);
1016 SelectObject (hdc
, hShade
);
1017 MoveToEx (hdc
, rect
.right
-1, rect
.top
, NULL
);
1018 LineTo (hdc
, rect
.right
-1, rect
.bottom
-1);
1019 LineTo (hdc
, rect
.left
, rect
.bottom
-1);
1021 SelectObject(hdc
, htmPen
);
1024 /******************************************************************************
1027 * This method repaints the tab control..
1029 static void TAB_Refresh (HWND hwnd
, HDC hdc
)
1031 TAB_INFO
*infoPtr
= TAB_GetInfoPtr(hwnd
);
1035 if (!infoPtr
->DoRedraw
)
1038 hOldFont
= SelectObject (hdc
, infoPtr
->hFont
);
1040 if (GetWindowLongA(hwnd
, GWL_STYLE
) & TCS_BUTTONS
)
1042 for (i
= 0; i
< infoPtr
->uNumItem
; i
++)
1044 TAB_DrawItem (hwnd
, hdc
, i
);
1050 * Draw all the non selected item first.
1052 for (i
= 0; i
< infoPtr
->uNumItem
; i
++)
1054 if (i
!= infoPtr
->iSelected
)
1055 TAB_DrawItem (hwnd
, hdc
, i
);
1059 * Now, draw the border, draw it before the selected item
1060 * since the selected item overwrites part of the border.
1062 TAB_DrawBorder (hwnd
, hdc
);
1065 * Then, draw the selected item
1067 TAB_DrawItem (hwnd
, hdc
, infoPtr
->iSelected
);
1070 SelectObject (hdc
, hOldFont
);
1074 TAB_SetRedraw (HWND hwnd
, WPARAM wParam
)
1076 TAB_INFO
*infoPtr
= TAB_GetInfoPtr(hwnd
);
1078 infoPtr
->DoRedraw
=(BOOL
) wParam
;
1082 static LRESULT
TAB_EraseBackground(
1089 HBRUSH brush
= CreateSolidBrush(GetSysColor(COLOR_BACKGROUND
));
1091 hdc
= givenDC
? givenDC
: GetDC(hwnd
);
1093 GetClientRect(hwnd
, &clientRect
);
1095 FillRect(hdc
, &clientRect
, brush
);
1098 ReleaseDC(hwnd
, hdc
);
1103 /******************************************************************************
1104 * TAB_EnsureSelectionVisible
1106 * This method will make sure that the current selection is completely
1107 * visible by scrolling until it is.
1109 static void TAB_EnsureSelectionVisible(
1119 * Do the trivial cases first.
1121 if ( (!infoPtr
->needsScrolling
) ||
1122 (infoPtr
->hwndUpDown
==0) )
1125 if (infoPtr
->leftmostVisible
> infoPtr
->iSelected
)
1127 infoPtr
->leftmostVisible
= infoPtr
->iSelected
;
1132 * Calculate the part of the client area that is visible.
1134 GetClientRect(hwnd
, &visibleRect
);
1135 GetClientRect(infoPtr
->hwndUpDown
, &scrollerRect
);
1136 visibleRect
.right
-= scrollerRect
.right
;
1139 * Get the rectangle for the item
1141 isVisible
= TAB_InternalGetItemRect(hwnd
,
1148 * If this function can't say it's completely invisible, maybe it
1149 * is partially visible. Let's check.
1156 pt1
.x
= selectedRect
.left
;
1157 pt1
.y
= selectedRect
.top
;
1158 pt2
.x
= selectedRect
.right
- 1;
1159 pt2
.y
= selectedRect
.bottom
- 1;
1161 isVisible
= PtInRect(&visibleRect
, pt1
) && PtInRect(&visibleRect
, pt2
);
1164 while ( (infoPtr
->leftmostVisible
< infoPtr
->iSelected
) &&
1167 infoPtr
->leftmostVisible
++;
1170 * Get the rectangle for the item
1172 isVisible
= TAB_InternalGetItemRect(hwnd
,
1179 * If this function can't say it's completely invisible, maybe it
1180 * is partially visible. Let's check.
1187 pt1
.x
= selectedRect
.left
;
1188 pt1
.y
= selectedRect
.top
;
1189 pt2
.x
= selectedRect
.right
- 1;
1190 pt2
.y
= selectedRect
.bottom
- 1;
1192 isVisible
= PtInRect(&visibleRect
, pt1
) && PtInRect(&visibleRect
, pt2
);
1197 /******************************************************************************
1198 * TAB_InvalidateTabArea
1200 * This method will invalidate the portion of the control that contains the
1201 * tabs. It is called when the state of the control changes and needs
1204 static void TAB_InvalidateTabArea(
1210 GetClientRect(hwnd
, &clientRect
);
1212 if (GetWindowLongA(hwnd
, GWL_STYLE
) & TCS_BOTTOM
)
1214 clientRect
.top
= clientRect
.bottom
- (infoPtr
->tabHeight
+ 1);
1218 clientRect
.bottom
= clientRect
.top
+ (infoPtr
->tabHeight
+ 1);
1221 InvalidateRect(hwnd
, &clientRect
, TRUE
);
1225 TAB_Paint (HWND hwnd
, WPARAM wParam
)
1230 hdc
= wParam
== 0 ? BeginPaint (hwnd
, &ps
) : (HDC
)wParam
;
1231 TAB_Refresh (hwnd
, hdc
);
1234 EndPaint (hwnd
, &ps
);
1240 TAB_InsertItem (HWND hwnd
, WPARAM wParam
, LPARAM lParam
)
1242 TAB_INFO
*infoPtr
= TAB_GetInfoPtr(hwnd
);
1247 GetClientRect (hwnd
, &rect
);
1248 TRACE(tab
, "Rect: %x T %i, L %i, B %i, R %i\n", hwnd
,
1249 rect
.top
, rect
.left
, rect
.bottom
, rect
.right
);
1251 pti
= (TCITEMA
*)lParam
;
1252 iItem
= (INT
)wParam
;
1254 if (iItem
< 0) return -1;
1255 if (iItem
> infoPtr
->uNumItem
)
1256 iItem
= infoPtr
->uNumItem
;
1258 if (infoPtr
->uNumItem
== 0) {
1259 infoPtr
->items
= COMCTL32_Alloc (sizeof (TAB_ITEM
));
1260 infoPtr
->uNumItem
++;
1263 TAB_ITEM
*oldItems
= infoPtr
->items
;
1265 infoPtr
->uNumItem
++;
1266 infoPtr
->items
= COMCTL32_Alloc (sizeof (TAB_ITEM
) * infoPtr
->uNumItem
);
1268 /* pre insert copy */
1270 memcpy (&infoPtr
->items
[0], &oldItems
[0],
1271 iItem
* sizeof(TAB_ITEM
));
1274 /* post insert copy */
1275 if (iItem
< infoPtr
->uNumItem
- 1) {
1276 memcpy (&infoPtr
->items
[iItem
+1], &oldItems
[iItem
],
1277 (infoPtr
->uNumItem
- iItem
- 1) * sizeof(TAB_ITEM
));
1281 COMCTL32_Free (oldItems
);
1284 infoPtr
->items
[iItem
].mask
= pti
->mask
;
1285 if (pti
->mask
& TCIF_TEXT
) {
1286 len
= lstrlenA (pti
->pszText
);
1287 infoPtr
->items
[iItem
].pszText
= COMCTL32_Alloc (len
+1);
1288 lstrcpyA (infoPtr
->items
[iItem
].pszText
, pti
->pszText
);
1289 infoPtr
->items
[iItem
].cchTextMax
= pti
->cchTextMax
;
1292 if (pti
->mask
& TCIF_IMAGE
)
1293 infoPtr
->items
[iItem
].iImage
= pti
->iImage
;
1295 if (pti
->mask
& TCIF_PARAM
)
1296 infoPtr
->items
[iItem
].lParam
= pti
->lParam
;
1298 TAB_InvalidateTabArea(hwnd
, infoPtr
);
1300 TRACE(tab
, "[%04x]: added item %d '%s'\n",
1301 hwnd
, iItem
, infoPtr
->items
[iItem
].pszText
);
1303 TAB_SetItemBounds(hwnd
);
1308 TAB_SetItemSize (HWND hwnd
, WPARAM wParam
, LPARAM lParam
)
1310 TAB_INFO
*infoPtr
= TAB_GetInfoPtr(hwnd
);
1311 LONG lStyle
= GetWindowLongA(hwnd
, GWL_STYLE
);
1314 if ((lStyle
& TCS_FIXEDWIDTH
) || (lStyle
& TCS_OWNERDRAWFIXED
))
1316 lResult
= MAKELONG(infoPtr
->tabWidth
, infoPtr
->tabHeight
);
1317 infoPtr
->tabWidth
= (INT
)LOWORD(lParam
);
1318 infoPtr
->tabHeight
= (INT
)HIWORD(lParam
);
1325 TAB_SetItemA (HWND hwnd
, WPARAM wParam
, LPARAM lParam
)
1327 TAB_INFO
*infoPtr
= TAB_GetInfoPtr(hwnd
);
1333 tabItem
=(LPTCITEMA
) lParam
;
1334 TRACE (tab
,"%d %p\n",iItem
, tabItem
);
1335 if ((iItem
<0) || (iItem
>infoPtr
->uNumItem
)) return FALSE
;
1337 wineItem
=& infoPtr
->items
[iItem
];
1339 if (tabItem
->mask
& TCIF_IMAGE
)
1340 wineItem
->iImage
=tabItem
->iImage
;
1342 if (tabItem
->mask
& TCIF_PARAM
)
1343 wineItem
->lParam
=tabItem
->lParam
;
1345 if (tabItem
->mask
& TCIF_RTLREADING
)
1346 FIXME (tab
,"TCIF_RTLREADING\n");
1348 if (tabItem
->mask
& TCIF_STATE
)
1349 wineItem
->dwState
=tabItem
->dwState
;
1351 if (tabItem
->mask
& TCIF_TEXT
) {
1352 len
=lstrlenA (tabItem
->pszText
);
1353 if (len
>wineItem
->cchTextMax
)
1354 wineItem
->pszText
= COMCTL32_ReAlloc (wineItem
->pszText
, len
+1);
1355 lstrcpynA (wineItem
->pszText
, tabItem
->pszText
, len
);
1362 TAB_GetItemCount (HWND hwnd
, WPARAM wParam
, LPARAM lParam
)
1364 TAB_INFO
*infoPtr
= TAB_GetInfoPtr(hwnd
);
1366 return infoPtr
->uNumItem
;
1371 TAB_GetItemA (HWND hwnd
, WPARAM wParam
, LPARAM lParam
)
1373 TAB_INFO
*infoPtr
= TAB_GetInfoPtr(hwnd
);
1379 tabItem
=(LPTCITEMA
) lParam
;
1381 if ((iItem
<0) || (iItem
>infoPtr
->uNumItem
)) return FALSE
;
1383 wineItem
=& infoPtr
->items
[iItem
];
1385 if (tabItem
->mask
& TCIF_IMAGE
)
1386 tabItem
->iImage
=wineItem
->iImage
;
1388 if (tabItem
->mask
& TCIF_PARAM
)
1389 tabItem
->lParam
=wineItem
->lParam
;
1391 if (tabItem
->mask
& TCIF_RTLREADING
)
1392 FIXME (tab
, "TCIF_RTLREADING\n");
1394 if (tabItem
->mask
& TCIF_STATE
)
1395 tabItem
->dwState
=wineItem
->dwState
;
1397 if (tabItem
->mask
& TCIF_TEXT
)
1398 lstrcpynA (tabItem
->pszText
, wineItem
->pszText
, tabItem
->cchTextMax
);
1404 TAB_DeleteItem (HWND hwnd
, WPARAM wParam
, LPARAM lParam
)
1406 TAB_INFO
*infoPtr
= TAB_GetInfoPtr(hwnd
);
1407 INT iItem
= (INT
) wParam
;
1408 BOOL bResult
= FALSE
;
1410 if ((iItem
>= 0) && (iItem
< infoPtr
->uNumItem
))
1412 TAB_ITEM
*oldItems
= infoPtr
->items
;
1414 infoPtr
->uNumItem
--;
1415 infoPtr
->items
= COMCTL32_Alloc(sizeof (TAB_ITEM
) * infoPtr
->uNumItem
);
1418 memcpy(&infoPtr
->items
[0], &oldItems
[0], iItem
* sizeof(TAB_ITEM
));
1420 if (iItem
< infoPtr
->uNumItem
)
1421 memcpy(&infoPtr
->items
[iItem
], &oldItems
[iItem
+ 1],
1422 (infoPtr
->uNumItem
- iItem
) * sizeof(TAB_ITEM
));
1424 COMCTL32_Free (oldItems
);
1427 * Readjust the selected index.
1429 if ((iItem
== infoPtr
->iSelected
) && (iItem
> 0))
1430 infoPtr
->iSelected
--;
1432 if (iItem
< infoPtr
->iSelected
)
1433 infoPtr
->iSelected
--;
1436 * Reposition and repaint tabs.
1438 TAB_SetItemBounds(hwnd
);
1439 TAB_InvalidateTabArea(hwnd
,infoPtr
);
1448 TAB_DeleteAllItems (HWND hwnd
, WPARAM wParam
, LPARAM lParam
)
1450 TAB_INFO
*infoPtr
= TAB_GetInfoPtr(hwnd
);
1452 COMCTL32_Free (infoPtr
->items
);
1453 infoPtr
->uNumItem
=0;
1460 TAB_GetFont (HWND hwnd
, WPARAM wParam
, LPARAM lParam
)
1462 TAB_INFO
*infoPtr
= TAB_GetInfoPtr(hwnd
);
1465 return (LRESULT
)infoPtr
->hFont
;
1469 TAB_SetFont (HWND hwnd
, WPARAM wParam
, LPARAM lParam
)
1472 TAB_INFO
*infoPtr
= TAB_GetInfoPtr(hwnd
);
1474 TRACE (tab
,"%x %lx\n",wParam
, lParam
);
1476 infoPtr
->hFont
= (HFONT
)wParam
;
1478 TAB_SetItemBounds(hwnd
);
1480 TAB_InvalidateTabArea(hwnd
, infoPtr
);
1487 TAB_GetImageList (HWND hwnd
, WPARAM wParam
, LPARAM lParam
)
1489 TAB_INFO
*infoPtr
= TAB_GetInfoPtr(hwnd
);
1492 return (LRESULT
)infoPtr
->himl
;
1496 TAB_SetImageList (HWND hwnd
, WPARAM wParam
, LPARAM lParam
)
1498 TAB_INFO
*infoPtr
= TAB_GetInfoPtr(hwnd
);
1499 HIMAGELIST himlPrev
;
1502 himlPrev
= infoPtr
->himl
;
1503 infoPtr
->himl
= (HIMAGELIST
)lParam
;
1504 return (LRESULT
)himlPrev
;
1509 TAB_Size (HWND hwnd
, WPARAM wParam
, LPARAM lParam
)
1512 /* I'm not really sure what the following code was meant to do.
1513 This is what it is doing:
1514 When WM_SIZE is sent with SIZE_RESTORED, the control
1515 gets positioned in the top left corner.
1519 UINT uPosFlags,cx,cy;
1523 parent = GetParent (hwnd);
1524 GetClientRect(parent, &parent_rect);
1527 if (GetWindowLongA(hwnd, GWL_STYLE) & CCS_NORESIZE)
1528 uPosFlags |= (SWP_NOSIZE | SWP_NOMOVE);
1530 SetWindowPos (hwnd, 0, parent_rect.left, parent_rect.top,
1531 cx, cy, uPosFlags | SWP_NOZORDER);
1533 FIXME (tab,"WM_SIZE flag %x %lx not handled\n", wParam, lParam);
1537 * Recompute the size/position of the tabs.
1539 TAB_SetItemBounds (hwnd
);
1542 * Force a repaint of the control.
1544 InvalidateRect(hwnd
, NULL
, TRUE
);
1551 TAB_Create (HWND hwnd
, WPARAM wParam
, LPARAM lParam
)
1554 TEXTMETRICA fontMetrics
;
1558 infoPtr
= (TAB_INFO
*)COMCTL32_Alloc (sizeof(TAB_INFO
));
1560 SetWindowLongA(hwnd
, 0, (DWORD
)infoPtr
);
1562 infoPtr
->uNumItem
= 0;
1565 infoPtr
->hcurArrow
= LoadCursorA (0, IDC_ARROWA
);
1566 infoPtr
->iSelected
= 0;
1567 infoPtr
->uFocus
= 0;
1568 infoPtr
->hwndToolTip
= 0;
1569 infoPtr
->DoRedraw
= TRUE
;
1570 infoPtr
->needsScrolling
= FALSE
;
1571 infoPtr
->hwndUpDown
= 0;
1572 infoPtr
->leftmostVisible
= 0;
1574 TRACE(tab
, "Created tab control, hwnd [%04x]\n", hwnd
);
1575 if (GetWindowLongA(hwnd
, GWL_STYLE
) & TCS_TOOLTIPS
) {
1576 /* Create tooltip control */
1577 infoPtr
->hwndToolTip
=
1578 CreateWindowExA (0, TOOLTIPS_CLASSA
, NULL
, 0,
1579 CW_USEDEFAULT
, CW_USEDEFAULT
,
1580 CW_USEDEFAULT
, CW_USEDEFAULT
,
1583 /* Send NM_TOOLTIPSCREATED notification */
1584 if (infoPtr
->hwndToolTip
) {
1585 NMTOOLTIPSCREATED nmttc
;
1587 nmttc
.hdr
.hwndFrom
= hwnd
;
1588 nmttc
.hdr
.idFrom
= GetWindowLongA(hwnd
, GWL_ID
);
1589 nmttc
.hdr
.code
= NM_TOOLTIPSCREATED
;
1590 nmttc
.hwndToolTips
= infoPtr
->hwndToolTip
;
1592 SendMessageA (GetParent (hwnd
), WM_NOTIFY
,
1593 (WPARAM
)GetWindowLongA(hwnd
, GWL_ID
), (LPARAM
)&nmttc
);
1598 * We need to get text information so we need a DC and we need to select
1602 hOldFont
= SelectObject (hdc
, GetStockObject (SYSTEM_FONT
));
1605 * Use the system font to determine the initial height of a tab.
1607 GetTextMetricsA(hdc
, &fontMetrics
);
1610 * Make sure there is enough space for the letters + growing the
1611 * selected item + extra space for the selected item.
1613 infoPtr
->tabHeight
= fontMetrics
.tmHeight
+ 2*VERTICAL_ITEM_PADDING
+
1614 SELECTED_TAB_OFFSET
;
1617 * Initialize the width of a tab.
1619 infoPtr
->tabWidth
= DEFAULT_TAB_WIDTH
;
1621 SelectObject (hdc
, hOldFont
);
1622 ReleaseDC(hwnd
, hdc
);
1628 TAB_Destroy (HWND hwnd
, WPARAM wParam
, LPARAM lParam
)
1630 TAB_INFO
*infoPtr
= TAB_GetInfoPtr(hwnd
);
1633 if (infoPtr
->items
) {
1634 for (iItem
= 0; iItem
< infoPtr
->uNumItem
; iItem
++) {
1635 if (infoPtr
->items
[iItem
].pszText
)
1636 COMCTL32_Free (infoPtr
->items
[iItem
].pszText
);
1638 COMCTL32_Free (infoPtr
->items
);
1641 if (infoPtr
->hwndToolTip
)
1642 DestroyWindow (infoPtr
->hwndToolTip
);
1644 if (infoPtr
->hwndUpDown
)
1645 DestroyWindow(infoPtr
->hwndUpDown
);
1647 COMCTL32_Free (infoPtr
);
1652 TAB_WindowProc (HWND hwnd
, UINT uMsg
, WPARAM wParam
, LPARAM lParam
)
1656 case TCM_GETIMAGELIST
:
1657 return TAB_GetImageList (hwnd
, wParam
, lParam
);
1659 case TCM_SETIMAGELIST
:
1660 return TAB_SetImageList (hwnd
, wParam
, lParam
);
1662 case TCM_GETITEMCOUNT
:
1663 return TAB_GetItemCount (hwnd
, wParam
, lParam
);
1666 return TAB_GetItemA (hwnd
, wParam
, lParam
);
1669 FIXME (tab
, "Unimplemented msg TCM_GETITEMW\n");
1673 return TAB_SetItemA (hwnd
, wParam
, lParam
);
1676 FIXME (tab
, "Unimplemented msg TCM_SETITEMW\n");
1679 case TCM_DELETEITEM
:
1680 return TAB_DeleteItem (hwnd
, wParam
, lParam
);
1682 case TCM_DELETEALLITEMS
:
1683 return TAB_DeleteAllItems (hwnd
, wParam
, lParam
);
1685 case TCM_GETITEMRECT
:
1686 return TAB_GetItemRect (hwnd
, wParam
, lParam
);
1689 return TAB_GetCurSel (hwnd
);
1692 return TAB_HitTest (hwnd
, wParam
, lParam
);
1695 return TAB_SetCurSel (hwnd
, wParam
);
1697 case TCM_INSERTITEMA
:
1698 return TAB_InsertItem (hwnd
, wParam
, lParam
);
1700 case TCM_INSERTITEMW
:
1701 FIXME (tab
, "Unimplemented msg TCM_INSERTITEM32W\n");
1704 case TCM_SETITEMEXTRA
:
1705 FIXME (tab
, "Unimplemented msg TCM_SETITEMEXTRA\n");
1708 case TCM_ADJUSTRECT
:
1709 return TAB_AdjustRect (hwnd
, (BOOL
)wParam
, (LPRECT
)lParam
);
1711 case TCM_SETITEMSIZE
:
1712 return TAB_SetItemSize (hwnd
, wParam
, lParam
);
1714 case TCM_REMOVEIMAGE
:
1715 FIXME (tab
, "Unimplemented msg TCM_REMOVEIMAGE\n");
1718 case TCM_SETPADDING
:
1719 FIXME (tab
, "Unimplemented msg TCM_SETPADDING\n");
1722 case TCM_GETROWCOUNT
:
1723 FIXME (tab
, "Unimplemented msg TCM_GETROWCOUNT\n");
1726 case TCM_GETUNICODEFORMAT
:
1727 FIXME (tab
, "Unimplemented msg TCM_GETUNICODEFORMAT\n");
1730 case TCM_SETUNICODEFORMAT
:
1731 FIXME (tab
, "Unimplemented msg TCM_SETUNICODEFORMAT\n");
1734 case TCM_HIGHLIGHTITEM
:
1735 FIXME (tab
, "Unimplemented msg TCM_HIGHLIGHTITEM\n");
1738 case TCM_GETTOOLTIPS
:
1739 return TAB_GetToolTips (hwnd
, wParam
, lParam
);
1741 case TCM_SETTOOLTIPS
:
1742 return TAB_SetToolTips (hwnd
, wParam
, lParam
);
1744 case TCM_GETCURFOCUS
:
1745 return TAB_GetCurFocus (hwnd
);
1747 case TCM_SETCURFOCUS
:
1748 return TAB_SetCurFocus (hwnd
, wParam
);
1750 case TCM_SETMINTTABWIDTH
:
1751 FIXME (tab
, "Unimplemented msg TCM_SETMINTTABWIDTH\n");
1754 case TCM_DESELECTALL
:
1755 FIXME (tab
, "Unimplemented msg TCM_DESELECTALL\n");
1758 case TCM_GETEXTENDEDSTYLE
:
1759 FIXME (tab
, "Unimplemented msg TCM_GETEXTENDEDSTYLE\n");
1762 case TCM_SETEXTENDEDSTYLE
:
1763 FIXME (tab
, "Unimplemented msg TCM_SETEXTENDEDSTYLE\n");
1767 return TAB_GetFont (hwnd
, wParam
, lParam
);
1770 return TAB_SetFont (hwnd
, wParam
, lParam
);
1773 return TAB_Create (hwnd
, wParam
, lParam
);
1776 return TAB_Destroy (hwnd
, wParam
, lParam
);
1779 return DLGC_WANTARROWS
| DLGC_WANTCHARS
;
1781 case WM_LBUTTONDOWN
:
1782 return TAB_LButtonDown (hwnd
, wParam
, lParam
);
1785 return TAB_LButtonUp (hwnd
, wParam
, lParam
);
1787 case WM_RBUTTONDOWN
:
1788 return TAB_RButtonDown (hwnd
, wParam
, lParam
);
1791 return TAB_MouseMove (hwnd
, wParam
, lParam
);
1794 return TAB_EraseBackground (hwnd
, (HDC
)wParam
);
1797 return TAB_Paint (hwnd
, wParam
);
1800 return TAB_Size (hwnd
, wParam
, lParam
);
1803 return TAB_SetRedraw (hwnd
, wParam
);
1806 return TAB_OnHScroll(hwnd
, (int)LOWORD(wParam
), (int)HIWORD(wParam
), (HWND
)lParam
);
1810 return TAB_FocusChanging(hwnd
, uMsg
, wParam
, lParam
);
1813 return TAB_KeyUp(hwnd
, wParam
);
1816 if (uMsg
>= WM_USER
)
1817 ERR (tab
, "unknown msg %04x wp=%08x lp=%08lx\n",
1818 uMsg
, wParam
, lParam
);
1819 return DefWindowProcA (hwnd
, uMsg
, wParam
, lParam
);
1831 if (GlobalFindAtomA (WC_TABCONTROLA
)) return;
1833 ZeroMemory (&wndClass
, sizeof(WNDCLASSA
));
1834 wndClass
.style
= CS_GLOBALCLASS
| CS_DBLCLKS
| CS_SAVEBITS
;
1835 wndClass
.lpfnWndProc
= (WNDPROC
)TAB_WindowProc
;
1836 wndClass
.cbClsExtra
= 0;
1837 wndClass
.cbWndExtra
= sizeof(TAB_INFO
*);
1838 wndClass
.hCursor
= LoadCursorA (0, IDC_ARROWA
);
1839 wndClass
.hbrBackground
= (HBRUSH
)NULL
;
1840 wndClass
.lpszClassName
= WC_TABCONTROLA
;
1842 RegisterClassA (&wndClass
);
1847 TAB_Unregister (VOID
)
1849 if (GlobalFindAtomA (WC_TABCONTROLA
))
1850 UnregisterClassA (WC_TABCONTROLA
, (HINSTANCE
)NULL
);