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