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 if (GetWindowLongA(hwnd
, GWL_STYLE
) & TCS_BUTTONS
) {
135 FIXME("Should set input focus\n");
137 if (infoPtr
->iSelected
!= iItem
|| infoPtr
->uFocus
== -1 ) {
138 infoPtr
->uFocus
=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)
579 * I use a scrollbar since it seems to be more stable than the Updown
582 infoPtr
->hwndUpDown
= CreateWindowA("msctls_updown32",
584 WS_VISIBLE
| WS_CHILD
| UDS_HORZ
,
585 controlPos
.left
, controlPos
.top
,
586 controlPos
.right
- controlPos
.left
,
587 controlPos
.bottom
- controlPos
.top
,
595 SetWindowPos(infoPtr
->hwndUpDown
,
597 controlPos
.left
, controlPos
.top
,
598 controlPos
.right
- controlPos
.left
,
599 controlPos
.bottom
- controlPos
.top
,
600 SWP_SHOWWINDOW
| SWP_NOZORDER
);
603 /* Now calculate upper limit of the updown control range.
604 * We do this by calculating how many tabs will be offscreen when the
605 * last tab is visible.
607 if(infoPtr
->uNumItem
)
609 vsize
= clientRect
->right
- (controlPos
.right
- controlPos
.left
+ 1);
610 maxRange
= infoPtr
->uNumItem
;
611 tabwidth
= infoPtr
->items
[maxRange
-1].rect
.right
;
613 for(; maxRange
> 0; maxRange
--)
615 if(tabwidth
- infoPtr
->items
[maxRange
- 1].rect
.left
> vsize
)
619 if(maxRange
== infoPtr
->uNumItem
)
626 * If we once had a scroll control... hide it.
628 if (infoPtr
->hwndUpDown
!=0)
630 ShowWindow(infoPtr
->hwndUpDown
, SW_HIDE
);
633 if (infoPtr
->hwndUpDown
)
634 SendMessageA(infoPtr
->hwndUpDown
, UDM_SETRANGE32
, 0, maxRange
);
637 /******************************************************************************
640 * This method will calculate the position rectangles of all the items in the
641 * control. The rectangle calculated starts at 0 for the first item in the
642 * list and ignores scrolling and selection.
643 * It also uses the current font to determine the height of the tab row and
644 * it checks if all the tabs fit in the client area of the window. If they
645 * dont, a scrolling control is added.
647 static void TAB_SetItemBounds (HWND hwnd
)
649 TAB_INFO
* infoPtr
= TAB_GetInfoPtr(hwnd
);
650 LONG lStyle
= GetWindowLongA(hwnd
, GWL_STYLE
);
651 TEXTMETRICA fontMetrics
;
654 HFONT hFont
, hOldFont
;
660 * We need to get text information so we need a DC and we need to select
665 hFont
= infoPtr
->hFont
? infoPtr
->hFont
: GetStockObject (SYSTEM_FONT
);
666 hOldFont
= SelectObject (hdc
, hFont
);
669 * We will base the rectangle calculations on the client rectangle
672 GetClientRect(hwnd
, &clientRect
);
675 * The leftmost item will be "0" aligned
679 if ( !(lStyle
& TCS_FIXEDWIDTH
) && !((lStyle
& TCS_OWNERDRAWFIXED
) && infoPtr
->fSizeSet
) )
685 * Use the current font to determine the height of a tab.
687 GetTextMetricsA(hdc
, &fontMetrics
);
690 * Get the icon height
693 ImageList_GetIconSize(infoPtr
->himl
, 0, &icon_height
);
696 * Take the highest between font or icon
698 if (fontMetrics
.tmHeight
> icon_height
)
699 item_height
= fontMetrics
.tmHeight
;
701 item_height
= icon_height
;
704 * Make sure there is enough space for the letters + icon + growing the
705 * selected item + extra space for the selected item.
707 infoPtr
->tabHeight
= item_height
+ 2*VERTICAL_ITEM_PADDING
+
711 for (curItem
= 0; curItem
< infoPtr
->uNumItem
; curItem
++)
714 * Calculate the vertical position of the tab
716 if (lStyle
& TCS_BOTTOM
)
718 infoPtr
->items
[curItem
].rect
.bottom
= clientRect
.bottom
-
720 infoPtr
->items
[curItem
].rect
.top
= clientRect
.bottom
-
725 infoPtr
->items
[curItem
].rect
.top
= clientRect
.top
+
727 infoPtr
->items
[curItem
].rect
.bottom
= clientRect
.top
+
732 * Set the leftmost position of the tab.
734 infoPtr
->items
[curItem
].rect
.left
= curItemLeftPos
;
736 if ( (lStyle
& TCS_FIXEDWIDTH
) || ((lStyle
& TCS_OWNERDRAWFIXED
) && infoPtr
->fSizeSet
))
738 infoPtr
->items
[curItem
].rect
.right
= infoPtr
->items
[curItem
].rect
.left
+
740 2*HORIZONTAL_ITEM_PADDING
;
748 * Calculate how wide the tab is depending on the text it contains
750 GetTextExtentPoint32A(hdc
, infoPtr
->items
[curItem
].pszText
,
751 lstrlenA(infoPtr
->items
[curItem
].pszText
), &size
);
758 ImageList_GetIconSize(infoPtr
->himl
, &icon_width
, 0);
762 infoPtr
->items
[curItem
].rect
.right
= infoPtr
->items
[curItem
].rect
.left
+
763 size
.cx
+ icon_width
+
764 num
*HORIZONTAL_ITEM_PADDING
;
767 TRACE("TextSize: %i\n ", size
.cx
);
768 TRACE("Rect: T %i, L %i, B %i, R %i\n",
769 infoPtr
->items
[curItem
].rect
.top
,
770 infoPtr
->items
[curItem
].rect
.left
,
771 infoPtr
->items
[curItem
].rect
.bottom
,
772 infoPtr
->items
[curItem
].rect
.right
);
775 * The leftmost position of the next item is the rightmost position
778 if (lStyle
& TCS_BUTTONS
)
779 curItemLeftPos
= infoPtr
->items
[curItem
].rect
.right
+ BUTTON_SPACINGX
;
781 curItemLeftPos
= infoPtr
->items
[curItem
].rect
.right
;
785 * Check if we need a scrolling control.
787 infoPtr
->needsScrolling
= (curItemLeftPos
+ (2*SELECTED_TAB_OFFSET
) >
790 /* Don't need scrolling, then update infoPtr->leftmostVisible */
791 if(!infoPtr
->needsScrolling
)
792 infoPtr
->leftmostVisible
= 0;
794 TAB_SetupScrolling(hwnd
, infoPtr
, &clientRect
);
799 SelectObject (hdc
, hOldFont
);
800 ReleaseDC (hwnd
, hdc
);
803 /******************************************************************************
806 * This method is used to draw a single tab into the tab control.
808 static void TAB_DrawItem(
813 TAB_INFO
*infoPtr
= TAB_GetInfoPtr(hwnd
);
814 LONG lStyle
= GetWindowLongA(hwnd
, GWL_STYLE
);
821 * Get the rectangle for the item.
823 isVisible
= TAB_InternalGetItemRect(hwnd
,
831 HBRUSH hbr
= CreateSolidBrush (GetSysColor(COLOR_BTNFACE
));
832 HPEN hwPen
= GetSysColorPen (COLOR_3DHILIGHT
);
833 HPEN hbPen
= GetSysColorPen (COLOR_BTNSHADOW
);
834 HPEN hsdPen
= GetSysColorPen (COLOR_BTNTEXT
);
835 HPEN hfocusPen
= CreatePen(PS_DOT
, 1, GetSysColor(COLOR_BTNTEXT
));
839 BOOL deleteBrush
= TRUE
;
841 if (lStyle
& TCS_BUTTONS
)
844 * Get item rectangle.
848 holdPen
= SelectObject (hdc
, hwPen
);
850 if (iItem
== infoPtr
->iSelected
)
855 if (!((lStyle
& TCS_OWNERDRAWFIXED
) && infoPtr
->fSizeSet
))
857 COLORREF bk
= GetSysColor(COLOR_3DHILIGHT
);
859 hbr
= GetSysColorBrush(COLOR_SCROLLBAR
);
860 SetTextColor(hdc
, GetSysColor(COLOR_3DFACE
));
863 /* if COLOR_WINDOW happens to be the same as COLOR_3DHILIGHT
864 * we better use 0x55aa bitmap brush to make scrollbar's background
865 * look different from the window background.
867 if (bk
== GetSysColor(COLOR_WINDOW
))
868 hbr
= CACHE_GetPattern55AABrush();
874 * Erase the background.
876 FillRect(hdc
, &r
, hbr
);
880 * The rectangles calculated exclude the right and bottom
881 * borders of the rectangle. To simply the following code, those
882 * borders are shaved-off beforehand.
888 MoveToEx (hdc
, r
.left
, r
.bottom
, NULL
);
889 LineTo (hdc
, r
.right
, r
.bottom
);
890 LineTo (hdc
, r
.right
, r
.top
);
893 SelectObject(hdc
, hbPen
);
894 LineTo (hdc
, r
.left
, r
.top
);
895 LineTo (hdc
, r
.left
, r
.bottom
);
900 * Erase the background.
902 FillRect(hdc
, &r
, hbr
);
905 MoveToEx (hdc
, r
.left
, r
.bottom
, NULL
);
906 LineTo (hdc
, r
.left
, r
.top
);
907 LineTo (hdc
, r
.right
, r
.top
);
910 SelectObject(hdc
, hbPen
);
911 LineTo (hdc
, r
.right
, r
.bottom
);
912 LineTo (hdc
, r
.left
, r
.bottom
);
921 hbr
= CreateSolidBrush(GetSysColor(COLOR_BTNFACE
));
924 * We draw a rectangle of different sizes depending on the selection
927 if (iItem
== infoPtr
->iSelected
)
933 * Erase the background.
934 * This is necessary when drawing the selected item since it is larger
935 * than the others, it might overlap with stuff already drawn by the
938 FillRect(hdc
, &r
, hbr
);
942 * The rectangles calculated exclude the right and bottom
943 * borders of the rectangle. To simply the following code, those
944 * borders are shaved-off beforehand.
949 holdPen
= SelectObject (hdc
, hwPen
);
951 if (lStyle
& TCS_BOTTOM
)
954 MoveToEx (hdc
, r
.left
, r
.top
, NULL
);
955 LineTo (hdc
, r
.left
, r
.bottom
- ROUND_CORNER_SIZE
);
956 LineTo (hdc
, r
.left
+ ROUND_CORNER_SIZE
, r
.bottom
);
959 SelectObject(hdc
, hbPen
);
960 LineTo (hdc
, r
.right
- ROUND_CORNER_SIZE
, r
.bottom
);
961 LineTo (hdc
, r
.right
, r
.bottom
- ROUND_CORNER_SIZE
);
962 LineTo (hdc
, r
.right
, r
.top
);
967 MoveToEx (hdc
, r
.left
, r
.bottom
, NULL
);
968 LineTo (hdc
, r
.left
, r
.top
+ ROUND_CORNER_SIZE
);
969 LineTo (hdc
, r
.left
+ ROUND_CORNER_SIZE
, r
.top
);
970 LineTo (hdc
, r
.right
- ROUND_CORNER_SIZE
, r
.top
);
973 SelectObject(hdc
, hbPen
);
974 LineTo (hdc
, r
.right
, r
.top
+ ROUND_CORNER_SIZE
);
975 LineTo (hdc
, r
.right
, r
.bottom
);
982 SelectObject(hdc
, hsdPen
);
984 oldBkMode
= SetBkMode(hdc
, TRANSPARENT
);
985 SetTextColor (hdc
, COLOR_BTNTEXT
);
988 * Deflate the rectangle to acount for the padding
990 InflateRect(&r
, -HORIZONTAL_ITEM_PADDING
, -VERTICAL_ITEM_PADDING
);
993 * if owner draw, tell the owner to draw
995 if ( (lStyle
& TCS_OWNERDRAWFIXED
) && GetParent(hwnd
) )
1002 * get the control id
1004 pwndPtr
= WIN_FindWndPtr( hwnd
);
1005 id
= pwndPtr
->wIDmenu
;
1006 WIN_ReleaseWndPtr(pwndPtr
);
1009 * put together the DRAWITEMSTRUCT
1011 dis
.CtlType
= ODT_TAB
;
1014 dis
.itemAction
= ODA_DRAWENTIRE
;
1015 if ( iItem
== infoPtr
->iSelected
)
1016 dis
.itemState
= ODS_SELECTED
;
1019 dis
.hwndItem
= hwnd
; /* */
1021 dis
.rcItem
= r
; /* */
1022 dis
.itemData
= infoPtr
->items
[iItem
].lParam
;
1025 * send the draw message
1027 SendMessageA( GetParent(hwnd
), WM_DRAWITEM
, (WPARAM
)id
, (LPARAM
)&dis
);
1032 * If not owner draw, then do the drawing ourselves.
1036 if (infoPtr
->himl
&& (infoPtr
->items
[iItem
].mask
& TCIF_IMAGE
) )
1038 ImageList_Draw (infoPtr
->himl
, infoPtr
->items
[iItem
].iImage
, hdc
,
1039 r
.left
, r
.top
+1, ILD_NORMAL
);
1040 ImageList_GetIconSize (infoPtr
->himl
, &cx
, &cy
);
1041 r
.left
+=(cx
+ HORIZONTAL_ITEM_PADDING
);
1048 infoPtr
->items
[iItem
].pszText
,
1049 lstrlenA(infoPtr
->items
[iItem
].pszText
),
1051 DT_LEFT
|DT_SINGLELINE
|DT_VCENTER
);
1055 * Draw the focus rectangle
1057 if (((lStyle
& TCS_FOCUSNEVER
) == 0) &&
1058 (GetFocus() == hwnd
) &&
1059 (iItem
== infoPtr
->uFocus
) )
1061 InflateRect(&r
, FOCUS_RECT_HOFFSET
, FOCUS_RECT_VOFFSET
);
1063 SelectObject(hdc
, hfocusPen
);
1065 MoveToEx (hdc
, r
.left
, r
.top
, NULL
);
1066 LineTo (hdc
, r
.right
-1, r
.top
);
1067 LineTo (hdc
, r
.right
-1, r
.bottom
-1);
1068 LineTo (hdc
, r
.left
, r
.bottom
-1);
1069 LineTo (hdc
, r
.left
, r
.top
);
1075 SetBkMode(hdc
, oldBkMode
);
1076 SelectObject(hdc
, holdPen
);
1077 DeleteObject(hfocusPen
);
1078 if (deleteBrush
) DeleteObject(hbr
);
1082 /******************************************************************************
1085 * This method is used to draw the raised border around the tab control
1088 static void TAB_DrawBorder (HWND hwnd
, HDC hdc
)
1090 TAB_INFO
*infoPtr
= TAB_GetInfoPtr(hwnd
);
1092 HPEN hwPen
= GetSysColorPen (COLOR_3DHILIGHT
);
1093 HPEN hbPen
= GetSysColorPen (COLOR_3DDKSHADOW
);
1094 HPEN hShade
= GetSysColorPen (COLOR_BTNSHADOW
);
1097 GetClientRect (hwnd
, &rect
);
1100 * Adjust for the style
1102 if (GetWindowLongA(hwnd
, GWL_STYLE
) & TCS_BOTTOM
)
1104 rect
.bottom
-= infoPtr
->tabHeight
;
1108 rect
.top
+= infoPtr
->tabHeight
;
1112 * Shave-off the right and bottom margins (exluded in the
1119 htmPen
= SelectObject (hdc
, hwPen
);
1121 MoveToEx (hdc
, rect
.left
, rect
.bottom
, NULL
);
1122 LineTo (hdc
, rect
.left
, rect
.top
);
1123 LineTo (hdc
, rect
.right
, rect
.top
);
1126 SelectObject (hdc
, hbPen
);
1127 LineTo (hdc
, rect
.right
, rect
.bottom
);
1128 LineTo (hdc
, rect
.left
, rect
.bottom
);
1131 SelectObject (hdc
, hShade
);
1132 MoveToEx (hdc
, rect
.right
-1, rect
.top
, NULL
);
1133 LineTo (hdc
, rect
.right
-1, rect
.bottom
-1);
1134 LineTo (hdc
, rect
.left
, rect
.bottom
-1);
1136 SelectObject(hdc
, htmPen
);
1139 /******************************************************************************
1142 * This method repaints the tab control..
1144 static void TAB_Refresh (HWND hwnd
, HDC hdc
)
1146 TAB_INFO
*infoPtr
= TAB_GetInfoPtr(hwnd
);
1150 if (!infoPtr
->DoRedraw
)
1153 hOldFont
= SelectObject (hdc
, infoPtr
->hFont
);
1155 if (GetWindowLongA(hwnd
, GWL_STYLE
) & TCS_BUTTONS
)
1157 for (i
= 0; i
< infoPtr
->uNumItem
; i
++)
1159 TAB_DrawItem (hwnd
, hdc
, i
);
1165 * Draw all the non selected item first.
1167 for (i
= 0; i
< infoPtr
->uNumItem
; i
++)
1169 if (i
!= infoPtr
->iSelected
)
1170 TAB_DrawItem (hwnd
, hdc
, i
);
1174 * Now, draw the border, draw it before the selected item
1175 * since the selected item overwrites part of the border.
1177 TAB_DrawBorder (hwnd
, hdc
);
1180 * Then, draw the selected item
1182 TAB_DrawItem (hwnd
, hdc
, infoPtr
->iSelected
);
1185 * If we haven't set the current focus yet, set it now.
1186 * Only happens when we first paint the tab controls.
1188 if (infoPtr
->uFocus
== -1)
1189 TAB_SetCurFocus(hwnd
, infoPtr
->iSelected
);
1192 SelectObject (hdc
, hOldFont
);
1196 TAB_SetRedraw (HWND hwnd
, WPARAM wParam
)
1198 TAB_INFO
*infoPtr
= TAB_GetInfoPtr(hwnd
);
1200 infoPtr
->DoRedraw
=(BOOL
) wParam
;
1204 static LRESULT
TAB_EraseBackground(
1211 HBRUSH brush
= CreateSolidBrush(GetSysColor(COLOR_BTNFACE
));
1213 hdc
= givenDC
? givenDC
: GetDC(hwnd
);
1215 GetClientRect(hwnd
, &clientRect
);
1217 FillRect(hdc
, &clientRect
, brush
);
1220 ReleaseDC(hwnd
, hdc
);
1222 DeleteObject(brush
);
1227 /******************************************************************************
1228 * TAB_EnsureSelectionVisible
1230 * This method will make sure that the current selection is completely
1231 * visible by scrolling until it is.
1233 static void TAB_EnsureSelectionVisible(
1237 INT iSelected
= infoPtr
->iSelected
;
1240 * Do the trivial cases first.
1242 if ( (!infoPtr
->needsScrolling
) ||
1243 (infoPtr
->hwndUpDown
==0) )
1246 if (infoPtr
->leftmostVisible
>= iSelected
)
1248 infoPtr
->leftmostVisible
= iSelected
;
1255 * Calculate the part of the client area that is visible.
1257 GetClientRect(hwnd
, &r
);
1260 GetClientRect(infoPtr
->hwndUpDown
, &r
);
1263 if ((infoPtr
->items
[iSelected
].rect
.right
-
1264 infoPtr
->items
[iSelected
].rect
.left
) >= width
)
1266 /* Special case: width of selected item is greater than visible
1269 infoPtr
->leftmostVisible
= iSelected
;
1273 for (i
= infoPtr
->leftmostVisible
; i
< infoPtr
->uNumItem
; i
++)
1275 if ((infoPtr
->items
[iSelected
].rect
.right
-
1276 infoPtr
->items
[i
].rect
.left
) < width
)
1279 infoPtr
->leftmostVisible
= i
;
1283 SendMessageA(infoPtr
->hwndUpDown
, UDM_SETPOS
, 0,
1284 MAKELONG(infoPtr
->leftmostVisible
, 0));
1287 /******************************************************************************
1288 * TAB_InvalidateTabArea
1290 * This method will invalidate the portion of the control that contains the
1291 * tabs. It is called when the state of the control changes and needs
1294 static void TAB_InvalidateTabArea(
1300 GetClientRect(hwnd
, &clientRect
);
1302 if (GetWindowLongA(hwnd
, GWL_STYLE
) & TCS_BOTTOM
)
1304 clientRect
.top
= clientRect
.bottom
- (infoPtr
->tabHeight
+ 3);
1308 clientRect
.bottom
= clientRect
.top
+ (infoPtr
->tabHeight
+ 1);
1311 InvalidateRect(hwnd
, &clientRect
, TRUE
);
1315 TAB_Paint (HWND hwnd
, WPARAM wParam
)
1320 hdc
= wParam
== 0 ? BeginPaint (hwnd
, &ps
) : (HDC
)wParam
;
1321 TAB_Refresh (hwnd
, hdc
);
1324 EndPaint (hwnd
, &ps
);
1330 TAB_InsertItem (HWND hwnd
, WPARAM wParam
, LPARAM lParam
)
1332 TAB_INFO
*infoPtr
= TAB_GetInfoPtr(hwnd
);
1337 GetClientRect (hwnd
, &rect
);
1338 TRACE("Rect: %x T %i, L %i, B %i, R %i\n", hwnd
,
1339 rect
.top
, rect
.left
, rect
.bottom
, rect
.right
);
1341 pti
= (TCITEMA
*)lParam
;
1342 iItem
= (INT
)wParam
;
1344 if (iItem
< 0) return -1;
1345 if (iItem
> infoPtr
->uNumItem
)
1346 iItem
= infoPtr
->uNumItem
;
1348 if (infoPtr
->uNumItem
== 0) {
1349 infoPtr
->items
= COMCTL32_Alloc (sizeof (TAB_ITEM
));
1350 infoPtr
->uNumItem
++;
1351 infoPtr
->iSelected
= 0;
1354 TAB_ITEM
*oldItems
= infoPtr
->items
;
1356 infoPtr
->uNumItem
++;
1357 infoPtr
->items
= COMCTL32_Alloc (sizeof (TAB_ITEM
) * infoPtr
->uNumItem
);
1359 /* pre insert copy */
1361 memcpy (&infoPtr
->items
[0], &oldItems
[0],
1362 iItem
* sizeof(TAB_ITEM
));
1365 /* post insert copy */
1366 if (iItem
< infoPtr
->uNumItem
- 1) {
1367 memcpy (&infoPtr
->items
[iItem
+1], &oldItems
[iItem
],
1368 (infoPtr
->uNumItem
- iItem
- 1) * sizeof(TAB_ITEM
));
1372 if (iItem
<= infoPtr
->iSelected
)
1373 infoPtr
->iSelected
++;
1375 COMCTL32_Free (oldItems
);
1378 infoPtr
->items
[iItem
].mask
= pti
->mask
;
1379 if (pti
->mask
& TCIF_TEXT
) {
1380 len
= lstrlenA (pti
->pszText
);
1381 infoPtr
->items
[iItem
].pszText
= COMCTL32_Alloc (len
+1);
1382 lstrcpyA (infoPtr
->items
[iItem
].pszText
, pti
->pszText
);
1383 infoPtr
->items
[iItem
].cchTextMax
= pti
->cchTextMax
;
1386 if (pti
->mask
& TCIF_IMAGE
)
1387 infoPtr
->items
[iItem
].iImage
= pti
->iImage
;
1389 if (pti
->mask
& TCIF_PARAM
)
1390 infoPtr
->items
[iItem
].lParam
= pti
->lParam
;
1392 TAB_SetItemBounds(hwnd
);
1393 TAB_InvalidateTabArea(hwnd
, infoPtr
);
1395 TRACE("[%04x]: added item %d '%s'\n",
1396 hwnd
, iItem
, infoPtr
->items
[iItem
].pszText
);
1402 TAB_SetItemSize (HWND hwnd
, WPARAM wParam
, LPARAM lParam
)
1404 TAB_INFO
*infoPtr
= TAB_GetInfoPtr(hwnd
);
1405 LONG lStyle
= GetWindowLongA(hwnd
, GWL_STYLE
);
1408 if ((lStyle
& TCS_FIXEDWIDTH
) || (lStyle
& TCS_OWNERDRAWFIXED
))
1410 lResult
= MAKELONG(infoPtr
->tabWidth
, infoPtr
->tabHeight
);
1411 infoPtr
->tabWidth
= (INT
)LOWORD(lParam
);
1412 infoPtr
->tabHeight
= (INT
)HIWORD(lParam
);
1414 infoPtr
->fSizeSet
= TRUE
;
1420 TAB_SetItemA (HWND hwnd
, WPARAM wParam
, LPARAM lParam
)
1422 TAB_INFO
*infoPtr
= TAB_GetInfoPtr(hwnd
);
1428 tabItem
=(LPTCITEMA
) lParam
;
1429 TRACE("%d %p\n",iItem
, tabItem
);
1430 if ((iItem
<0) || (iItem
>=infoPtr
->uNumItem
)) return FALSE
;
1432 wineItem
=& infoPtr
->items
[iItem
];
1434 if (tabItem
->mask
& TCIF_IMAGE
)
1435 wineItem
->iImage
=tabItem
->iImage
;
1437 if (tabItem
->mask
& TCIF_PARAM
)
1438 wineItem
->lParam
=tabItem
->lParam
;
1440 if (tabItem
->mask
& TCIF_RTLREADING
)
1441 FIXME("TCIF_RTLREADING\n");
1443 if (tabItem
->mask
& TCIF_STATE
)
1444 wineItem
->dwState
=tabItem
->dwState
;
1446 if (tabItem
->mask
& TCIF_TEXT
) {
1447 len
=lstrlenA (tabItem
->pszText
);
1448 if (len
>wineItem
->cchTextMax
)
1449 wineItem
->pszText
= COMCTL32_ReAlloc (wineItem
->pszText
, len
+1);
1450 lstrcpyA (wineItem
->pszText
, tabItem
->pszText
);
1454 * Update and repaint tabs.
1456 TAB_SetItemBounds(hwnd
);
1457 TAB_InvalidateTabArea(hwnd
,infoPtr
);
1463 TAB_GetItemCount (HWND hwnd
, WPARAM wParam
, LPARAM lParam
)
1465 TAB_INFO
*infoPtr
= TAB_GetInfoPtr(hwnd
);
1467 return infoPtr
->uNumItem
;
1472 TAB_GetItemA (HWND hwnd
, WPARAM wParam
, LPARAM lParam
)
1474 TAB_INFO
*infoPtr
= TAB_GetInfoPtr(hwnd
);
1480 tabItem
=(LPTCITEMA
) lParam
;
1482 if ((iItem
<0) || (iItem
>=infoPtr
->uNumItem
)) return FALSE
;
1484 wineItem
=& infoPtr
->items
[iItem
];
1486 if (tabItem
->mask
& TCIF_IMAGE
)
1487 tabItem
->iImage
=wineItem
->iImage
;
1489 if (tabItem
->mask
& TCIF_PARAM
)
1490 tabItem
->lParam
=wineItem
->lParam
;
1492 if (tabItem
->mask
& TCIF_RTLREADING
)
1493 FIXME("TCIF_RTLREADING\n");
1495 if (tabItem
->mask
& TCIF_STATE
)
1496 tabItem
->dwState
=wineItem
->dwState
;
1498 if (tabItem
->mask
& TCIF_TEXT
)
1499 lstrcpynA (tabItem
->pszText
, wineItem
->pszText
, tabItem
->cchTextMax
);
1505 TAB_DeleteItem (HWND hwnd
, WPARAM wParam
, LPARAM lParam
)
1507 TAB_INFO
*infoPtr
= TAB_GetInfoPtr(hwnd
);
1508 INT iItem
= (INT
) wParam
;
1509 BOOL bResult
= FALSE
;
1511 if ((iItem
>= 0) && (iItem
< infoPtr
->uNumItem
))
1513 TAB_ITEM
*oldItems
= infoPtr
->items
;
1515 infoPtr
->uNumItem
--;
1516 infoPtr
->items
= COMCTL32_Alloc(sizeof (TAB_ITEM
) * infoPtr
->uNumItem
);
1519 memcpy(&infoPtr
->items
[0], &oldItems
[0], iItem
* sizeof(TAB_ITEM
));
1521 if (iItem
< infoPtr
->uNumItem
)
1522 memcpy(&infoPtr
->items
[iItem
], &oldItems
[iItem
+ 1],
1523 (infoPtr
->uNumItem
- iItem
) * sizeof(TAB_ITEM
));
1525 COMCTL32_Free (oldItems
);
1528 * Readjust the selected index.
1530 if ((iItem
== infoPtr
->iSelected
) && (iItem
> 0))
1531 infoPtr
->iSelected
--;
1533 if (iItem
< infoPtr
->iSelected
)
1534 infoPtr
->iSelected
--;
1536 if (infoPtr
->uNumItem
== 0)
1537 infoPtr
->iSelected
= -1;
1540 * Reposition and repaint tabs.
1542 TAB_SetItemBounds(hwnd
);
1543 TAB_InvalidateTabArea(hwnd
,infoPtr
);
1552 TAB_DeleteAllItems (HWND hwnd
, WPARAM wParam
, LPARAM lParam
)
1554 TAB_INFO
*infoPtr
= TAB_GetInfoPtr(hwnd
);
1556 COMCTL32_Free (infoPtr
->items
);
1557 infoPtr
->uNumItem
= 0;
1558 infoPtr
->iSelected
= -1;
1560 TAB_SetItemBounds(hwnd
);
1561 TAB_InvalidateTabArea(hwnd
,infoPtr
);
1567 TAB_GetFont (HWND hwnd
, WPARAM wParam
, LPARAM lParam
)
1569 TAB_INFO
*infoPtr
= TAB_GetInfoPtr(hwnd
);
1572 return (LRESULT
)infoPtr
->hFont
;
1576 TAB_SetFont (HWND hwnd
, WPARAM wParam
, LPARAM lParam
)
1579 TAB_INFO
*infoPtr
= TAB_GetInfoPtr(hwnd
);
1581 TRACE("%x %lx\n",wParam
, lParam
);
1583 infoPtr
->hFont
= (HFONT
)wParam
;
1585 TAB_SetItemBounds(hwnd
);
1587 TAB_InvalidateTabArea(hwnd
, infoPtr
);
1594 TAB_GetImageList (HWND hwnd
, WPARAM wParam
, LPARAM lParam
)
1596 TAB_INFO
*infoPtr
= TAB_GetInfoPtr(hwnd
);
1599 return (LRESULT
)infoPtr
->himl
;
1603 TAB_SetImageList (HWND hwnd
, WPARAM wParam
, LPARAM lParam
)
1605 TAB_INFO
*infoPtr
= TAB_GetInfoPtr(hwnd
);
1606 HIMAGELIST himlPrev
;
1609 himlPrev
= infoPtr
->himl
;
1610 infoPtr
->himl
= (HIMAGELIST
)lParam
;
1611 return (LRESULT
)himlPrev
;
1616 TAB_Size (HWND hwnd
, WPARAM wParam
, LPARAM lParam
)
1619 /* I'm not really sure what the following code was meant to do.
1620 This is what it is doing:
1621 When WM_SIZE is sent with SIZE_RESTORED, the control
1622 gets positioned in the top left corner.
1626 UINT uPosFlags,cx,cy;
1630 parent = GetParent (hwnd);
1631 GetClientRect(parent, &parent_rect);
1634 if (GetWindowLongA(hwnd, GWL_STYLE) & CCS_NORESIZE)
1635 uPosFlags |= (SWP_NOSIZE | SWP_NOMOVE);
1637 SetWindowPos (hwnd, 0, parent_rect.left, parent_rect.top,
1638 cx, cy, uPosFlags | SWP_NOZORDER);
1640 FIXME (tab,"WM_SIZE flag %x %lx not handled\n", wParam, lParam);
1644 * Recompute the size/position of the tabs.
1646 TAB_SetItemBounds (hwnd
);
1649 * Force a repaint of the control.
1651 InvalidateRect(hwnd
, NULL
, TRUE
);
1658 TAB_Create (HWND hwnd
, WPARAM wParam
, LPARAM lParam
)
1661 TEXTMETRICA fontMetrics
;
1666 infoPtr
= (TAB_INFO
*)COMCTL32_Alloc (sizeof(TAB_INFO
));
1668 SetWindowLongA(hwnd
, 0, (DWORD
)infoPtr
);
1670 infoPtr
->uNumItem
= 0;
1673 infoPtr
->hcurArrow
= LoadCursorA (0, IDC_ARROWA
);
1674 infoPtr
->iSelected
= -1;
1675 infoPtr
->uFocus
= -1;
1676 infoPtr
->hwndToolTip
= 0;
1677 infoPtr
->DoRedraw
= TRUE
;
1678 infoPtr
->needsScrolling
= FALSE
;
1679 infoPtr
->hwndUpDown
= 0;
1680 infoPtr
->leftmostVisible
= 0;
1681 infoPtr
->fSizeSet
= FALSE
;
1683 TRACE("Created tab control, hwnd [%04x]\n", hwnd
);
1685 /* The tab control always has the WS_CLIPSIBLINGS style. Even
1686 if you don't specify in CreateWindow. This is necesary in
1687 order for paint to work correctly. This follows windows behaviour. */
1688 dwStyle
= GetWindowLongA(hwnd
, GWL_STYLE
);
1689 SetWindowLongA(hwnd
, GWL_STYLE
, dwStyle
|WS_CLIPSIBLINGS
);
1691 if (dwStyle
& TCS_TOOLTIPS
) {
1692 /* Create tooltip control */
1693 infoPtr
->hwndToolTip
=
1694 CreateWindowExA (0, TOOLTIPS_CLASSA
, NULL
, 0,
1695 CW_USEDEFAULT
, CW_USEDEFAULT
,
1696 CW_USEDEFAULT
, CW_USEDEFAULT
,
1699 /* Send NM_TOOLTIPSCREATED notification */
1700 if (infoPtr
->hwndToolTip
) {
1701 NMTOOLTIPSCREATED nmttc
;
1703 nmttc
.hdr
.hwndFrom
= hwnd
;
1704 nmttc
.hdr
.idFrom
= GetWindowLongA(hwnd
, GWL_ID
);
1705 nmttc
.hdr
.code
= NM_TOOLTIPSCREATED
;
1706 nmttc
.hwndToolTips
= infoPtr
->hwndToolTip
;
1708 SendMessageA (GetParent (hwnd
), WM_NOTIFY
,
1709 (WPARAM
)GetWindowLongA(hwnd
, GWL_ID
), (LPARAM
)&nmttc
);
1714 * We need to get text information so we need a DC and we need to select
1718 hOldFont
= SelectObject (hdc
, GetStockObject (SYSTEM_FONT
));
1721 * Use the system font to determine the initial height of a tab.
1723 GetTextMetricsA(hdc
, &fontMetrics
);
1726 * Make sure there is enough space for the letters + growing the
1727 * selected item + extra space for the selected item.
1729 infoPtr
->tabHeight
= fontMetrics
.tmHeight
+ 2*VERTICAL_ITEM_PADDING
+
1730 SELECTED_TAB_OFFSET
;
1733 * Initialize the width of a tab.
1735 infoPtr
->tabWidth
= DEFAULT_TAB_WIDTH
;
1737 SelectObject (hdc
, hOldFont
);
1738 ReleaseDC(hwnd
, hdc
);
1744 TAB_Destroy (HWND hwnd
, WPARAM wParam
, LPARAM lParam
)
1746 TAB_INFO
*infoPtr
= TAB_GetInfoPtr(hwnd
);
1752 if (infoPtr
->items
) {
1753 for (iItem
= 0; iItem
< infoPtr
->uNumItem
; iItem
++) {
1754 if (infoPtr
->items
[iItem
].pszText
)
1755 COMCTL32_Free (infoPtr
->items
[iItem
].pszText
);
1757 COMCTL32_Free (infoPtr
->items
);
1760 if (infoPtr
->hwndToolTip
)
1761 DestroyWindow (infoPtr
->hwndToolTip
);
1763 if (infoPtr
->hwndUpDown
)
1764 DestroyWindow(infoPtr
->hwndUpDown
);
1766 COMCTL32_Free (infoPtr
);
1770 static LRESULT WINAPI
1771 TAB_WindowProc (HWND hwnd
, UINT uMsg
, WPARAM wParam
, LPARAM lParam
)
1775 case TCM_GETIMAGELIST
:
1776 return TAB_GetImageList (hwnd
, wParam
, lParam
);
1778 case TCM_SETIMAGELIST
:
1779 return TAB_SetImageList (hwnd
, wParam
, lParam
);
1781 case TCM_GETITEMCOUNT
:
1782 return TAB_GetItemCount (hwnd
, wParam
, lParam
);
1785 return TAB_GetItemA (hwnd
, wParam
, lParam
);
1788 FIXME("Unimplemented msg TCM_GETITEMW\n");
1792 return TAB_SetItemA (hwnd
, wParam
, lParam
);
1795 FIXME("Unimplemented msg TCM_SETITEMW\n");
1798 case TCM_DELETEITEM
:
1799 return TAB_DeleteItem (hwnd
, wParam
, lParam
);
1801 case TCM_DELETEALLITEMS
:
1802 return TAB_DeleteAllItems (hwnd
, wParam
, lParam
);
1804 case TCM_GETITEMRECT
:
1805 return TAB_GetItemRect (hwnd
, wParam
, lParam
);
1808 return TAB_GetCurSel (hwnd
);
1811 return TAB_HitTest (hwnd
, wParam
, lParam
);
1814 return TAB_SetCurSel (hwnd
, wParam
);
1816 case TCM_INSERTITEMA
:
1817 return TAB_InsertItem (hwnd
, wParam
, lParam
);
1819 case TCM_INSERTITEMW
:
1820 FIXME("Unimplemented msg TCM_INSERTITEMW\n");
1823 case TCM_SETITEMEXTRA
:
1824 FIXME("Unimplemented msg TCM_SETITEMEXTRA\n");
1827 case TCM_ADJUSTRECT
:
1828 return TAB_AdjustRect (hwnd
, (BOOL
)wParam
, (LPRECT
)lParam
);
1830 case TCM_SETITEMSIZE
:
1831 return TAB_SetItemSize (hwnd
, wParam
, lParam
);
1833 case TCM_REMOVEIMAGE
:
1834 FIXME("Unimplemented msg TCM_REMOVEIMAGE\n");
1837 case TCM_SETPADDING
:
1838 FIXME("Unimplemented msg TCM_SETPADDING\n");
1841 case TCM_GETROWCOUNT
:
1842 FIXME("Unimplemented msg TCM_GETROWCOUNT\n");
1845 case TCM_GETUNICODEFORMAT
:
1846 FIXME("Unimplemented msg TCM_GETUNICODEFORMAT\n");
1849 case TCM_SETUNICODEFORMAT
:
1850 FIXME("Unimplemented msg TCM_SETUNICODEFORMAT\n");
1853 case TCM_HIGHLIGHTITEM
:
1854 FIXME("Unimplemented msg TCM_HIGHLIGHTITEM\n");
1857 case TCM_GETTOOLTIPS
:
1858 return TAB_GetToolTips (hwnd
, wParam
, lParam
);
1860 case TCM_SETTOOLTIPS
:
1861 return TAB_SetToolTips (hwnd
, wParam
, lParam
);
1863 case TCM_GETCURFOCUS
:
1864 return TAB_GetCurFocus (hwnd
);
1866 case TCM_SETCURFOCUS
:
1867 return TAB_SetCurFocus (hwnd
, wParam
);
1869 case TCM_SETMINTABWIDTH
:
1870 FIXME("Unimplemented msg TCM_SETMINTABWIDTH\n");
1873 case TCM_DESELECTALL
:
1874 FIXME("Unimplemented msg TCM_DESELECTALL\n");
1877 case TCM_GETEXTENDEDSTYLE
:
1878 FIXME("Unimplemented msg TCM_GETEXTENDEDSTYLE\n");
1881 case TCM_SETEXTENDEDSTYLE
:
1882 FIXME("Unimplemented msg TCM_SETEXTENDEDSTYLE\n");
1886 return TAB_GetFont (hwnd
, wParam
, lParam
);
1889 return TAB_SetFont (hwnd
, wParam
, lParam
);
1892 return TAB_Create (hwnd
, wParam
, lParam
);
1895 return TAB_Destroy (hwnd
, wParam
, lParam
);
1898 return DLGC_WANTARROWS
| DLGC_WANTCHARS
;
1900 case WM_LBUTTONDOWN
:
1901 return TAB_LButtonDown (hwnd
, wParam
, lParam
);
1904 return TAB_LButtonUp (hwnd
, wParam
, lParam
);
1906 case WM_RBUTTONDOWN
:
1907 return TAB_RButtonDown (hwnd
, wParam
, lParam
);
1910 return TAB_MouseMove (hwnd
, wParam
, lParam
);
1913 return TAB_EraseBackground (hwnd
, (HDC
)wParam
);
1916 return TAB_Paint (hwnd
, wParam
);
1919 return TAB_Size (hwnd
, wParam
, lParam
);
1922 return TAB_SetRedraw (hwnd
, wParam
);
1925 return TAB_OnHScroll(hwnd
, (int)LOWORD(wParam
), (int)HIWORD(wParam
), (HWND
)lParam
);
1927 case WM_STYLECHANGED
:
1928 TAB_SetItemBounds (hwnd
);
1929 InvalidateRect(hwnd
, NULL
, TRUE
);
1934 return TAB_FocusChanging(hwnd
, uMsg
, wParam
, lParam
);
1937 return TAB_KeyUp(hwnd
, wParam
);
1940 if (uMsg
>= WM_USER
)
1941 WARN("unknown msg %04x wp=%08x lp=%08lx\n",
1942 uMsg
, wParam
, lParam
);
1943 return DefWindowProcA (hwnd
, uMsg
, wParam
, lParam
);
1955 ZeroMemory (&wndClass
, sizeof(WNDCLASSA
));
1956 wndClass
.style
= CS_GLOBALCLASS
| CS_DBLCLKS
| CS_HREDRAW
| CS_VREDRAW
;
1957 wndClass
.lpfnWndProc
= (WNDPROC
)TAB_WindowProc
;
1958 wndClass
.cbClsExtra
= 0;
1959 wndClass
.cbWndExtra
= sizeof(TAB_INFO
*);
1960 wndClass
.hCursor
= LoadCursorA (0, IDC_ARROWA
);
1961 wndClass
.hbrBackground
= (HBRUSH
)NULL
;
1962 wndClass
.lpszClassName
= WC_TABCONTROLA
;
1964 RegisterClassA (&wndClass
);
1969 TAB_Unregister (void)
1971 UnregisterClassA (WC_TABCONTROLA
, (HINSTANCE
)NULL
);