ReactOS 0.4.16-dev-340-g0540c21
tab.c
Go to the documentation of this file.
1/*
2 * Tab control
3 *
4 * Copyright 1998 Anders Carlsson
5 * Copyright 1999 Alex Priem <alexp@sci.kun.nl>
6 * Copyright 1999 Francis Beaudet
7 * Copyright 2003 Vitaliy Margolen
8 *
9 * This library is free software; you can redistribute it and/or
10 * modify it under the terms of the GNU Lesser General Public
11 * License as published by the Free Software Foundation; either
12 * version 2.1 of the License, or (at your option) any later version.
13 *
14 * This library is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
17 * Lesser General Public License for more details.
18 *
19 * You should have received a copy of the GNU Lesser General Public
20 * License along with this library; if not, write to the Free Software
21 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
22 *
23 * NOTES
24 *
25 * This code was audited for completeness against the documented features
26 * of Comctl32.dll version 6.0 on May. 20, 2005, by James Hawkins.
27 *
28 * Unless otherwise noted, we believe this code to be complete, as per
29 * the specification mentioned above.
30 * If you discover missing features, or bugs, please note them below.
31 *
32 * TODO:
33 *
34 * Styles:
35 * TCS_MULTISELECT - implement for VK_SPACE selection
36 * TCS_RIGHT
37 * TCS_RIGHTJUSTIFY
38 * TCS_SCROLLOPPOSITE
39 * TCS_SINGLELINE
40 * TCIF_RTLREADING
41 *
42 * Extended Styles:
43 * TCS_EX_REGISTERDROP
44 *
45 * Notifications:
46 * NM_RELEASEDCAPTURE
47 * TCN_FOCUSCHANGE
48 * TCN_GETOBJECT
49 *
50 * Macros:
51 * TabCtrl_AdjustRect
52 *
53 */
54
55#include <assert.h>
56#include <stdarg.h>
57#include <string.h>
58
59#include "windef.h"
60#include "winbase.h"
61#include "wingdi.h"
62#include "winuser.h"
63#include "winnls.h"
64#include "commctrl.h"
65#include "comctl32.h"
66#include "uxtheme.h"
67#include "vssym32.h"
68#include "wine/debug.h"
69#include <math.h>
70
72
73typedef struct
74{
78 RECT rect; /* bounding rectangle of the item relative to the
79 * leftmost item (the leftmost item, 0, would have a
80 * "left" member of 0 in this rectangle)
81 *
82 * additionally the top member holds the row number
83 * and bottom is unused and should be 0 */
84 BYTE extra[1]; /* Space for caller supplied info, variable size */
85} TAB_ITEM;
86
87/* The size of a tab item depends on how much extra data is requested.
88 TCM_INSERTITEM always stores at least LPARAM sized data. */
89#define EXTRA_ITEM_SIZE(infoPtr) (max((infoPtr)->cbInfo, sizeof(LPARAM)))
90#define TAB_ITEM_SIZE(infoPtr) FIELD_OFFSET(TAB_ITEM, extra[EXTRA_ITEM_SIZE(infoPtr)])
91
92typedef struct
93{
94 HWND hwnd; /* Tab control window */
95 HWND hwndNotify; /* notification window (parent) */
96 UINT uNumItem; /* number of tab items */
97 UINT uNumRows; /* number of tab rows */
98 INT tabHeight; /* height of the tab row */
99 INT tabWidth; /* width of tabs */
100 INT tabMinWidth; /* minimum width of items */
101 USHORT uHItemPadding; /* amount of horizontal padding, in pixels */
102 USHORT uVItemPadding; /* amount of vertical padding, in pixels */
103 USHORT uHItemPadding_s; /* Set amount of horizontal padding, in pixels */
104 USHORT uVItemPadding_s; /* Set amount of vertical padding, in pixels */
105 HFONT hFont; /* handle to the current font */
106 HCURSOR hcurArrow; /* handle to the current cursor */
107 HIMAGELIST himl; /* handle to an image list (may be 0) */
108 HWND hwndToolTip; /* handle to tab's tooltip */
109 INT leftmostVisible; /* Used for scrolling, this member contains
110 * the index of the first visible item */
111 INT iSelected; /* the currently selected item */
112 INT iHotTracked; /* the highlighted item under the mouse */
113 INT uFocus; /* item which has the focus */
114 BOOL DoRedraw; /* flag for redrawing when tab contents is changed*/
115 BOOL needsScrolling; /* TRUE if the size of the tabs is greater than
116 * the size of the control */
117 BOOL fHeightSet; /* was the height of the tabs explicitly set? */
118 BOOL bUnicode; /* Unicode control? */
119 HWND hwndUpDown; /* Updown control used for scrolling */
120 INT cbInfo; /* Number of bytes of caller supplied info per tab */
121
122 DWORD exStyle; /* Extended style used, currently:
123 TCS_EX_FLATSEPARATORS, TCS_EX_REGISTERDROP */
124 DWORD dwStyle; /* the cached window GWL_STYLE */
125
126 HDPA items; /* dynamic array of TAB_ITEM* pointers */
127} TAB_INFO;
128
129/******************************************************************************
130 * Positioning constants
131 */
132#define SELECTED_TAB_OFFSET 2
133#define ROUND_CORNER_SIZE 2
134#define DISPLAY_AREA_PADDINGX 2
135#define DISPLAY_AREA_PADDINGY 2
136#define CONTROL_BORDER_SIZEX 2
137#define CONTROL_BORDER_SIZEY 2
138#define BUTTON_SPACINGX 3
139#define BUTTON_SPACINGY 3
140#define FLAT_BTN_SPACINGX 8
141#define DEFAULT_MIN_TAB_WIDTH 54
142#define DEFAULT_PADDING_X 6
143#define EXTRA_ICON_PADDING 3
144
145#define TAB_GetInfoPtr(hwnd) ((TAB_INFO *)GetWindowLongPtrW(hwnd,0))
146
147#define GET_DEFAULT_MIN_TAB_WIDTH(infoPtr) (DEFAULT_MIN_TAB_WIDTH - (DEFAULT_PADDING_X - (infoPtr)->uHItemPadding) * 2)
148
149/******************************************************************************
150 * Hot-tracking timer constants
151 */
152#define TAB_HOTTRACK_TIMER 1
153#define TAB_HOTTRACK_TIMER_INTERVAL 100 /* milliseconds */
154
155static const WCHAR themeClass[] = { 'T','a','b',0 };
156
157static inline TAB_ITEM* TAB_GetItem(const TAB_INFO *infoPtr, INT i)
158{
159 assert(i >= 0 && i < infoPtr->uNumItem);
160 return DPA_GetPtr(infoPtr->items, i);
161}
162
163/******************************************************************************
164 * Prototypes
165 */
166static void TAB_InvalidateTabArea(const TAB_INFO *);
168static void TAB_DrawItemInterior(const TAB_INFO *, HDC, INT, RECT*);
170static BOOL TAB_InternalGetItemRect(const TAB_INFO *, INT, RECT*, RECT*);
171
172static BOOL
174{
175 NMHDR nmhdr;
176
177 nmhdr.hwndFrom = infoPtr->hwnd;
178 nmhdr.idFrom = GetWindowLongPtrW(infoPtr->hwnd, GWLP_ID);
179 nmhdr.code = code;
180
181 return (BOOL) SendMessageW (infoPtr->hwndNotify, WM_NOTIFY,
182 nmhdr.idFrom, (LPARAM) &nmhdr);
183}
184
185static void
186TAB_RelayEvent (HWND hwndTip, HWND hwndMsg, UINT uMsg,
188{
189 MSG msg;
190
191 msg.hwnd = hwndMsg;
192 msg.message = uMsg;
193 msg.wParam = wParam;
194 msg.lParam = lParam;
195 msg.time = GetMessageTime ();
196 msg.pt.x = (short)LOWORD(GetMessagePos ());
197 msg.pt.y = (short)HIWORD(GetMessagePos ());
198
199 SendMessageW (hwndTip, TTM_RELAYEVENT, 0, (LPARAM)&msg);
200}
201
202static void
204{
205 if (TRACE_ON(tab)) {
206 TRACE("external tab %d, mask=0x%08x, dwState=0x%08x, dwStateMask=0x%08x, cchTextMax=0x%08x\n",
207 iItem, pti->mask, pti->dwState, pti->dwStateMask, pti->cchTextMax);
208 TRACE("external tab %d, iImage=%d, lParam=0x%08lx, pszTextW=%s\n",
209 iItem, pti->iImage, pti->lParam, isW ? debugstr_w(pti->pszText) : debugstr_a((LPSTR)pti->pszText));
210 }
211}
212
213static void
214TAB_DumpItemInternal(const TAB_INFO *infoPtr, UINT iItem)
215{
216 if (TRACE_ON(tab)) {
217 TAB_ITEM *ti = TAB_GetItem(infoPtr, iItem);
218
219 TRACE("tab %d, dwState=0x%08x, pszText=%s, iImage=%d\n",
220 iItem, ti->dwState, debugstr_w(ti->pszText), ti->iImage);
221 TRACE("tab %d, rect.left=%d, rect.top(row)=%d\n",
222 iItem, ti->rect.left, ti->rect.top);
223 }
224}
225
226/* RETURNS
227 * the index of the selected tab, or -1 if no tab is selected. */
228static inline LRESULT TAB_GetCurSel (const TAB_INFO *infoPtr)
229{
230 TRACE("(%p)\n", infoPtr);
231 return infoPtr->iSelected;
232}
233
234/* RETURNS
235 * the index of the tab item that has the focus. */
236static inline LRESULT
237TAB_GetCurFocus (const TAB_INFO *infoPtr)
238{
239 TRACE("(%p)\n", infoPtr);
240 return infoPtr->uFocus;
241}
242
243static inline LRESULT TAB_GetToolTips (const TAB_INFO *infoPtr)
244{
245 TRACE("(%p)\n", infoPtr);
246 return (LRESULT)infoPtr->hwndToolTip;
247}
248
249static inline LRESULT TAB_SetCurSel (TAB_INFO *infoPtr, INT iItem)
250{
251 INT prevItem = infoPtr->iSelected;
252
253 TRACE("(%p %d)\n", infoPtr, iItem);
254
255 if (iItem >= (INT)infoPtr->uNumItem)
256 return -1;
257
258 if (prevItem != iItem) {
259 if (prevItem != -1)
260 TAB_GetItem(infoPtr, prevItem)->dwState &= ~TCIS_BUTTONPRESSED;
261
262 if (iItem >= 0)
263 {
264 TAB_GetItem(infoPtr, iItem)->dwState |= TCIS_BUTTONPRESSED;
265 infoPtr->iSelected = iItem;
266 infoPtr->uFocus = iItem;
267 }
268 else
269 {
270 infoPtr->iSelected = -1;
271 infoPtr->uFocus = -1;
272 }
273
275 TAB_InvalidateTabArea(infoPtr);
276 }
277
278 return prevItem;
279}
280
281static LRESULT TAB_SetCurFocus (TAB_INFO *infoPtr, INT iItem)
282{
283 TRACE("(%p %d)\n", infoPtr, iItem);
284
285 if (iItem < 0) {
286 infoPtr->uFocus = -1;
287 if (infoPtr->iSelected != -1) {
288#ifdef __REACTOS__
289 TAB_GetItem(infoPtr, infoPtr->iSelected)->dwState &= ~TCIS_BUTTONPRESSED;
290#endif
291 infoPtr->iSelected = -1;
293 TAB_InvalidateTabArea(infoPtr);
294 }
295 }
296 else if (iItem < infoPtr->uNumItem) {
297 if (infoPtr->dwStyle & TCS_BUTTONS) {
298 /* set focus to new item, leave selection as is */
299 if (infoPtr->uFocus != iItem) {
300 INT prev_focus = infoPtr->uFocus;
301 RECT r;
302
303 infoPtr->uFocus = iItem;
304
305 if (prev_focus != infoPtr->iSelected) {
306 if (TAB_InternalGetItemRect(infoPtr, prev_focus, &r, NULL))
307 InvalidateRect(infoPtr->hwnd, &r, FALSE);
308 }
309
310 if (TAB_InternalGetItemRect(infoPtr, iItem, &r, NULL))
311 InvalidateRect(infoPtr->hwnd, &r, FALSE);
312
314 }
315 } else {
316#ifdef __REACTOS__
317 INT oldItem = infoPtr->iSelected;
318#endif
319 INT oldFocus = infoPtr->uFocus;
320 if (infoPtr->iSelected != iItem || oldFocus == -1 ) {
321 infoPtr->uFocus = iItem;
322 if (oldFocus != -1) {
323 if (!TAB_SendSimpleNotify(infoPtr, TCN_SELCHANGING)) {
324#ifdef __REACTOS__
325 if (oldItem != -1)
326 TAB_GetItem(infoPtr, oldItem)->dwState &= ~TCIS_BUTTONPRESSED;
327#endif
328 infoPtr->iSelected = iItem;
329#ifdef __REACTOS__
330 TAB_GetItem(infoPtr, iItem)->dwState |= TCIS_BUTTONPRESSED;
331#endif
333 }
334 else
335 infoPtr->iSelected = iItem;
337 TAB_InvalidateTabArea(infoPtr);
338 }
339 }
340 }
341 }
342 return 0;
343}
344
345static inline LRESULT
346TAB_SetToolTips (TAB_INFO *infoPtr, HWND hwndToolTip)
347{
348 TRACE("%p %p\n", infoPtr, hwndToolTip);
349 infoPtr->hwndToolTip = hwndToolTip;
350 return 0;
351}
352
353static inline LRESULT
355{
356 TRACE("(%p %d %d)\n", infoPtr, LOWORD(lParam), HIWORD(lParam));
357 infoPtr->uHItemPadding_s = LOWORD(lParam);
358 infoPtr->uVItemPadding_s = HIWORD(lParam);
359
360 return 0;
361}
362
363/******************************************************************************
364 * TAB_InternalGetItemRect
365 *
366 * This method will calculate the rectangle representing a given tab item in
367 * client coordinates. This method takes scrolling into account.
368 *
369 * This method returns TRUE if the item is visible in the window and FALSE
370 * if it is completely outside the client area.
371 */
373 const TAB_INFO* infoPtr,
374 INT itemIndex,
375 RECT* itemRect,
376 RECT* selectedRect)
377{
378 RECT tmpItemRect,clientRect;
379
380 /* Perform a sanity check and a trivial visibility check. */
381 if ( (infoPtr->uNumItem <= 0) ||
382 (itemIndex >= infoPtr->uNumItem) ||
383 (!(((infoPtr->dwStyle & TCS_MULTILINE) || (infoPtr->dwStyle & TCS_VERTICAL))) &&
384 (itemIndex < infoPtr->leftmostVisible)))
385 {
386 TRACE("Not Visible\n");
387 SetRect(itemRect, 0, 0, 0, infoPtr->tabHeight);
388 SetRectEmpty(selectedRect);
389 return FALSE;
390 }
391
392 /*
393 * Avoid special cases in this procedure by assigning the "out"
394 * parameters if the caller didn't supply them
395 */
396 if (itemRect == NULL)
397 itemRect = &tmpItemRect;
398
399 /* Retrieve the unmodified item rect. */
400 *itemRect = TAB_GetItem(infoPtr,itemIndex)->rect;
401
402 /* calculate the times bottom and top based on the row */
403 GetClientRect(infoPtr->hwnd, &clientRect);
404
405 if ((infoPtr->dwStyle & TCS_BOTTOM) && (infoPtr->dwStyle & TCS_VERTICAL))
406 {
407 itemRect->right = clientRect.right - SELECTED_TAB_OFFSET - itemRect->left * infoPtr->tabHeight -
408 ((infoPtr->dwStyle & TCS_BUTTONS) ? itemRect->left * BUTTON_SPACINGX : 0);
409 itemRect->left = itemRect->right - infoPtr->tabHeight;
410 }
411 else if (infoPtr->dwStyle & TCS_VERTICAL)
412 {
413 itemRect->left = clientRect.left + SELECTED_TAB_OFFSET + itemRect->left * infoPtr->tabHeight +
414 ((infoPtr->dwStyle & TCS_BUTTONS) ? itemRect->left * BUTTON_SPACINGX : 0);
415 itemRect->right = itemRect->left + infoPtr->tabHeight;
416 }
417 else if (infoPtr->dwStyle & TCS_BOTTOM)
418 {
419 itemRect->bottom = clientRect.bottom - itemRect->top * infoPtr->tabHeight -
420 ((infoPtr->dwStyle & TCS_BUTTONS) ? itemRect->top * BUTTON_SPACINGY : SELECTED_TAB_OFFSET);
421 itemRect->top = itemRect->bottom - infoPtr->tabHeight;
422 }
423 else /* not TCS_BOTTOM and not TCS_VERTICAL */
424 {
425 itemRect->top = clientRect.top + itemRect->top * infoPtr->tabHeight +
426 ((infoPtr->dwStyle & TCS_BUTTONS) ? itemRect->top * BUTTON_SPACINGY : SELECTED_TAB_OFFSET);
427 itemRect->bottom = itemRect->top + infoPtr->tabHeight;
428 }
429
430 /*
431 * "scroll" it to make sure the item at the very left of the
432 * tab control is the leftmost visible tab.
433 */
434 if(infoPtr->dwStyle & TCS_VERTICAL)
435 {
436 OffsetRect(itemRect,
437 0,
438 -TAB_GetItem(infoPtr, infoPtr->leftmostVisible)->rect.top);
439
440 /*
441 * Move the rectangle so the first item is slightly offset from
442 * the bottom of the tab control.
443 */
444 OffsetRect(itemRect,
445 0,
447
448 } else
449 {
450 OffsetRect(itemRect,
451 -TAB_GetItem(infoPtr, infoPtr->leftmostVisible)->rect.left,
452 0);
453
454 /*
455 * Move the rectangle so the first item is slightly offset from
456 * the left of the tab control.
457 */
458 OffsetRect(itemRect,
460 0);
461 }
462 TRACE("item %d tab h=%d, rect=(%s)\n",
463 itemIndex, infoPtr->tabHeight, wine_dbgstr_rect(itemRect));
464
465 /* Now, calculate the position of the item as if it were selected. */
466 if (selectedRect!=NULL)
467 {
468 *selectedRect = *itemRect;
469
470 /* The rectangle of a selected item is a bit wider. */
471 if(infoPtr->dwStyle & TCS_VERTICAL)
472 InflateRect(selectedRect, 0, SELECTED_TAB_OFFSET);
473 else
474 InflateRect(selectedRect, SELECTED_TAB_OFFSET, 0);
475
476 /* If it also a bit higher. */
477 if ((infoPtr->dwStyle & TCS_BOTTOM) && (infoPtr->dwStyle & TCS_VERTICAL))
478 {
479 selectedRect->left -= 2; /* the border is thicker on the right */
480 selectedRect->right += SELECTED_TAB_OFFSET;
481 }
482 else if (infoPtr->dwStyle & TCS_VERTICAL)
483 {
484 selectedRect->left -= SELECTED_TAB_OFFSET;
485 selectedRect->right += 1;
486 }
487 else if (infoPtr->dwStyle & TCS_BOTTOM)
488 {
489 selectedRect->bottom += SELECTED_TAB_OFFSET;
490 }
491 else /* not TCS_BOTTOM and not TCS_VERTICAL */
492 {
493 selectedRect->top -= SELECTED_TAB_OFFSET;
494 selectedRect->bottom -= 1;
495 }
496 }
497
498 /* Check for visibility */
499 if (infoPtr->dwStyle & TCS_VERTICAL)
500 return (itemRect->top < clientRect.bottom) && (itemRect->bottom > clientRect.top);
501 else
502 return (itemRect->left < clientRect.right) && (itemRect->right > clientRect.left);
503}
504
505static inline BOOL
507{
508 TRACE("(%p, %d, %p)\n", infoPtr, item, rect);
509 return TAB_InternalGetItemRect(infoPtr, item, rect, NULL);
510}
511
512/******************************************************************************
513 * TAB_KeyDown
514 *
515 * This method is called to handle keyboard input
516 */
517static LRESULT TAB_KeyDown(TAB_INFO* infoPtr, WPARAM keyCode, LPARAM lParam)
518{
519 INT newItem = -1;
520 NMTCKEYDOWN nm;
521
522 /* TCN_KEYDOWN notification sent always */
523 nm.hdr.hwndFrom = infoPtr->hwnd;
524 nm.hdr.idFrom = GetWindowLongPtrW(infoPtr->hwnd, GWLP_ID);
525 nm.hdr.code = TCN_KEYDOWN;
526 nm.wVKey = keyCode;
527 nm.flags = lParam;
528 SendMessageW(infoPtr->hwndNotify, WM_NOTIFY, nm.hdr.idFrom, (LPARAM)&nm);
529
530 switch (keyCode)
531 {
532 case VK_LEFT:
533 newItem = infoPtr->uFocus - 1;
534 break;
535 case VK_RIGHT:
536 newItem = infoPtr->uFocus + 1;
537 break;
538 }
539
540 /* If we changed to a valid item, change focused item */
541 if (newItem >= 0 && newItem < infoPtr->uNumItem && infoPtr->uFocus != newItem)
542 TAB_SetCurFocus(infoPtr, newItem);
543
544 return 0;
545}
546
547/*
548 * WM_KILLFOCUS handler
549 */
550static void TAB_KillFocus(TAB_INFO *infoPtr)
551{
552 /* clear current focused item back to selected for TCS_BUTTONS */
553 if ((infoPtr->dwStyle & TCS_BUTTONS) && (infoPtr->uFocus != infoPtr->iSelected))
554 {
555 RECT r;
556
557 if (TAB_InternalGetItemRect(infoPtr, infoPtr->uFocus, &r, NULL))
558 InvalidateRect(infoPtr->hwnd, &r, FALSE);
559
560 infoPtr->uFocus = infoPtr->iSelected;
561 }
562}
563
564/******************************************************************************
565 * TAB_FocusChanging
566 *
567 * This method is called whenever the focus goes in or out of this control
568 * it is used to update the visual state of the control.
569 */
570static void TAB_FocusChanging(const TAB_INFO *infoPtr)
571{
572 RECT selectedRect;
573 BOOL isVisible;
574
575 /*
576 * Get the rectangle for the item.
577 */
578 isVisible = TAB_InternalGetItemRect(infoPtr,
579 infoPtr->uFocus,
580 NULL,
581 &selectedRect);
582
583 /*
584 * If the rectangle is not completely invisible, invalidate that
585 * portion of the window.
586 */
587 if (isVisible)
588 {
589 TRACE("invalidate (%s)\n", wine_dbgstr_rect(&selectedRect));
590 InvalidateRect(infoPtr->hwnd, &selectedRect, TRUE);
591 }
592}
593
595{
596 RECT rect;
597 INT iCount;
598
599 for (iCount = 0; iCount < infoPtr->uNumItem; iCount++)
600 {
601 TAB_InternalGetItemRect(infoPtr, iCount, &rect, NULL);
602
603 if (PtInRect(&rect, pt))
604 {
606 return iCount;
607 }
608 }
609
611 return -1;
612}
613
614static inline LRESULT
615TAB_HitTest (const TAB_INFO *infoPtr, LPTCHITTESTINFO lptest)
616{
617 TRACE("(%p, %p)\n", infoPtr, lptest);
618 return TAB_InternalHitTest (infoPtr, lptest->pt, &lptest->flags);
619}
620
621/******************************************************************************
622 * TAB_NCHitTest
623 *
624 * Napster v2b5 has a tab control for its main navigation which has a client
625 * area that covers the whole area of the dialog pages.
626 * That's why it receives all msgs for that area and the underlying dialog ctrls
627 * are dead.
628 * So I decided that we should handle WM_NCHITTEST here and return
629 * HTTRANSPARENT if we don't hit the tab control buttons.
630 * FIXME: WM_NCHITTEST handling correct ? Fix it if you know that Windows
631 * doesn't do it that way. Maybe depends on tab control styles ?
632 */
633static inline LRESULT
635{
636 POINT pt;
637 UINT dummyflag;
638
639 pt.x = (short)LOWORD(lParam);
640 pt.y = (short)HIWORD(lParam);
641 ScreenToClient(infoPtr->hwnd, &pt);
642
643 if (TAB_InternalHitTest(infoPtr, pt, &dummyflag) == -1)
644 return HTTRANSPARENT;
645 else
646 return HTCLIENT;
647}
648
649static LRESULT
651{
652 POINT pt;
653 INT newItem;
654 UINT dummy;
655
656 if (infoPtr->hwndToolTip)
657 TAB_RelayEvent (infoPtr->hwndToolTip, infoPtr->hwnd,
659
660 if (!(infoPtr->dwStyle & TCS_FOCUSNEVER)) {
661 SetFocus (infoPtr->hwnd);
662 }
663
664 if (infoPtr->hwndToolTip)
665 TAB_RelayEvent (infoPtr->hwndToolTip, infoPtr->hwnd,
667
668 pt.x = (short)LOWORD(lParam);
669 pt.y = (short)HIWORD(lParam);
670
671 newItem = TAB_InternalHitTest (infoPtr, pt, &dummy);
672
673 TRACE("On Tab, item %d\n", newItem);
674
675 if ((newItem != -1) && (infoPtr->iSelected != newItem))
676 {
677 if ((infoPtr->dwStyle & TCS_BUTTONS) && (infoPtr->dwStyle & TCS_MULTISELECT) &&
678 (wParam & MK_CONTROL))
679 {
680 RECT r;
681
682 /* toggle multiselection */
683 TAB_GetItem(infoPtr, newItem)->dwState ^= TCIS_BUTTONPRESSED;
684 if (TAB_InternalGetItemRect (infoPtr, newItem, &r, NULL))
685 InvalidateRect (infoPtr->hwnd, &r, TRUE);
686 }
687 else
688 {
689 INT i;
690 BOOL pressed = FALSE;
691
692 /* any button pressed ? */
693 for (i = 0; i < infoPtr->uNumItem; i++)
694 if ((TAB_GetItem (infoPtr, i)->dwState & TCIS_BUTTONPRESSED) &&
695 (infoPtr->iSelected != i))
696 {
697 pressed = TRUE;
698 break;
699 }
700
702 return 0;
703
704 if (pressed)
705 TAB_DeselectAll (infoPtr, FALSE);
706 else
707 TAB_SetCurSel(infoPtr, newItem);
708
710 }
711 }
712
713 return 0;
714}
715
716static inline LRESULT
717TAB_LButtonUp (const TAB_INFO *infoPtr)
718{
720
721 return 0;
722}
723
724static inline void
725TAB_RButtonUp (const TAB_INFO *infoPtr)
726{
728}
729
730/******************************************************************************
731 * TAB_DrawLoneItemInterior
732 *
733 * This calls TAB_DrawItemInterior. However, TAB_DrawItemInterior is normally
734 * called by TAB_DrawItem which is normally called by TAB_Refresh which sets
735 * up the device context and font. This routine does the same setup but
736 * only calls TAB_DrawItemInterior for the single specified item.
737 */
738static void
739TAB_DrawLoneItemInterior(const TAB_INFO* infoPtr, int iItem)
740{
741 HDC hdc = GetDC(infoPtr->hwnd);
742 RECT r, rC;
743
744 /* Clip UpDown control to not draw over it */
745 if (infoPtr->needsScrolling)
746 {
747 GetWindowRect(infoPtr->hwnd, &rC);
748 GetWindowRect(infoPtr->hwndUpDown, &r);
749 ExcludeClipRect(hdc, r.left - rC.left, r.top - rC.top, r.right - rC.left, r.bottom - rC.top);
750 }
751 TAB_DrawItemInterior(infoPtr, hdc, iItem, NULL);
752 ReleaseDC(infoPtr->hwnd, hdc);
753}
754
755/* update a tab after hottracking - invalidate it or just redraw the interior,
756 * based on whether theming is used or not */
757static inline void hottrack_refresh(const TAB_INFO *infoPtr, int tabIndex)
758{
759 if (tabIndex == -1) return;
760
761 if (GetWindowTheme (infoPtr->hwnd))
762 {
763 RECT rect;
764 TAB_InternalGetItemRect(infoPtr, tabIndex, &rect, NULL);
765 InvalidateRect (infoPtr->hwnd, &rect, FALSE);
766 }
767 else
768 TAB_DrawLoneItemInterior(infoPtr, tabIndex);
769}
770
771/******************************************************************************
772 * TAB_HotTrackTimerProc
773 *
774 * When a mouse-move event causes a tab to be highlighted (hot-tracking), a
775 * timer is setup so we can check if the mouse is moved out of our window.
776 * (We don't get an event when the mouse leaves, the mouse-move events just
777 * stop being delivered to our window and just start being delivered to
778 * another window.) This function is called when the timer triggers so
779 * we can check if the mouse has left our window. If so, we un-highlight
780 * the hot-tracked tab.
781 */
782static void CALLBACK
784 (
785 HWND hwnd, /* handle of window for timer messages */
786 UINT uMsg, /* WM_TIMER message */
787 UINT_PTR idEvent, /* timer identifier */
788 DWORD dwTime /* current system time */
789 )
790{
791 TAB_INFO* infoPtr = TAB_GetInfoPtr(hwnd);
792
793 if (infoPtr != NULL && infoPtr->iHotTracked >= 0)
794 {
795 POINT pt;
796
797 /*
798 ** If we can't get the cursor position, or if the cursor is outside our
799 ** window, we un-highlight the hot-tracked tab. Note that the cursor is
800 ** "outside" even if it is within our bounding rect if another window
801 ** overlaps. Note also that the case where the cursor stayed within our
802 ** window but has moved off the hot-tracked tab will be handled by the
803 ** WM_MOUSEMOVE event.
804 */
805 if (!GetCursorPos(&pt) || WindowFromPoint(pt) != hwnd)
806 {
807 /* Redraw iHotTracked to look normal */
808 INT iRedraw = infoPtr->iHotTracked;
809 infoPtr->iHotTracked = -1;
810 hottrack_refresh (infoPtr, iRedraw);
811
812 /* Kill this timer */
814 }
815 }
816}
817
818/******************************************************************************
819 * TAB_RecalcHotTrack
820 *
821 * If a tab control has the TCS_HOTTRACK style, then the tab under the mouse
822 * should be highlighted. This function determines which tab in a tab control,
823 * if any, is under the mouse and records that information. The caller may
824 * supply output parameters to receive the item number of the tab item which
825 * was highlighted but isn't any longer and of the tab item which is now
826 * highlighted but wasn't previously. The caller can use this information to
827 * selectively redraw those tab items.
828 *
829 * If the caller has a mouse position, it can supply it through the pos
830 * parameter. For example, TAB_MouseMove does this. Otherwise, the caller
831 * supplies NULL and this function determines the current mouse position
832 * itself.
833 */
834static void
836 (
837 TAB_INFO* infoPtr,
838 const LPARAM* pos,
839 int* out_redrawLeave,
840 int* out_redrawEnter
841 )
842{
843 int item = -1;
844
845
846 if (out_redrawLeave != NULL)
847 *out_redrawLeave = -1;
848 if (out_redrawEnter != NULL)
849 *out_redrawEnter = -1;
850
851 if ((infoPtr->dwStyle & TCS_HOTTRACK) || GetWindowTheme(infoPtr->hwnd))
852 {
853 POINT pt;
854 UINT flags;
855
856 if (pos == NULL)
857 {
859 ScreenToClient(infoPtr->hwnd, &pt);
860 }
861 else
862 {
863 pt.x = (short)LOWORD(*pos);
864 pt.y = (short)HIWORD(*pos);
865 }
866
867 item = TAB_InternalHitTest(infoPtr, pt, &flags);
868 }
869
870 if (item != infoPtr->iHotTracked)
871 {
872 if (infoPtr->iHotTracked >= 0)
873 {
874 /* Mark currently hot-tracked to be redrawn to look normal */
875 if (out_redrawLeave != NULL)
876 *out_redrawLeave = infoPtr->iHotTracked;
877
878 if (item < 0)
879 {
880 /* Kill timer which forces recheck of mouse pos */
882 }
883 }
884 else
885 {
886 /* Start timer so we recheck mouse pos */
887 UINT timerID = SetTimer
888 (
889 infoPtr->hwnd,
893 );
894
895 if (timerID == 0)
896 return; /* Hot tracking not available */
897 }
898
899 infoPtr->iHotTracked = item;
900
901 if (item >= 0)
902 {
903 /* Mark new hot-tracked to be redrawn to look highlighted */
904 if (out_redrawEnter != NULL)
905 *out_redrawEnter = item;
906 }
907 }
908}
909
910/******************************************************************************
911 * TAB_MouseMove
912 *
913 * Handles the mouse-move event. Updates tooltips. Updates hot-tracking.
914 */
915static LRESULT
917{
918 int redrawLeave;
919 int redrawEnter;
920
921 if (infoPtr->hwndToolTip)
922 TAB_RelayEvent (infoPtr->hwndToolTip, infoPtr->hwnd,
924
925 /* Determine which tab to highlight. Redraw tabs which change highlight
926 ** status. */
927 TAB_RecalcHotTrack(infoPtr, &lParam, &redrawLeave, &redrawEnter);
928
929 hottrack_refresh (infoPtr, redrawLeave);
930 hottrack_refresh (infoPtr, redrawEnter);
931
932 return 0;
933}
934
935/******************************************************************************
936 * TAB_AdjustRect
937 *
938 * Calculates the tab control's display area given the window rectangle or
939 * the window rectangle given the requested display rectangle.
940 */
941static LRESULT TAB_AdjustRect(const TAB_INFO *infoPtr, WPARAM fLarger, LPRECT prc)
942{
943 LONG *iRightBottom, *iLeftTop;
944
945 TRACE ("hwnd=%p fLarger=%ld (%s)\n", infoPtr->hwnd, fLarger,
947
948 if (!prc) return -1;
949
950 if(infoPtr->dwStyle & TCS_VERTICAL)
951 {
952 iRightBottom = &(prc->right);
953 iLeftTop = &(prc->left);
954 }
955 else
956 {
957 iRightBottom = &(prc->bottom);
958 iLeftTop = &(prc->top);
959 }
960
961 if (fLarger) /* Go from display rectangle */
962 {
963 /* Add the height of the tabs. */
964 if (infoPtr->dwStyle & TCS_BOTTOM)
965 *iRightBottom += infoPtr->tabHeight * infoPtr->uNumRows;
966 else
967 *iLeftTop -= infoPtr->tabHeight * infoPtr->uNumRows +
968 ((infoPtr->dwStyle & TCS_BUTTONS)? 3 * (infoPtr->uNumRows - 1) : 0);
969
970 /* Inflate the rectangle for the padding */
972
973 /* Inflate for the border */
975 }
976 else /* Go from window rectangle. */
977 {
978 /* Deflate the rectangle for the border */
980
981 /* Deflate the rectangle for the padding */
983
984 /* Remove the height of the tabs. */
985 if (infoPtr->dwStyle & TCS_BOTTOM)
986 *iRightBottom -= infoPtr->tabHeight * infoPtr->uNumRows;
987 else
988 *iLeftTop += (infoPtr->tabHeight) * infoPtr->uNumRows +
989 ((infoPtr->dwStyle & TCS_BUTTONS)? 3 * (infoPtr->uNumRows - 1) : 0);
990 }
991
992 return 0;
993}
994
995/******************************************************************************
996 * TAB_OnHScroll
997 *
998 * This method will handle the notification from the scroll control and
999 * perform the scrolling operation on the tab control.
1000 */
1001static LRESULT TAB_OnHScroll(TAB_INFO *infoPtr, int nScrollCode, int nPos)
1002{
1003 if(nScrollCode == SB_THUMBPOSITION && nPos != infoPtr->leftmostVisible)
1004 {
1005 if(nPos < infoPtr->leftmostVisible)
1006 infoPtr->leftmostVisible--;
1007 else
1008 infoPtr->leftmostVisible++;
1009
1010 TAB_RecalcHotTrack(infoPtr, NULL, NULL, NULL);
1011 TAB_InvalidateTabArea(infoPtr);
1012 SendMessageW(infoPtr->hwndUpDown, UDM_SETPOS, 0,
1013 MAKELONG(infoPtr->leftmostVisible, 0));
1014 }
1015
1016 return 0;
1017}
1018
1019/******************************************************************************
1020 * TAB_SetupScrolling
1021 *
1022 * This method will check the current scrolling state and make sure the
1023 * scrolling control is displayed (or not).
1024 */
1026 TAB_INFO* infoPtr,
1027 const RECT* clientRect)
1028{
1029 static const WCHAR emptyW[] = { 0 };
1030 INT maxRange = 0;
1031
1032 if (infoPtr->needsScrolling)
1033 {
1034 RECT controlPos;
1035 INT vsize, tabwidth;
1036
1037 /*
1038 * Calculate the position of the scroll control.
1039 */
1040 controlPos.right = clientRect->right;
1041 controlPos.left = controlPos.right - 2 * GetSystemMetrics(SM_CXHSCROLL);
1042
1043 if (infoPtr->dwStyle & TCS_BOTTOM)
1044 {
1045 controlPos.top = clientRect->bottom - infoPtr->tabHeight;
1046 controlPos.bottom = controlPos.top + GetSystemMetrics(SM_CYHSCROLL);
1047 }
1048 else
1049 {
1050 controlPos.bottom = clientRect->top + infoPtr->tabHeight;
1051 controlPos.top = controlPos.bottom - GetSystemMetrics(SM_CYHSCROLL);
1052 }
1053
1054 /*
1055 * If we don't have a scroll control yet, we want to create one.
1056 * If we have one, we want to make sure it's positioned properly.
1057 */
1058 if (infoPtr->hwndUpDown==0)
1059 {
1062 controlPos.left, controlPos.top,
1063 controlPos.right - controlPos.left,
1064 controlPos.bottom - controlPos.top,
1065 infoPtr->hwnd, NULL, NULL, NULL);
1066 }
1067 else
1068 {
1069 SetWindowPos(infoPtr->hwndUpDown,
1070 NULL,
1071 controlPos.left, controlPos.top,
1072 controlPos.right - controlPos.left,
1073 controlPos.bottom - controlPos.top,
1075 }
1076
1077 /* Now calculate upper limit of the updown control range.
1078 * We do this by calculating how many tabs will be offscreen when the
1079 * last tab is visible.
1080 */
1081 if(infoPtr->uNumItem)
1082 {
1083 vsize = clientRect->right - (controlPos.right - controlPos.left + 1);
1084 maxRange = infoPtr->uNumItem;
1085 tabwidth = TAB_GetItem(infoPtr, infoPtr->uNumItem - 1)->rect.right;
1086
1087 for(; maxRange > 0; maxRange--)
1088 {
1089 if(tabwidth - TAB_GetItem(infoPtr,maxRange - 1)->rect.left > vsize)
1090 break;
1091 }
1092
1093 if(maxRange == infoPtr->uNumItem)
1094 maxRange--;
1095 }
1096 }
1097 else
1098 {
1099 /* If we once had a scroll control... hide it */
1100 if (infoPtr->hwndUpDown)
1101 ShowWindow(infoPtr->hwndUpDown, SW_HIDE);
1102 }
1103 if (infoPtr->hwndUpDown)
1104 SendMessageW(infoPtr->hwndUpDown, UDM_SETRANGE32, 0, maxRange);
1105}
1106
1107/******************************************************************************
1108 * TAB_SetItemBounds
1109 *
1110 * This method will calculate the position rectangles of all the items in the
1111 * control. The rectangle calculated starts at 0 for the first item in the
1112 * list and ignores scrolling and selection.
1113 * It also uses the current font to determine the height of the tab row and
1114 * it checks if all the tabs fit in the client area of the window. If they
1115 * don't, a scrolling control is added.
1116 */
1117static void TAB_SetItemBounds (TAB_INFO *infoPtr)
1118{
1119 TEXTMETRICW fontMetrics;
1120 UINT curItem;
1121 INT curItemLeftPos;
1122 INT curItemRowCount;
1123 HFONT hFont, hOldFont;
1124 HDC hdc;
1125 RECT clientRect;
1126 INT iTemp;
1127 RECT* rcItem;
1128 INT iIndex;
1129 INT icon_width = 0;
1130
1131 /*
1132 * We need to get text information so we need a DC and we need to select
1133 * a font.
1134 */
1135 hdc = GetDC(infoPtr->hwnd);
1136
1137 hFont = infoPtr->hFont ? infoPtr->hFont : GetStockObject (SYSTEM_FONT);
1138 hOldFont = SelectObject (hdc, hFont);
1139
1140 /*
1141 * We will base the rectangle calculations on the client rectangle
1142 * of the control.
1143 */
1144 GetClientRect(infoPtr->hwnd, &clientRect);
1145
1146 /* if TCS_VERTICAL then swap the height and width so this code places the
1147 tabs along the top of the rectangle and we can just rotate them after
1148 rather than duplicate all of the below code */
1149 if(infoPtr->dwStyle & TCS_VERTICAL)
1150 {
1151 iTemp = clientRect.bottom;
1152 clientRect.bottom = clientRect.right;
1153 clientRect.right = iTemp;
1154 }
1155
1156 /* Now use hPadding and vPadding */
1157 infoPtr->uHItemPadding = infoPtr->uHItemPadding_s;
1158 infoPtr->uVItemPadding = infoPtr->uVItemPadding_s;
1159
1160 /* The leftmost item will be "0" aligned */
1161 curItemLeftPos = 0;
1162 curItemRowCount = infoPtr->uNumItem ? 1 : 0;
1163
1164 if (!(infoPtr->fHeightSet))
1165 {
1166 int item_height;
1167 INT icon_height = 0, cx;
1168
1169 /* Use the current font to determine the height of a tab. */
1170 GetTextMetricsW(hdc, &fontMetrics);
1171
1172 /* Get the icon height */
1173 if (infoPtr->himl)
1174 ImageList_GetIconSize(infoPtr->himl, &cx, &icon_height);
1175
1176 /* Take the highest between font or icon */
1177 if (fontMetrics.tmHeight > icon_height)
1178 item_height = fontMetrics.tmHeight + 2;
1179 else
1180 item_height = icon_height;
1181
1182 /*
1183 * Make sure there is enough space for the letters + icon + growing the
1184 * selected item + extra space for the selected item.
1185 */
1186 infoPtr->tabHeight = item_height +
1187 ((infoPtr->dwStyle & TCS_BUTTONS) ? 2 : 1) *
1188 infoPtr->uVItemPadding;
1189
1190 TRACE("tabH=%d, tmH=%d, iconh=%d\n",
1191 infoPtr->tabHeight, fontMetrics.tmHeight, icon_height);
1192 }
1193
1194 TRACE("client right=%d\n", clientRect.right);
1195
1196 /* Get the icon width */
1197 if (infoPtr->himl)
1198 {
1199 INT cy;
1200
1201 ImageList_GetIconSize(infoPtr->himl, &icon_width, &cy);
1202
1203 if (infoPtr->dwStyle & TCS_FIXEDWIDTH)
1204 icon_width += 4;
1205 else
1206 /* Add padding if icon is present */
1207 icon_width += infoPtr->uHItemPadding;
1208 }
1209
1210 for (curItem = 0; curItem < infoPtr->uNumItem; curItem++)
1211 {
1212 TAB_ITEM *curr = TAB_GetItem(infoPtr, curItem);
1213
1214 /* Set the leftmost position of the tab. */
1215 curr->rect.left = curItemLeftPos;
1216
1217 if (infoPtr->dwStyle & TCS_FIXEDWIDTH)
1218 {
1219 curr->rect.right = curr->rect.left +
1220 max(infoPtr->tabWidth, icon_width);
1221 }
1222 else if (!curr->pszText)
1223 {
1224 /* If no text use minimum tab width including padding. */
1225 if (infoPtr->tabMinWidth < 0)
1226 curr->rect.right = curr->rect.left + GET_DEFAULT_MIN_TAB_WIDTH(infoPtr);
1227 else
1228 {
1229 curr->rect.right = curr->rect.left + infoPtr->tabMinWidth;
1230
1231 /* Add extra padding if icon is present */
1232 if (infoPtr->himl && infoPtr->tabMinWidth > 0 && infoPtr->tabMinWidth < DEFAULT_MIN_TAB_WIDTH
1233 && infoPtr->uHItemPadding > 1)
1234 curr->rect.right += EXTRA_ICON_PADDING * (infoPtr->uHItemPadding-1);
1235 }
1236 }
1237 else
1238 {
1239 int tabwidth;
1240 SIZE size;
1241 /* Calculate how wide the tab is depending on the text it contains */
1243 lstrlenW(curr->pszText), &size);
1244
1245 tabwidth = size.cx + icon_width + 2 * infoPtr->uHItemPadding;
1246
1247 if (infoPtr->tabMinWidth < 0)
1248 tabwidth = max(tabwidth, GET_DEFAULT_MIN_TAB_WIDTH(infoPtr));
1249 else
1250 tabwidth = max(tabwidth, infoPtr->tabMinWidth);
1251
1252 curr->rect.right = curr->rect.left + tabwidth;
1253 TRACE("for <%s>, rect %s\n", debugstr_w(curr->pszText), wine_dbgstr_rect(&curr->rect));
1254 }
1255
1256 /*
1257 * Check if this is a multiline tab control and if so
1258 * check to see if we should wrap the tabs
1259 *
1260 * Wrap all these tabs. We will arrange them evenly later.
1261 *
1262 */
1263
1264 if (((infoPtr->dwStyle & TCS_MULTILINE) || (infoPtr->dwStyle & TCS_VERTICAL)) &&
1265 (curr->rect.right >
1267 {
1268 curr->rect.right -= curr->rect.left;
1269
1270 curr->rect.left = 0;
1271 curItemRowCount++;
1272 TRACE("wrapping <%s>, rect %s\n", debugstr_w(curr->pszText), wine_dbgstr_rect(&curr->rect));
1273 }
1274
1275 curr->rect.bottom = 0;
1276 curr->rect.top = curItemRowCount - 1;
1277
1278 TRACE("Rect: %s\n", wine_dbgstr_rect(&curr->rect));
1279
1280 /*
1281 * The leftmost position of the next item is the rightmost position
1282 * of this one.
1283 */
1284 if (infoPtr->dwStyle & TCS_BUTTONS)
1285 {
1286 curItemLeftPos = curr->rect.right + BUTTON_SPACINGX;
1287 if (infoPtr->dwStyle & TCS_FLATBUTTONS)
1288 curItemLeftPos += FLAT_BTN_SPACINGX;
1289 }
1290 else
1291 curItemLeftPos = curr->rect.right;
1292 }
1293
1294 if (!((infoPtr->dwStyle & TCS_MULTILINE) || (infoPtr->dwStyle & TCS_VERTICAL)))
1295 {
1296 /*
1297 * Check if we need a scrolling control.
1298 */
1299 infoPtr->needsScrolling = (curItemLeftPos + (2 * SELECTED_TAB_OFFSET) >
1300 clientRect.right);
1301
1302 /* Don't need scrolling, then update infoPtr->leftmostVisible */
1303 if(!infoPtr->needsScrolling)
1304 infoPtr->leftmostVisible = 0;
1305 }
1306 else
1307 {
1308 /*
1309 * No scrolling in Multiline or Vertical styles.
1310 */
1311 infoPtr->needsScrolling = FALSE;
1312 infoPtr->leftmostVisible = 0;
1313 }
1314 TAB_SetupScrolling(infoPtr, &clientRect);
1315
1316 /* Set the number of rows */
1317 infoPtr->uNumRows = curItemRowCount;
1318
1319 /* Arrange all tabs evenly if style says so */
1320 if (!(infoPtr->dwStyle & TCS_RAGGEDRIGHT) &&
1321 ((infoPtr->dwStyle & TCS_MULTILINE) || (infoPtr->dwStyle & TCS_VERTICAL)) &&
1322 (infoPtr->uNumItem > 0) &&
1323 (infoPtr->uNumRows > 1))
1324 {
1325 INT tabPerRow,remTab,iRow;
1326 UINT iItm;
1327 INT iCount=0;
1328
1329 /*
1330 * Ok windows tries to even out the rows. place the same
1331 * number of tabs in each row. So lets give that a shot
1332 */
1333
1334 tabPerRow = infoPtr->uNumItem / (infoPtr->uNumRows);
1335 remTab = infoPtr->uNumItem % (infoPtr->uNumRows);
1336
1337 for (iItm=0,iRow=0,iCount=0,curItemLeftPos=0;
1338 iItm<infoPtr->uNumItem;
1339 iItm++,iCount++)
1340 {
1341 /* normalize the current rect */
1342 TAB_ITEM *curr = TAB_GetItem(infoPtr, iItm);
1343
1344 /* shift the item to the left side of the clientRect */
1345 curr->rect.right -= curr->rect.left;
1346 curr->rect.left = 0;
1347
1348 TRACE("r=%d, cl=%d, cl.r=%d, iCount=%d, iRow=%d, uNumRows=%d, remTab=%d, tabPerRow=%d\n",
1349 curr->rect.right, curItemLeftPos, clientRect.right,
1350 iCount, iRow, infoPtr->uNumRows, remTab, tabPerRow);
1351
1352 /* if we have reached the maximum number of tabs on this row */
1353 /* move to the next row, reset our current item left position and */
1354 /* the count of items on this row */
1355
1356 if (infoPtr->dwStyle & TCS_VERTICAL) {
1357 /* Vert: Add the remaining tabs in the *last* remainder rows */
1358 if (iCount >= ((iRow>=(INT)infoPtr->uNumRows - remTab)?tabPerRow + 1:tabPerRow)) {
1359 iRow++;
1360 curItemLeftPos = 0;
1361 iCount = 0;
1362 }
1363 } else {
1364 /* Horz: Add the remaining tabs in the *first* remainder rows */
1365 if (iCount >= ((iRow<remTab)?tabPerRow + 1:tabPerRow)) {
1366 iRow++;
1367 curItemLeftPos = 0;
1368 iCount = 0;
1369 }
1370 }
1371
1372 /* shift the item to the right to place it as the next item in this row */
1373 curr->rect.left += curItemLeftPos;
1374 curr->rect.right += curItemLeftPos;
1375 curr->rect.top = iRow;
1376 if (infoPtr->dwStyle & TCS_BUTTONS)
1377 {
1378 curItemLeftPos = curr->rect.right + 1;
1379 if (infoPtr->dwStyle & TCS_FLATBUTTONS)
1380 curItemLeftPos += FLAT_BTN_SPACINGX;
1381 }
1382 else
1383 curItemLeftPos = curr->rect.right;
1384
1385 TRACE("arranging <%s>, rect %s\n", debugstr_w(curr->pszText), wine_dbgstr_rect(&curr->rect));
1386 }
1387
1388 /*
1389 * Justify the rows
1390 */
1391 {
1392 INT widthDiff, iIndexStart=0, iIndexEnd=0;
1393 INT remainder;
1394 INT iCount=0;
1395
1396 while(iIndexStart < infoPtr->uNumItem)
1397 {
1398 TAB_ITEM *start = TAB_GetItem(infoPtr, iIndexStart);
1399
1400 /*
1401 * find the index of the row
1402 */
1403 /* find the first item on the next row */
1404 for (iIndexEnd=iIndexStart;
1405 (iIndexEnd < infoPtr->uNumItem) &&
1406 (TAB_GetItem(infoPtr, iIndexEnd)->rect.top ==
1407 start->rect.top) ;
1408 iIndexEnd++)
1409 /* intentionally blank */;
1410
1411 /*
1412 * we need to justify these tabs so they fill the whole given
1413 * client area
1414 *
1415 */
1416 /* find the amount of space remaining on this row */
1417 widthDiff = clientRect.right - (2 * SELECTED_TAB_OFFSET) -
1418 TAB_GetItem(infoPtr, iIndexEnd - 1)->rect.right;
1419
1420 /* iCount is the number of tab items on this row */
1421 iCount = iIndexEnd - iIndexStart;
1422
1423 if (iCount > 1)
1424 {
1425 remainder = widthDiff % iCount;
1426 widthDiff = widthDiff / iCount;
1427 /* add widthDiff/iCount, or extra space/items on row, to each item on this row */
1428 for (iIndex=iIndexStart, iCount=0; iIndex < iIndexEnd; iIndex++, iCount++)
1429 {
1430 TAB_ITEM *item = TAB_GetItem(infoPtr, iIndex);
1431
1432 item->rect.left += iCount * widthDiff;
1433 item->rect.right += (iCount + 1) * widthDiff;
1434
1435 TRACE("adjusting 1 <%s>, rect %s\n", debugstr_w(item->pszText), wine_dbgstr_rect(&item->rect));
1436
1437 }
1438 TAB_GetItem(infoPtr, iIndex - 1)->rect.right += remainder;
1439 }
1440 else /* we have only one item on this row, make it take up the entire row */
1441 {
1442 start->rect.left = clientRect.left;
1443 start->rect.right = clientRect.right - 4;
1444
1445 TRACE("adjusting 2 <%s>, rect %s\n", debugstr_w(start->pszText), wine_dbgstr_rect(&start->rect));
1446 }
1447
1448 iIndexStart = iIndexEnd;
1449 }
1450 }
1451 }
1452
1453 /* if TCS_VERTICAL rotate the tabs so they are along the side of the clientRect */
1454 if(infoPtr->dwStyle & TCS_VERTICAL)
1455 {
1456 RECT rcOriginal;
1457 for(iIndex = 0; iIndex < infoPtr->uNumItem; iIndex++)
1458 {
1459 rcItem = &TAB_GetItem(infoPtr, iIndex)->rect;
1460
1461 rcOriginal = *rcItem;
1462
1463 /* this is rotating the items by 90 degrees clockwise around the center of the control */
1464 rcItem->top = (rcOriginal.left - clientRect.left);
1465 rcItem->bottom = rcItem->top + (rcOriginal.right - rcOriginal.left);
1466 rcItem->left = rcOriginal.top;
1467 rcItem->right = rcOriginal.bottom;
1468 }
1469 }
1470
1472 TAB_RecalcHotTrack(infoPtr, NULL, NULL, NULL);
1473
1474 /* Cleanup */
1475 SelectObject (hdc, hOldFont);
1476 ReleaseDC (infoPtr->hwnd, hdc);
1477}
1478
1479
1480static void
1481TAB_EraseTabInterior(const TAB_INFO *infoPtr, HDC hdc, INT iItem, const RECT *drawRect)
1482{
1484 BOOL deleteBrush = TRUE;
1485 RECT rTemp = *drawRect;
1486
1487 if (infoPtr->dwStyle & TCS_BUTTONS)
1488 {
1489 if (iItem == infoPtr->iSelected)
1490 {
1491 /* Background color */
1492 if (!(infoPtr->dwStyle & TCS_OWNERDRAWFIXED))
1493 {
1494 DeleteObject(hbr);
1496
1499
1500 /* if COLOR_WINDOW happens to be the same as COLOR_3DHILIGHT
1501 * we better use 0x55aa bitmap brush to make scrollbar's background
1502 * look different from the window background.
1503 */
1506
1507 deleteBrush = FALSE;
1508 }
1509 FillRect(hdc, &rTemp, hbr);
1510 }
1511 else /* ! selected */
1512 {
1513 if (infoPtr->dwStyle & TCS_FLATBUTTONS)
1514 {
1515 InflateRect(&rTemp, 2, 2);
1516 FillRect(hdc, &rTemp, hbr);
1517 if (iItem == infoPtr->iHotTracked ||
1518 (iItem != infoPtr->iSelected && iItem == infoPtr->uFocus))
1520 }
1521 else
1522 FillRect(hdc, &rTemp, hbr);
1523 }
1524
1525 }
1526 else /* !TCS_BUTTONS */
1527 {
1528 InflateRect(&rTemp, -2, -2);
1529 if (!GetWindowTheme (infoPtr->hwnd))
1530 FillRect(hdc, &rTemp, hbr);
1531 }
1532
1533 /* highlighting is drawn on top of previous fills */
1534 if (TAB_GetItem(infoPtr, iItem)->dwState & TCIS_HIGHLIGHTED)
1535 {
1536 if (deleteBrush)
1537 {
1538 DeleteObject(hbr);
1539 deleteBrush = FALSE;
1540 }
1542 FillRect(hdc, &rTemp, hbr);
1543 }
1544
1545 /* Cleanup */
1546 if (deleteBrush) DeleteObject(hbr);
1547}
1548
1549/******************************************************************************
1550 * TAB_DrawItemInterior
1551 *
1552 * This method is used to draw the interior (text and icon) of a single tab
1553 * into the tab control.
1554 */
1555static void
1556TAB_DrawItemInterior(const TAB_INFO *infoPtr, HDC hdc, INT iItem, RECT *drawRect)
1557{
1558 RECT localRect;
1559
1560 HPEN htextPen;
1561 HPEN holdPen;
1562 INT oldBkMode;
1563 HFONT hOldFont;
1564#ifdef __REACTOS__
1565HTHEME theme = GetWindowTheme (infoPtr->hwnd);
1566#endif
1567
1568/* if (drawRect == NULL) */
1569 {
1570 BOOL isVisible;
1571 RECT itemRect;
1572 RECT selectedRect;
1573
1574 /*
1575 * Get the rectangle for the item.
1576 */
1577 isVisible = TAB_InternalGetItemRect(infoPtr, iItem, &itemRect, &selectedRect);
1578 if (!isVisible)
1579 return;
1580
1581 /*
1582 * Make sure drawRect points to something valid; simplifies code.
1583 */
1584 drawRect = &localRect;
1585
1586 /*
1587 * This logic copied from the part of TAB_DrawItem which draws
1588 * the tab background. It's important to keep it in sync. I
1589 * would have liked to avoid code duplication, but couldn't figure
1590 * out how without making spaghetti of TAB_DrawItem.
1591 */
1592 if (iItem == infoPtr->iSelected)
1593 *drawRect = selectedRect;
1594 else
1595 *drawRect = itemRect;
1596
1597 if (infoPtr->dwStyle & TCS_BUTTONS)
1598 {
1599 if (iItem == infoPtr->iSelected)
1600 {
1601 drawRect->left += 4;
1602 drawRect->top += 4;
1603 drawRect->right -= 4;
1604
1605 if (infoPtr->dwStyle & TCS_VERTICAL)
1606 {
1607 if (!(infoPtr->dwStyle & TCS_BOTTOM)) drawRect->right += 1;
1608 drawRect->bottom -= 4;
1609 }
1610 else
1611 {
1612 if (infoPtr->dwStyle & TCS_BOTTOM)
1613 {
1614 drawRect->top -= 2;
1615 drawRect->bottom -= 4;
1616 }
1617 else
1618 drawRect->bottom -= 1;
1619 }
1620 }
1621 else
1622 InflateRect(drawRect, -2, -2);
1623 }
1624 else
1625 {
1626 if ((infoPtr->dwStyle & TCS_VERTICAL) && (infoPtr->dwStyle & TCS_BOTTOM))
1627 {
1628 if (iItem != infoPtr->iSelected)
1629 {
1630 drawRect->left += 2;
1631 InflateRect(drawRect, 0, -2);
1632 }
1633 }
1634 else if (infoPtr->dwStyle & TCS_VERTICAL)
1635 {
1636 if (iItem == infoPtr->iSelected)
1637 {
1638 drawRect->right += 1;
1639 }
1640 else
1641 {
1642 drawRect->right -= 2;
1643 InflateRect(drawRect, 0, -2);
1644 }
1645 }
1646 else if (infoPtr->dwStyle & TCS_BOTTOM)
1647 {
1648 if (iItem == infoPtr->iSelected)
1649 {
1650 drawRect->top -= 2;
1651 }
1652 else
1653 {
1654 InflateRect(drawRect, -2, -2);
1655 drawRect->bottom += 2;
1656 }
1657 }
1658 else
1659 {
1660 if (iItem == infoPtr->iSelected)
1661 {
1662 drawRect->bottom += 3;
1663 }
1664 else
1665 {
1666 drawRect->bottom -= 2;
1667 InflateRect(drawRect, -2, 0);
1668 }
1669 }
1670 }
1671 }
1672 TRACE("drawRect=(%s)\n", wine_dbgstr_rect(drawRect));
1673
1674 /* Clear interior */
1675 TAB_EraseTabInterior (infoPtr, hdc, iItem, drawRect);
1676
1677 /* Draw the focus rectangle */
1678 if (!(infoPtr->dwStyle & TCS_FOCUSNEVER) &&
1679 (GetFocus() == infoPtr->hwnd) &&
1680 (iItem == infoPtr->uFocus) )
1681 {
1682 RECT rFocus = *drawRect;
1683
1684 if (!(infoPtr->dwStyle & TCS_BUTTONS)) InflateRect(&rFocus, -3, -3);
1685 if (infoPtr->dwStyle & TCS_BOTTOM && !(infoPtr->dwStyle & TCS_VERTICAL))
1686 rFocus.top -= 3;
1687
1688 /* focus should stay on selected item for TCS_BUTTONS style */
1689 if (!((infoPtr->dwStyle & TCS_BUTTONS) && (infoPtr->iSelected != iItem)))
1690 DrawFocusRect(hdc, &rFocus);
1691 }
1692
1693 /*
1694 * Text pen
1695 */
1696 htextPen = CreatePen( PS_SOLID, 1, comctl32_color.clrBtnText );
1697 holdPen = SelectObject(hdc, htextPen);
1698 hOldFont = SelectObject(hdc, infoPtr->hFont);
1699
1700 /*
1701 * Setup for text output
1702 */
1703 oldBkMode = SetBkMode(hdc, TRANSPARENT);
1704 if (!GetWindowTheme (infoPtr->hwnd) || (infoPtr->dwStyle & TCS_BUTTONS))
1705 {
1706 if ((infoPtr->dwStyle & TCS_HOTTRACK) && (iItem == infoPtr->iHotTracked) &&
1707 !(infoPtr->dwStyle & TCS_FLATBUTTONS))
1709 else if (TAB_GetItem(infoPtr, iItem)->dwState & TCIS_HIGHLIGHTED)
1711 else
1713 }
1714
1715 /*
1716 * if owner draw, tell the owner to draw
1717 */
1718 if ((infoPtr->dwStyle & TCS_OWNERDRAWFIXED) && IsWindow(infoPtr->hwndNotify))
1719 {
1720 DRAWITEMSTRUCT dis;
1721 UINT id;
1722
1723 drawRect->top += 2;
1724 drawRect->right -= 1;
1725 if ( iItem == infoPtr->iSelected )
1726 InflateRect(drawRect, -1, 0);
1727
1728 id = (UINT)GetWindowLongPtrW( infoPtr->hwnd, GWLP_ID );
1729
1730 /* fill DRAWITEMSTRUCT */
1731 dis.CtlType = ODT_TAB;
1732 dis.CtlID = id;
1733 dis.itemID = iItem;
1735 dis.itemState = 0;
1736 if ( iItem == infoPtr->iSelected )
1737 dis.itemState |= ODS_SELECTED;
1738 if (infoPtr->uFocus == iItem)
1739 dis.itemState |= ODS_FOCUS;
1740 dis.hwndItem = infoPtr->hwnd;
1741 dis.hDC = hdc;
1742 dis.rcItem = *drawRect;
1743
1744 /* when extra data fits ULONG_PTR, store it directly */
1745 if (infoPtr->cbInfo > sizeof(LPARAM))
1746 dis.itemData = (ULONG_PTR) TAB_GetItem(infoPtr, iItem)->extra;
1747 else
1748 {
1749 /* this could be considered broken on 64 bit, but that's how it works -
1750 only first 4 bytes are copied */
1751 dis.itemData = 0;
1752 memcpy(&dis.itemData, (ULONG_PTR*)TAB_GetItem(infoPtr, iItem)->extra, 4);
1753 }
1754
1755 /* draw notification */
1756 SendMessageW( infoPtr->hwndNotify, WM_DRAWITEM, id, (LPARAM)&dis );
1757 }
1758 else
1759 {
1760 TAB_ITEM *item = TAB_GetItem(infoPtr, iItem);
1761 RECT rcTemp;
1762 RECT rcImage;
1763
1764 /* used to center the icon and text in the tab */
1765 RECT rcText;
1766 INT center_offset_h, center_offset_v;
1767
1768 /* set rcImage to drawRect, we will use top & left in our ImageList_Draw call */
1769 rcImage = *drawRect;
1770
1771 rcTemp = *drawRect;
1772 SetRectEmpty(&rcText);
1773
1774 /* get the rectangle that the text fits in */
1775 if (item->pszText)
1776 {
1777 DrawTextW(hdc, item->pszText, -1, &rcText, DT_CALCRECT);
1778 }
1779 /*
1780 * If not owner draw, then do the drawing ourselves.
1781 *
1782 * Draw the icon.
1783 */
1784 if (infoPtr->himl && item->iImage != -1)
1785 {
1786 INT cx;
1787 INT cy;
1788
1789 ImageList_GetIconSize(infoPtr->himl, &cx, &cy);
1790
1791 if(infoPtr->dwStyle & TCS_VERTICAL)
1792 {
1793 center_offset_h = ((drawRect->bottom - drawRect->top) - (cy + infoPtr->uHItemPadding + (rcText.right - rcText.left))) / 2;
1794 center_offset_v = ((drawRect->right - drawRect->left) - cx) / 2;
1795 }
1796 else
1797 {
1798 center_offset_h = ((drawRect->right - drawRect->left) - (cx + infoPtr->uHItemPadding + (rcText.right - rcText.left))) / 2;
1799 center_offset_v = ((drawRect->bottom - drawRect->top) - cy) / 2;
1800 }
1801
1802 /* if an item is selected, the icon is shifted up instead of down */
1803 if (iItem == infoPtr->iSelected)
1804 center_offset_v -= infoPtr->uVItemPadding / 2;
1805 else
1806 center_offset_v += infoPtr->uVItemPadding / 2;
1807
1808 if (infoPtr->dwStyle & TCS_FIXEDWIDTH && infoPtr->dwStyle & (TCS_FORCELABELLEFT | TCS_FORCEICONLEFT))
1809 center_offset_h = infoPtr->uHItemPadding;
1810
1811 if (center_offset_h < 2)
1812 center_offset_h = 2;
1813
1814 if (center_offset_v < 0)
1815 center_offset_v = 0;
1816
1817 TRACE("for <%s>, c_o_h=%d, c_o_v=%d, draw=(%s), textlen=%d\n",
1818 debugstr_w(item->pszText), center_offset_h, center_offset_v,
1819 wine_dbgstr_rect(drawRect), (rcText.right-rcText.left));
1820
1821 if((infoPtr->dwStyle & TCS_VERTICAL) && (infoPtr->dwStyle & TCS_BOTTOM))
1822 {
1823 rcImage.top = drawRect->top + center_offset_h;
1824 /* if tab is TCS_VERTICAL and TCS_BOTTOM, the text is drawn from the */
1825 /* right side of the tab, but the image still uses the left as its x position */
1826 /* this keeps the image always drawn off of the same side of the tab */
1827 rcImage.left = drawRect->right - cx - center_offset_v;
1828 drawRect->top += cy + infoPtr->uHItemPadding;
1829 }
1830 else if(infoPtr->dwStyle & TCS_VERTICAL)
1831 {
1832 rcImage.top = drawRect->bottom - cy - center_offset_h;
1833 rcImage.left = drawRect->left + center_offset_v;
1834 drawRect->bottom -= cy + infoPtr->uHItemPadding;
1835 }
1836 else /* normal style, whether TCS_BOTTOM or not */
1837 {
1838 rcImage.left = drawRect->left + center_offset_h;
1839 rcImage.top = drawRect->top + center_offset_v;
1840 drawRect->left += cx + infoPtr->uHItemPadding;
1841 }
1842
1843 TRACE("drawing image=%d, left=%d, top=%d\n",
1844 item->iImage, rcImage.left, rcImage.top-1);
1846 (
1847 infoPtr->himl,
1848 item->iImage,
1849 hdc,
1850 rcImage.left,
1851 rcImage.top,
1853 );
1854 }
1855
1856 /* Now position text */
1857 if (infoPtr->dwStyle & TCS_FIXEDWIDTH && infoPtr->dwStyle & TCS_FORCELABELLEFT)
1858 center_offset_h = infoPtr->uHItemPadding;
1859 else
1860 if(infoPtr->dwStyle & TCS_VERTICAL)
1861 center_offset_h = ((drawRect->bottom - drawRect->top) - (rcText.right - rcText.left)) / 2;
1862 else
1863 center_offset_h = ((drawRect->right - drawRect->left) - (rcText.right - rcText.left)) / 2;
1864
1865 if(infoPtr->dwStyle & TCS_VERTICAL)
1866 {
1867 if(infoPtr->dwStyle & TCS_BOTTOM)
1868 drawRect->top+=center_offset_h;
1869 else
1870 drawRect->bottom-=center_offset_h;
1871
1872 center_offset_v = ((drawRect->right - drawRect->left) - (rcText.bottom - rcText.top)) / 2;
1873 }
1874 else
1875 {
1876 drawRect->left += center_offset_h;
1877 center_offset_v = ((drawRect->bottom - drawRect->top) - (rcText.bottom - rcText.top)) / 2;
1878 }
1879
1880 /* if an item is selected, the text is shifted up instead of down */
1881 if (iItem == infoPtr->iSelected)
1882 center_offset_v -= infoPtr->uVItemPadding / 2;
1883 else
1884 center_offset_v += infoPtr->uVItemPadding / 2;
1885
1886 if (center_offset_v < 0)
1887 center_offset_v = 0;
1888
1889 if(infoPtr->dwStyle & TCS_VERTICAL)
1890 drawRect->left += center_offset_v;
1891 else
1892 drawRect->top += center_offset_v;
1893
1894 /* Draw the text */
1895 if(infoPtr->dwStyle & TCS_VERTICAL) /* if we are vertical rotate the text and each character */
1896 {
1897 LOGFONTW logfont;
1898 HFONT hFont;
1899 INT nEscapement = 900;
1900 INT nOrientation = 900;
1901
1902 if(infoPtr->dwStyle & TCS_BOTTOM)
1903 {
1904 nEscapement = -900;
1905 nOrientation = -900;
1906 }
1907
1908 /* to get a font with the escapement and orientation we are looking for, we need to */
1909 /* call CreateFontIndirect, which requires us to set the values of the logfont we pass in */
1910 if (!GetObjectW(infoPtr->hFont, sizeof(logfont), &logfont))
1911 GetObjectW(GetStockObject(DEFAULT_GUI_FONT), sizeof(logfont), &logfont);
1912
1913 logfont.lfEscapement = nEscapement;
1914 logfont.lfOrientation = nOrientation;
1915 hFont = CreateFontIndirectW(&logfont);
1917
1918 if (item->pszText)
1919 {
1921 (infoPtr->dwStyle & TCS_BOTTOM) ? drawRect->right : drawRect->left,
1922 (!(infoPtr->dwStyle & TCS_BOTTOM)) ? drawRect->bottom : drawRect->top,
1924 drawRect,
1925 item->pszText,
1926 lstrlenW(item->pszText),
1927 0);
1928 }
1929
1931 }
1932 else
1933 {
1934 TRACE("for <%s>, c_o_h=%d, c_o_v=%d, draw=(%s), textlen=%d\n",
1935 debugstr_w(item->pszText), center_offset_h, center_offset_v,
1936 wine_dbgstr_rect(drawRect), (rcText.right-rcText.left));
1937#ifdef __REACTOS__
1938 if (theme && item->pszText)
1939 {
1940 int partIndex = iItem == infoPtr->iSelected ? TABP_TABITEM : TABP_TOPTABITEM;
1941 int stateId = TIS_NORMAL;
1942
1943 if (iItem == infoPtr->iSelected)
1944 stateId = TIS_SELECTED;
1945 else if (iItem == infoPtr->iHotTracked)
1946 stateId = TIS_HOT;
1947 else if (iItem == infoPtr->uFocus)
1948 stateId = TIS_FOCUSED;
1949
1950 DrawThemeText(theme,
1951 hdc,
1952 partIndex,
1953 stateId,
1954 item->pszText,
1955 lstrlenW(item->pszText),
1956 DT_LEFT | DT_SINGLELINE, 0, drawRect);
1957 }
1958 else
1959#endif
1960 if (item->pszText)
1961 {
1962 DrawTextW
1963 (
1964 hdc,
1965 item->pszText,
1966 lstrlenW(item->pszText),
1967 drawRect,
1969 );
1970 }
1971 }
1972
1973 *drawRect = rcTemp; /* restore drawRect */
1974 }
1975
1976 /*
1977 * Cleanup
1978 */
1979 SelectObject(hdc, hOldFont);
1980 SetBkMode(hdc, oldBkMode);
1981 SelectObject(hdc, holdPen);
1982 DeleteObject( htextPen );
1983}
1984
1985/******************************************************************************
1986 * TAB_DrawItem
1987 *
1988 * This method is used to draw a single tab into the tab control.
1989 */
1990static void TAB_DrawItem(const TAB_INFO *infoPtr, HDC hdc, INT iItem)
1991{
1992 RECT itemRect;
1993 RECT selectedRect;
1994 BOOL isVisible;
1995 RECT r, fillRect, r1;
1996 INT clRight = 0;
1997 INT clBottom = 0;
1998 COLORREF bkgnd, corner;
1999 HTHEME theme;
2000
2001 /*
2002 * Get the rectangle for the item.
2003 */
2004 isVisible = TAB_InternalGetItemRect(infoPtr,
2005 iItem,
2006 &itemRect,
2007 &selectedRect);
2008
2009 if (isVisible)
2010 {
2011 RECT rUD, rC;
2012
2013 /* Clip UpDown control to not draw over it */
2014 if (infoPtr->needsScrolling)
2015 {
2016 GetWindowRect(infoPtr->hwnd, &rC);
2017 GetWindowRect(infoPtr->hwndUpDown, &rUD);
2018 ExcludeClipRect(hdc, rUD.left - rC.left, rUD.top - rC.top, rUD.right - rC.left, rUD.bottom - rC.top);
2019 }
2020
2021 /* If you need to see what the control is doing,
2022 * then override these variables. They will change what
2023 * fill colors are used for filling the tabs, and the
2024 * corners when drawing the edge.
2025 */
2026 bkgnd = comctl32_color.clrBtnFace;
2027 corner = comctl32_color.clrBtnFace;
2028
2029 if (infoPtr->dwStyle & TCS_BUTTONS)
2030 {
2031 /* Get item rectangle */
2032 r = itemRect;
2033
2034 /* Separators between flat buttons */
2035 if ((infoPtr->dwStyle & TCS_FLATBUTTONS) && (infoPtr->exStyle & TCS_EX_FLATSEPARATORS))
2036 {
2037 r1 = r;
2038 r1.right += (FLAT_BTN_SPACINGX -2);
2040 }
2041
2042 if (iItem == infoPtr->iSelected)
2043 {
2045
2046 OffsetRect(&r, 1, 1);
2047 }
2048 else /* ! selected */
2049 {
2050 DWORD state = TAB_GetItem(infoPtr, iItem)->dwState;
2051
2052 if ((state & TCIS_BUTTONPRESSED) || (iItem == infoPtr->uFocus))
2054 else
2055 if (!(infoPtr->dwStyle & TCS_FLATBUTTONS))
2057 }
2058 }
2059 else /* !TCS_BUTTONS */
2060 {
2061 /* We draw a rectangle of different sizes depending on the selection
2062 * state. */
2063 if (iItem == infoPtr->iSelected) {
2064 RECT rect;
2065 GetClientRect (infoPtr->hwnd, &rect);
2066 clRight = rect.right;
2067 clBottom = rect.bottom;
2068 r = selectedRect;
2069 }
2070 else
2071 r = itemRect;
2072
2073 /*
2074 * Erase the background. (Delay it but setup rectangle.)
2075 * This is necessary when drawing the selected item since it is larger
2076 * than the others, it might overlap with stuff already drawn by the
2077 * other tabs
2078 */
2079 fillRect = r;
2080
2081 /* Draw themed tabs - but only if they are at the top.
2082 * Windows draws even side or bottom tabs themed, with wacky results.
2083 * However, since in Wine apps may get themed that did not opt in via
2084 * a manifest avoid theming when we know the result will be wrong */
2085 if ((theme = GetWindowTheme (infoPtr->hwnd))
2086 && ((infoPtr->dwStyle & (TCS_VERTICAL | TCS_BOTTOM)) == 0))
2087 {
2088 static const int partIds[8] = {
2089 /* Normal item */
2094 /* Selected tab */
2099 };
2100 int partIndex = 0;
2101 int stateId = TIS_NORMAL;
2102
2103 /* selected and unselected tabs have different parts */
2104 if (iItem == infoPtr->iSelected)
2105 partIndex += 4;
2106 /* The part also differs on the position of a tab on a line.
2107 * "Visually" determining the position works well enough. */
2108 GetClientRect(infoPtr->hwnd, &r1);
2109 if(selectedRect.left == 0)
2110 partIndex += 1;
2111 if(selectedRect.right == r1.right)
2112 partIndex += 2;
2113
2114 if (iItem == infoPtr->iSelected)
2115 stateId = TIS_SELECTED;
2116 else if (iItem == infoPtr->iHotTracked)
2117 stateId = TIS_HOT;
2118 else if (iItem == infoPtr->uFocus)
2119 stateId = TIS_FOCUSED;
2120
2121 /* Adjust rectangle for bottommost row */
2122 if (TAB_GetItem(infoPtr, iItem)->rect.top == infoPtr->uNumRows-1)
2123 r.bottom += 3;
2124
2125 DrawThemeBackground (theme, hdc, partIds[partIndex], stateId, &r, NULL);
2126 GetThemeBackgroundContentRect (theme, hdc, partIds[partIndex], stateId, &r, &r);
2127 }
2128 else if(infoPtr->dwStyle & TCS_VERTICAL)
2129 {
2130 /* These are for adjusting the drawing of a Selected tab */
2131 /* The initial values are for the normal case of non-Selected */
2132 int ZZ = 1; /* Do not stretch if selected */
2133 if (iItem == infoPtr->iSelected) {
2134 ZZ = 0;
2135
2136 /* if leftmost draw the line longer */
2137 if(selectedRect.top == 0)
2138 fillRect.top += CONTROL_BORDER_SIZEY;
2139 /* if rightmost draw the line longer */
2140 if(selectedRect.bottom == clBottom)
2141 fillRect.bottom -= CONTROL_BORDER_SIZEY;
2142 }
2143
2144 if (infoPtr->dwStyle & TCS_BOTTOM)
2145 {
2146 /* Adjust both rectangles to match native */
2147 r.left += (1-ZZ);
2148
2149 TRACE("<right> item=%d, fill=(%s), edge=(%s)\n",
2150 iItem, wine_dbgstr_rect(&fillRect), wine_dbgstr_rect(&r));
2151
2152 /* Clear interior */
2153 SetBkColor(hdc, bkgnd);
2154 ExtTextOutW(hdc, 0, 0, 2, &fillRect, NULL, 0, 0);
2155
2156 /* Draw rectangular edge around tab */
2158
2159 /* Now erase the top corner and draw diagonal edge */
2160 SetBkColor(hdc, corner);
2161 r1.left = r.right - ROUND_CORNER_SIZE - 1;
2162 r1.top = r.top;
2163 r1.right = r.right;
2164 r1.bottom = r1.top + ROUND_CORNER_SIZE;
2165 ExtTextOutW(hdc, 0, 0, 2, &r1, NULL, 0, 0);
2166 r1.right--;
2168
2169 /* Now erase the bottom corner and draw diagonal edge */
2170 r1.left = r.right - ROUND_CORNER_SIZE - 1;
2171 r1.bottom = r.bottom;
2172 r1.right = r.right;
2173 r1.top = r1.bottom - ROUND_CORNER_SIZE;
2174 ExtTextOutW(hdc, 0, 0, 2, &r1, NULL, 0, 0);
2175 r1.right--;
2177
2178 if ((iItem == infoPtr->iSelected) && (selectedRect.top == 0)) {
2179 r1 = r;
2180 r1.right = r1.left;
2181 r1.left--;
2183 }
2184
2185 }
2186 else
2187 {
2188 TRACE("<left> item=%d, fill=(%s), edge=(%s)\n",
2189 iItem, wine_dbgstr_rect(&fillRect), wine_dbgstr_rect(&r));
2190
2191 /* Clear interior */
2192 SetBkColor(hdc, bkgnd);
2193 ExtTextOutW(hdc, 0, 0, 2, &fillRect, NULL, 0, 0);
2194
2195 /* Draw rectangular edge around tab */
2197
2198 /* Now erase the top corner and draw diagonal edge */
2199 SetBkColor(hdc, corner);
2200 r1.left = r.left;
2201 r1.top = r.top;
2202 r1.right = r1.left + ROUND_CORNER_SIZE + 1;
2203 r1.bottom = r1.top + ROUND_CORNER_SIZE;
2204 ExtTextOutW(hdc, 0, 0, 2, &r1, NULL, 0, 0);
2205 r1.left++;
2207
2208 /* Now erase the bottom corner and draw diagonal edge */
2209 r1.left = r.left;
2210 r1.bottom = r.bottom;
2211 r1.right = r1.left + ROUND_CORNER_SIZE + 1;
2212 r1.top = r1.bottom - ROUND_CORNER_SIZE;
2213 ExtTextOutW(hdc, 0, 0, 2, &r1, NULL, 0, 0);
2214 r1.left++;
2216 }
2217 }
2218 else /* ! TCS_VERTICAL */
2219 {
2220 /* These are for adjusting the drawing of a Selected tab */
2221 /* The initial values are for the normal case of non-Selected */
2222 if (iItem == infoPtr->iSelected) {
2223 /* if leftmost draw the line longer */
2224 if(selectedRect.left == 0)
2225 fillRect.left += CONTROL_BORDER_SIZEX;
2226 /* if rightmost draw the line longer */
2227 if(selectedRect.right == clRight)
2228 fillRect.right -= CONTROL_BORDER_SIZEX;
2229 }
2230
2231 if (infoPtr->dwStyle & TCS_BOTTOM)
2232 {
2233 /* Adjust both rectangles for topmost row */
2234 if (TAB_GetItem(infoPtr, iItem)->rect.top == infoPtr->uNumRows-1)
2235 {
2236 fillRect.top -= 2;
2237 r.top -= 1;
2238 }
2239
2240 TRACE("<bottom> item=%d, fill=(%s), edge=(%s)\n",
2241 iItem, wine_dbgstr_rect(&fillRect), wine_dbgstr_rect(&r));
2242
2243 /* Clear interior */
2244 SetBkColor(hdc, bkgnd);
2245 ExtTextOutW(hdc, 0, 0, 2, &fillRect, NULL, 0, 0);
2246
2247 /* Draw rectangular edge around tab */
2249
2250 /* Now erase the righthand corner and draw diagonal edge */
2251 SetBkColor(hdc, corner);
2252 r1.left = r.right - ROUND_CORNER_SIZE;
2253 r1.bottom = r.bottom;
2254 r1.right = r.right;
2255 r1.top = r1.bottom - ROUND_CORNER_SIZE - 1;
2256 ExtTextOutW(hdc, 0, 0, 2, &r1, NULL, 0, 0);
2257 r1.bottom--;
2259
2260 /* Now erase the lefthand corner and draw diagonal edge */
2261 r1.left = r.left;
2262 r1.bottom = r.bottom;
2263 r1.right = r1.left + ROUND_CORNER_SIZE;
2264 r1.top = r1.bottom - ROUND_CORNER_SIZE - 1;
2265 ExtTextOutW(hdc, 0, 0, 2, &r1, NULL, 0, 0);
2266 r1.bottom--;
2268
2269 if (iItem == infoPtr->iSelected)
2270 {
2271 r.top += 2;
2272 r.left += 1;
2273 if (selectedRect.left == 0)
2274 {
2275 r1 = r;
2276 r1.bottom = r1.top;
2277 r1.top--;
2279 }
2280 }
2281
2282 }
2283 else
2284 {
2285 /* Adjust both rectangles for bottommost row */
2286 if (TAB_GetItem(infoPtr, iItem)->rect.top == infoPtr->uNumRows-1)
2287 {
2288 fillRect.bottom += 3;
2289 r.bottom += 2;
2290 }
2291
2292 TRACE("<top> item=%d, fill=(%s), edge=(%s)\n",
2293 iItem, wine_dbgstr_rect(&fillRect), wine_dbgstr_rect(&r));
2294
2295 /* Clear interior */
2296 SetBkColor(hdc, bkgnd);
2297 ExtTextOutW(hdc, 0, 0, 2, &fillRect, NULL, 0, 0);
2298
2299 /* Draw rectangular edge around tab */
2301
2302 /* Now erase the righthand corner and draw diagonal edge */
2303 SetBkColor(hdc, corner);
2304 r1.left = r.right - ROUND_CORNER_SIZE;
2305 r1.top = r.top;
2306 r1.right = r.right;
2307 r1.bottom = r1.top + ROUND_CORNER_SIZE + 1;
2308 ExtTextOutW(hdc, 0, 0, 2, &r1, NULL, 0, 0);
2309 r1.top++;
2311
2312 /* Now erase the lefthand corner and draw diagonal edge */
2313 r1.left = r.left;
2314 r1.top = r.top;
2315 r1.right = r1.left + ROUND_CORNER_SIZE;
2316 r1.bottom = r1.top + ROUND_CORNER_SIZE + 1;
2317 ExtTextOutW(hdc, 0, 0, 2, &r1, NULL, 0, 0);
2318 r1.top++;
2320 }
2321 }
2322 }
2323
2324 TAB_DumpItemInternal(infoPtr, iItem);
2325
2326 /* This modifies r to be the text rectangle. */
2327 TAB_DrawItemInterior(infoPtr, hdc, iItem, &r);
2328 }
2329}
2330
2331/******************************************************************************
2332 * TAB_DrawBorder
2333 *
2334 * This method is used to draw the raised border around the tab control
2335 * "content" area.
2336 */
2337static void TAB_DrawBorder(const TAB_INFO *infoPtr, HDC hdc)
2338{
2339 RECT rect;
2340 HTHEME theme = GetWindowTheme (infoPtr->hwnd);
2341
2342 GetClientRect (infoPtr->hwnd, &rect);
2343
2344 /*
2345 * Adjust for the style
2346 */
2347
2348 if (infoPtr->uNumItem)
2349 {
2350 if ((infoPtr->dwStyle & TCS_BOTTOM) && !(infoPtr->dwStyle & TCS_VERTICAL))
2351 rect.bottom -= infoPtr->tabHeight * infoPtr->uNumRows + CONTROL_BORDER_SIZEX;
2352 else if((infoPtr->dwStyle & TCS_BOTTOM) && (infoPtr->dwStyle & TCS_VERTICAL))
2353 rect.right -= infoPtr->tabHeight * infoPtr->uNumRows + CONTROL_BORDER_SIZEX;
2354 else if(infoPtr->dwStyle & TCS_VERTICAL)
2355 rect.left += infoPtr->tabHeight * infoPtr->uNumRows + CONTROL_BORDER_SIZEX;
2356 else /* not TCS_VERTICAL and not TCS_BOTTOM */
2357 rect.top += infoPtr->tabHeight * infoPtr->uNumRows + CONTROL_BORDER_SIZEX;
2358 }
2359
2360 TRACE("border=(%s)\n", wine_dbgstr_rect(&rect));
2361
2362 if (theme)
2363 DrawThemeBackground (theme, hdc, TABP_PANE, 0, &rect, NULL);
2364 else
2366}
2367
2368/******************************************************************************
2369 * TAB_Refresh
2370 *
2371 * This method repaints the tab control..
2372 */
2373static void TAB_Refresh (const TAB_INFO *infoPtr, HDC hdc)
2374{
2375 HFONT hOldFont;
2376 INT i;
2377
2378 if (!infoPtr->DoRedraw)
2379 return;
2380
2381 hOldFont = SelectObject (hdc, infoPtr->hFont);
2382
2383 if (infoPtr->dwStyle & TCS_BUTTONS)
2384 {
2385 for (i = 0; i < infoPtr->uNumItem; i++)
2386 TAB_DrawItem (infoPtr, hdc, i);
2387 }
2388 else
2389 {
2390 /* Draw all the non selected item first */
2391 for (i = 0; i < infoPtr->uNumItem; i++)
2392 {
2393 if (i != infoPtr->iSelected)
2394 TAB_DrawItem (infoPtr, hdc, i);
2395 }
2396
2397 /* Now, draw the border, draw it before the selected item
2398 * since the selected item overwrites part of the border. */
2399 TAB_DrawBorder (infoPtr, hdc);
2400
2401 /* Then, draw the selected item */
2402 TAB_DrawItem (infoPtr, hdc, infoPtr->iSelected);
2403 }
2404
2405 SelectObject (hdc, hOldFont);
2406}
2407
2408static inline DWORD TAB_GetRowCount (const TAB_INFO *infoPtr)
2409{
2410 TRACE("(%p)\n", infoPtr);
2411 return infoPtr->uNumRows;
2412}
2413
2414static inline LRESULT TAB_SetRedraw (TAB_INFO *infoPtr, BOOL doRedraw)
2415{
2416 infoPtr->DoRedraw = doRedraw;
2417 return 0;
2418}
2419
2420/******************************************************************************
2421 * TAB_EnsureSelectionVisible
2422 *
2423 * This method will make sure that the current selection is completely
2424 * visible by scrolling until it is.
2425 */
2427 TAB_INFO* infoPtr)
2428{
2429 INT iSelected = infoPtr->iSelected;
2430 INT iOrigLeftmostVisible = infoPtr->leftmostVisible;
2431
2432 if (iSelected < 0)
2433 return;
2434
2435 /* set the items row to the bottommost row or topmost row depending on
2436 * style */
2437 if ((infoPtr->uNumRows > 1) && !(infoPtr->dwStyle & TCS_BUTTONS))
2438 {
2439 TAB_ITEM *selected = TAB_GetItem(infoPtr, iSelected);
2440 INT newselected;
2441 INT iTargetRow;
2442
2443 if(infoPtr->dwStyle & TCS_VERTICAL)
2444 newselected = selected->rect.left;
2445 else
2446 newselected = selected->rect.top;
2447
2448 /* the target row is always (number of rows - 1)
2449 as row 0 is furthest from the clientRect */
2450 iTargetRow = infoPtr->uNumRows - 1;
2451
2452 if (newselected != iTargetRow)
2453 {
2454 UINT i;
2455 if(infoPtr->dwStyle & TCS_VERTICAL)
2456 {
2457 for (i=0; i < infoPtr->uNumItem; i++)
2458 {
2459 /* move everything in the row of the selected item to the iTargetRow */
2460 TAB_ITEM *item = TAB_GetItem(infoPtr, i);
2461
2462 if (item->rect.left == newselected )
2463 item->rect.left = iTargetRow;
2464 else
2465 {
2466 if (item->rect.left > newselected)
2467 item->rect.left-=1;
2468 }
2469 }
2470 }
2471 else
2472 {
2473 for (i=0; i < infoPtr->uNumItem; i++)
2474 {
2475 TAB_ITEM *item = TAB_GetItem(infoPtr, i);
2476
2477 if (item->rect.top == newselected )
2478 item->rect.top = iTargetRow;
2479 else
2480 {
2481 if (item->rect.top > newselected)
2482 item->rect.top-=1;
2483 }
2484 }
2485 }
2486 TAB_RecalcHotTrack(infoPtr, NULL, NULL, NULL);
2487 }
2488 }
2489
2490 /*
2491 * Do the trivial cases first.
2492 */
2493 if ( (!infoPtr->needsScrolling) ||
2494 (infoPtr->hwndUpDown==0) || (infoPtr->dwStyle & TCS_VERTICAL))
2495 return;
2496
2497 if (infoPtr->leftmostVisible >= iSelected)
2498 {
2499 infoPtr->leftmostVisible = iSelected;
2500 }
2501 else
2502 {
2503 TAB_ITEM *selected = TAB_GetItem(infoPtr, iSelected);
2504 RECT r;
2505 INT width;
2506 UINT i;
2507
2508 /* Calculate the part of the client area that is visible */
2509 GetClientRect(infoPtr->hwnd, &r);
2510 width = r.right;
2511
2512 GetClientRect(infoPtr->hwndUpDown, &r);
2513 width -= r.right;
2514
2515 if ((selected->rect.right -
2516 selected->rect.left) >= width )
2517 {
2518 /* Special case: width of selected item is greater than visible
2519 * part of control.
2520 */
2521 infoPtr->leftmostVisible = iSelected;
2522 }
2523 else
2524 {
2525 for (i = infoPtr->leftmostVisible; i < infoPtr->uNumItem; i++)
2526 {
2527 if ((selected->rect.right - TAB_GetItem(infoPtr, i)->rect.left) < width)
2528 break;
2529 }
2530 infoPtr->leftmostVisible = i;
2531 }
2532 }
2533
2534 if (infoPtr->leftmostVisible != iOrigLeftmostVisible)
2535 TAB_RecalcHotTrack(infoPtr, NULL, NULL, NULL);
2536
2537 SendMessageW(infoPtr->hwndUpDown, UDM_SETPOS, 0,
2538 MAKELONG(infoPtr->leftmostVisible, 0));
2539}
2540
2541/******************************************************************************
2542 * TAB_InvalidateTabArea
2543 *
2544 * This method will invalidate the portion of the control that contains the
2545 * tabs. It is called when the state of the control changes and needs
2546 * to be redisplayed
2547 */
2548static void TAB_InvalidateTabArea(const TAB_INFO *infoPtr)
2549{
2550 RECT clientRect, rInvalidate, rAdjClient;
2551 INT lastRow = infoPtr->uNumRows - 1;
2552 RECT rect;
2553
2554 if (lastRow < 0) return;
2555
2556 GetClientRect(infoPtr->hwnd, &clientRect);
2557 rInvalidate = clientRect;
2558 rAdjClient = clientRect;
2559
2560 TAB_AdjustRect(infoPtr, 0, &rAdjClient);
2561
2562 TAB_InternalGetItemRect(infoPtr, infoPtr->uNumItem-1 , &rect, NULL);
2563 if ((infoPtr->dwStyle & TCS_BOTTOM) && (infoPtr->dwStyle & TCS_VERTICAL))
2564 {
2565 rInvalidate.left = rAdjClient.right;
2566 if (infoPtr->uNumRows == 1)
2567 rInvalidate.bottom = clientRect.top + rect.bottom + 2 * SELECTED_TAB_OFFSET;
2568 }
2569 else if(infoPtr->dwStyle & TCS_VERTICAL)
2570 {
2571 rInvalidate.right = rAdjClient.left;
2572 if (infoPtr->uNumRows == 1)
2573 rInvalidate.bottom = clientRect.top + rect.bottom + 2 * SELECTED_TAB_OFFSET;
2574 }
2575 else if (infoPtr->dwStyle & TCS_BOTTOM)
2576 {
2577 rInvalidate.top = rAdjClient.bottom;
2578 if (infoPtr->uNumRows == 1)
2579 rInvalidate.right = clientRect.left + rect.right + 2 * SELECTED_TAB_OFFSET;
2580 }
2581 else
2582 {
2583 rInvalidate.bottom = rAdjClient.top;
2584 if (infoPtr->uNumRows == 1)
2585 rInvalidate.right = clientRect.left + rect.right + 2 * SELECTED_TAB_OFFSET;
2586 }
2587
2588 /* Punch out the updown control */
2589 if (infoPtr->needsScrolling && (rInvalidate.right > 0)) {
2590 RECT r;
2591 GetClientRect(infoPtr->hwndUpDown, &r);
2592 if (rInvalidate.right > clientRect.right - r.left)
2593 rInvalidate.right = rInvalidate.right - (r.right - r.left);
2594 else
2595 rInvalidate.right = clientRect.right - r.left;
2596 }
2597
2598 TRACE("invalidate (%s)\n", wine_dbgstr_rect(&rInvalidate));
2599
2600 InvalidateRect(infoPtr->hwnd, &rInvalidate, TRUE);
2601}
2602
2603static inline LRESULT TAB_Paint (TAB_INFO *infoPtr, HDC hdcPaint)
2604{
2605 HDC hdc;
2606 PAINTSTRUCT ps;
2607
2608 if (hdcPaint)
2609 hdc = hdcPaint;
2610 else
2611 {
2612 hdc = BeginPaint (infoPtr->hwnd, &ps);
2613 TRACE("erase %d, rect=(%s)\n", ps.fErase, wine_dbgstr_rect(&ps.rcPaint));
2614 }
2615
2616 TAB_Refresh (infoPtr, hdc);
2617
2618 if (!hdcPaint)
2619 EndPaint (infoPtr->hwnd, &ps);
2620
2621 return 0;
2622}
2623
2624static LRESULT
2625TAB_InsertItemT (TAB_INFO *infoPtr, INT iItem, const TCITEMW *pti, BOOL bUnicode)
2626{
2627 TAB_ITEM *item;
2628 RECT rect;
2629
2630 GetClientRect (infoPtr->hwnd, &rect);
2631 TRACE("Rect: %p %s\n", infoPtr->hwnd, wine_dbgstr_rect(&rect));
2632
2633 if (iItem < 0) return -1;
2634 if (iItem > infoPtr->uNumItem)
2635 iItem = infoPtr->uNumItem;
2636
2637 TAB_DumpItemExternalT(pti, iItem, bUnicode);
2638
2639 if (!(item = Alloc(TAB_ITEM_SIZE(infoPtr)))) return FALSE;
2640 if (DPA_InsertPtr(infoPtr->items, iItem, item) == -1)
2641 {
2642 Free(item);
2643 return FALSE;
2644 }
2645
2646 if (infoPtr->uNumItem == 0)
2647 infoPtr->iSelected = 0;
2648 else if (iItem <= infoPtr->iSelected)
2649 infoPtr->iSelected++;
2650
2651 infoPtr->uNumItem++;
2652
2653 item->pszText = NULL;
2654 if (pti->mask & TCIF_TEXT)
2655 {
2656 if (bUnicode)
2657 Str_SetPtrW (&item->pszText, pti->pszText);
2658 else
2659 Str_SetPtrAtoW (&item->pszText, (LPSTR)pti->pszText);
2660 }
2661
2662 if (pti->mask & TCIF_IMAGE)
2663 item->iImage = pti->iImage;
2664 else
2665 item->iImage = -1;
2666
2667 if (pti->mask & TCIF_PARAM)
2668 memcpy(item->extra, &pti->lParam, EXTRA_ITEM_SIZE(infoPtr));
2669 else
2670 memset(item->extra, 0, EXTRA_ITEM_SIZE(infoPtr));
2671
2672 TAB_SetItemBounds(infoPtr);
2673 if (infoPtr->uNumItem > 1)
2674 TAB_InvalidateTabArea(infoPtr);
2675 else
2676 InvalidateRect(infoPtr->hwnd, NULL, TRUE);
2677
2678 TRACE("[%p]: added item %d %s\n",
2679 infoPtr->hwnd, iItem, debugstr_w(item->pszText));
2680
2681 /* If we haven't set the current focus yet, set it now. */
2682 if (infoPtr->uFocus == -1)
2683 TAB_SetCurFocus(infoPtr, iItem);
2684
2685 return iItem;
2686}
2687
2688static LRESULT
2690{
2691 LONG lResult = 0;
2692 BOOL bNeedPaint = FALSE;
2693
2694 lResult = MAKELONG(infoPtr->tabWidth, infoPtr->tabHeight);
2695
2696 /* UNDOCUMENTED: If requested Width or Height is 0 this means that program wants to use auto size. */
2697 if (infoPtr->dwStyle & TCS_FIXEDWIDTH && (infoPtr->tabWidth != cx))
2698 {
2699 infoPtr->tabWidth = cx;
2700 bNeedPaint = TRUE;
2701 }
2702
2703 if (infoPtr->tabHeight != cy)
2704 {
2705 if ((infoPtr->fHeightSet = (cy != 0)))
2706 infoPtr->tabHeight = cy;
2707
2708 bNeedPaint = TRUE;
2709 }
2710 TRACE("was h=%d,w=%d, now h=%d,w=%d\n",
2711 HIWORD(lResult), LOWORD(lResult),
2712 infoPtr->tabHeight, infoPtr->tabWidth);
2713
2714 if (bNeedPaint)
2715 {
2716 TAB_SetItemBounds(infoPtr);
2718 }
2719
2720 return lResult;
2721}
2722
2723static inline LRESULT TAB_SetMinTabWidth (TAB_INFO *infoPtr, INT cx)
2724{
2725 INT oldcx = 0;
2726
2727 TRACE("(%p,%d)\n", infoPtr, cx);
2728
2729 if (infoPtr->tabMinWidth < 0)
2730 oldcx = DEFAULT_MIN_TAB_WIDTH;
2731 else
2732 oldcx = infoPtr->tabMinWidth;
2733 infoPtr->tabMinWidth = cx;
2734 TAB_SetItemBounds(infoPtr);
2735 return oldcx;
2736}
2737
2738static inline LRESULT
2739TAB_HighlightItem (TAB_INFO *infoPtr, INT iItem, BOOL fHighlight)
2740{
2741 LPDWORD lpState;
2742 DWORD oldState;
2743 RECT r;
2744
2745 TRACE("(%p,%d,%s)\n", infoPtr, iItem, fHighlight ? "true" : "false");
2746
2747 if (iItem < 0 || iItem >= infoPtr->uNumItem)
2748 return FALSE;
2749
2750 lpState = &TAB_GetItem(infoPtr, iItem)->dwState;
2751 oldState = *lpState;
2752
2753 if (fHighlight)
2754 *lpState |= TCIS_HIGHLIGHTED;
2755 else
2756 *lpState &= ~TCIS_HIGHLIGHTED;
2757
2758 if ((oldState != *lpState) && TAB_InternalGetItemRect (infoPtr, iItem, &r, NULL))
2759 InvalidateRect (infoPtr->hwnd, &r, TRUE);
2760
2761 return TRUE;
2762}
2763
2764static LRESULT
2765TAB_SetItemT (TAB_INFO *infoPtr, INT iItem, LPTCITEMW tabItem, BOOL bUnicode)
2766{
2767 TAB_ITEM *wineItem;
2768
2769 TRACE("(%p,%d,%p,%s)\n", infoPtr, iItem, tabItem, bUnicode ? "true" : "false");
2770
2771 if (iItem < 0 || iItem >= infoPtr->uNumItem)
2772 return FALSE;
2773
2774 TAB_DumpItemExternalT(tabItem, iItem, bUnicode);
2775
2776 wineItem = TAB_GetItem(infoPtr, iItem);
2777
2778 if (tabItem->mask & TCIF_IMAGE)
2779 wineItem->iImage = tabItem->iImage;
2780
2781 if (tabItem->mask & TCIF_PARAM)
2782 memcpy(wineItem->extra, &tabItem->lParam, infoPtr->cbInfo);
2783
2784 if (tabItem->mask & TCIF_RTLREADING)
2785 FIXME("TCIF_RTLREADING\n");
2786
2787 if (tabItem->mask & TCIF_STATE)
2788 wineItem->dwState = (wineItem->dwState & ~tabItem->dwStateMask) |
2789 ( tabItem->dwState & tabItem->dwStateMask);
2790
2791 if (tabItem->mask & TCIF_TEXT)
2792 {
2793 Free(wineItem->pszText);
2794 wineItem->pszText = NULL;
2795 if (bUnicode)
2796 Str_SetPtrW(&wineItem->pszText, tabItem->pszText);
2797 else
2798 Str_SetPtrAtoW(&wineItem->pszText, (LPSTR)tabItem->pszText);
2799 }
2800
2801 /* Update and repaint tabs */
2802 TAB_SetItemBounds(infoPtr);
2803#ifdef __REACTOS__
2804 InvalidateRect(infoPtr->hwnd, NULL, TRUE);
2805#else
2806 TAB_InvalidateTabArea(infoPtr);
2807#endif
2808
2809 return TRUE;
2810}
2811
2812static inline LRESULT TAB_GetItemCount (const TAB_INFO *infoPtr)
2813{
2814 TRACE("\n");
2815 return infoPtr->uNumItem;
2816}
2817
2818
2819static LRESULT
2820TAB_GetItemT (TAB_INFO *infoPtr, INT iItem, LPTCITEMW tabItem, BOOL bUnicode)
2821{
2822 TAB_ITEM *wineItem;
2823
2824 TRACE("(%p,%d,%p,%s)\n", infoPtr, iItem, tabItem, bUnicode ? "true" : "false");
2825
2826 if (!tabItem) return FALSE;
2827
2828 if (iItem < 0 || iItem >= infoPtr->uNumItem)
2829 {
2830 /* init requested fields */
2831 if (tabItem->mask & TCIF_IMAGE) tabItem->iImage = 0;
2832 if (tabItem->mask & TCIF_PARAM) tabItem->lParam = 0;
2833 if (tabItem->mask & TCIF_STATE) tabItem->dwState = 0;
2834 return FALSE;
2835 }
2836
2837 wineItem = TAB_GetItem(infoPtr, iItem);
2838
2839 if (tabItem->mask & TCIF_IMAGE)
2840 tabItem->iImage = wineItem->iImage;
2841
2842 if (tabItem->mask & TCIF_PARAM)
2843 memcpy(&tabItem->lParam, wineItem->extra, infoPtr->cbInfo);
2844
2845 if (tabItem->mask & TCIF_RTLREADING)
2846 FIXME("TCIF_RTLREADING\n");
2847
2848 if (tabItem->mask & TCIF_STATE)
2849 tabItem->dwState = wineItem->dwState & tabItem->dwStateMask;
2850
2851 if (tabItem->mask & TCIF_TEXT)
2852 {
2853 if (bUnicode)
2854 Str_GetPtrW (wineItem->pszText, tabItem->pszText, tabItem->cchTextMax);
2855 else
2856 Str_GetPtrWtoA (wineItem->pszText, (LPSTR)tabItem->pszText, tabItem->cchTextMax);
2857 }
2858
2859 TAB_DumpItemExternalT(tabItem, iItem, bUnicode);
2860
2861 return TRUE;
2862}
2863
2864
2865static LRESULT TAB_DeleteItem (TAB_INFO *infoPtr, INT iItem)
2866{
2867 TAB_ITEM *item;
2868
2869 TRACE("(%p, %d)\n", infoPtr, iItem);
2870
2871 if (iItem < 0 || iItem >= infoPtr->uNumItem) return FALSE;
2872
2873 TAB_InvalidateTabArea(infoPtr);
2874 item = TAB_GetItem(infoPtr, iItem);
2875 Free(item->pszText);
2876 Free(item);
2877 infoPtr->uNumItem--;
2878 DPA_DeletePtr(infoPtr->items, iItem);
2879
2880 if (infoPtr->uNumItem == 0)
2881 {
2882 if (infoPtr->iHotTracked >= 0)
2883 {
2885 infoPtr->iHotTracked = -1;
2886 }
2887
2888 infoPtr->iSelected = -1;
2889 }
2890 else
2891 {
2892 if (iItem <= infoPtr->iHotTracked)
2893 {
2894 /* When tabs move left/up, the hot track item may change */
2895 FIXME("Recalc hot track\n");
2896 }
2897 }
2898
2899 /* adjust the selected index */
2900 if (iItem == infoPtr->iSelected)
2901 infoPtr->iSelected = -1;
2902 else if (iItem < infoPtr->iSelected)
2903 infoPtr->iSelected--;
2904
2905 /* reposition and repaint tabs */
2906 TAB_SetItemBounds(infoPtr);
2907
2908 return TRUE;
2909}
2910
2911static inline LRESULT TAB_DeleteAllItems (TAB_INFO *infoPtr)
2912{
2913 TRACE("(%p)\n", infoPtr);
2914 while (infoPtr->uNumItem)
2915 TAB_DeleteItem (infoPtr, 0);
2916 return TRUE;
2917}
2918
2919
2920static inline LRESULT TAB_GetFont (const TAB_INFO *infoPtr)
2921{
2922 TRACE("(%p) returning %p\n", infoPtr, infoPtr->hFont);
2923 return (LRESULT)infoPtr->hFont;
2924}
2925
2926static inline LRESULT TAB_SetFont (TAB_INFO *infoPtr, HFONT hNewFont)
2927{
2928 TRACE("(%p,%p)\n", infoPtr, hNewFont);
2929
2930 infoPtr->hFont = hNewFont;
2931
2932 TAB_SetItemBounds(infoPtr);
2933
2934 TAB_InvalidateTabArea(infoPtr);
2935
2936 return 0;
2937}
2938
2939
2940static inline LRESULT TAB_GetImageList (const TAB_INFO *infoPtr)
2941{
2942 TRACE("\n");
2943 return (LRESULT)infoPtr->himl;
2944}
2945
2946static inline LRESULT TAB_SetImageList (TAB_INFO *infoPtr, HIMAGELIST himlNew)
2947{
2948 HIMAGELIST himlPrev = infoPtr->himl;
2949 TRACE("himl=%p\n", himlNew);
2950 infoPtr->himl = himlNew;
2951 TAB_SetItemBounds(infoPtr);
2952 InvalidateRect(infoPtr->hwnd, NULL, TRUE);
2953 return (LRESULT)himlPrev;
2954}
2955
2956static inline LRESULT TAB_GetUnicodeFormat (const TAB_INFO *infoPtr)
2957{
2958 TRACE("(%p)\n", infoPtr);
2959 return infoPtr->bUnicode;
2960}
2961
2962static inline LRESULT TAB_SetUnicodeFormat (TAB_INFO *infoPtr, BOOL bUnicode)
2963{
2964 BOOL bTemp = infoPtr->bUnicode;
2965
2966 TRACE("(%p %d)\n", infoPtr, bUnicode);
2967 infoPtr->bUnicode = bUnicode;
2968
2969 return bTemp;
2970}
2971
2972static inline LRESULT TAB_Size (TAB_INFO *infoPtr)
2973{
2974/* I'm not really sure what the following code was meant to do.
2975 This is what it is doing:
2976 When WM_SIZE is sent with SIZE_RESTORED, the control
2977 gets positioned in the top left corner.
2978
2979 RECT parent_rect;
2980 HWND parent;
2981 UINT uPosFlags,cx,cy;
2982
2983 uPosFlags=0;
2984 if (!wParam) {
2985 parent = GetParent (hwnd);
2986 GetClientRect(parent, &parent_rect);
2987 cx=LOWORD (lParam);
2988 cy=HIWORD (lParam);
2989 if (GetWindowLongW(hwnd, GWL_STYLE) & CCS_NORESIZE)
2990 uPosFlags |= (SWP_NOSIZE | SWP_NOMOVE);
2991
2992 SetWindowPos (hwnd, 0, parent_rect.left, parent_rect.top,
2993 cx, cy, uPosFlags | SWP_NOZORDER);
2994 } else {
2995 FIXME("WM_SIZE flag %x %lx not handled\n", wParam, lParam);
2996 } */
2997
2998 /* Recompute the size/position of the tabs. */
2999 TAB_SetItemBounds (infoPtr);
3000
3001 /* Force a repaint of the control. */
3002 InvalidateRect(infoPtr->hwnd, NULL, TRUE);
3003
3004 return 0;
3005}
3006
3007
3009{
3010 TAB_INFO *infoPtr;
3011 TEXTMETRICW fontMetrics;
3012 HDC hdc;
3013 HFONT hOldFont;
3014 DWORD style;
3015
3016 infoPtr = Alloc (sizeof(TAB_INFO));
3017
3018 SetWindowLongPtrW(hwnd, 0, (DWORD_PTR)infoPtr);
3019
3020 infoPtr->hwnd = hwnd;
3021 infoPtr->hwndNotify = ((LPCREATESTRUCTW)lParam)->hwndParent;
3022 infoPtr->uNumItem = 0;
3023 infoPtr->uNumRows = 0;
3024 infoPtr->uHItemPadding = 6;
3025 infoPtr->uVItemPadding = 3;
3026 infoPtr->uHItemPadding_s = 6;
3027 infoPtr->uVItemPadding_s = 3;
3028 infoPtr->hFont = 0;
3029 infoPtr->items = DPA_Create(8);
3030 infoPtr->hcurArrow = LoadCursorW (0, (LPWSTR)IDC_ARROW);
3031 infoPtr->iSelected = -1;
3032 infoPtr->iHotTracked = -1;
3033 infoPtr->uFocus = -1;
3034 infoPtr->hwndToolTip = 0;
3035 infoPtr->DoRedraw = TRUE;
3036 infoPtr->needsScrolling = FALSE;
3037 infoPtr->hwndUpDown = 0;
3038 infoPtr->leftmostVisible = 0;
3039 infoPtr->fHeightSet = FALSE;
3040 infoPtr->bUnicode = IsWindowUnicode (hwnd);
3041 infoPtr->cbInfo = sizeof(LPARAM);
3042
3043 TRACE("Created tab control, hwnd [%p]\n", hwnd);
3044
3045 /* The tab control always has the WS_CLIPSIBLINGS style. Even
3046 if you don't specify it in CreateWindow. This is necessary in
3047 order for paint to work correctly. This follows windows behaviour. */
3052
3053 infoPtr->dwStyle = style;
3055
3056 if (infoPtr->dwStyle & TCS_TOOLTIPS) {
3057 /* Create tooltip control */
3058 infoPtr->hwndToolTip =
3062 hwnd, 0, 0, 0);
3063
3064 /* Send NM_TOOLTIPSCREATED notification */
3065 if (infoPtr->hwndToolTip) {
3066 NMTOOLTIPSCREATED nmttc;
3067
3068 nmttc.hdr.hwndFrom = hwnd;
3070 nmttc.hdr.code = NM_TOOLTIPSCREATED;
3071 nmttc.hwndToolTips = infoPtr->hwndToolTip;
3072
3075 }
3076 }
3077
3078 OpenThemeData (infoPtr->hwnd, themeClass);
3079
3080 /*
3081 * We need to get text information so we need a DC and we need to select
3082 * a font.
3083 */
3084 hdc = GetDC(hwnd);
3086
3087 /* Use the system font to determine the initial height of a tab. */
3088 GetTextMetricsW(hdc, &fontMetrics);
3089
3090 /*
3091 * Make sure there is enough space for the letters + growing the
3092 * selected item + extra space for the selected item.
3093 */
3094 infoPtr->tabHeight = fontMetrics.tmHeight + SELECTED_TAB_OFFSET +
3095 ((infoPtr->dwStyle & TCS_BUTTONS) ? 2 : 1) *
3096 infoPtr->uVItemPadding;
3097
3098 /* Initialize the width of a tab. */
3099 if (infoPtr->dwStyle & TCS_FIXEDWIDTH)
3100 infoPtr->tabWidth = GetDeviceCaps(hdc, LOGPIXELSX);
3101
3102 infoPtr->tabMinWidth = -1;
3103
3104 TRACE("tabH=%d, tabW=%d\n", infoPtr->tabHeight, infoPtr->tabWidth);
3105
3106 SelectObject (hdc, hOldFont);
3107 ReleaseDC(hwnd, hdc);
3108
3109 return 0;
3110}
3111
3112static LRESULT
3114{
3115 INT iItem;
3116
3117 SetWindowLongPtrW(infoPtr->hwnd, 0, 0);
3118
3119 for (iItem = infoPtr->uNumItem - 1; iItem >= 0; iItem--)
3120 {
3121 TAB_ITEM *tab = TAB_GetItem(infoPtr, iItem);
3122
3123 DPA_DeletePtr(infoPtr->items, iItem);
3124 infoPtr->uNumItem--;
3125
3126 Free(tab->pszText);
3127 Free(tab);
3128 }
3129 DPA_Destroy(infoPtr->items);
3130 infoPtr->items = NULL;
3131
3132 if (infoPtr->hwndToolTip)
3133 DestroyWindow (infoPtr->hwndToolTip);
3134
3135 if (infoPtr->hwndUpDown)
3136 DestroyWindow(infoPtr->hwndUpDown);
3137
3138 if (infoPtr->iHotTracked >= 0)
3140
3141 CloseThemeData (GetWindowTheme (infoPtr->hwnd));
3142
3143 Free (infoPtr);
3144 return 0;
3145}
3146
3147/* update theme after a WM_THEMECHANGED message */
3148static LRESULT theme_changed(const TAB_INFO *infoPtr)
3149{
3150 HTHEME theme = GetWindowTheme (infoPtr->hwnd);
3151 CloseThemeData (theme);
3152 OpenThemeData (infoPtr->hwnd, themeClass);
3153 return 0;
3154}
3155
3157{
3158 if (!wParam)
3159 return 0;
3160 return WVR_ALIGNTOP;
3161}
3162
3163static inline LRESULT
3165{
3166 TRACE("(%p %d)\n", infoPtr, cbInfo);
3167
3168 if (cbInfo < 0 || infoPtr->uNumItem) return FALSE;
3169
3170 infoPtr->cbInfo = cbInfo;
3171 return TRUE;
3172}
3173
3175{
3176 TRACE("%p %d\n", infoPtr, image);
3177
3178 if (ImageList_Remove (infoPtr->himl, image))
3179 {
3180 INT i, *idx;
3181 RECT r;
3182
3183 /* shift indices, repaint items if needed */
3184 for (i = 0; i < infoPtr->uNumItem; i++)
3185 {
3186 idx = &TAB_GetItem(infoPtr, i)->iImage;
3187 if (*idx >= image)
3188 {
3189 if (*idx == image)
3190 *idx = -1;
3191 else
3192 (*idx)--;
3193
3194 /* repaint item */
3195 if (TAB_InternalGetItemRect (infoPtr, i, &r, NULL))
3196 InvalidateRect (infoPtr->hwnd, &r, TRUE);
3197 }
3198 }
3199 }
3200
3201 return 0;
3202}
3203
3204static LRESULT
3205TAB_SetExtendedStyle (TAB_INFO *infoPtr, DWORD exMask, DWORD exStyle)
3206{
3207 DWORD prevstyle = infoPtr->exStyle;
3208
3209 /* zero mask means all styles */
3210 if (exMask == 0) exMask = ~0;
3211
3212 if (exMask & TCS_EX_REGISTERDROP)
3213 {
3214 FIXME("TCS_EX_REGISTERDROP style unimplemented\n");
3215 exMask &= ~TCS_EX_REGISTERDROP;
3216 exStyle &= ~TCS_EX_REGISTERDROP;
3217 }
3218
3219 if (exMask & TCS_EX_FLATSEPARATORS)
3220 {
3221 if ((prevstyle ^ exStyle) & TCS_EX_FLATSEPARATORS)
3222 {
3223 infoPtr->exStyle ^= TCS_EX_FLATSEPARATORS;
3224 TAB_InvalidateTabArea(infoPtr);
3225 }
3226 }
3227
3228 return prevstyle;
3229}
3230
3231static inline LRESULT
3233{
3234 return infoPtr->exStyle;
3235}
3236
3237static LRESULT
3238TAB_DeselectAll (TAB_INFO *infoPtr, BOOL excludesel)
3239{
3240 BOOL paint = FALSE;
3241 INT i, selected = infoPtr->iSelected;
3242
3243 TRACE("(%p, %d)\n", infoPtr, excludesel);
3244
3245 if (!(infoPtr->dwStyle & TCS_BUTTONS))
3246 return 0;
3247
3248 for (i = 0; i < infoPtr->uNumItem; i++)
3249 {
3250 if ((TAB_GetItem(infoPtr, i)->dwState & TCIS_BUTTONPRESSED) &&
3251 (selected != i))
3252 {
3253 TAB_GetItem(infoPtr, i)->dwState &= ~TCIS_BUTTONPRESSED;
3254 paint = TRUE;
3255 }
3256 }
3257
3258 if (!excludesel && (selected != -1))
3259 {
3260 TAB_GetItem(infoPtr, selected)->dwState &= ~TCIS_BUTTONPRESSED;
3261 infoPtr->iSelected = -1;
3262 paint = TRUE;
3263 }
3264
3265 if (paint)
3266 TAB_InvalidateTabArea (infoPtr);
3267
3268 return 0;
3269}
3270
3271/***
3272 * DESCRIPTION:
3273 * Processes WM_STYLECHANGED messages.
3274 *
3275 * PARAMETER(S):
3276 * [I] infoPtr : valid pointer to the tab data structure
3277 * [I] wStyleType : window style type (normal or extended)
3278 * [I] lpss : window style information
3279 *
3280 * RETURN:
3281 * Zero
3282 */
3283static INT TAB_StyleChanged(TAB_INFO *infoPtr, WPARAM wStyleType,
3284 const STYLESTRUCT *lpss)
3285{
3286 TRACE("(styletype=%lx, styleOld=0x%08x, styleNew=0x%08x)\n",
3287 wStyleType, lpss->styleOld, lpss->styleNew);
3288
3289 if (wStyleType != GWL_STYLE) return 0;
3290
3291 infoPtr->dwStyle = lpss->styleNew;
3292
3293 TAB_SetItemBounds (infoPtr);
3294 InvalidateRect(infoPtr->hwnd, NULL, TRUE);
3295
3296 return 0;
3297}
3298
3299static LRESULT WINAPI
3301{
3302 TAB_INFO *infoPtr = TAB_GetInfoPtr(hwnd);
3303
3304 TRACE("hwnd=%p msg=%x wParam=%lx lParam=%lx\n", hwnd, uMsg, wParam, lParam);
3305 if (!infoPtr && (uMsg != WM_CREATE))
3306 return DefWindowProcW (hwnd, uMsg, wParam, lParam);
3307
3308 switch (uMsg)
3309 {
3310 case TCM_GETIMAGELIST:
3311 return TAB_GetImageList (infoPtr);
3312
3313 case TCM_SETIMAGELIST:
3314 return TAB_SetImageList (infoPtr, (HIMAGELIST)lParam);
3315
3316 case TCM_GETITEMCOUNT:
3317 return TAB_GetItemCount (infoPtr);
3318
3319 case TCM_GETITEMA:
3320 case TCM_GETITEMW:
3321 return TAB_GetItemT (infoPtr, (INT)wParam, (LPTCITEMW)lParam, uMsg == TCM_GETITEMW);
3322
3323 case TCM_SETITEMA:
3324 case TCM_SETITEMW:
3325 return TAB_SetItemT (infoPtr, (INT)wParam, (LPTCITEMW)lParam, uMsg == TCM_SETITEMW);
3326
3327 case TCM_DELETEITEM:
3328 return TAB_DeleteItem (infoPtr, (INT)wParam);
3329
3330 case TCM_DELETEALLITEMS:
3331 return TAB_DeleteAllItems (infoPtr);
3332
3333 case TCM_GETITEMRECT:
3334 return TAB_GetItemRect (infoPtr, (INT)wParam, (LPRECT)lParam);
3335
3336 case TCM_GETCURSEL:
3337 return TAB_GetCurSel (infoPtr);
3338
3339 case TCM_HITTEST:
3340 return TAB_HitTest (infoPtr, (LPTCHITTESTINFO)lParam);
3341
3342 case TCM_SETCURSEL:
3343 return TAB_SetCurSel (infoPtr, (INT)wParam);
3344
3345 case TCM_INSERTITEMA:
3346 case TCM_INSERTITEMW:
3347 return TAB_InsertItemT (infoPtr, (INT)wParam, (TCITEMW*)lParam, uMsg == TCM_INSERTITEMW);
3348
3349 case TCM_SETITEMEXTRA:
3350 return TAB_SetItemExtra (infoPtr, (INT)wParam);
3351
3352 case TCM_ADJUSTRECT:
3353 return TAB_AdjustRect (infoPtr, (BOOL)wParam, (LPRECT)lParam);
3354
3355 case TCM_SETITEMSIZE:
3356 return TAB_SetItemSize (infoPtr, (INT)LOWORD(lParam), (INT)HIWORD(lParam));
3357
3358 case TCM_REMOVEIMAGE:
3359 return TAB_RemoveImage (infoPtr, (INT)wParam);
3360
3361 case TCM_SETPADDING:
3362 return TAB_SetPadding (infoPtr, lParam);
3363
3364 case TCM_GETROWCOUNT:
3365 return TAB_GetRowCount(infoPtr);
3366
3368 return TAB_GetUnicodeFormat (infoPtr);
3369
3371 return TAB_SetUnicodeFormat (infoPtr, (BOOL)wParam);
3372
3373 case TCM_HIGHLIGHTITEM:
3374 return TAB_HighlightItem (infoPtr, (INT)wParam, (BOOL)LOWORD(lParam));
3375
3376 case TCM_GETTOOLTIPS:
3377 return TAB_GetToolTips (infoPtr);
3378
3379 case TCM_SETTOOLTIPS:
3380 return TAB_SetToolTips (infoPtr, (HWND)wParam);
3381
3382 case TCM_GETCURFOCUS:
3383 return TAB_GetCurFocus (infoPtr);
3384
3385 case TCM_SETCURFOCUS:
3386 return TAB_SetCurFocus (infoPtr, (INT)wParam);
3387
3388 case TCM_SETMINTABWIDTH:
3389 return TAB_SetMinTabWidth(infoPtr, (INT)lParam);
3390
3391 case TCM_DESELECTALL:
3392 return TAB_DeselectAll (infoPtr, (BOOL)wParam);
3393
3395 return TAB_GetExtendedStyle (infoPtr);
3396
3398 return TAB_SetExtendedStyle (infoPtr, wParam, lParam);
3399
3400 case WM_GETFONT:
3401 return TAB_GetFont (infoPtr);
3402
3403 case WM_SETFONT:
3404 return TAB_SetFont (infoPtr, (HFONT)wParam);
3405
3406 case WM_CREATE:
3407 return TAB_Create (hwnd, lParam);
3408
3409 case WM_NCDESTROY:
3410 return TAB_Destroy (infoPtr);
3411
3412 case WM_GETDLGCODE:
3414
3415 case WM_LBUTTONDOWN:
3416 return TAB_LButtonDown (infoPtr, wParam, lParam);
3417
3418 case WM_LBUTTONUP:
3419 return TAB_LButtonUp (infoPtr);
3420
3421 case WM_NOTIFY:
3422 return SendMessageW(infoPtr->hwndNotify, WM_NOTIFY, wParam, lParam);
3423
3424 case WM_RBUTTONUP:
3425 TAB_RButtonUp (infoPtr);
3426 return DefWindowProcW (hwnd, uMsg, wParam, lParam);
3427
3428 case WM_MOUSEMOVE:
3429 return TAB_MouseMove (infoPtr, wParam, lParam);
3430
3431 case WM_PRINTCLIENT:
3432 case WM_PAINT:
3433 return TAB_Paint (infoPtr, (HDC)wParam);
3434
3435 case WM_SIZE:
3436 return TAB_Size (infoPtr);
3437
3438 case WM_SETREDRAW:
3439 return TAB_SetRedraw (infoPtr, (BOOL)wParam);
3440
3441 case WM_HSCROLL:
3442 return TAB_OnHScroll(infoPtr, (int)LOWORD(wParam), (int)HIWORD(wParam));
3443
3444 case WM_STYLECHANGED:
3445 return TAB_StyleChanged(infoPtr, wParam, (LPSTYLESTRUCT)lParam);
3446
3447 case WM_SYSCOLORCHANGE:
3449 return 0;
3450
3451 case WM_THEMECHANGED:
3452 return theme_changed (infoPtr);
3453
3454 case WM_KILLFOCUS:
3455 TAB_KillFocus(infoPtr);
3456 case WM_SETFOCUS:
3457 TAB_FocusChanging(infoPtr);
3458 break; /* Don't disturb normal focus behavior */
3459
3460 case WM_KEYDOWN:
3461 return TAB_KeyDown(infoPtr, wParam, lParam);
3462
3463 case WM_NCHITTEST:
3464 return TAB_NCHitTest(infoPtr, lParam);
3465
3466 case WM_NCCALCSIZE:
3467 return TAB_NCCalcSize(wParam);
3468
3469 default:
3470 if (uMsg >= WM_USER && uMsg < WM_APP && !COMCTL32_IsReflectedMessage(uMsg))
3471 WARN("unknown msg %04x wp=%08lx lp=%08lx\n",
3472 uMsg, wParam, lParam);
3473 break;
3474 }
3475 return DefWindowProcW(hwnd, uMsg, wParam, lParam);
3476}
3477
3478
3479void
3481{
3482 WNDCLASSW wndClass;
3483
3484 ZeroMemory (&wndClass, sizeof(WNDCLASSW));
3486 wndClass.lpfnWndProc = TAB_WindowProc;
3487 wndClass.cbClsExtra = 0;
3488 wndClass.cbWndExtra = sizeof(TAB_INFO *);
3489 wndClass.hCursor = LoadCursorW (0, (LPWSTR)IDC_ARROW);
3490 wndClass.hbrBackground = (HBRUSH)(COLOR_BTNFACE+1);
3491 wndClass.lpszClassName = WC_TABCONTROLW;
3492
3493 RegisterClassW (&wndClass);
3494}
3495
3496
3497void
3499{
3501}
Arabic default style
Definition: afstyles.h:94
static int state
Definition: maze.c:121
static const char * wine_dbgstr_rect(const RECT *prc)
Definition: atltest.h:160
#define msg(x)
Definition: auth_time.c:54
#define WINE_DEFAULT_DEBUG_CHANNEL(t)
Definition: precomp.h:23
HFONT hFont
Definition: main.c:53
#define FIXME(fmt,...)
Definition: precomp.h:53
#define WARN(fmt,...)
Definition: precomp.h:61
PVOID Alloc(IN DWORD dwFlags, IN SIZE_T dwBytes)
Definition: main.c:63
WPARAM wParam
Definition: combotst.c:138
LPARAM lParam
Definition: combotst.c:139
INT Str_GetPtrWtoA(LPCWSTR lpSrc, LPSTR lpDest, INT nMaxLen) DECLSPEC_HIDDEN
BOOL COMCTL32_IsReflectedMessage(UINT uMsg) DECLSPEC_HIDDEN
Definition: commctrl.c:1755
BOOL Str_SetPtrAtoW(LPWSTR *lppDest, LPCSTR lpSrc) DECLSPEC_HIDDEN
VOID COMCTL32_RefreshSysColors(void) DECLSPEC_HIDDEN
Definition: commctrl.c:1593
INT WINAPI Str_GetPtrW(LPCWSTR, LPWSTR, INT)
Definition: string.c:200
COMCTL32_SysColor comctl32_color
Definition: commctrl.c:82
HBRUSH COMCTL32_hPattern55AABrush
Definition: commctrl.c:81
static char selected[MAX_PATH+1]
Definition: dirdlg.c:7
#define NULL
Definition: types.h:112
#define TRUE
Definition: types.h:120
#define FALSE
Definition: types.h:117
unsigned int idx
Definition: utils.c:41
LPVOID WINAPI DPA_DeletePtr(HDPA hdpa, INT i)
Definition: dpa.c:677
BOOL WINAPI DPA_Destroy(HDPA hdpa)
Definition: dpa.c:396
HDPA WINAPI DPA_Create(INT nGrow)
Definition: dpa.c:950
INT WINAPI DPA_InsertPtr(HDPA hdpa, INT i, LPVOID p)
Definition: dpa.c:591
BOOL WINAPI ImageList_Draw(HIMAGELIST himl, INT i, HDC hdc, INT x, INT y, UINT fStyle)
Definition: imagelist.c:1228
BOOL WINAPI ImageList_Remove(HIMAGELIST himl, INT i)
Definition: imagelist.c:2568
BOOL WINAPI ImageList_GetIconSize(HIMAGELIST himl, INT *cx, INT *cy)
Definition: imagelist.c:2037
BOOL WINAPI Str_SetPtrW(LPWSTR *lppDest, LPCWSTR lpSrc)
Definition: string.c:232
static LRESULT TAB_MouseMove(TAB_INFO *infoPtr, WPARAM wParam, LPARAM lParam)
Definition: tab.c:916
static void TAB_RButtonUp(const TAB_INFO *infoPtr)
Definition: tab.c:725
static LRESULT TAB_KeyDown(TAB_INFO *infoPtr, WPARAM keyCode, LPARAM lParam)
Definition: tab.c:517
#define TAB_GetInfoPtr(hwnd)
Definition: tab.c:145
static LRESULT TAB_SetRedraw(TAB_INFO *infoPtr, BOOL doRedraw)
Definition: tab.c:2414
static void TAB_DrawLoneItemInterior(const TAB_INFO *infoPtr, int iItem)
Definition: tab.c:739
static LRESULT TAB_OnHScroll(TAB_INFO *infoPtr, int nScrollCode, int nPos)
Definition: tab.c:1001
static LRESULT TAB_Size(TAB_INFO *infoPtr)
Definition: tab.c:2972
static LRESULT TAB_RemoveImage(TAB_INFO *infoPtr, INT image)
Definition: tab.c:3174
static LRESULT TAB_GetItemT(TAB_INFO *infoPtr, INT iItem, LPTCITEMW tabItem, BOOL bUnicode)
Definition: tab.c:2820
static LRESULT TAB_GetFont(const TAB_INFO *infoPtr)
Definition: tab.c:2920
static LRESULT TAB_SetCurSel(TAB_INFO *infoPtr, INT iItem)
Definition: tab.c:249
static LRESULT TAB_NCCalcSize(WPARAM wParam)
Definition: tab.c:3156
#define BUTTON_SPACINGY
Definition: tab.c:139
static LRESULT TAB_SetFont(TAB_INFO *infoPtr, HFONT hNewFont)
Definition: tab.c:2926
static LRESULT TAB_SetPadding(TAB_INFO *infoPtr, LPARAM lParam)
Definition: tab.c:354
static void TAB_DumpItemExternalT(const TCITEMW *pti, UINT iItem, BOOL isW)
Definition: tab.c:203
static LRESULT TAB_GetUnicodeFormat(const TAB_INFO *infoPtr)
Definition: tab.c:2956
static LRESULT TAB_SetItemT(TAB_INFO *infoPtr, INT iItem, LPTCITEMW tabItem, BOOL bUnicode)
Definition: tab.c:2765
#define SELECTED_TAB_OFFSET
Definition: tab.c:132
static LRESULT TAB_SetExtendedStyle(TAB_INFO *infoPtr, DWORD exMask, DWORD exStyle)
Definition: tab.c:3205
#define CONTROL_BORDER_SIZEY
Definition: tab.c:137
static LRESULT TAB_LButtonUp(const TAB_INFO *infoPtr)
Definition: tab.c:717
#define ROUND_CORNER_SIZE
Definition: tab.c:133
static LRESULT TAB_SetItemSize(TAB_INFO *infoPtr, INT cx, INT cy)
Definition: tab.c:2689
static BOOL TAB_InternalGetItemRect(const TAB_INFO *, INT, RECT *, RECT *)
Definition: tab.c:372
static LRESULT TAB_DeleteItem(TAB_INFO *infoPtr, INT iItem)
Definition: tab.c:2865
#define EXTRA_ICON_PADDING
Definition: tab.c:143
static LRESULT WINAPI TAB_WindowProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
Definition: tab.c:3300
static INT TAB_StyleChanged(TAB_INFO *infoPtr, WPARAM wStyleType, const STYLESTRUCT *lpss)
Definition: tab.c:3283
static LRESULT TAB_AdjustRect(const TAB_INFO *infoPtr, WPARAM fLarger, LPRECT prc)
Definition: tab.c:941
static LRESULT TAB_DeleteAllItems(TAB_INFO *infoPtr)
Definition: tab.c:2911
static void TAB_SetItemBounds(TAB_INFO *infoPtr)
Definition: tab.c:1117
void TAB_Unregister(void)
Definition: tab.c:3498
#define EXTRA_ITEM_SIZE(infoPtr)
Definition: tab.c:89
static LRESULT TAB_SetToolTips(TAB_INFO *infoPtr, HWND hwndToolTip)
Definition: tab.c:346
static void TAB_RelayEvent(HWND hwndTip, HWND hwndMsg, UINT uMsg, WPARAM wParam, LPARAM lParam)
Definition: tab.c:186
static void TAB_SetupScrolling(TAB_INFO *infoPtr, const RECT *clientRect)
Definition: tab.c:1025
static LRESULT TAB_LButtonDown(TAB_INFO *infoPtr, WPARAM wParam, LPARAM lParam)
Definition: tab.c:650
static void CALLBACK TAB_HotTrackTimerProc(HWND hwnd, UINT uMsg, UINT_PTR idEvent, DWORD dwTime)
Definition: tab.c:784
static DWORD TAB_GetRowCount(const TAB_INFO *infoPtr)
Definition: tab.c:2408
static INT TAB_InternalHitTest(const TAB_INFO *infoPtr, POINT pt, UINT *flags)
Definition: tab.c:594
#define GET_DEFAULT_MIN_TAB_WIDTH(infoPtr)
Definition: tab.c:147
#define DEFAULT_MIN_TAB_WIDTH
Definition: tab.c:141
void TAB_Register(void)
Definition: tab.c:3480
static BOOL TAB_GetItemRect(const TAB_INFO *infoPtr, INT item, RECT *rect)
Definition: tab.c:506
static LRESULT TAB_SetUnicodeFormat(TAB_INFO *infoPtr, BOOL bUnicode)
Definition: tab.c:2962
static LRESULT TAB_HitTest(const TAB_INFO *infoPtr, LPTCHITTESTINFO lptest)
Definition: tab.c:615
#define TAB_ITEM_SIZE(infoPtr)
Definition: tab.c:90
static LRESULT TAB_SetImageList(TAB_INFO *infoPtr, HIMAGELIST himlNew)
Definition: tab.c:2946
static const WCHAR themeClass[]
Definition: tab.c:155
static LRESULT TAB_GetImageList(const TAB_INFO *infoPtr)
Definition: tab.c:2940
#define CONTROL_BORDER_SIZEX
Definition: tab.c:136
static TAB_ITEM * TAB_GetItem(const TAB_INFO *infoPtr, INT i)
Definition: tab.c:157
static LRESULT TAB_NCHitTest(const TAB_INFO *infoPtr, LPARAM lParam)
Definition: tab.c:634
static LRESULT TAB_GetCurFocus(const TAB_INFO *infoPtr)
Definition: tab.c:237
static LRESULT TAB_GetToolTips(const TAB_INFO *infoPtr)
Definition: tab.c:243
static LRESULT TAB_GetExtendedStyle(const TAB_INFO *infoPtr)
Definition: tab.c:3232
static LRESULT TAB_SetMinTabWidth(TAB_INFO *infoPtr, INT cx)
Definition: tab.c:2723
static LRESULT TAB_Create(HWND hwnd, LPARAM lParam)
Definition: tab.c:3008
static void TAB_InvalidateTabArea(const TAB_INFO *)
Definition: tab.c:2548
static void TAB_DrawItemInterior(const TAB_INFO *, HDC, INT, RECT *)
Definition: tab.c:1556
static LRESULT TAB_SetCurFocus(TAB_INFO *infoPtr, INT iItem)
Definition: tab.c:281
static void TAB_KillFocus(TAB_INFO *infoPtr)
Definition: tab.c:550
static LRESULT TAB_Destroy(TAB_INFO *infoPtr)
Definition: tab.c:3113
static LRESULT TAB_SetItemExtra(TAB_INFO *infoPtr, INT cbInfo)
Definition: tab.c:3164
static void TAB_DrawItem(const TAB_INFO *infoPtr, HDC hdc, INT iItem)
Definition: tab.c:1990
static void TAB_RecalcHotTrack(TAB_INFO *infoPtr, const LPARAM *pos, int *out_redrawLeave, int *out_redrawEnter)
Definition: tab.c:836
static void TAB_FocusChanging(const TAB_INFO *infoPtr)
Definition: tab.c:570
static LRESULT theme_changed(const TAB_INFO *infoPtr)
Definition: tab.c:3148
static LRESULT TAB_GetItemCount(const TAB_INFO *infoPtr)
Definition: tab.c:2812
#define DISPLAY_AREA_PADDINGX
Definition: tab.c:134
static void TAB_EnsureSelectionVisible(TAB_INFO *)
Definition: tab.c:2426
static LRESULT TAB_InsertItemT(TAB_INFO *infoPtr, INT iItem, const TCITEMW *pti, BOOL bUnicode)
Definition: tab.c:2625
static void TAB_Refresh(const TAB_INFO *infoPtr, HDC hdc)
Definition: tab.c:2373
#define TAB_HOTTRACK_TIMER_INTERVAL
Definition: tab.c:153
static void TAB_DrawBorder(const TAB_INFO *infoPtr, HDC hdc)
Definition: tab.c:2337
static void TAB_DumpItemInternal(const TAB_INFO *infoPtr, UINT iItem)
Definition: tab.c:214
#define FLAT_BTN_SPACINGX
Definition: tab.c:140
static void hottrack_refresh(const TAB_INFO *infoPtr, int tabIndex)
Definition: tab.c:757
static LRESULT TAB_HighlightItem(TAB_INFO *infoPtr, INT iItem, BOOL fHighlight)
Definition: tab.c:2739
static void TAB_EraseTabInterior(const TAB_INFO *infoPtr, HDC hdc, INT iItem, const RECT *drawRect)
Definition: tab.c:1481
#define BUTTON_SPACINGX
Definition: tab.c:138
static BOOL TAB_SendSimpleNotify(const TAB_INFO *infoPtr, UINT code)
Definition: tab.c:173
static LRESULT TAB_GetCurSel(const TAB_INFO *infoPtr)
Definition: tab.c:228
static LRESULT TAB_DeselectAll(TAB_INFO *, BOOL)
Definition: tab.c:3238
static LRESULT TAB_Paint(TAB_INFO *infoPtr, HDC hdcPaint)
Definition: tab.c:2603
#define TAB_HOTTRACK_TIMER
Definition: tab.c:152
#define DISPLAY_AREA_PADDINGY
Definition: tab.c:135
#define TRACE_ON(x)
Definition: compat.h:75
#define CALLBACK
Definition: compat.h:35
#define lstrlenW
Definition: compat.h:750
HRESULT WINAPI DrawThemeBackground(HTHEME hTheme, HDC hdc, int iPartId, int iStateId, const RECT *pRect, const RECT *pClipRect)
Definition: draw.c:128
HRESULT WINAPI DrawThemeText(HTHEME hTheme, HDC hdc, int iPartId, int iStateId, LPCWSTR pszText, int iCharCount, DWORD dwTextFlags, DWORD dwTextFlags2, const RECT *pRect)
Definition: draw.c:1500
HRESULT WINAPI GetThemeBackgroundContentRect(HTHEME hTheme, HDC hdc, int iPartId, int iStateId, const RECT *pBoundingRect, RECT *pContentRect)
Definition: draw.c:1523
HTHEME WINAPI OpenThemeData(HWND hwnd, LPCWSTR classlist)
Definition: system.c:835
HTHEME WINAPI GetWindowTheme(HWND hwnd)
Definition: system.c:851
HRESULT WINAPI CloseThemeData(HTHEME hTheme)
Definition: system.c:950
unsigned short(__cdecl typeof(TIFFCurrentDirectory))(struct tiff *)
Definition: typeof.h:94
#define assert(x)
Definition: debug.h:53
#define pt(x, y)
Definition: drawing.c:79
#define WM_APP
Definition: eventvwr.h:73
unsigned int BOOL
Definition: ntddk_ex.h:94
unsigned long DWORD
Definition: ntddk_ex.h:95
pKey DeleteObject()
GLuint start
Definition: gl.h:1545
GLdouble GLdouble GLdouble r
Definition: gl.h:2055
GLint GLint GLsizei width
Definition: gl.h:1546
GLsizeiptr size
Definition: glext.h:5919
GLbitfield flags
Definition: glext.h:7161
GLuint id
Definition: glext.h:5910
GLsizei GLenum const GLvoid GLsizei GLenum GLbyte GLbyte GLbyte GLdouble GLdouble GLdouble GLfloat GLfloat GLfloat GLint GLint GLint GLshort GLshort GLshort GLubyte GLubyte GLubyte GLuint GLuint GLuint GLushort GLushort GLushort GLbyte GLbyte GLbyte GLbyte GLdouble GLdouble GLdouble GLdouble GLfloat GLfloat GLfloat GLfloat GLint GLint GLint GLint GLshort GLshort GLshort GLshort GLubyte GLubyte GLubyte GLubyte GLuint GLuint GLuint GLuint GLushort GLushort GLushort GLushort GLboolean const GLdouble const GLfloat const GLint const GLshort const GLbyte const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLdouble const GLfloat const GLfloat const GLint const GLint const GLshort const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort GLenum GLenum GLenum GLfloat GLenum GLint GLenum GLenum GLenum GLfloat GLenum GLenum GLint GLenum GLfloat GLenum GLint GLint GLushort GLenum GLenum GLfloat GLenum GLenum GLint GLfloat const GLubyte GLenum GLenum GLenum const GLfloat GLenum GLenum const GLint GLenum GLint GLint GLsizei GLsizei GLint GLenum GLenum const GLvoid GLenum GLenum const GLfloat GLenum GLenum const GLint GLenum GLenum const GLdouble GLenum GLenum const GLfloat GLenum GLenum const GLint GLsizei GLuint GLfloat GLuint GLbitfield GLfloat GLint GLuint GLboolean GLenum GLfloat GLenum GLbitfield GLenum GLfloat GLfloat GLint GLint const GLfloat GLenum GLfloat GLfloat GLint GLint GLfloat GLfloat GLint GLint const GLfloat GLint GLfloat GLfloat GLint GLfloat GLfloat GLint GLfloat GLfloat const GLdouble const GLfloat const GLdouble const GLfloat GLint i
Definition: glfuncs.h:248
@ extra
Definition: id3.c:95
static const WCHAR emptyW[]
Definition: navigate.c:40
#define debugstr_a
Definition: kernel32.h:31
#define debugstr_w
Definition: kernel32.h:32
if(dx< 0)
Definition: linetemp.h:194
double __cdecl remainder(double, double)
Definition: remainder.c:75
#define memcpy(s1, s2, n)
Definition: mkisofs.h:878
HDC hdc
Definition: main.c:9
static HDC
Definition: imagelist.c:88
static DNS_RECORDW r1
Definition: record.c:37
static DWORD *static HFONT(WINAPI *pCreateFontIndirectExA)(const ENUMLOGFONTEXDVA *)
static ATOM item
Definition: dde.c:856
static HTHEME(WINAPI *pOpenThemeDataEx)(HWND
unsigned __int3264 UINT_PTR
Definition: mstsclib_h.h:274
unsigned int UINT
Definition: ndis.h:50
_Out_ LPRECT prc
Definition: ntgdi.h:1658
INT WINAPI DrawTextW(HDC hdc, LPCWSTR str, INT count, LPRECT rect, UINT flags)
Definition: defwnd.c:16
#define LOWORD(l)
Definition: pedump.c:82
#define WS_CHILD
Definition: pedump.c:617
#define WS_POPUP
Definition: pedump.c:616
#define WS_VISIBLE
Definition: pedump.c:620
long LONG
Definition: pedump.c:60
#define WS_CLIPSIBLINGS
Definition: pedump.c:618
unsigned short USHORT
Definition: pedump.c:61
#define WC_TABCONTROLW
Definition: commctrl.h:3940
#define UPDOWN_CLASSW
Definition: commctrl.h:2124
#define TCS_EX_REGISTERDROP
Definition: commctrl.h:3965
_Out_opt_ int _Out_opt_ int * cy
Definition: commctrl.h:586
#define TCS_FOCUSNEVER
Definition: commctrl.h:3962
#define TCM_SETIMAGELIST
Definition: commctrl.h:3970
#define ILD_NORMAL
Definition: commctrl.h:417
#define TCM_GETTOOLTIPS
Definition: commctrl.h:4100
#define TCS_FIXEDWIDTH
Definition: commctrl.h:3957
#define TCS_EX_FLATSEPARATORS
Definition: commctrl.h:3964
#define TCIF_STATE
Definition: commctrl.h:3980
#define TCS_OWNERDRAWFIXED
Definition: commctrl.h:3960
#define TCM_GETCURSEL
Definition: commctrl.h:4067
#define TCIS_BUTTONPRESSED
Definition: commctrl.h:3982
#define TCM_DELETEALLITEMS
Definition: commctrl.h:4061
#define TCHT_ONITEM
Definition: commctrl.h:4076
#define TTM_RELAYEVENT
Definition: commctrl.h:1797
#define UDM_SETPOS
Definition: commctrl.h:2148
#define TCM_GETIMAGELIST
Definition: commctrl.h:3967
#define TCS_MULTISELECT
Definition: commctrl.h:3946
#define TCM_DESELECTALL
Definition: commctrl.h:4110
#define TCM_GETCURFOCUS
Definition: commctrl.h:4104
#define TCM_SETPADDING
Definition: commctrl.h:4096
#define TOOLTIPS_CLASSW
Definition: commctrl.h:1707
#define TCM_GETROWCOUNT
Definition: commctrl.h:4098
_Out_opt_ int * cx
Definition: commctrl.h:585
#define TCM_INSERTITEMW
Definition: commctrl.h:4052
#define TCM_SETTOOLTIPS
Definition: commctrl.h:4102
#define TCN_KEYDOWN
Definition: commctrl.h:4123
#define TCN_SELCHANGING
Definition: commctrl.h:4138
#define NM_TOOLTIPSCREATED
Definition: commctrl.h:144
#define TCHT_NOWHERE
Definition: commctrl.h:4073
#define NM_CLICK
Definition: commctrl.h:130
#define TCM_SETITEMA
Definition: commctrl.h:4044
#define TCIS_HIGHLIGHTED
Definition: commctrl.h:3983
#define TCM_SETITEMW
Definition: commctrl.h:4045
#define TCM_ADJUSTRECT
Definition: commctrl.h:4090
#define TCS_HOTTRACK
Definition: commctrl.h:3950
#define TCS_FORCELABELLEFT
Definition: commctrl.h:3949
#define TCM_SETEXTENDEDSTYLE
Definition: commctrl.h:4114
#define TCIF_PARAM
Definition: commctrl.h:3979
#define TCM_GETITEMCOUNT
Definition: commctrl.h:3973
#define TCM_GETEXTENDEDSTYLE
Definition: commctrl.h:4116
#define TCM_GETITEMA
Definition: commctrl.h:4037
#define TCM_SETITEMSIZE
Definition: commctrl.h:4092
#define ODT_TAB
Definition: commctrl.h:79
#define TCS_FLATBUTTONS
Definition: commctrl.h:3947
#define TCM_GETUNICODEFORMAT
Definition: commctrl.h:4120
#define TCN_SELCHANGE
Definition: commctrl.h:4137
#define TCM_SETMINTABWIDTH
Definition: commctrl.h:4108
#define TCN_FOCUSCHANGE
Definition: commctrl.h:4140
#define TCM_HIGHLIGHTITEM
Definition: commctrl.h:4112
#define NM_RCLICK
Definition: commctrl.h:133
#define TCM_SETUNICODEFORMAT
Definition: commctrl.h:4118
#define UDS_HORZ
Definition: commctrl.h:2142
#define TCS_FORCEICONLEFT
Definition: commctrl.h:3948
#define TCM_SETCURSEL
Definition: commctrl.h:4070
#define UDM_SETRANGE32
Definition: commctrl.h:2156
#define TCS_RAGGEDRIGHT
Definition: commctrl.h:3958
#define TCM_GETITEMW
Definition: commctrl.h:4038
#define TCS_TOOLTIPS
Definition: commctrl.h:3961
#define TCM_INSERTITEMA
Definition: commctrl.h:4051
#define TCM_REMOVEIMAGE
Definition: commctrl.h:4094
#define TCIF_RTLREADING
Definition: commctrl.h:3978
#define TCM_HITTEST
Definition: commctrl.h:4086
#define TCS_BUTTONS
Definition: commctrl.h:3953
#define TCIF_TEXT
Definition: commctrl.h:3976
#define TCM_GETITEMRECT
Definition: commctrl.h:4064
#define TCM_SETITEMEXTRA
Definition: commctrl.h:4088
#define TCS_BOTTOM
Definition: commctrl.h:3944
#define TCM_DELETEITEM
Definition: commctrl.h:4058
#define TCS_MULTILINE
Definition: commctrl.h:3955
#define TCIF_IMAGE
Definition: commctrl.h:3977
#define TCS_VERTICAL
Definition: commctrl.h:3951
#define TCM_SETCURFOCUS
Definition: commctrl.h:4106
#define DPA_GetPtr
Definition: commctrl.h:5
#define WM_PRINTCLIENT
Definition: richedit.h:70
#define WM_NOTIFY
Definition: richedit.h:61
#define memset(x, y, z)
Definition: compat.h:39
#define TRACE(s)
Definition: solgame.cpp:4
DWORD dwTime
Definition: solitaire.cpp:27
& rect
Definition: startmenu.cpp:1413
COLORREF clrHighlightText
Definition: comctl32.h:176
COLORREF clrBtnText
Definition: comctl32.h:173
COLORREF clrBtnFace
Definition: comctl32.h:174
COLORREF clrWindow
Definition: comctl32.h:182
COLORREF clr3dFace
Definition: comctl32.h:181
COLORREF clr3dHilight
Definition: comctl32.h:178
COLORREF clrHighlight
Definition: comctl32.h:175
LONG lfOrientation
Definition: dimm.idl:62
LONG lfEscapement
Definition: dimm.idl:61
Definition: tab.c:93
INT leftmostVisible
Definition: tab.c:109
DWORD exStyle
Definition: tab.c:122
BOOL bUnicode
Definition: tab.c:118
USHORT uVItemPadding
Definition: tab.c:102
INT tabMinWidth
Definition: tab.c:100
HFONT hFont
Definition: tab.c:105
HDPA items
Definition: tab.c:126
INT tabWidth
Definition: tab.c:99
USHORT uHItemPadding
Definition: tab.c:101
HWND hwndUpDown
Definition: tab.c:119
INT uFocus
Definition: tab.c:113
HCURSOR hcurArrow
Definition: tab.c:106
BOOL DoRedraw
Definition: tab.c:114
BOOL fHeightSet
Definition: tab.c:117
INT cbInfo
Definition: tab.c:120
HIMAGELIST himl
Definition: tab.c:107
HWND hwndToolTip
Definition: tab.c:108
UINT uNumRows
Definition: tab.c:97
HWND hwnd
Definition: tab.c:94
INT iHotTracked
Definition: tab.c:112
UINT uNumItem
Definition: tab.c:96
BOOL needsScrolling
Definition: tab.c:115
INT tabHeight
Definition: tab.c:98
INT iSelected
Definition: tab.c:111
USHORT uVItemPadding_s
Definition: tab.c:104
HWND hwndNotify
Definition: tab.c:95
USHORT uHItemPadding_s
Definition: tab.c:103
DWORD dwStyle
Definition: tab.c:124
Definition: tab.c:74
BYTE extra[1]
Definition: tab.c:84
LPWSTR pszText
Definition: tab.c:76
INT iImage
Definition: tab.c:77
DWORD dwState
Definition: tab.c:75
RECT rect
Definition: tab.c:78
Definition: dpa.c:49
LPCWSTR lpszClassName
Definition: winuser.h:3188
HBRUSH hbrBackground
Definition: winuser.h:3186
int cbClsExtra
Definition: winuser.h:3181
UINT style
Definition: winuser.h:3179
WNDPROC lpfnWndProc
Definition: winuser.h:3180
int cbWndExtra
Definition: winuser.h:3182
HCURSOR hCursor
Definition: winuser.h:3185
Definition: inflate.c:139
ULONG_PTR itemData
Definition: winuser.h:3096
UINT_PTR idFrom
Definition: winuser.h:3161
UINT code
Definition: winuser.h:3162
HWND hwndFrom
Definition: winuser.h:3160
LONG right
Definition: windef.h:308
LONG bottom
Definition: windef.h:309
LONG top
Definition: windef.h:307
LONG left
Definition: windef.h:306
DWORD styleNew
Definition: winuser.h:3696
DWORD styleOld
Definition: winuser.h:3695
LPARAM lParam
Definition: commctrl.h:4031
DWORD dwState
Definition: commctrl.h:4026
LPWSTR pszText
Definition: commctrl.h:4028
int iImage
Definition: commctrl.h:4030
DWORD dwStateMask
Definition: commctrl.h:4027
int cchTextMax
Definition: commctrl.h:4029
UINT mask
Definition: commctrl.h:4025
LONG tmHeight
Definition: wingdi.h:2383
#define max(a, b)
Definition: svc.c:63
TW_UINT32 TW_UINT16 TW_UINT16 MSG
Definition: twain.h:1829
uint32_t DWORD_PTR
Definition: typedefs.h:65
uint32_t * LPDWORD
Definition: typedefs.h:59
int32_t INT
Definition: typedefs.h:58
uint32_t ULONG_PTR
Definition: typedefs.h:65
#define MAKELONG(a, b)
Definition: typedefs.h:249
#define HIWORD(l)
Definition: typedefs.h:247
static const WCHAR isW[]
Definition: lex.c:62
@ TIS_FOCUSED
Definition: vsstyle.h:1238
@ TIS_SELECTED
Definition: vsstyle.h:1236
@ TIS_HOT
Definition: vsstyle.h:1235
@ TIS_NORMAL
Definition: vsstyle.h:1234
@ TABP_TOPTABITEMRIGHTEDGE
Definition: vsstyle.h:1224
@ TABP_TOPTABITEMBOTHEDGE
Definition: vsstyle.h:1225
@ TABP_TABITEMRIGHTEDGE
Definition: vsstyle.h:1220
@ TABP_TABITEM
Definition: vsstyle.h:1218
@ TABP_TABITEMLEFTEDGE
Definition: vsstyle.h:1219
@ TABP_TABITEMBOTHEDGE
Definition: vsstyle.h:1221
@ TABP_TOPTABITEM
Definition: vsstyle.h:1222
@ TABP_PANE
Definition: vsstyle.h:1226
@ TABP_TOPTABITEMLEFTEDGE
Definition: vsstyle.h:1223
#define ZeroMemory
Definition: winbase.h:1737
_In_ LONG _In_ HWND hwnd
Definition: winddi.h:4023
LONG_PTR LPARAM
Definition: windef.h:208
LONG_PTR LRESULT
Definition: windef.h:209
UINT_PTR WPARAM
Definition: windef.h:207
DWORD COLORREF
Definition: windef.h:300
HICON HCURSOR
Definition: windef.h:299
#define WINAPI
Definition: msvc.h:6
BOOL WINAPI GetTextMetricsW(_In_ HDC, _Out_ LPTEXTMETRICW)
Definition: text.c:221
HGDIOBJ WINAPI GetStockObject(_In_ int)
int WINAPI GetObjectW(_In_ HANDLE h, _In_ int c, _Out_writes_bytes_opt_(c) LPVOID pv)
int WINAPI GetDeviceCaps(_In_opt_ HDC, _In_ int)
COLORREF WINAPI SetBkColor(_In_ HDC, _In_ COLORREF)
Definition: dc.c:999
int WINAPI ExcludeClipRect(_In_ HDC, _In_ int, _In_ int, _In_ int, _In_ int)
#define DEFAULT_GUI_FONT
Definition: wingdi.h:909
HGDIOBJ WINAPI SelectObject(_In_ HDC, _In_ HGDIOBJ)
Definition: dc.c:1546
#define TRANSPARENT
Definition: wingdi.h:950
#define ETO_CLIPPED
Definition: wingdi.h:648
BOOL WINAPI ExtTextOutW(_In_ HDC hdc, _In_ int x, _In_ int y, _In_ UINT options, _In_opt_ const RECT *lprect, _In_reads_opt_(c) LPCWSTR lpString, _In_ UINT c, _In_reads_opt_(c) const INT *lpDx)
#define SYSTEM_FONT
Definition: wingdi.h:911
#define LOGPIXELSX
Definition: wingdi.h:718
int WINAPI FillRect(HDC, LPCRECT, HBRUSH)
HFONT WINAPI CreateFontIndirectW(_In_ const LOGFONTW *)
int WINAPI SetBkMode(_In_ HDC, _In_ int)
Definition: dc.c:1056
COLORREF WINAPI SetTextColor(_In_ HDC, _In_ COLORREF)
Definition: text.c:918
HBRUSH WINAPI CreateSolidBrush(_In_ COLORREF)
HPEN WINAPI CreatePen(_In_ int, _In_ int, _In_ COLORREF)
#define PS_SOLID
Definition: wingdi.h:586
BOOL WINAPI GetTextExtentPoint32W(_In_ HDC hdc, _In_reads_(c) LPCWSTR lpString, _In_ int c, _Out_ LPSIZE psizl)
#define WM_PAINT
Definition: winuser.h:1623
HWND WINAPI GetFocus(void)
Definition: window.c:1865
int WINAPI ReleaseDC(_In_opt_ HWND, _In_ HDC)
#define CS_VREDRAW
Definition: winuser.h:658
BOOL WINAPI IsWindow(_In_opt_ HWND)
#define ODS_SELECTED
Definition: winuser.h:2548
#define SW_HIDE
Definition: winuser.h:771
BOOL WINAPI RedrawWindow(_In_opt_ HWND, _In_opt_ LPCRECT, _In_opt_ HRGN, _In_ UINT)
#define GetWindowLongPtrW
Definition: winuser.h:4832
#define WM_HSCROLL
Definition: winuser.h:1746
#define EDGE_SUNKEN
Definition: winuser.h:451
BOOL WINAPI ShowWindow(_In_ HWND, _In_ int)
#define COLOR_SCROLLBAR
Definition: winuser.h:915
DWORD WINAPI GetMessagePos(void)
Definition: message.c:1351
#define ODA_DRAWENTIRE
Definition: winuser.h:2545
LRESULT WINAPI DefWindowProcW(_In_ HWND, _In_ UINT, _In_ WPARAM, _In_ LPARAM)
BOOL WINAPI GetWindowRect(_In_ HWND, _Out_ LPRECT)
#define WM_CREATE
Definition: winuser.h:1611
#define DLGC_WANTCHARS
Definition: winuser.h:2621
BOOL WINAPI SetWindowPos(_In_ HWND, _In_opt_ HWND, _In_ int, _In_ int, _In_ int, _In_ int, _In_ UINT)
#define WVR_ALIGNTOP
Definition: winuser.h:2518
#define WM_SIZE
Definition: winuser.h:1614
#define COLOR_HIGHLIGHT
Definition: winuser.h:929
HBRUSH WINAPI GetSysColorBrush(_In_ int)
LONG WINAPI SetWindowLongW(_In_ HWND, _In_ int, _In_ LONG)
LONG WINAPI GetWindowLongW(_In_ HWND, _In_ int)
#define DT_SINGLELINE
Definition: winuser.h:540
#define CS_HREDRAW
Definition: winuser.h:653
ATOM WINAPI RegisterClassW(_In_ CONST WNDCLASSW *)
#define BF_LEFT
Definition: winuser.h:454
#define IDC_ARROW
Definition: winuser.h:687
BOOL WINAPI GetCursorPos(_Out_ LPPOINT)
Definition: cursoricon.c:2722
#define WM_NCHITTEST
Definition: winuser.h:1689
#define BF_DIAGONAL_ENDTOPRIGHT
Definition: winuser.h:464
#define WM_RBUTTONUP
Definition: winuser.h:1783
#define WM_SETFOCUS
Definition: winuser.h:1616
#define EDGE_ETCHED
Definition: winuser.h:452
#define WM_MOUSEMOVE
Definition: winuser.h:1778
#define RDW_UPDATENOW
Definition: winuser.h:1223
#define RDW_ERASE
Definition: winuser.h:1214
#define BF_BOTTOM
Definition: winuser.h:457
#define CS_DBLCLKS
Definition: winuser.h:651
#define WM_LBUTTONDOWN
Definition: winuser.h:1779
#define WM_SYSCOLORCHANGE
Definition: winuser.h:1629
HCURSOR WINAPI LoadCursorW(_In_opt_ HINSTANCE, _In_ LPCWSTR)
Definition: cursoricon.c:2157
#define WM_GETFONT
Definition: winuser.h:1654
#define SM_CYHSCROLL
Definition: winuser.h:965
#define WM_DRAWITEM
Definition: winuser.h:1648
UINT_PTR WINAPI SetTimer(_In_opt_ HWND, _In_ UINT_PTR, _In_ UINT, _In_opt_ TIMERPROC)
BOOL WINAPI PtInRect(_In_ LPCRECT, _In_ POINT)
BOOL WINAPI IsWindowUnicode(_In_ HWND)
#define DT_LEFT
Definition: winuser.h:534
BOOL WINAPI GetClientRect(_In_ HWND, _Out_ LPRECT)
BOOL WINAPI DrawEdge(_In_ HDC, _Inout_ LPRECT, _In_ UINT, _In_ UINT)
HWND WINAPI SetFocus(_In_opt_ HWND)
#define MK_CONTROL
Definition: winuser.h:2373
#define BF_TOP
Definition: winuser.h:455
#define WM_SETFONT
Definition: winuser.h:1653
HWND WINAPI CreateWindowExW(_In_ DWORD dwExStyle, _In_opt_ LPCWSTR lpClassName, _In_opt_ LPCWSTR lpWindowName, _In_ DWORD dwStyle, _In_ int X, _In_ int Y, _In_ int nWidth, _In_ int nHeight, _In_opt_ HWND hWndParent, _In_opt_ HMENU hMenu, _In_opt_ HINSTANCE hInstance, _In_opt_ LPVOID lpParam)
BOOL WINAPI EndPaint(_In_ HWND, _In_ const PAINTSTRUCT *)
#define BF_RIGHT
Definition: winuser.h:456
#define DLGC_WANTARROWS
Definition: winuser.h:2613
#define BDR_RAISEDINNER
Definition: winuser.h:444
#define HTCLIENT
Definition: winuser.h:2478
#define SWP_SHOWWINDOW
Definition: winuser.h:1251
#define BF_DIAGONAL_ENDBOTTOMLEFT
Definition: winuser.h:466
HDC WINAPI GetDC(_In_opt_ HWND)
#define CreateWindowW(a, b, c, d, e, f, g, h, i, j, k)
Definition: winuser.h:4319
#define WM_LBUTTONUP
Definition: winuser.h:1780
LONG WINAPI GetMessageTime(void)
Definition: message.c:1361
BOOL WINAPI SetRectEmpty(_Out_ LPRECT)
#define SM_CXHSCROLL
Definition: winuser.h:985
#define CW_USEDEFAULT
Definition: winuser.h:225
#define BF_DIAGONAL_ENDBOTTOMRIGHT
Definition: winuser.h:467
#define CS_GLOBALCLASS
Definition: winuser.h:652
#define VK_LEFT
Definition: winuser.h:2227
#define WM_NCDESTROY
Definition: winuser.h:1687
#define VK_RIGHT
Definition: winuser.h:2229
#define HTTRANSPARENT
Definition: winuser.h:2476
HWND WINAPI WindowFromPoint(_In_ POINT)
#define GWLP_ID
Definition: winuser.h:863
#define WM_USER
Definition: winuser.h:1898
BOOL WINAPI OffsetRect(_Inout_ LPRECT, _In_ int, _In_ int)
BOOL WINAPI UnregisterClassW(_In_ LPCWSTR, HINSTANCE)
#define WM_KEYDOWN
Definition: winuser.h:1718
BOOL WINAPI DrawFocusRect(_In_ HDC, _In_ LPCRECT)
BOOL WINAPI InvalidateRect(_In_opt_ HWND, _In_opt_ LPCRECT, _In_ BOOL)
#define SWP_NOZORDER
Definition: winuser.h:1250
#define DT_CALCRECT
Definition: winuser.h:526
HDC WINAPI BeginPaint(_In_ HWND, _Out_ LPPAINTSTRUCT)
BOOL WINAPI KillTimer(_In_opt_ HWND, _In_ UINT_PTR)
#define BF_SOFT
Definition: winuser.h:469
#define SetWindowLongPtrW
Definition: winuser.h:5358
BOOL WINAPI InflateRect(_Inout_ LPRECT, _In_ int, _In_ int)
#define BF_RECT
Definition: winuser.h:462
#define WM_NCCALCSIZE
Definition: winuser.h:1688
#define GWL_STYLE
Definition: winuser.h:855
BOOL WINAPI DestroyWindow(_In_ HWND)
#define EDGE_RAISED
Definition: winuser.h:450
#define BF_DIAGONAL_ENDTOPLEFT
Definition: winuser.h:465
#define WM_KILLFOCUS
Definition: winuser.h:1617
struct tagCREATESTRUCTW * LPCREATESTRUCTW
#define ODS_FOCUS
Definition: winuser.h:2552
int WINAPI GetSystemMetrics(_In_ int)
#define RDW_INVALIDATE
Definition: winuser.h:1217
#define WM_GETDLGCODE
Definition: winuser.h:1692
LRESULT WINAPI SendMessageW(_In_ HWND, _In_ UINT, _In_ WPARAM, _In_ LPARAM)
#define COLOR_BTNFACE
Definition: winuser.h:931
BOOL WINAPI SetRect(_Out_ LPRECT, _In_ int, _In_ int, _In_ int, _In_ int)
#define WM_SETREDRAW
Definition: winuser.h:1619
#define SB_THUMBPOSITION
Definition: winuser.h:572
BOOL WINAPI ScreenToClient(_In_ HWND, _Inout_ LPPOINT)
_In_opt_ PALLOCATE_FUNCTION _In_opt_ PFREE_FUNCTION Free
Definition: exfuncs.h:815
char * LPSTR
Definition: