4 * Copyright 1998 Anders Carlsson
5 * Copyright 1999 Alex Priem <alexp@sci.kun.nl>
6 * Copyright 1999 Francis Beaudet
19 #include "debugtools.h"
22 DEFAULT_DEBUG_CHANNEL(tab
)
24 /******************************************************************************
25 * Positioning constants
27 #define SELECTED_TAB_OFFSET 2
28 #define HORIZONTAL_ITEM_PADDING 5
29 #define VERTICAL_ITEM_PADDING 3
30 #define ROUND_CORNER_SIZE 2
31 #define FOCUS_RECT_HOFFSET 2
32 #define FOCUS_RECT_VOFFSET 1
33 #define DISPLAY_AREA_PADDINGX 5
34 #define DISPLAY_AREA_PADDINGY 5
35 #define CONTROL_BORDER_SIZEX 2
36 #define CONTROL_BORDER_SIZEY 2
37 #define BUTTON_SPACINGX 10
38 #define DEFAULT_TAB_WIDTH 96
40 #define TAB_GetInfoPtr(hwnd) ((TAB_INFO *)GetWindowLongA(hwnd,0))
42 /******************************************************************************
45 static void TAB_Refresh (HWND hwnd
, HDC hdc
);
46 static void TAB_InvalidateTabArea(HWND hwnd
, TAB_INFO
* infoPtr
);
47 static void TAB_EnsureSelectionVisible(HWND hwnd
, TAB_INFO
* infoPtr
);
50 TAB_SendSimpleNotify (HWND hwnd
, UINT code
)
54 nmhdr
.hwndFrom
= hwnd
;
55 nmhdr
.idFrom
= GetWindowLongA(hwnd
, GWL_ID
);
58 return (BOOL
) SendMessageA (GetParent (hwnd
), WM_NOTIFY
,
59 (WPARAM
) nmhdr
.idFrom
, (LPARAM
) &nmhdr
);
64 TAB_RelayEvent (HWND hwndTip
, HWND hwndMsg
, UINT uMsg
,
65 WPARAM wParam
, LPARAM lParam
)
73 msg
.time
= GetMessageTime ();
74 msg
.pt
.x
= LOWORD(GetMessagePos ());
75 msg
.pt
.y
= HIWORD(GetMessagePos ());
77 SendMessageA (hwndTip
, TTM_RELAYEVENT
, 0, (LPARAM
)&msg
);
83 TAB_GetCurSel (HWND hwnd
)
85 TAB_INFO
*infoPtr
= TAB_GetInfoPtr(hwnd
);
87 return infoPtr
->iSelected
;
91 TAB_GetCurFocus (HWND hwnd
)
93 TAB_INFO
*infoPtr
= TAB_GetInfoPtr(hwnd
);
95 return infoPtr
->uFocus
;
99 TAB_GetToolTips (HWND hwnd
, WPARAM wParam
, LPARAM lParam
)
101 TAB_INFO
*infoPtr
= TAB_GetInfoPtr(hwnd
);
103 if (infoPtr
== NULL
) return 0;
104 return infoPtr
->hwndToolTip
;
109 TAB_SetCurSel (HWND hwnd
,WPARAM wParam
)
111 TAB_INFO
*infoPtr
= TAB_GetInfoPtr(hwnd
);
112 INT iItem
=(INT
) wParam
;
116 if ((iItem
>= 0) && (iItem
< infoPtr
->uNumItem
)) {
117 prevItem
=infoPtr
->iSelected
;
118 infoPtr
->iSelected
=iItem
;
119 TAB_EnsureSelectionVisible(hwnd
, infoPtr
);
120 TAB_InvalidateTabArea(hwnd
, infoPtr
);
126 TAB_SetCurFocus (HWND hwnd
,WPARAM wParam
)
128 TAB_INFO
*infoPtr
= TAB_GetInfoPtr(hwnd
);
129 INT iItem
=(INT
) wParam
;
131 if ((iItem
< 0) || (iItem
>= infoPtr
->uNumItem
)) return 0;
133 infoPtr
->uFocus
=iItem
;
134 if (GetWindowLongA(hwnd
, GWL_STYLE
) & TCS_BUTTONS
) {
135 FIXME("Should set input focus\n");
137 if (infoPtr
->iSelected
!= iItem
) {
138 if (TAB_SendSimpleNotify(hwnd
, TCN_SELCHANGING
)!=TRUE
) {
139 infoPtr
->iSelected
= iItem
;
140 TAB_SendSimpleNotify(hwnd
, TCN_SELCHANGE
);
142 TAB_EnsureSelectionVisible(hwnd
, infoPtr
);
143 TAB_InvalidateTabArea(hwnd
, infoPtr
);
151 TAB_SetToolTips (HWND hwnd
, WPARAM wParam
, LPARAM lParam
)
153 TAB_INFO
*infoPtr
= TAB_GetInfoPtr(hwnd
);
155 if (infoPtr
== NULL
) return 0;
156 infoPtr
->hwndToolTip
= (HWND
)wParam
;
160 /******************************************************************************
161 * TAB_InternalGetItemRect
163 * This method will calculate the rectangle representing a given tab item in
164 * client coordinates. This method takes scrolling into account.
166 * This method returns TRUE if the item is visible in the window and FALSE
167 * if it is completely outside the client area.
169 static BOOL
TAB_InternalGetItemRect(
179 * Perform a sanity check and a trivial visibility check.
181 if ( (infoPtr
->uNumItem
<=0) ||
182 (itemIndex
>= infoPtr
->uNumItem
) ||
183 (itemIndex
< infoPtr
->leftmostVisible
) )
187 * Avoid special cases in this procedure by assigning the "out"
188 * parameters if the caller didn't supply them
191 itemRect
= &tmpItemRect
;
194 * Retrieve the unmodified item rect.
196 *itemRect
= infoPtr
->items
[itemIndex
].rect
;
199 * "scroll" it to make sure the item at the very left of the
200 * tab control is the leftmost visible tab.
203 -infoPtr
->items
[infoPtr
->leftmostVisible
].rect
.left
,
207 * Move the rectangle so the first item is slightly offset from
208 * the left of the tab control.
216 * Now, calculate the position of the item as if it were selected.
218 if (selectedRect
!=NULL
)
220 CopyRect(selectedRect
, itemRect
);
223 * The rectangle of a selected item is a bit wider.
225 InflateRect(selectedRect
, SELECTED_TAB_OFFSET
, 0);
228 * If it also a bit higher.
230 if (GetWindowLongA(hwnd
, GWL_STYLE
) & TCS_BOTTOM
)
232 selectedRect
->top
-=2; /* the border is thicker on the bottom */
233 selectedRect
->bottom
+=SELECTED_TAB_OFFSET
;
237 selectedRect
->top
-=SELECTED_TAB_OFFSET
;
238 selectedRect
->bottom
+=1;
245 static BOOL
TAB_GetItemRect(HWND hwnd
, WPARAM wParam
, LPARAM lParam
)
247 return TAB_InternalGetItemRect(hwnd
, TAB_GetInfoPtr(hwnd
), (INT
)wParam
,
248 (LPRECT
)lParam
, (LPRECT
)NULL
);
251 /******************************************************************************
254 * This method is called to handle keyboard input
256 static LRESULT
TAB_KeyUp(
260 TAB_INFO
* infoPtr
= TAB_GetInfoPtr(hwnd
);
266 newItem
= infoPtr
->uFocus
-1;
269 newItem
= infoPtr
->uFocus
+1;
274 * If we changed to a valid item, change the selection
276 if ( (newItem
>= 0) &&
277 (newItem
< infoPtr
->uNumItem
) &&
278 (infoPtr
->uFocus
!= newItem
) )
280 if (!TAB_SendSimpleNotify(hwnd
, TCN_SELCHANGING
))
282 infoPtr
->iSelected
= newItem
;
283 infoPtr
->uFocus
= newItem
;
284 TAB_SendSimpleNotify(hwnd
, TCN_SELCHANGE
);
286 TAB_EnsureSelectionVisible(hwnd
, infoPtr
);
287 TAB_InvalidateTabArea(hwnd
, infoPtr
);
294 /******************************************************************************
297 * This method is called whenever the focus goes in or out of this control
298 * it is used to update the visual state of the control.
300 static LRESULT
TAB_FocusChanging(
306 TAB_INFO
*infoPtr
= TAB_GetInfoPtr(hwnd
);
311 * Get the rectangle for the item.
313 isVisible
= TAB_InternalGetItemRect(hwnd
,
320 * If the rectangle is not completely invisible, invalidate that
321 * portion of the window.
325 InvalidateRect(hwnd
, &selectedRect
, TRUE
);
329 * Don't otherwise disturb normal behavior.
331 return DefWindowProcA (hwnd
, uMsg
, wParam
, lParam
);
334 static HWND
TAB_InternalHitTest (
344 for (iCount
= 0; iCount
< infoPtr
->uNumItem
; iCount
++)
346 TAB_InternalGetItemRect(hwnd
,
352 if (PtInRect (&rect
, pt
))
354 *flags
= TCHT_ONITEM
;
364 TAB_HitTest (HWND hwnd
, WPARAM wParam
, LPARAM lParam
)
366 TAB_INFO
*infoPtr
= TAB_GetInfoPtr(hwnd
);
367 LPTCHITTESTINFO lptest
=(LPTCHITTESTINFO
) lParam
;
369 return TAB_InternalHitTest (hwnd
, infoPtr
,lptest
->pt
,&lptest
->flags
);
374 TAB_LButtonDown (HWND hwnd
, WPARAM wParam
, LPARAM lParam
)
376 TAB_INFO
*infoPtr
= TAB_GetInfoPtr(hwnd
);
380 if (infoPtr
->hwndToolTip
)
381 TAB_RelayEvent (infoPtr
->hwndToolTip
, hwnd
,
382 WM_LBUTTONDOWN
, wParam
, lParam
);
384 if (GetWindowLongA(hwnd
, GWL_STYLE
) & TCS_FOCUSONBUTTONDOWN
) {
388 if (infoPtr
->hwndToolTip
)
389 TAB_RelayEvent (infoPtr
->hwndToolTip
, hwnd
,
390 WM_LBUTTONDOWN
, wParam
, lParam
);
392 pt
.x
= (INT
)LOWORD(lParam
);
393 pt
.y
= (INT
)HIWORD(lParam
);
395 newItem
=TAB_InternalHitTest (hwnd
, infoPtr
,pt
,&dummy
);
397 TRACE("On Tab, item %d\n", newItem
);
399 if ( (newItem
!=-1) &&
400 (infoPtr
->iSelected
!= newItem
) )
402 if (TAB_SendSimpleNotify(hwnd
, TCN_SELCHANGING
)!=TRUE
)
404 infoPtr
->iSelected
= newItem
;
405 infoPtr
->uFocus
= newItem
;
406 TAB_SendSimpleNotify(hwnd
, TCN_SELCHANGE
);
408 TAB_EnsureSelectionVisible(hwnd
, infoPtr
);
410 TAB_InvalidateTabArea(hwnd
, infoPtr
);
417 TAB_LButtonUp (HWND hwnd
, WPARAM wParam
, LPARAM lParam
)
419 TAB_SendSimpleNotify(hwnd
, NM_CLICK
);
425 TAB_RButtonDown (HWND hwnd
, WPARAM wParam
, LPARAM lParam
)
427 TAB_SendSimpleNotify(hwnd
, NM_RCLICK
);
432 TAB_MouseMove (HWND hwnd
, WPARAM wParam
, LPARAM lParam
)
434 TAB_INFO
*infoPtr
= TAB_GetInfoPtr(hwnd
);
436 if (infoPtr
->hwndToolTip
)
437 TAB_RelayEvent (infoPtr
->hwndToolTip
, hwnd
,
438 WM_LBUTTONDOWN
, wParam
, lParam
);
442 /******************************************************************************
445 * Calculates the tab control's display area given the windows rectangle or
446 * the window rectangle given the requested display rectangle.
448 static LRESULT
TAB_AdjustRect(
453 TAB_INFO
*infoPtr
= TAB_GetInfoPtr(hwnd
);
458 * Go from display rectangle
462 * Add the height of the tabs.
464 if (GetWindowLongA(hwnd
, GWL_STYLE
) & TCS_BOTTOM
)
465 prc
->bottom
+= infoPtr
->tabHeight
;
467 prc
->top
-= infoPtr
->tabHeight
;
470 * Inflate the rectangle for the padding
472 InflateRect(prc
, DISPLAY_AREA_PADDINGX
, DISPLAY_AREA_PADDINGY
);
475 * Inflate for the border
477 InflateRect(prc
, CONTROL_BORDER_SIZEX
, CONTROL_BORDER_SIZEX
);
482 * Go from window rectangle.
486 * Deflate the rectangle for the border
488 InflateRect(prc
, -CONTROL_BORDER_SIZEX
, -CONTROL_BORDER_SIZEX
);
491 * Deflate the rectangle for the padding
493 InflateRect(prc
, -DISPLAY_AREA_PADDINGX
, -DISPLAY_AREA_PADDINGY
);
496 * Remove the height of the tabs.
498 if (GetWindowLongA(hwnd
, GWL_STYLE
) & TCS_BOTTOM
)
499 prc
->bottom
-= infoPtr
->tabHeight
;
501 prc
->top
+= infoPtr
->tabHeight
;
508 /******************************************************************************
511 * This method will handle the notification from the scroll control and
512 * perform the scrolling operation on the tab control.
514 static LRESULT
TAB_OnHScroll(
520 TAB_INFO
*infoPtr
= TAB_GetInfoPtr(hwnd
);
522 if (nScrollCode
== SB_LINELEFT
)
524 if (infoPtr
->leftmostVisible
>0)
526 infoPtr
->leftmostVisible
--;
528 TAB_InvalidateTabArea(hwnd
, infoPtr
);
531 else if (nScrollCode
== SB_LINERIGHT
)
533 if (infoPtr
->leftmostVisible
< (infoPtr
->uNumItem
-1))
535 infoPtr
->leftmostVisible
++;
537 TAB_InvalidateTabArea(hwnd
, infoPtr
);
544 /******************************************************************************
547 * This method will check the current scrolling state and make sure the
548 * scrolling control is displayed (or not).
550 static void TAB_SetupScrolling(
553 const RECT
* clientRect
)
555 if (infoPtr
->needsScrolling
)
560 * Calculate the position of the scroll control.
562 controlPos
.right
= clientRect
->right
;
563 controlPos
.left
= controlPos
.right
- 2*GetSystemMetrics(SM_CXHSCROLL
);
565 if (GetWindowLongA(hwnd
, GWL_STYLE
) & TCS_BOTTOM
)
567 controlPos
.top
= clientRect
->bottom
- infoPtr
->tabHeight
;
568 controlPos
.bottom
= controlPos
.top
+ GetSystemMetrics(SM_CYHSCROLL
);
572 controlPos
.bottom
= clientRect
->top
+ infoPtr
->tabHeight
;
573 controlPos
.top
= controlPos
.bottom
- GetSystemMetrics(SM_CYHSCROLL
);
577 * If we don't have a scroll control yet, we want to create one.
578 * If we have one, we want to make sure it's positioned right.
580 if (infoPtr
->hwndUpDown
==0)
583 * I use a scrollbar since it seems to be more stable than the Updown
586 infoPtr
->hwndUpDown
= CreateWindowA("ScrollBar",
588 WS_VISIBLE
| WS_CHILD
| WS_OVERLAPPED
| SBS_HORZ
,
589 controlPos
.left
, controlPos
.top
,
590 controlPos
.right
- controlPos
.left
,
591 controlPos
.bottom
- controlPos
.top
,
599 SetWindowPos(infoPtr
->hwndUpDown
,
601 controlPos
.left
, controlPos
.top
,
602 controlPos
.right
- controlPos
.left
,
603 controlPos
.bottom
- controlPos
.top
,
604 SWP_SHOWWINDOW
| SWP_NOZORDER
);
610 * If we once had a scroll control... hide it.
612 if (infoPtr
->hwndUpDown
!=0)
614 ShowWindow(infoPtr
->hwndUpDown
, SW_HIDE
);
619 /******************************************************************************
622 * This method will calculate the position rectangles of all the items in the
623 * control. The rectangle calculated starts at 0 for the first item in the
624 * list and ignores scrolling and selection.
625 * It also uses the current font to determine the height of the tab row and
626 * it checks if all the tabs fit in the client area of the window. If they
627 * dont, a scrolling control is added.
629 static void TAB_SetItemBounds (HWND hwnd
)
631 TAB_INFO
* infoPtr
= TAB_GetInfoPtr(hwnd
);
632 LONG lStyle
= GetWindowLongA(hwnd
, GWL_STYLE
);
633 TEXTMETRICA fontMetrics
;
636 HFONT hFont
, hOldFont
;
642 * We need to get text information so we need a DC and we need to select
647 hFont
= infoPtr
->hFont
? infoPtr
->hFont
: GetStockObject (SYSTEM_FONT
);
648 hOldFont
= SelectObject (hdc
, hFont
);
651 * We will base the rectangle calculations on the client rectangle
654 GetClientRect(hwnd
, &clientRect
);
657 * The leftmost item will be "0" aligned
661 if (!((lStyle
& TCS_FIXEDWIDTH
) || (lStyle
& TCS_OWNERDRAWFIXED
)))
667 * Use the current font to determine the height of a tab.
669 GetTextMetricsA(hdc
, &fontMetrics
);
672 * Get the icon height
675 ImageList_GetIconSize(infoPtr
->himl
, 0, &icon_height
);
678 * Take the highest between font or icon
680 if (fontMetrics
.tmHeight
> icon_height
)
681 item_height
= fontMetrics
.tmHeight
;
683 item_height
= icon_height
;
686 * Make sure there is enough space for the letters + icon + growing the
687 * selected item + extra space for the selected item.
689 infoPtr
->tabHeight
= item_height
+ 2*VERTICAL_ITEM_PADDING
+
693 for (curItem
= 0; curItem
< infoPtr
->uNumItem
; curItem
++)
696 * Calculate the vertical position of the tab
698 if (lStyle
& TCS_BOTTOM
)
700 infoPtr
->items
[curItem
].rect
.bottom
= clientRect
.bottom
-
702 infoPtr
->items
[curItem
].rect
.top
= clientRect
.bottom
-
707 infoPtr
->items
[curItem
].rect
.top
= clientRect
.top
+
709 infoPtr
->items
[curItem
].rect
.bottom
= clientRect
.top
+
714 * Set the leftmost position of the tab.
716 infoPtr
->items
[curItem
].rect
.left
= curItemLeftPos
;
718 if ((lStyle
& TCS_FIXEDWIDTH
) || (lStyle
& TCS_OWNERDRAWFIXED
))
720 infoPtr
->items
[curItem
].rect
.right
= infoPtr
->items
[curItem
].rect
.left
+
722 2*HORIZONTAL_ITEM_PADDING
;
730 * Calculate how wide the tab is depending on the text it contains
732 GetTextExtentPoint32A(hdc
, infoPtr
->items
[curItem
].pszText
,
733 lstrlenA(infoPtr
->items
[curItem
].pszText
), &size
);
740 ImageList_GetIconSize(infoPtr
->himl
, &icon_width
, 0);
744 infoPtr
->items
[curItem
].rect
.right
= infoPtr
->items
[curItem
].rect
.left
+
745 size
.cx
+ icon_width
+
746 num
*HORIZONTAL_ITEM_PADDING
;
749 TRACE("TextSize: %i\n ", size
.cx
);
750 TRACE("Rect: T %i, L %i, B %i, R %i\n",
751 infoPtr
->items
[curItem
].rect
.top
,
752 infoPtr
->items
[curItem
].rect
.left
,
753 infoPtr
->items
[curItem
].rect
.bottom
,
754 infoPtr
->items
[curItem
].rect
.right
);
757 * The leftmost position of the next item is the rightmost position
760 if (lStyle
& TCS_BUTTONS
)
761 curItemLeftPos
= infoPtr
->items
[curItem
].rect
.right
+ BUTTON_SPACINGX
;
763 curItemLeftPos
= infoPtr
->items
[curItem
].rect
.right
;
767 * Check if we need a scrolling control.
769 infoPtr
->needsScrolling
= (curItemLeftPos
+ (2*SELECTED_TAB_OFFSET
) >
772 TAB_SetupScrolling(hwnd
, infoPtr
, &clientRect
);
777 SelectObject (hdc
, hOldFont
);
778 ReleaseDC (hwnd
, hdc
);
781 /******************************************************************************
784 * This method is used to draw a single tab into the tab control.
786 static void TAB_DrawItem(
791 TAB_INFO
*infoPtr
= TAB_GetInfoPtr(hwnd
);
792 LONG lStyle
= GetWindowLongA(hwnd
, GWL_STYLE
);
799 * Get the rectangle for the item.
801 isVisible
= TAB_InternalGetItemRect(hwnd
,
809 HBRUSH hbr
= CreateSolidBrush (GetSysColor(COLOR_BTNFACE
));
810 HPEN hwPen
= GetSysColorPen (COLOR_3DHILIGHT
);
811 HPEN hbPen
= GetSysColorPen (COLOR_BTNSHADOW
);
812 HPEN hsdPen
= GetSysColorPen (COLOR_BTNTEXT
);
813 HPEN hfocusPen
= CreatePen(PS_DOT
, 1, GetSysColor(COLOR_BTNTEXT
));
817 BOOL deleteBrush
= TRUE
;
819 if (lStyle
& TCS_BUTTONS
)
822 * Get item rectangle.
826 holdPen
= SelectObject (hdc
, hwPen
);
828 if (iItem
== infoPtr
->iSelected
)
833 if (!(lStyle
& TCS_OWNERDRAWFIXED
))
835 COLORREF bk
= GetSysColor(COLOR_3DHILIGHT
);
837 hbr
= GetSysColorBrush(COLOR_SCROLLBAR
);
838 SetTextColor(hdc
, GetSysColor(COLOR_3DFACE
));
841 /* if COLOR_WINDOW happens to be the same as COLOR_3DHILIGHT
842 * we better use 0x55aa bitmap brush to make scrollbar's background
843 * look different from the window background.
845 if (bk
== GetSysColor(COLOR_WINDOW
))
846 hbr
= CACHE_GetPattern55AABrush();
852 * Erase the background.
854 FillRect(hdc
, &r
, hbr
);
858 * The rectangles calculated exclude the right and bottom
859 * borders of the rectangle. To simply the following code, those
860 * borders are shaved-off beforehand.
866 MoveToEx (hdc
, r
.left
, r
.bottom
, NULL
);
867 LineTo (hdc
, r
.right
, r
.bottom
);
868 LineTo (hdc
, r
.right
, r
.top
);
871 SelectObject(hdc
, hbPen
);
872 LineTo (hdc
, r
.left
, r
.top
);
873 LineTo (hdc
, r
.left
, r
.bottom
);
878 * Erase the background.
880 FillRect(hdc
, &r
, hbr
);
883 MoveToEx (hdc
, r
.left
, r
.bottom
, NULL
);
884 LineTo (hdc
, r
.left
, r
.top
);
885 LineTo (hdc
, r
.right
, r
.top
);
888 SelectObject(hdc
, hbPen
);
889 LineTo (hdc
, r
.right
, r
.bottom
);
890 LineTo (hdc
, r
.left
, r
.bottom
);
899 hbr
= CreateSolidBrush(GetSysColor(COLOR_BTNFACE
));
902 * We draw a rectangle of different sizes depending on the selection
905 if (iItem
== infoPtr
->iSelected
)
911 * Erase the background.
912 * This is necessary when drawing the selected item since it is larger
913 * than the others, it might overlap with stuff already drawn by the
916 FillRect(hdc
, &r
, hbr
);
920 * The rectangles calculated exclude the right and bottom
921 * borders of the rectangle. To simply the following code, those
922 * borders are shaved-off beforehand.
927 holdPen
= SelectObject (hdc
, hwPen
);
929 if (lStyle
& TCS_BOTTOM
)
932 MoveToEx (hdc
, r
.left
, r
.top
, NULL
);
933 LineTo (hdc
, r
.left
, r
.bottom
- ROUND_CORNER_SIZE
);
934 LineTo (hdc
, r
.left
+ ROUND_CORNER_SIZE
, r
.bottom
);
937 SelectObject(hdc
, hbPen
);
938 LineTo (hdc
, r
.right
- ROUND_CORNER_SIZE
, r
.bottom
);
939 LineTo (hdc
, r
.right
, r
.bottom
- ROUND_CORNER_SIZE
);
940 LineTo (hdc
, r
.right
, r
.top
);
945 MoveToEx (hdc
, r
.left
, r
.bottom
, NULL
);
946 LineTo (hdc
, r
.left
, r
.top
+ ROUND_CORNER_SIZE
);
947 LineTo (hdc
, r
.left
+ ROUND_CORNER_SIZE
, r
.top
);
948 LineTo (hdc
, r
.right
- ROUND_CORNER_SIZE
, r
.top
);
951 SelectObject(hdc
, hbPen
);
952 LineTo (hdc
, r
.right
, r
.top
+ ROUND_CORNER_SIZE
);
953 LineTo (hdc
, r
.right
, r
.bottom
);
960 SelectObject(hdc
, hsdPen
);
962 oldBkMode
= SetBkMode(hdc
, TRANSPARENT
);
963 SetTextColor (hdc
, COLOR_BTNTEXT
);
966 * Deflate the rectangle to acount for the padding
968 InflateRect(&r
, -HORIZONTAL_ITEM_PADDING
, -VERTICAL_ITEM_PADDING
);
975 ImageList_Draw (infoPtr
->himl
, iItem
, hdc
,
976 r
.left
, r
.top
+1, ILD_NORMAL
);
977 ImageList_GetIconSize (infoPtr
->himl
, &cx
, &cy
);
978 r
.left
+=(cx
+ HORIZONTAL_ITEM_PADDING
);
985 infoPtr
->items
[iItem
].pszText
,
986 lstrlenA(infoPtr
->items
[iItem
].pszText
),
988 DT_LEFT
|DT_SINGLELINE
|DT_VCENTER
);
991 * Draw the focus rectangle
993 if (((lStyle
& TCS_FOCUSNEVER
) == 0) &&
994 (GetFocus() == hwnd
) &&
995 (iItem
== infoPtr
->uFocus
) )
997 InflateRect(&r
, FOCUS_RECT_HOFFSET
, FOCUS_RECT_VOFFSET
);
999 SelectObject(hdc
, hfocusPen
);
1001 MoveToEx (hdc
, r
.left
, r
.top
, NULL
);
1002 LineTo (hdc
, r
.right
-1, r
.top
);
1003 LineTo (hdc
, r
.right
-1, r
.bottom
-1);
1004 LineTo (hdc
, r
.left
, r
.bottom
-1);
1005 LineTo (hdc
, r
.left
, r
.top
);
1011 SetBkMode(hdc
, oldBkMode
);
1012 SelectObject(hdc
, holdPen
);
1013 DeleteObject(hfocusPen
);
1014 if (deleteBrush
) DeleteObject(hbr
);
1018 /******************************************************************************
1021 * This method is used to draw the raised border around the tab control
1024 static void TAB_DrawBorder (HWND hwnd
, HDC hdc
)
1026 TAB_INFO
*infoPtr
= TAB_GetInfoPtr(hwnd
);
1028 HPEN hwPen
= GetSysColorPen (COLOR_3DHILIGHT
);
1029 HPEN hbPen
= GetSysColorPen (COLOR_3DDKSHADOW
);
1030 HPEN hShade
= GetSysColorPen (COLOR_BTNSHADOW
);
1033 GetClientRect (hwnd
, &rect
);
1036 * Adjust for the style
1038 if (GetWindowLongA(hwnd
, GWL_STYLE
) & TCS_BOTTOM
)
1040 rect
.bottom
-= infoPtr
->tabHeight
;
1044 rect
.top
+= infoPtr
->tabHeight
;
1048 * Shave-off the right and bottom margins (exluded in the
1055 htmPen
= SelectObject (hdc
, hwPen
);
1057 MoveToEx (hdc
, rect
.left
, rect
.bottom
, NULL
);
1058 LineTo (hdc
, rect
.left
, rect
.top
);
1059 LineTo (hdc
, rect
.right
, rect
.top
);
1062 SelectObject (hdc
, hbPen
);
1063 LineTo (hdc
, rect
.right
, rect
.bottom
);
1064 LineTo (hdc
, rect
.left
, rect
.bottom
);
1067 SelectObject (hdc
, hShade
);
1068 MoveToEx (hdc
, rect
.right
-1, rect
.top
, NULL
);
1069 LineTo (hdc
, rect
.right
-1, rect
.bottom
-1);
1070 LineTo (hdc
, rect
.left
, rect
.bottom
-1);
1072 SelectObject(hdc
, htmPen
);
1075 /******************************************************************************
1078 * This method repaints the tab control..
1080 static void TAB_Refresh (HWND hwnd
, HDC hdc
)
1082 TAB_INFO
*infoPtr
= TAB_GetInfoPtr(hwnd
);
1086 if (!infoPtr
->DoRedraw
)
1089 hOldFont
= SelectObject (hdc
, infoPtr
->hFont
);
1091 if (GetWindowLongA(hwnd
, GWL_STYLE
) & TCS_BUTTONS
)
1093 for (i
= 0; i
< infoPtr
->uNumItem
; i
++)
1095 TAB_DrawItem (hwnd
, hdc
, i
);
1101 * Draw all the non selected item first.
1103 for (i
= 0; i
< infoPtr
->uNumItem
; i
++)
1105 if (i
!= infoPtr
->iSelected
)
1106 TAB_DrawItem (hwnd
, hdc
, i
);
1110 * Now, draw the border, draw it before the selected item
1111 * since the selected item overwrites part of the border.
1113 TAB_DrawBorder (hwnd
, hdc
);
1116 * Then, draw the selected item
1118 TAB_DrawItem (hwnd
, hdc
, infoPtr
->iSelected
);
1121 SelectObject (hdc
, hOldFont
);
1125 TAB_SetRedraw (HWND hwnd
, WPARAM wParam
)
1127 TAB_INFO
*infoPtr
= TAB_GetInfoPtr(hwnd
);
1129 infoPtr
->DoRedraw
=(BOOL
) wParam
;
1133 static LRESULT
TAB_EraseBackground(
1140 HBRUSH brush
= CreateSolidBrush(GetSysColor(COLOR_BTNFACE
));
1142 hdc
= givenDC
? givenDC
: GetDC(hwnd
);
1144 GetClientRect(hwnd
, &clientRect
);
1146 FillRect(hdc
, &clientRect
, brush
);
1149 ReleaseDC(hwnd
, hdc
);
1151 DeleteObject(brush
);
1156 /******************************************************************************
1157 * TAB_EnsureSelectionVisible
1159 * This method will make sure that the current selection is completely
1160 * visible by scrolling until it is.
1162 static void TAB_EnsureSelectionVisible(
1172 * Do the trivial cases first.
1174 if ( (!infoPtr
->needsScrolling
) ||
1175 (infoPtr
->hwndUpDown
==0) )
1178 if (infoPtr
->leftmostVisible
> infoPtr
->iSelected
)
1180 infoPtr
->leftmostVisible
= infoPtr
->iSelected
;
1185 * Calculate the part of the client area that is visible.
1187 GetClientRect(hwnd
, &visibleRect
);
1188 GetClientRect(infoPtr
->hwndUpDown
, &scrollerRect
);
1189 visibleRect
.right
-= scrollerRect
.right
;
1192 * Get the rectangle for the item
1194 isVisible
= TAB_InternalGetItemRect(hwnd
,
1201 * If this function can't say it's completely invisible, maybe it
1202 * is partially visible. Let's check.
1209 pt1
.x
= selectedRect
.left
;
1210 pt1
.y
= selectedRect
.top
;
1211 pt2
.x
= selectedRect
.right
- 1;
1212 pt2
.y
= selectedRect
.bottom
- 1;
1214 isVisible
= PtInRect(&visibleRect
, pt1
) && PtInRect(&visibleRect
, pt2
);
1217 while ( (infoPtr
->leftmostVisible
< infoPtr
->iSelected
) &&
1220 infoPtr
->leftmostVisible
++;
1223 * Get the rectangle for the item
1225 isVisible
= TAB_InternalGetItemRect(hwnd
,
1232 * If this function can't say it's completely invisible, maybe it
1233 * is partially visible. Let's check.
1240 pt1
.x
= selectedRect
.left
;
1241 pt1
.y
= selectedRect
.top
;
1242 pt2
.x
= selectedRect
.right
- 1;
1243 pt2
.y
= selectedRect
.bottom
- 1;
1245 isVisible
= PtInRect(&visibleRect
, pt1
) && PtInRect(&visibleRect
, pt2
);
1250 /******************************************************************************
1251 * TAB_InvalidateTabArea
1253 * This method will invalidate the portion of the control that contains the
1254 * tabs. It is called when the state of the control changes and needs
1257 static void TAB_InvalidateTabArea(
1263 GetClientRect(hwnd
, &clientRect
);
1265 if (GetWindowLongA(hwnd
, GWL_STYLE
) & TCS_BOTTOM
)
1267 clientRect
.top
= clientRect
.bottom
- (infoPtr
->tabHeight
+ 1);
1271 clientRect
.bottom
= clientRect
.top
+ (infoPtr
->tabHeight
+ 1);
1274 InvalidateRect(hwnd
, &clientRect
, TRUE
);
1278 TAB_Paint (HWND hwnd
, WPARAM wParam
)
1283 hdc
= wParam
== 0 ? BeginPaint (hwnd
, &ps
) : (HDC
)wParam
;
1284 TAB_Refresh (hwnd
, hdc
);
1287 EndPaint (hwnd
, &ps
);
1293 TAB_InsertItem (HWND hwnd
, WPARAM wParam
, LPARAM lParam
)
1295 TAB_INFO
*infoPtr
= TAB_GetInfoPtr(hwnd
);
1300 GetClientRect (hwnd
, &rect
);
1301 TRACE("Rect: %x T %i, L %i, B %i, R %i\n", hwnd
,
1302 rect
.top
, rect
.left
, rect
.bottom
, rect
.right
);
1304 pti
= (TCITEMA
*)lParam
;
1305 iItem
= (INT
)wParam
;
1307 if (iItem
< 0) return -1;
1308 if (iItem
> infoPtr
->uNumItem
)
1309 iItem
= infoPtr
->uNumItem
;
1311 if (infoPtr
->uNumItem
== 0) {
1312 infoPtr
->items
= COMCTL32_Alloc (sizeof (TAB_ITEM
));
1313 infoPtr
->uNumItem
++;
1314 infoPtr
->iSelected
= 0;
1317 TAB_ITEM
*oldItems
= infoPtr
->items
;
1319 infoPtr
->uNumItem
++;
1320 infoPtr
->items
= COMCTL32_Alloc (sizeof (TAB_ITEM
) * infoPtr
->uNumItem
);
1322 /* pre insert copy */
1324 memcpy (&infoPtr
->items
[0], &oldItems
[0],
1325 iItem
* sizeof(TAB_ITEM
));
1328 /* post insert copy */
1329 if (iItem
< infoPtr
->uNumItem
- 1) {
1330 memcpy (&infoPtr
->items
[iItem
+1], &oldItems
[iItem
],
1331 (infoPtr
->uNumItem
- iItem
- 1) * sizeof(TAB_ITEM
));
1335 if (iItem
<= infoPtr
->iSelected
)
1336 infoPtr
->iSelected
++;
1338 COMCTL32_Free (oldItems
);
1341 infoPtr
->items
[iItem
].mask
= pti
->mask
;
1342 if (pti
->mask
& TCIF_TEXT
) {
1343 len
= lstrlenA (pti
->pszText
);
1344 infoPtr
->items
[iItem
].pszText
= COMCTL32_Alloc (len
+1);
1345 lstrcpyA (infoPtr
->items
[iItem
].pszText
, pti
->pszText
);
1346 infoPtr
->items
[iItem
].cchTextMax
= pti
->cchTextMax
;
1349 if (pti
->mask
& TCIF_IMAGE
)
1350 infoPtr
->items
[iItem
].iImage
= pti
->iImage
;
1352 if (pti
->mask
& TCIF_PARAM
)
1353 infoPtr
->items
[iItem
].lParam
= pti
->lParam
;
1355 TAB_InvalidateTabArea(hwnd
, infoPtr
);
1357 TRACE("[%04x]: added item %d '%s'\n",
1358 hwnd
, iItem
, infoPtr
->items
[iItem
].pszText
);
1360 TAB_SetItemBounds(hwnd
);
1365 TAB_SetItemSize (HWND hwnd
, WPARAM wParam
, LPARAM lParam
)
1367 TAB_INFO
*infoPtr
= TAB_GetInfoPtr(hwnd
);
1368 LONG lStyle
= GetWindowLongA(hwnd
, GWL_STYLE
);
1371 if ((lStyle
& TCS_FIXEDWIDTH
) || (lStyle
& TCS_OWNERDRAWFIXED
))
1373 lResult
= MAKELONG(infoPtr
->tabWidth
, infoPtr
->tabHeight
);
1374 infoPtr
->tabWidth
= (INT
)LOWORD(lParam
);
1375 infoPtr
->tabHeight
= (INT
)HIWORD(lParam
);
1382 TAB_SetItemA (HWND hwnd
, WPARAM wParam
, LPARAM lParam
)
1384 TAB_INFO
*infoPtr
= TAB_GetInfoPtr(hwnd
);
1390 tabItem
=(LPTCITEMA
) lParam
;
1391 TRACE("%d %p\n",iItem
, tabItem
);
1392 if ((iItem
<0) || (iItem
>=infoPtr
->uNumItem
)) return FALSE
;
1394 wineItem
=& infoPtr
->items
[iItem
];
1396 if (tabItem
->mask
& TCIF_IMAGE
)
1397 wineItem
->iImage
=tabItem
->iImage
;
1399 if (tabItem
->mask
& TCIF_PARAM
)
1400 wineItem
->lParam
=tabItem
->lParam
;
1402 if (tabItem
->mask
& TCIF_RTLREADING
)
1403 FIXME("TCIF_RTLREADING\n");
1405 if (tabItem
->mask
& TCIF_STATE
)
1406 wineItem
->dwState
=tabItem
->dwState
;
1408 if (tabItem
->mask
& TCIF_TEXT
) {
1409 len
=lstrlenA (tabItem
->pszText
);
1410 if (len
>wineItem
->cchTextMax
)
1411 wineItem
->pszText
= COMCTL32_ReAlloc (wineItem
->pszText
, len
+1);
1412 lstrcpyA (wineItem
->pszText
, tabItem
->pszText
);
1416 * Update and repaint tabs.
1418 TAB_SetItemBounds(hwnd
);
1419 TAB_InvalidateTabArea(hwnd
,infoPtr
);
1425 TAB_GetItemCount (HWND hwnd
, WPARAM wParam
, LPARAM lParam
)
1427 TAB_INFO
*infoPtr
= TAB_GetInfoPtr(hwnd
);
1429 return infoPtr
->uNumItem
;
1434 TAB_GetItemA (HWND hwnd
, WPARAM wParam
, LPARAM lParam
)
1436 TAB_INFO
*infoPtr
= TAB_GetInfoPtr(hwnd
);
1442 tabItem
=(LPTCITEMA
) lParam
;
1444 if ((iItem
<0) || (iItem
>=infoPtr
->uNumItem
)) return FALSE
;
1446 wineItem
=& infoPtr
->items
[iItem
];
1448 if (tabItem
->mask
& TCIF_IMAGE
)
1449 tabItem
->iImage
=wineItem
->iImage
;
1451 if (tabItem
->mask
& TCIF_PARAM
)
1452 tabItem
->lParam
=wineItem
->lParam
;
1454 if (tabItem
->mask
& TCIF_RTLREADING
)
1455 FIXME("TCIF_RTLREADING\n");
1457 if (tabItem
->mask
& TCIF_STATE
)
1458 tabItem
->dwState
=wineItem
->dwState
;
1460 if (tabItem
->mask
& TCIF_TEXT
)
1461 lstrcpynA (tabItem
->pszText
, wineItem
->pszText
, tabItem
->cchTextMax
);
1467 TAB_DeleteItem (HWND hwnd
, WPARAM wParam
, LPARAM lParam
)
1469 TAB_INFO
*infoPtr
= TAB_GetInfoPtr(hwnd
);
1470 INT iItem
= (INT
) wParam
;
1471 BOOL bResult
= FALSE
;
1473 if ((iItem
>= 0) && (iItem
< infoPtr
->uNumItem
))
1475 TAB_ITEM
*oldItems
= infoPtr
->items
;
1477 infoPtr
->uNumItem
--;
1478 infoPtr
->items
= COMCTL32_Alloc(sizeof (TAB_ITEM
) * infoPtr
->uNumItem
);
1481 memcpy(&infoPtr
->items
[0], &oldItems
[0], iItem
* sizeof(TAB_ITEM
));
1483 if (iItem
< infoPtr
->uNumItem
)
1484 memcpy(&infoPtr
->items
[iItem
], &oldItems
[iItem
+ 1],
1485 (infoPtr
->uNumItem
- iItem
) * sizeof(TAB_ITEM
));
1487 COMCTL32_Free (oldItems
);
1490 * Readjust the selected index.
1492 if ((iItem
== infoPtr
->iSelected
) && (iItem
> 0))
1493 infoPtr
->iSelected
--;
1495 if (iItem
< infoPtr
->iSelected
)
1496 infoPtr
->iSelected
--;
1498 if (infoPtr
->uNumItem
== 0)
1499 infoPtr
->iSelected
= -1;
1502 * Reposition and repaint tabs.
1504 TAB_SetItemBounds(hwnd
);
1505 TAB_InvalidateTabArea(hwnd
,infoPtr
);
1514 TAB_DeleteAllItems (HWND hwnd
, WPARAM wParam
, LPARAM lParam
)
1516 TAB_INFO
*infoPtr
= TAB_GetInfoPtr(hwnd
);
1518 COMCTL32_Free (infoPtr
->items
);
1519 infoPtr
->uNumItem
= 0;
1520 infoPtr
->iSelected
= -1;
1527 TAB_GetFont (HWND hwnd
, WPARAM wParam
, LPARAM lParam
)
1529 TAB_INFO
*infoPtr
= TAB_GetInfoPtr(hwnd
);
1532 return (LRESULT
)infoPtr
->hFont
;
1536 TAB_SetFont (HWND hwnd
, WPARAM wParam
, LPARAM lParam
)
1539 TAB_INFO
*infoPtr
= TAB_GetInfoPtr(hwnd
);
1541 TRACE("%x %lx\n",wParam
, lParam
);
1543 infoPtr
->hFont
= (HFONT
)wParam
;
1545 TAB_SetItemBounds(hwnd
);
1547 TAB_InvalidateTabArea(hwnd
, infoPtr
);
1554 TAB_GetImageList (HWND hwnd
, WPARAM wParam
, LPARAM lParam
)
1556 TAB_INFO
*infoPtr
= TAB_GetInfoPtr(hwnd
);
1559 return (LRESULT
)infoPtr
->himl
;
1563 TAB_SetImageList (HWND hwnd
, WPARAM wParam
, LPARAM lParam
)
1565 TAB_INFO
*infoPtr
= TAB_GetInfoPtr(hwnd
);
1566 HIMAGELIST himlPrev
;
1569 himlPrev
= infoPtr
->himl
;
1570 infoPtr
->himl
= (HIMAGELIST
)lParam
;
1571 return (LRESULT
)himlPrev
;
1576 TAB_Size (HWND hwnd
, WPARAM wParam
, LPARAM lParam
)
1579 /* I'm not really sure what the following code was meant to do.
1580 This is what it is doing:
1581 When WM_SIZE is sent with SIZE_RESTORED, the control
1582 gets positioned in the top left corner.
1586 UINT uPosFlags,cx,cy;
1590 parent = GetParent (hwnd);
1591 GetClientRect(parent, &parent_rect);
1594 if (GetWindowLongA(hwnd, GWL_STYLE) & CCS_NORESIZE)
1595 uPosFlags |= (SWP_NOSIZE | SWP_NOMOVE);
1597 SetWindowPos (hwnd, 0, parent_rect.left, parent_rect.top,
1598 cx, cy, uPosFlags | SWP_NOZORDER);
1600 FIXME (tab,"WM_SIZE flag %x %lx not handled\n", wParam, lParam);
1604 * Recompute the size/position of the tabs.
1606 TAB_SetItemBounds (hwnd
);
1609 * Force a repaint of the control.
1611 InvalidateRect(hwnd
, NULL
, TRUE
);
1618 TAB_Create (HWND hwnd
, WPARAM wParam
, LPARAM lParam
)
1621 TEXTMETRICA fontMetrics
;
1625 infoPtr
= (TAB_INFO
*)COMCTL32_Alloc (sizeof(TAB_INFO
));
1627 SetWindowLongA(hwnd
, 0, (DWORD
)infoPtr
);
1629 infoPtr
->uNumItem
= 0;
1632 infoPtr
->hcurArrow
= LoadCursorA (0, IDC_ARROWA
);
1633 infoPtr
->iSelected
= -1;
1634 infoPtr
->uFocus
= 0;
1635 infoPtr
->hwndToolTip
= 0;
1636 infoPtr
->DoRedraw
= TRUE
;
1637 infoPtr
->needsScrolling
= FALSE
;
1638 infoPtr
->hwndUpDown
= 0;
1639 infoPtr
->leftmostVisible
= 0;
1641 TRACE("Created tab control, hwnd [%04x]\n", hwnd
);
1642 if (GetWindowLongA(hwnd
, GWL_STYLE
) & TCS_TOOLTIPS
) {
1643 /* Create tooltip control */
1644 infoPtr
->hwndToolTip
=
1645 CreateWindowExA (0, TOOLTIPS_CLASSA
, NULL
, 0,
1646 CW_USEDEFAULT
, CW_USEDEFAULT
,
1647 CW_USEDEFAULT
, CW_USEDEFAULT
,
1650 /* Send NM_TOOLTIPSCREATED notification */
1651 if (infoPtr
->hwndToolTip
) {
1652 NMTOOLTIPSCREATED nmttc
;
1654 nmttc
.hdr
.hwndFrom
= hwnd
;
1655 nmttc
.hdr
.idFrom
= GetWindowLongA(hwnd
, GWL_ID
);
1656 nmttc
.hdr
.code
= NM_TOOLTIPSCREATED
;
1657 nmttc
.hwndToolTips
= infoPtr
->hwndToolTip
;
1659 SendMessageA (GetParent (hwnd
), WM_NOTIFY
,
1660 (WPARAM
)GetWindowLongA(hwnd
, GWL_ID
), (LPARAM
)&nmttc
);
1665 * We need to get text information so we need a DC and we need to select
1669 hOldFont
= SelectObject (hdc
, GetStockObject (SYSTEM_FONT
));
1672 * Use the system font to determine the initial height of a tab.
1674 GetTextMetricsA(hdc
, &fontMetrics
);
1677 * Make sure there is enough space for the letters + growing the
1678 * selected item + extra space for the selected item.
1680 infoPtr
->tabHeight
= fontMetrics
.tmHeight
+ 2*VERTICAL_ITEM_PADDING
+
1681 SELECTED_TAB_OFFSET
;
1684 * Initialize the width of a tab.
1686 infoPtr
->tabWidth
= DEFAULT_TAB_WIDTH
;
1688 SelectObject (hdc
, hOldFont
);
1689 ReleaseDC(hwnd
, hdc
);
1695 TAB_Destroy (HWND hwnd
, WPARAM wParam
, LPARAM lParam
)
1697 TAB_INFO
*infoPtr
= TAB_GetInfoPtr(hwnd
);
1700 if (infoPtr
->items
) {
1701 for (iItem
= 0; iItem
< infoPtr
->uNumItem
; iItem
++) {
1702 if (infoPtr
->items
[iItem
].pszText
)
1703 COMCTL32_Free (infoPtr
->items
[iItem
].pszText
);
1705 COMCTL32_Free (infoPtr
->items
);
1708 if (infoPtr
->hwndToolTip
)
1709 DestroyWindow (infoPtr
->hwndToolTip
);
1711 if (infoPtr
->hwndUpDown
)
1712 DestroyWindow(infoPtr
->hwndUpDown
);
1714 COMCTL32_Free (infoPtr
);
1718 static LRESULT WINAPI
1719 TAB_WindowProc (HWND hwnd
, UINT uMsg
, WPARAM wParam
, LPARAM lParam
)
1723 case TCM_GETIMAGELIST
:
1724 return TAB_GetImageList (hwnd
, wParam
, lParam
);
1726 case TCM_SETIMAGELIST
:
1727 return TAB_SetImageList (hwnd
, wParam
, lParam
);
1729 case TCM_GETITEMCOUNT
:
1730 return TAB_GetItemCount (hwnd
, wParam
, lParam
);
1733 return TAB_GetItemA (hwnd
, wParam
, lParam
);
1736 FIXME("Unimplemented msg TCM_GETITEMW\n");
1740 return TAB_SetItemA (hwnd
, wParam
, lParam
);
1743 FIXME("Unimplemented msg TCM_SETITEMW\n");
1746 case TCM_DELETEITEM
:
1747 return TAB_DeleteItem (hwnd
, wParam
, lParam
);
1749 case TCM_DELETEALLITEMS
:
1750 return TAB_DeleteAllItems (hwnd
, wParam
, lParam
);
1752 case TCM_GETITEMRECT
:
1753 return TAB_GetItemRect (hwnd
, wParam
, lParam
);
1756 return TAB_GetCurSel (hwnd
);
1759 return TAB_HitTest (hwnd
, wParam
, lParam
);
1762 return TAB_SetCurSel (hwnd
, wParam
);
1764 case TCM_INSERTITEMA
:
1765 return TAB_InsertItem (hwnd
, wParam
, lParam
);
1767 case TCM_INSERTITEMW
:
1768 FIXME("Unimplemented msg TCM_INSERTITEM32W\n");
1771 case TCM_SETITEMEXTRA
:
1772 FIXME("Unimplemented msg TCM_SETITEMEXTRA\n");
1775 case TCM_ADJUSTRECT
:
1776 return TAB_AdjustRect (hwnd
, (BOOL
)wParam
, (LPRECT
)lParam
);
1778 case TCM_SETITEMSIZE
:
1779 return TAB_SetItemSize (hwnd
, wParam
, lParam
);
1781 case TCM_REMOVEIMAGE
:
1782 FIXME("Unimplemented msg TCM_REMOVEIMAGE\n");
1785 case TCM_SETPADDING
:
1786 FIXME("Unimplemented msg TCM_SETPADDING\n");
1789 case TCM_GETROWCOUNT
:
1790 FIXME("Unimplemented msg TCM_GETROWCOUNT\n");
1793 case TCM_GETUNICODEFORMAT
:
1794 FIXME("Unimplemented msg TCM_GETUNICODEFORMAT\n");
1797 case TCM_SETUNICODEFORMAT
:
1798 FIXME("Unimplemented msg TCM_SETUNICODEFORMAT\n");
1801 case TCM_HIGHLIGHTITEM
:
1802 FIXME("Unimplemented msg TCM_HIGHLIGHTITEM\n");
1805 case TCM_GETTOOLTIPS
:
1806 return TAB_GetToolTips (hwnd
, wParam
, lParam
);
1808 case TCM_SETTOOLTIPS
:
1809 return TAB_SetToolTips (hwnd
, wParam
, lParam
);
1811 case TCM_GETCURFOCUS
:
1812 return TAB_GetCurFocus (hwnd
);
1814 case TCM_SETCURFOCUS
:
1815 return TAB_SetCurFocus (hwnd
, wParam
);
1817 case TCM_SETMINTTABWIDTH
:
1818 FIXME("Unimplemented msg TCM_SETMINTTABWIDTH\n");
1821 case TCM_DESELECTALL
:
1822 FIXME("Unimplemented msg TCM_DESELECTALL\n");
1825 case TCM_GETEXTENDEDSTYLE
:
1826 FIXME("Unimplemented msg TCM_GETEXTENDEDSTYLE\n");
1829 case TCM_SETEXTENDEDSTYLE
:
1830 FIXME("Unimplemented msg TCM_SETEXTENDEDSTYLE\n");
1834 return TAB_GetFont (hwnd
, wParam
, lParam
);
1837 return TAB_SetFont (hwnd
, wParam
, lParam
);
1840 return TAB_Create (hwnd
, wParam
, lParam
);
1843 return TAB_Destroy (hwnd
, wParam
, lParam
);
1846 return DLGC_WANTARROWS
| DLGC_WANTCHARS
;
1848 case WM_LBUTTONDOWN
:
1849 return TAB_LButtonDown (hwnd
, wParam
, lParam
);
1852 return TAB_LButtonUp (hwnd
, wParam
, lParam
);
1854 case WM_RBUTTONDOWN
:
1855 return TAB_RButtonDown (hwnd
, wParam
, lParam
);
1858 return TAB_MouseMove (hwnd
, wParam
, lParam
);
1861 return TAB_EraseBackground (hwnd
, (HDC
)wParam
);
1864 return TAB_Paint (hwnd
, wParam
);
1867 return TAB_Size (hwnd
, wParam
, lParam
);
1870 return TAB_SetRedraw (hwnd
, wParam
);
1873 return TAB_OnHScroll(hwnd
, (int)LOWORD(wParam
), (int)HIWORD(wParam
), (HWND
)lParam
);
1877 return TAB_FocusChanging(hwnd
, uMsg
, wParam
, lParam
);
1880 return TAB_KeyUp(hwnd
, wParam
);
1883 if (uMsg
>= WM_USER
)
1884 ERR("unknown msg %04x wp=%08x lp=%08lx\n",
1885 uMsg
, wParam
, lParam
);
1886 return DefWindowProcA (hwnd
, uMsg
, wParam
, lParam
);
1898 if (GlobalFindAtomA (WC_TABCONTROLA
)) return;
1900 ZeroMemory (&wndClass
, sizeof(WNDCLASSA
));
1901 wndClass
.style
= CS_GLOBALCLASS
| CS_DBLCLKS
| CS_SAVEBITS
;
1902 wndClass
.lpfnWndProc
= (WNDPROC
)TAB_WindowProc
;
1903 wndClass
.cbClsExtra
= 0;
1904 wndClass
.cbWndExtra
= sizeof(TAB_INFO
*);
1905 wndClass
.hCursor
= LoadCursorA (0, IDC_ARROWA
);
1906 wndClass
.hbrBackground
= (HBRUSH
)NULL
;
1907 wndClass
.lpszClassName
= WC_TABCONTROLA
;
1909 RegisterClassA (&wndClass
);
1914 TAB_Unregister (void)
1916 if (GlobalFindAtomA (WC_TABCONTROLA
))
1917 UnregisterClassA (WC_TABCONTROLA
, (HINSTANCE
)NULL
);