ReactOS 0.4.15-dev-7127-g2dd0c6c
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 TAB_InvalidateTabArea(infoPtr);
2804
2805 return TRUE;
2806}
2807
2808static inline LRESULT TAB_GetItemCount (const TAB_INFO *infoPtr)
2809{
2810 TRACE("\n");
2811 return infoPtr->uNumItem;
2812}
2813
2814
2815static LRESULT
2816TAB_GetItemT (TAB_INFO *infoPtr, INT iItem, LPTCITEMW tabItem, BOOL bUnicode)
2817{
2818 TAB_ITEM *wineItem;
2819
2820 TRACE("(%p,%d,%p,%s)\n", infoPtr, iItem, tabItem, bUnicode ? "true" : "false");
2821
2822 if (!tabItem) return FALSE;
2823
2824 if (iItem < 0 || iItem >= infoPtr->uNumItem)
2825 {
2826 /* init requested fields */
2827 if (tabItem->mask & TCIF_IMAGE) tabItem->iImage = 0;
2828 if (tabItem->mask & TCIF_PARAM) tabItem->lParam = 0;
2829 if (tabItem->mask & TCIF_STATE) tabItem->dwState = 0;
2830 return FALSE;
2831 }
2832
2833 wineItem = TAB_GetItem(infoPtr, iItem);
2834
2835 if (tabItem->mask & TCIF_IMAGE)
2836 tabItem->iImage = wineItem->iImage;
2837
2838 if (tabItem->mask & TCIF_PARAM)
2839 memcpy(&tabItem->lParam, wineItem->extra, infoPtr->cbInfo);
2840
2841 if (tabItem->mask & TCIF_RTLREADING)
2842 FIXME("TCIF_RTLREADING\n");
2843
2844 if (tabItem->mask & TCIF_STATE)
2845 tabItem->dwState = wineItem->dwState & tabItem->dwStateMask;
2846
2847 if (tabItem->mask & TCIF_TEXT)
2848 {
2849 if (bUnicode)
2850 Str_GetPtrW (wineItem->pszText, tabItem->pszText, tabItem->cchTextMax);
2851 else
2852 Str_GetPtrWtoA (wineItem->pszText, (LPSTR)tabItem->pszText, tabItem->cchTextMax);
2853 }
2854
2855 TAB_DumpItemExternalT(tabItem, iItem, bUnicode);
2856
2857 return TRUE;
2858}
2859
2860
2861static LRESULT TAB_DeleteItem (TAB_INFO *infoPtr, INT iItem)
2862{
2863 TAB_ITEM *item;
2864
2865 TRACE("(%p, %d)\n", infoPtr, iItem);
2866
2867 if (iItem < 0 || iItem >= infoPtr->uNumItem) return FALSE;
2868
2869 TAB_InvalidateTabArea(infoPtr);
2870 item = TAB_GetItem(infoPtr, iItem);
2871 Free(item->pszText);
2872 Free(item);
2873 infoPtr->uNumItem--;
2874 DPA_DeletePtr(infoPtr->items, iItem);
2875
2876 if (infoPtr->uNumItem == 0)
2877 {
2878 if (infoPtr->iHotTracked >= 0)
2879 {
2881 infoPtr->iHotTracked = -1;
2882 }
2883
2884 infoPtr->iSelected = -1;
2885 }
2886 else
2887 {
2888 if (iItem <= infoPtr->iHotTracked)
2889 {
2890 /* When tabs move left/up, the hot track item may change */
2891 FIXME("Recalc hot track\n");
2892 }
2893 }
2894
2895 /* adjust the selected index */
2896 if (iItem == infoPtr->iSelected)
2897 infoPtr->iSelected = -1;
2898 else if (iItem < infoPtr->iSelected)
2899 infoPtr->iSelected--;
2900
2901 /* reposition and repaint tabs */
2902 TAB_SetItemBounds(infoPtr);
2903
2904 return TRUE;
2905}
2906
2907static inline LRESULT TAB_DeleteAllItems (TAB_INFO *infoPtr)
2908{
2909 TRACE("(%p)\n", infoPtr);
2910 while (infoPtr->uNumItem)
2911 TAB_DeleteItem (infoPtr, 0);
2912 return TRUE;
2913}
2914
2915
2916static inline LRESULT TAB_GetFont (const TAB_INFO *infoPtr)
2917{
2918 TRACE("(%p) returning %p\n", infoPtr, infoPtr->hFont);
2919 return (LRESULT)infoPtr->hFont;
2920}
2921
2922static inline LRESULT TAB_SetFont (TAB_INFO *infoPtr, HFONT hNewFont)
2923{
2924 TRACE("(%p,%p)\n", infoPtr, hNewFont);
2925
2926 infoPtr->hFont = hNewFont;
2927
2928 TAB_SetItemBounds(infoPtr);
2929
2930 TAB_InvalidateTabArea(infoPtr);
2931
2932 return 0;
2933}
2934
2935
2936static inline LRESULT TAB_GetImageList (const TAB_INFO *infoPtr)
2937{
2938 TRACE("\n");
2939 return (LRESULT)infoPtr->himl;
2940}
2941
2942static inline LRESULT TAB_SetImageList (TAB_INFO *infoPtr, HIMAGELIST himlNew)
2943{
2944 HIMAGELIST himlPrev = infoPtr->himl;
2945 TRACE("himl=%p\n", himlNew);
2946 infoPtr->himl = himlNew;
2947 TAB_SetItemBounds(infoPtr);
2948 InvalidateRect(infoPtr->hwnd, NULL, TRUE);
2949 return (LRESULT)himlPrev;
2950}
2951
2952static inline LRESULT TAB_GetUnicodeFormat (const TAB_INFO *infoPtr)
2953{
2954 TRACE("(%p)\n", infoPtr);
2955 return infoPtr->bUnicode;
2956}
2957
2958static inline LRESULT TAB_SetUnicodeFormat (TAB_INFO *infoPtr, BOOL bUnicode)
2959{
2960 BOOL bTemp = infoPtr->bUnicode;
2961
2962 TRACE("(%p %d)\n", infoPtr, bUnicode);
2963 infoPtr->bUnicode = bUnicode;
2964
2965 return bTemp;
2966}
2967
2968static inline LRESULT TAB_Size (TAB_INFO *infoPtr)
2969{
2970/* I'm not really sure what the following code was meant to do.
2971 This is what it is doing:
2972 When WM_SIZE is sent with SIZE_RESTORED, the control
2973 gets positioned in the top left corner.
2974
2975 RECT parent_rect;
2976 HWND parent;
2977 UINT uPosFlags,cx,cy;
2978
2979 uPosFlags=0;
2980 if (!wParam) {
2981 parent = GetParent (hwnd);
2982 GetClientRect(parent, &parent_rect);
2983 cx=LOWORD (lParam);
2984 cy=HIWORD (lParam);
2985 if (GetWindowLongW(hwnd, GWL_STYLE) & CCS_NORESIZE)
2986 uPosFlags |= (SWP_NOSIZE | SWP_NOMOVE);
2987
2988 SetWindowPos (hwnd, 0, parent_rect.left, parent_rect.top,
2989 cx, cy, uPosFlags | SWP_NOZORDER);
2990 } else {
2991 FIXME("WM_SIZE flag %x %lx not handled\n", wParam, lParam);
2992 } */
2993
2994 /* Recompute the size/position of the tabs. */
2995 TAB_SetItemBounds (infoPtr);
2996
2997 /* Force a repaint of the control. */
2998 InvalidateRect(infoPtr->hwnd, NULL, TRUE);
2999
3000 return 0;
3001}
3002
3003
3005{
3006 TAB_INFO *infoPtr;
3007 TEXTMETRICW fontMetrics;
3008 HDC hdc;
3009 HFONT hOldFont;
3010 DWORD style;
3011
3012 infoPtr = Alloc (sizeof(TAB_INFO));
3013
3014 SetWindowLongPtrW(hwnd, 0, (DWORD_PTR)infoPtr);
3015
3016 infoPtr->hwnd = hwnd;
3017 infoPtr->hwndNotify = ((LPCREATESTRUCTW)lParam)->hwndParent;
3018 infoPtr->uNumItem = 0;
3019 infoPtr->uNumRows = 0;
3020 infoPtr->uHItemPadding = 6;
3021 infoPtr->uVItemPadding = 3;
3022 infoPtr->uHItemPadding_s = 6;
3023 infoPtr->uVItemPadding_s = 3;
3024 infoPtr->hFont = 0;
3025 infoPtr->items = DPA_Create(8);
3026 infoPtr->hcurArrow = LoadCursorW (0, (LPWSTR)IDC_ARROW);
3027 infoPtr->iSelected = -1;
3028 infoPtr->iHotTracked = -1;
3029 infoPtr->uFocus = -1;
3030 infoPtr->hwndToolTip = 0;
3031 infoPtr->DoRedraw = TRUE;
3032 infoPtr->needsScrolling = FALSE;
3033 infoPtr->hwndUpDown = 0;
3034 infoPtr->leftmostVisible = 0;
3035 infoPtr->fHeightSet = FALSE;
3036 infoPtr->bUnicode = IsWindowUnicode (hwnd);
3037 infoPtr->cbInfo = sizeof(LPARAM);
3038
3039 TRACE("Created tab control, hwnd [%p]\n", hwnd);
3040
3041 /* The tab control always has the WS_CLIPSIBLINGS style. Even
3042 if you don't specify it in CreateWindow. This is necessary in
3043 order for paint to work correctly. This follows windows behaviour. */
3048
3049 infoPtr->dwStyle = style;
3051
3052 if (infoPtr->dwStyle & TCS_TOOLTIPS) {
3053 /* Create tooltip control */
3054 infoPtr->hwndToolTip =
3058 hwnd, 0, 0, 0);
3059
3060 /* Send NM_TOOLTIPSCREATED notification */
3061 if (infoPtr->hwndToolTip) {
3062 NMTOOLTIPSCREATED nmttc;
3063
3064 nmttc.hdr.hwndFrom = hwnd;
3066 nmttc.hdr.code = NM_TOOLTIPSCREATED;
3067 nmttc.hwndToolTips = infoPtr->hwndToolTip;
3068
3071 }
3072 }
3073
3074 OpenThemeData (infoPtr->hwnd, themeClass);
3075
3076 /*
3077 * We need to get text information so we need a DC and we need to select
3078 * a font.
3079 */
3080 hdc = GetDC(hwnd);
3082
3083 /* Use the system font to determine the initial height of a tab. */
3084 GetTextMetricsW(hdc, &fontMetrics);
3085
3086 /*
3087 * Make sure there is enough space for the letters + growing the
3088 * selected item + extra space for the selected item.
3089 */
3090 infoPtr->tabHeight = fontMetrics.tmHeight + SELECTED_TAB_OFFSET +
3091 ((infoPtr->dwStyle & TCS_BUTTONS) ? 2 : 1) *
3092 infoPtr->uVItemPadding;
3093
3094 /* Initialize the width of a tab. */
3095 if (infoPtr->dwStyle & TCS_FIXEDWIDTH)
3096 infoPtr->tabWidth = GetDeviceCaps(hdc, LOGPIXELSX);
3097
3098 infoPtr->tabMinWidth = -1;
3099
3100 TRACE("tabH=%d, tabW=%d\n", infoPtr->tabHeight, infoPtr->tabWidth);
3101
3102 SelectObject (hdc, hOldFont);
3103 ReleaseDC(hwnd, hdc);
3104
3105 return 0;
3106}
3107
3108static LRESULT
3110{
3111 INT iItem;
3112
3113 SetWindowLongPtrW(infoPtr->hwnd, 0, 0);
3114
3115 for (iItem = infoPtr->uNumItem - 1; iItem >= 0; iItem--)
3116 {
3117 TAB_ITEM *tab = TAB_GetItem(infoPtr, iItem);
3118
3119 DPA_DeletePtr(infoPtr->items, iItem);
3120 infoPtr->uNumItem--;
3121
3122 Free(tab->pszText);
3123 Free(tab);
3124 }
3125 DPA_Destroy(infoPtr->items);
3126 infoPtr->items = NULL;
3127
3128 if (infoPtr->hwndToolTip)
3129 DestroyWindow (infoPtr->hwndToolTip);
3130
3131 if (infoPtr->hwndUpDown)
3132 DestroyWindow(infoPtr->hwndUpDown);
3133
3134 if (infoPtr->iHotTracked >= 0)
3136
3137 CloseThemeData (GetWindowTheme (infoPtr->hwnd));
3138
3139 Free (infoPtr);
3140 return 0;
3141}
3142
3143/* update theme after a WM_THEMECHANGED message */
3144static LRESULT theme_changed(const TAB_INFO *infoPtr)
3145{
3146 HTHEME theme = GetWindowTheme (infoPtr->hwnd);
3147 CloseThemeData (theme);
3148 OpenThemeData (infoPtr->hwnd, themeClass);
3149 return 0;
3150}
3151
3153{
3154 if (!wParam)
3155 return 0;
3156 return WVR_ALIGNTOP;
3157}
3158
3159static inline LRESULT
3161{
3162 TRACE("(%p %d)\n", infoPtr, cbInfo);
3163
3164 if (cbInfo < 0 || infoPtr->uNumItem) return FALSE;
3165
3166 infoPtr->cbInfo = cbInfo;
3167 return TRUE;
3168}
3169
3171{
3172 TRACE("%p %d\n", infoPtr, image);
3173
3174 if (ImageList_Remove (infoPtr->himl, image))
3175 {
3176 INT i, *idx;
3177 RECT r;
3178
3179 /* shift indices, repaint items if needed */
3180 for (i = 0; i < infoPtr->uNumItem; i++)
3181 {
3182 idx = &TAB_GetItem(infoPtr, i)->iImage;
3183 if (*idx >= image)
3184 {
3185 if (*idx == image)
3186 *idx = -1;
3187 else
3188 (*idx)--;
3189
3190 /* repaint item */
3191 if (TAB_InternalGetItemRect (infoPtr, i, &r, NULL))
3192 InvalidateRect (infoPtr->hwnd, &r, TRUE);
3193 }
3194 }
3195 }
3196
3197 return 0;
3198}
3199
3200static LRESULT
3201TAB_SetExtendedStyle (TAB_INFO *infoPtr, DWORD exMask, DWORD exStyle)
3202{
3203 DWORD prevstyle = infoPtr->exStyle;
3204
3205 /* zero mask means all styles */
3206 if (exMask == 0) exMask = ~0;
3207
3208 if (exMask & TCS_EX_REGISTERDROP)
3209 {
3210 FIXME("TCS_EX_REGISTERDROP style unimplemented\n");
3211 exMask &= ~TCS_EX_REGISTERDROP;
3212 exStyle &= ~TCS_EX_REGISTERDROP;
3213 }
3214
3215 if (exMask & TCS_EX_FLATSEPARATORS)
3216 {
3217 if ((prevstyle ^ exStyle) & TCS_EX_FLATSEPARATORS)
3218 {
3219 infoPtr->exStyle ^= TCS_EX_FLATSEPARATORS;
3220 TAB_InvalidateTabArea(infoPtr);
3221 }
3222 }
3223
3224 return prevstyle;
3225}
3226
3227static inline LRESULT
3229{
3230 return infoPtr->exStyle;
3231}
3232
3233static LRESULT
3234TAB_DeselectAll (TAB_INFO *infoPtr, BOOL excludesel)
3235{
3236 BOOL paint = FALSE;
3237 INT i, selected = infoPtr->iSelected;
3238
3239 TRACE("(%p, %d)\n", infoPtr, excludesel);
3240
3241 if (!(infoPtr->dwStyle & TCS_BUTTONS))
3242 return 0;
3243
3244 for (i = 0; i < infoPtr->uNumItem; i++)
3245 {
3246 if ((TAB_GetItem(infoPtr, i)->dwState & TCIS_BUTTONPRESSED) &&
3247 (selected != i))
3248 {
3249 TAB_GetItem(infoPtr, i)->dwState &= ~TCIS_BUTTONPRESSED;
3250 paint = TRUE;
3251 }
3252 }
3253
3254 if (!excludesel && (selected != -1))
3255 {
3256 TAB_GetItem(infoPtr, selected)->dwState &= ~TCIS_BUTTONPRESSED;
3257 infoPtr->iSelected = -1;
3258 paint = TRUE;
3259 }
3260
3261 if (paint)
3262 TAB_InvalidateTabArea (infoPtr);
3263
3264 return 0;
3265}
3266
3267/***
3268 * DESCRIPTION:
3269 * Processes WM_STYLECHANGED messages.
3270 *
3271 * PARAMETER(S):
3272 * [I] infoPtr : valid pointer to the tab data structure
3273 * [I] wStyleType : window style type (normal or extended)
3274 * [I] lpss : window style information
3275 *
3276 * RETURN:
3277 * Zero
3278 */
3279static INT TAB_StyleChanged(TAB_INFO *infoPtr, WPARAM wStyleType,
3280 const STYLESTRUCT *lpss)
3281{
3282 TRACE("(styletype=%lx, styleOld=0x%08x, styleNew=0x%08x)\n",
3283 wStyleType, lpss->styleOld, lpss->styleNew);
3284
3285 if (wStyleType != GWL_STYLE) return 0;
3286
3287 infoPtr->dwStyle = lpss->styleNew;
3288
3289 TAB_SetItemBounds (infoPtr);
3290 InvalidateRect(infoPtr->hwnd, NULL, TRUE);
3291
3292 return 0;
3293}
3294
3295static LRESULT WINAPI
3297{
3298 TAB_INFO *infoPtr = TAB_GetInfoPtr(hwnd);
3299
3300 TRACE("hwnd=%p msg=%x wParam=%lx lParam=%lx\n", hwnd, uMsg, wParam, lParam);
3301 if (!infoPtr && (uMsg != WM_CREATE))
3302 return DefWindowProcW (hwnd, uMsg, wParam, lParam);
3303
3304 switch (uMsg)
3305 {
3306 case TCM_GETIMAGELIST:
3307 return TAB_GetImageList (infoPtr);
3308
3309 case TCM_SETIMAGELIST:
3310 return TAB_SetImageList (infoPtr, (HIMAGELIST)lParam);
3311
3312 case TCM_GETITEMCOUNT:
3313 return TAB_GetItemCount (infoPtr);
3314
3315 case TCM_GETITEMA:
3316 case TCM_GETITEMW:
3317 return TAB_GetItemT (infoPtr, (INT)wParam, (LPTCITEMW)lParam, uMsg == TCM_GETITEMW);
3318
3319 case TCM_SETITEMA:
3320 case TCM_SETITEMW:
3321 return TAB_SetItemT (infoPtr, (INT)wParam, (LPTCITEMW)lParam, uMsg == TCM_SETITEMW);
3322
3323 case TCM_DELETEITEM:
3324 return TAB_DeleteItem (infoPtr, (INT)wParam);
3325
3326 case TCM_DELETEALLITEMS:
3327 return TAB_DeleteAllItems (infoPtr);
3328
3329 case TCM_GETITEMRECT:
3330 return TAB_GetItemRect (infoPtr, (INT)wParam, (LPRECT)lParam);
3331
3332 case TCM_GETCURSEL:
3333 return TAB_GetCurSel (infoPtr);
3334
3335 case TCM_HITTEST:
3336 return TAB_HitTest (infoPtr, (LPTCHITTESTINFO)lParam);
3337
3338 case TCM_SETCURSEL:
3339 return TAB_SetCurSel (infoPtr, (INT)wParam);
3340
3341 case TCM_INSERTITEMA:
3342 case TCM_INSERTITEMW:
3343 return TAB_InsertItemT (infoPtr, (INT)wParam, (TCITEMW*)lParam, uMsg == TCM_INSERTITEMW);
3344
3345 case TCM_SETITEMEXTRA:
3346 return TAB_SetItemExtra (infoPtr, (INT)wParam);
3347
3348 case TCM_ADJUSTRECT:
3349 return TAB_AdjustRect (infoPtr, (BOOL)wParam, (LPRECT)lParam);
3350
3351 case TCM_SETITEMSIZE:
3352 return TAB_SetItemSize (infoPtr, (INT)LOWORD(lParam), (INT)HIWORD(lParam));
3353
3354 case TCM_REMOVEIMAGE:
3355 return TAB_RemoveImage (infoPtr, (INT)wParam);
3356
3357 case TCM_SETPADDING:
3358 return TAB_SetPadding (infoPtr, lParam);
3359
3360 case TCM_GETROWCOUNT:
3361 return TAB_GetRowCount(infoPtr);
3362
3364 return TAB_GetUnicodeFormat (infoPtr);
3365
3367 return TAB_SetUnicodeFormat (infoPtr, (BOOL)wParam);
3368
3369 case TCM_HIGHLIGHTITEM:
3370 return TAB_HighlightItem (infoPtr, (INT)wParam, (BOOL)LOWORD(lParam));
3371
3372 case TCM_GETTOOLTIPS:
3373 return TAB_GetToolTips (infoPtr);
3374
3375 case TCM_SETTOOLTIPS:
3376 return TAB_SetToolTips (infoPtr, (HWND)wParam);
3377
3378 case TCM_GETCURFOCUS:
3379 return TAB_GetCurFocus (infoPtr);
3380
3381 case TCM_SETCURFOCUS:
3382 return TAB_SetCurFocus (infoPtr, (INT)wParam);
3383
3384 case TCM_SETMINTABWIDTH:
3385 return TAB_SetMinTabWidth(infoPtr, (INT)lParam);
3386
3387 case TCM_DESELECTALL:
3388 return TAB_DeselectAll (infoPtr, (BOOL)wParam);
3389
3391 return TAB_GetExtendedStyle (infoPtr);
3392
3394 return TAB_SetExtendedStyle (infoPtr, wParam, lParam);
3395
3396 case WM_GETFONT:
3397 return TAB_GetFont (infoPtr);
3398
3399 case WM_SETFONT:
3400 return TAB_SetFont (infoPtr, (HFONT)wParam);
3401
3402 case WM_CREATE:
3403 return TAB_Create (hwnd, lParam);
3404
3405 case WM_NCDESTROY:
3406 return TAB_Destroy (infoPtr);
3407
3408 case WM_GETDLGCODE:
3410
3411 case WM_LBUTTONDOWN:
3412 return TAB_LButtonDown (infoPtr, wParam, lParam);
3413
3414 case WM_LBUTTONUP:
3415 return TAB_LButtonUp (infoPtr);
3416
3417 case WM_NOTIFY:
3418 return SendMessageW(infoPtr->hwndNotify, WM_NOTIFY, wParam, lParam);
3419
3420 case WM_RBUTTONUP:
3421 TAB_RButtonUp (infoPtr);
3422 return DefWindowProcW (hwnd, uMsg, wParam, lParam);
3423
3424 case WM_MOUSEMOVE:
3425 return TAB_MouseMove (infoPtr, wParam, lParam);
3426
3427 case WM_PRINTCLIENT:
3428 case WM_PAINT:
3429 return TAB_Paint (infoPtr, (HDC)wParam);
3430
3431 case WM_SIZE:
3432 return TAB_Size (infoPtr);
3433
3434 case WM_SETREDRAW:
3435 return TAB_SetRedraw (infoPtr, (BOOL)wParam);
3436
3437 case WM_HSCROLL:
3438 return TAB_OnHScroll(infoPtr, (int)LOWORD(wParam), (int)HIWORD(wParam));
3439
3440 case WM_STYLECHANGED:
3441 return TAB_StyleChanged(infoPtr, wParam, (LPSTYLESTRUCT)lParam);
3442
3443 case WM_SYSCOLORCHANGE:
3445 return 0;
3446
3447 case WM_THEMECHANGED:
3448 return theme_changed (infoPtr);
3449
3450 case WM_KILLFOCUS:
3451 TAB_KillFocus(infoPtr);
3452 case WM_SETFOCUS:
3453 TAB_FocusChanging(infoPtr);
3454 break; /* Don't disturb normal focus behavior */
3455
3456 case WM_KEYDOWN:
3457 return TAB_KeyDown(infoPtr, wParam, lParam);
3458
3459 case WM_NCHITTEST:
3460 return TAB_NCHitTest(infoPtr, lParam);
3461
3462 case WM_NCCALCSIZE:
3463 return TAB_NCCalcSize(wParam);
3464
3465 default:
3466 if (uMsg >= WM_USER && uMsg < WM_APP && !COMCTL32_IsReflectedMessage(uMsg))
3467 WARN("unknown msg %04x wp=%08lx lp=%08lx\n",
3468 uMsg, wParam, lParam);
3469 break;
3470 }
3471 return DefWindowProcW(hwnd, uMsg, wParam, lParam);
3472}
3473
3474
3475void
3477{
3478 WNDCLASSW wndClass;
3479
3480 ZeroMemory (&wndClass, sizeof(WNDCLASSW));
3482 wndClass.lpfnWndProc = TAB_WindowProc;
3483 wndClass.cbClsExtra = 0;
3484 wndClass.cbWndExtra = sizeof(TAB_INFO *);
3485 wndClass.hCursor = LoadCursorW (0, (LPWSTR)IDC_ARROW);
3486 wndClass.hbrBackground = (HBRUSH)(COLOR_BTNFACE+1);
3487 wndClass.lpszClassName = WC_TABCONTROLW;
3488
3489 RegisterClassW (&wndClass);
3490}
3491
3492
3493void
3495{
3497}
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
PVOID Alloc(IN DWORD dwFlags, IN SIZE_T dwBytes)
Definition: main.c:63
#define FIXME(fmt,...)
Definition: debug.h:111
#define WARN(fmt,...)
Definition: debug.h:112
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:1748
BOOL Str_SetPtrAtoW(LPWSTR *lppDest, LPCSTR lpSrc) DECLSPEC_HIDDEN
VOID COMCTL32_RefreshSysColors(void) DECLSPEC_HIDDEN
Definition: commctrl.c:1586
INT WINAPI Str_GetPtrW(LPCWSTR, LPWSTR, INT)
Definition: string.c:204
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:236
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:2968
static LRESULT TAB_RemoveImage(TAB_INFO *infoPtr, INT image)
Definition: tab.c:3170
static LRESULT TAB_GetItemT(TAB_INFO *infoPtr, INT iItem, LPTCITEMW tabItem, BOOL bUnicode)
Definition: tab.c:2816
static LRESULT TAB_GetFont(const TAB_INFO *infoPtr)
Definition: tab.c:2916
static LRESULT TAB_SetCurSel(TAB_INFO *infoPtr, INT iItem)
Definition: tab.c:249
static LRESULT TAB_NCCalcSize(WPARAM wParam)
Definition: tab.c:3152
#define BUTTON_SPACINGY
Definition: tab.c:139
static LRESULT TAB_SetFont(TAB_INFO *infoPtr, HFONT hNewFont)
Definition: tab.c:2922
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:2952
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:3201
#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:2861
#define EXTRA_ICON_PADDING
Definition: tab.c:143
static LRESULT WINAPI TAB_WindowProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
Definition: tab.c:3296
static INT TAB_StyleChanged(TAB_INFO *infoPtr, WPARAM wStyleType, const STYLESTRUCT *lpss)
Definition: tab.c:3279
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:2907
static void TAB_SetItemBounds(TAB_INFO *infoPtr)
Definition: tab.c:1117
void TAB_Unregister(void)
Definition: tab.c:3494
#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:3476
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:2958
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:2942
static const WCHAR themeClass[]
Definition: tab.c:155
static LRESULT TAB_GetImageList(const TAB_INFO *infoPtr)
Definition: tab.c:2936
#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:3228
static LRESULT TAB_SetMinTabWidth(TAB_INFO *infoPtr, INT cx)
Definition: tab.c:2723
static LRESULT TAB_Create(HWND hwnd, LPARAM lParam)
Definition: tab.c:3004
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:3109
static LRESULT TAB_SetItemExtra(TAB_INFO *infoPtr, INT cbInfo)
Definition: tab.c:3160
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:3144
static LRESULT TAB_GetItemCount(const TAB_INFO *infoPtr)
Definition: tab.c:2808
#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:3234
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:1377
HRESULT WINAPI GetThemeBackgroundContentRect(HTHEME hTheme, HDC hdc, int iPartId, int iStateId, const RECT *pBoundingRect, RECT *pContentRect)
Definition: draw.c:1479
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:92
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:3935
#define UPDOWN_CLASSW
Definition: commctrl.h:2119
#define TCS_EX_REGISTERDROP
Definition: commctrl.h:3960
_Out_opt_ int _Out_opt_ int * cy
Definition: commctrl.h:586
#define TCS_FOCUSNEVER
Definition: commctrl.h:3957
#define TCM_SETIMAGELIST
Definition: commctrl.h:3965
#define ILD_NORMAL
Definition: commctrl.h:417
#define TCM_GETTOOLTIPS
Definition: commctrl.h:4095
#define TCS_FIXEDWIDTH
Definition: commctrl.h:3952
#define TCS_EX_FLATSEPARATORS
Definition: commctrl.h:3959
#define TCIF_STATE
Definition: commctrl.h:3975
#define TCS_OWNERDRAWFIXED
Definition: commctrl.h:3955
#define TCM_GETCURSEL
Definition: commctrl.h:4062
#define TCIS_BUTTONPRESSED
Definition: commctrl.h:3977
#define TCM_DELETEALLITEMS
Definition: commctrl.h:4056
#define TCHT_ONITEM
Definition: commctrl.h:4071
#define TTM_RELAYEVENT
Definition: commctrl.h:1792
#define UDM_SETPOS
Definition: commctrl.h:2143
#define TCM_GETIMAGELIST
Definition: commctrl.h:3962
#define TCS_MULTISELECT
Definition: commctrl.h:3941
#define TCM_DESELECTALL
Definition: commctrl.h:4105
#define TCM_GETCURFOCUS
Definition: commctrl.h:4099
#define TCM_SETPADDING
Definition: commctrl.h:4091
#define TOOLTIPS_CLASSW
Definition: commctrl.h:1707
#define TCM_GETROWCOUNT
Definition: commctrl.h:4093
_Out_opt_ int * cx
Definition: commctrl.h:585
#define TCM_INSERTITEMW
Definition: commctrl.h:4047
#define TCM_SETTOOLTIPS
Definition: commctrl.h:4097
#define TCN_KEYDOWN
Definition: commctrl.h:4118
#define TCN_SELCHANGING
Definition: commctrl.h:4133
#define NM_TOOLTIPSCREATED
Definition: commctrl.h:144
#define TCHT_NOWHERE
Definition: commctrl.h:4068
#define NM_CLICK
Definition: commctrl.h:130
#define TCM_SETITEMA
Definition: commctrl.h:4039
#define TCIS_HIGHLIGHTED
Definition: commctrl.h:3978
#define TCM_SETITEMW
Definition: commctrl.h:4040
#define TCM_ADJUSTRECT
Definition: commctrl.h:4085
#define TCS_HOTTRACK
Definition: commctrl.h:3945
#define TCS_FORCELABELLEFT
Definition: commctrl.h:3944
#define TCM_SETEXTENDEDSTYLE
Definition: commctrl.h:4109
#define TCIF_PARAM
Definition: commctrl.h:3974
#define TCM_GETITEMCOUNT
Definition: commctrl.h:3968
#define TCM_GETEXTENDEDSTYLE
Definition: commctrl.h:4111
#define TCM_GETITEMA
Definition: commctrl.h:4032
#define TCM_SETITEMSIZE
Definition: commctrl.h:4087
#define ODT_TAB
Definition: commctrl.h:79
#define TCS_FLATBUTTONS
Definition: commctrl.h:3942
#define TCM_GETUNICODEFORMAT
Definition: commctrl.h:4115
#define TCN_SELCHANGE
Definition: commctrl.h:4132
#define TCM_SETMINTABWIDTH
Definition: commctrl.h:4103
#define TCN_FOCUSCHANGE
Definition: commctrl.h:4135
#define TCM_HIGHLIGHTITEM
Definition: commctrl.h:4107
#define NM_RCLICK
Definition: commctrl.h:133
#define TCM_SETUNICODEFORMAT
Definition: commctrl.h:4113
#define UDS_HORZ
Definition: commctrl.h:2137
#define TCS_FORCEICONLEFT
Definition: commctrl.h:3943
#define TCM_SETCURSEL
Definition: commctrl.h:4065
#define UDM_SETRANGE32
Definition: commctrl.h:2151
#define TCS_RAGGEDRIGHT
Definition: commctrl.h:3953
#define TCM_GETITEMW
Definition: commctrl.h:4033
#define TCS_TOOLTIPS
Definition: commctrl.h:3956
#define TCM_INSERTITEMA
Definition: commctrl.h:4046
#define TCM_REMOVEIMAGE
Definition: commctrl.h:4089
#define TCIF_RTLREADING
Definition: commctrl.h:3973
#define TCM_HITTEST
Definition: commctrl.h:4081
#define TCS_BUTTONS
Definition: commctrl.h:3948
#define TCIF_TEXT
Definition: commctrl.h:3971
#define TCM_GETITEMRECT
Definition: commctrl.h:4059
#define TCM_SETITEMEXTRA
Definition: commctrl.h:4083
#define TCS_BOTTOM
Definition: commctrl.h:3939
#define TCM_DELETEITEM
Definition: commctrl.h:4053
#define TCS_MULTILINE
Definition: commctrl.h:3950
#define TCIF_IMAGE
Definition: commctrl.h:3972
#define TCS_VERTICAL
Definition: commctrl.h:3946
#define TCM_SETCURFOCUS
Definition: commctrl.h:4101
#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:170
COLORREF clrBtnText
Definition: comctl32.h:167
COLORREF clrBtnFace
Definition: comctl32.h:168
COLORREF clrWindow
Definition: comctl32.h:176
COLORREF clr3dFace
Definition: comctl32.h:175
COLORREF clr3dHilight
Definition: comctl32.h:172
COLORREF clrHighlight
Definition: comctl32.h:169
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:3184
HBRUSH hbrBackground
Definition: winuser.h:3182
int cbClsExtra
Definition: winuser.h:3177
UINT style
Definition: winuser.h:3175
WNDPROC lpfnWndProc
Definition: winuser.h:3176
int cbWndExtra
Definition: winuser.h:3178
HCURSOR hCursor
Definition: winuser.h:3181
Definition: inflate.c:139
ULONG_PTR itemData
Definition: winuser.h:3092
UINT_PTR idFrom
Definition: winuser.h:3157
UINT code
Definition: winuser.h:3158
HWND hwndFrom
Definition: winuser.h:3156
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:3692
DWORD styleOld
Definition: winuser.h:3691
LPARAM lParam
Definition: commctrl.h:4026
DWORD dwState
Definition: commctrl.h:4021
LPWSTR pszText
Definition: commctrl.h:4023
int iImage
Definition: commctrl.h:4025
DWORD dwStateMask
Definition: commctrl.h:4022
int cchTextMax
Definition: commctrl.h:4024
UINT mask
Definition: commctrl.h:4020
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:1712
_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:1539
#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:1619
HWND WINAPI GetFocus(void)
Definition: window.c:1893
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:2544
#define SW_HIDE
Definition: winuser.h:767
BOOL WINAPI RedrawWindow(_In_opt_ HWND, _In_opt_ LPCRECT, _In_opt_ HRGN, _In_ UINT)
#define GetWindowLongPtrW
Definition: winuser.h:4828
#define WM_HSCROLL
Definition: winuser.h:1742
#define EDGE_SUNKEN
Definition: winuser.h:451
BOOL WINAPI ShowWindow(_In_ HWND, _In_ int)
#define COLOR_SCROLLBAR
Definition: winuser.h:911
DWORD WINAPI GetMessagePos(void)
Definition: message.c:1351
#define ODA_DRAWENTIRE
Definition: winuser.h:2541
LRESULT WINAPI DefWindowProcW(_In_ HWND, _In_ UINT, _In_ WPARAM, _In_ LPARAM)
BOOL WINAPI GetWindowRect(_In_ HWND, _Out_ LPRECT)
#define WM_CREATE
Definition: winuser.h:1607
#define DLGC_WANTCHARS
Definition: winuser.h:2617
BOOL WINAPI SetWindowPos(_In_ HWND, _In_opt_ HWND, _In_ int, _In_ int, _In_ int, _In_ int, _In_ UINT)
#define WVR_ALIGNTOP
Definition: winuser.h:2514
#define WM_SIZE
Definition: winuser.h:1610
#define COLOR_HIGHLIGHT
Definition: winuser.h:925
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:2639
#define WM_NCHITTEST
Definition: winuser.h:1685
#define BF_DIAGONAL_ENDTOPRIGHT
Definition: winuser.h:464
#define WM_RBUTTONUP
Definition: winuser.h:1779
#define WM_SETFOCUS
Definition: winuser.h:1612
#define EDGE_ETCHED
Definition: winuser.h:452
#define WM_MOUSEMOVE
Definition: winuser.h:1774
#define RDW_UPDATENOW
Definition: winuser.h:1219
#define RDW_ERASE
Definition: winuser.h:1210
#define BF_BOTTOM
Definition: winuser.h:457
#define CS_DBLCLKS
Definition: winuser.h:651
#define WM_LBUTTONDOWN
Definition: winuser.h:1775
#define WM_SYSCOLORCHANGE
Definition: winuser.h:1625
HCURSOR WINAPI LoadCursorW(_In_opt_ HINSTANCE, _In_ LPCWSTR)
Definition: cursoricon.c:2074
#define WM_GETFONT
Definition: winuser.h:1650
#define SM_CYHSCROLL
Definition: winuser.h:961
#define WM_DRAWITEM
Definition: winuser.h:1644
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:2369
#define BF_TOP
Definition: winuser.h:455
#define WM_SETFONT
Definition: winuser.h:1649
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:2609
#define BDR_RAISEDINNER
Definition: winuser.h:444
#define HTCLIENT
Definition: winuser.h:2474
#define SWP_SHOWWINDOW
Definition: winuser.h:1247
#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:4315
#define WM_LBUTTONUP
Definition: winuser.h:1776
LONG WINAPI GetMessageTime(void)
Definition: message.c:1361
BOOL WINAPI SetRectEmpty(_Out_ LPRECT)
#define SM_CXHSCROLL
Definition: winuser.h:981
#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:2223
#define WM_NCDESTROY
Definition: winuser.h:1683
#define VK_RIGHT
Definition: winuser.h:2225
#define HTTRANSPARENT
Definition: winuser.h:2472
HWND WINAPI WindowFromPoint(_In_ POINT)
#define GWLP_ID
Definition: winuser.h:859
#define WM_USER
Definition: winuser.h:1894
BOOL WINAPI OffsetRect(_Inout_ LPRECT, _In_ int, _In_ int)
BOOL WINAPI UnregisterClassW(_In_ LPCWSTR, HINSTANCE)
#define WM_KEYDOWN
Definition: winuser.h:1714
BOOL WINAPI DrawFocusRect(_In_ HDC, _In_ LPCRECT)
BOOL WINAPI InvalidateRect(_In_opt_ HWND, _In_opt_ LPCRECT, _In_ BOOL)
#define SWP_NOZORDER
Definition: winuser.h:1246
#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:5345
BOOL WINAPI InflateRect(_Inout_ LPRECT, _In_ int, _In_ int)
#define BF_RECT
Definition: winuser.h:462
#define WM_NCCALCSIZE
Definition: winuser.h:1684
#define GWL_STYLE
Definition: winuser.h:851
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:1613
struct tagCREATESTRUCTW * LPCREATESTRUCTW
#define ODS_FOCUS
Definition: winuser.h:2548
int WINAPI GetSystemMetrics(_In_ int)
#define RDW_INVALIDATE
Definition: winuser.h:1213
#define WM_GETDLGCODE
Definition: winuser.h:1688
LRESULT WINAPI SendMessageW(_In_ HWND, _In_ UINT, _In_ WPARAM, _In_ LPARAM)
#define COLOR_BTNFACE
Definition: winuser.h:927
BOOL WINAPI SetRect(_Out_ LPRECT, _In_ int, _In_ int, _In_ int, _In_ int)
#define WM_SETREDRAW
Definition: winuser.h:1615
#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: xmlstorage.h:182
__wchar_t WCHAR
Definition: xmlstorage.h:180
WCHAR * LPWSTR
Definition: xmlstorage.h:184