- New implementation of SendMessage, ReceiveMessage, ReplyMessage functions
[wine] / dlls / comctl32 / tab.c
1 /*
2  * Tab control
3  *
4  * Copyright 1998 Anders Carlsson
5  * Copyright 1999 Alex Priem <alexp@sci.kun.nl>
6  *
7  * TODO:
8  *  Image list support
9  *  Multiline support
10  *  Unicode support
11  *  Updown control support
12  *  Look and feel
13  *
14  */
15
16 #include "commctrl.h"
17 #include "tab.h"
18 #include "win.h"
19 #include "debug.h"
20
21
22 #define TAB_GetInfoPtr(wndPtr) ((TAB_INFO *)wndPtr->wExtra[0])
23
24
25
26
27 static void TAB_Refresh (WND *wndPtr, HDC32 hdc);
28
29
30 static BOOL32
31 TAB_SendSimpleNotify (WND *wndPtr, UINT32 code)
32 {
33     NMHDR nmhdr;
34
35     nmhdr.hwndFrom = wndPtr->hwndSelf;
36     nmhdr.idFrom = wndPtr->wIDmenu;
37     nmhdr.code = code;
38
39     return (BOOL32) SendMessage32A (GetParent32 (wndPtr->hwndSelf), WM_NOTIFY,
40                                     (WPARAM32) nmhdr.idFrom, (LPARAM) &nmhdr);
41 }
42
43
44 static VOID
45 TAB_RelayEvent (HWND32 hwndTip, HWND32 hwndMsg, UINT32 uMsg,
46             WPARAM32 wParam, LPARAM lParam)
47 {
48     MSG32 msg;
49
50     msg.hwnd = hwndMsg;
51     msg.message = uMsg;
52     msg.wParam = wParam;
53     msg.lParam = lParam;
54     msg.time = GetMessageTime ();
55     msg.pt.x = LOWORD(GetMessagePos ());
56     msg.pt.y = HIWORD(GetMessagePos ());
57
58     SendMessage32A (hwndTip, TTM_RELAYEVENT, 0, (LPARAM)&msg);
59 }
60
61
62
63 static LRESULT
64 TAB_GetCurSel (WND *wndPtr)
65 {
66     TAB_INFO *infoPtr = TAB_GetInfoPtr(wndPtr);
67  
68     return infoPtr->iSelected;
69 }
70
71 static LRESULT
72 TAB_GetCurFocus (WND *wndPtr)
73 {
74     TAB_INFO *infoPtr = TAB_GetInfoPtr(wndPtr);
75  
76     return infoPtr->uFocus;
77 }
78
79 static LRESULT
80 TAB_GetToolTips (WND *wndPtr, WPARAM32 wParam, LPARAM lParam)
81 {
82     TAB_INFO *infoPtr = TAB_GetInfoPtr(wndPtr);
83
84     if (infoPtr == NULL) return 0;
85     return infoPtr->hwndToolTip;
86 }
87
88
89 static LRESULT
90 TAB_SetCurSel (WND *wndPtr,WPARAM32 wParam)
91 {
92     TAB_INFO *infoPtr = TAB_GetInfoPtr(wndPtr);
93         INT32 iItem=(INT32) wParam;
94         INT32 prevItem;
95  
96         prevItem=-1;
97         if ((iItem >= 0) && (iItem < infoPtr->uNumItem)) {
98                 prevItem=infoPtr->iSelected;
99         infoPtr->iSelected=iItem;
100         }
101         return prevItem;
102 }
103
104 static LRESULT
105 TAB_SetCurFocus (WND *wndPtr,WPARAM32 wParam)
106 {
107     TAB_INFO *infoPtr = TAB_GetInfoPtr(wndPtr);
108         INT32 iItem=(INT32) wParam;
109         HDC32 hdc;
110  
111         if ((iItem < 0) || (iItem > infoPtr->uNumItem)) return 0;
112
113         infoPtr->uFocus=iItem;
114         if (wndPtr->dwStyle & TCS_BUTTONS) {
115                 FIXME (tab,"Should set input focus\n");
116         } else { 
117                 if (infoPtr->iSelected != iItem) {
118                 if (TAB_SendSimpleNotify(wndPtr, TCN_SELCHANGING)!=TRUE)  {
119                                 infoPtr->iSelected = iItem;
120                                 TAB_SendSimpleNotify(wndPtr, TCN_SELCHANGE);
121                         hdc = GetDC32 (wndPtr->hwndSelf);
122                         TAB_Refresh (wndPtr, hdc);
123                         ReleaseDC32 (wndPtr->hwndSelf, hdc);
124                         }
125                 }
126         }
127   return 0;
128 }
129
130 static LRESULT
131 TAB_SetToolTips (WND *wndPtr, WPARAM32 wParam, LPARAM lParam)
132 {
133     TAB_INFO *infoPtr = TAB_GetInfoPtr(wndPtr);
134
135     if (infoPtr == NULL) return 0;
136     infoPtr->hwndToolTip = (HWND32)wParam;
137     return 0;
138 }
139
140
141 static HWND32 TAB_InternalHitTest (TAB_INFO *infoPtr, POINT32 pt, 
142                                                                         UINT32 *flags)
143
144 {
145   RECT32 rect;
146   int iCount; 
147   
148   for (iCount = 0; iCount < infoPtr->uNumItem; iCount++) {
149             rect = infoPtr->items[iCount].rect;
150             if (PtInRect32 (&rect, pt)) return iCount;
151         }
152   *flags=TCHT_NOWHERE;
153   return -1;
154 }
155
156 static LRESULT
157 TAB_HitTest (WND *wndPtr, WPARAM32 wParam, LPARAM lParam)
158 {
159     TAB_INFO *infoPtr = TAB_GetInfoPtr(wndPtr);
160         LPTCHITTESTINFO lptest=(LPTCHITTESTINFO) lParam;
161  
162     return TAB_InternalHitTest (infoPtr,lptest->pt,&lptest->flags);
163 }
164
165
166 static LRESULT
167 TAB_LButtonDown (WND *wndPtr, WPARAM32 wParam, LPARAM lParam)
168 {
169     TAB_INFO *infoPtr = TAB_GetInfoPtr(wndPtr);
170
171         if (infoPtr->hwndToolTip)
172     TAB_RelayEvent (infoPtr->hwndToolTip, wndPtr->hwndSelf,
173                 WM_LBUTTONDOWN, wParam, lParam);
174
175         if (wndPtr->dwStyle & TCS_FOCUSONBUTTONDOWN ) {
176                 SetFocus32 (wndPtr->hwndSelf);
177         }
178         return 0;
179 }
180
181 static LRESULT
182 TAB_LButtonUp (WND *wndPtr, WPARAM32 wParam, LPARAM lParam)
183 {
184     TAB_INFO *infoPtr = TAB_GetInfoPtr(wndPtr);
185     POINT32 pt;
186     INT32 newItem,dummy;
187         HDC32 hdc;
188
189         if (infoPtr->hwndToolTip)
190     TAB_RelayEvent (infoPtr->hwndToolTip, wndPtr->hwndSelf,
191                 WM_LBUTTONDOWN, wParam, lParam);
192
193     pt.x = (INT32)LOWORD(lParam);
194     pt.y = (INT32)HIWORD(lParam);
195
196         newItem=TAB_InternalHitTest (infoPtr,pt,&dummy);
197         if (!newItem) return 0;
198         TRACE(tab, "On Tab, item %d\n", newItem);
199                 
200         if (infoPtr->iSelected != newItem) {
201             if (TAB_SendSimpleNotify(wndPtr, TCN_SELCHANGING)!=TRUE)  {
202                         infoPtr->iSelected = newItem;
203                         TAB_SendSimpleNotify(wndPtr, TCN_SELCHANGE);
204                 hdc = GetDC32 (wndPtr->hwndSelf);
205                 TAB_Refresh (wndPtr, hdc);
206                 ReleaseDC32 (wndPtr->hwndSelf, hdc);
207                 }
208         }
209         TAB_SendSimpleNotify(wndPtr, NM_CLICK);
210
211     return 0;
212 }
213
214 static LRESULT
215 TAB_RButtonDown (WND *wndPtr, WPARAM32 wParam, LPARAM lParam)
216 {
217         TAB_SendSimpleNotify(wndPtr, NM_RCLICK);
218         return 0;
219 }
220
221 static LRESULT
222 TAB_MouseMove (WND *wndPtr, WPARAM32 wParam, LPARAM lParam)
223 {
224     TAB_INFO *infoPtr = TAB_GetInfoPtr(wndPtr);
225
226     if (infoPtr->hwndToolTip)
227     TAB_RelayEvent (infoPtr->hwndToolTip, wndPtr->hwndSelf,
228                 WM_LBUTTONDOWN, wParam, lParam);
229         return 0;
230 }
231
232 static LRESULT
233 TAB_AdjustRect (WND *wndPtr, WPARAM32 wParam, LPARAM lParam)
234 {
235
236         if (wParam==TRUE) {
237                 FIXME (tab,"Should set display rectangle\n");
238         } else {
239                 FIXME (tab,"Should set window rectangle\n");
240         }
241         
242         return 0;
243 }
244
245 static void 
246 TAB_SetItemBounds (WND *wndPtr)
247 {
248     TAB_INFO *infoPtr = TAB_GetInfoPtr(wndPtr);
249     RECT32 rect;
250     HFONT32 hFont, hOldFont;
251     INT32 i, left;
252     SIZE32 size;
253     HDC32 hdc;
254
255     /* FIXME: Is this needed? */
256     GetClientRect32 (wndPtr->hwndSelf, &rect);
257         left += (size.cx + 11);
258     
259     hdc = GetDC32(wndPtr->hwndSelf); 
260     
261     hFont = infoPtr->hFont ? infoPtr->hFont : GetStockObject32 (SYSTEM_FONT);
262     hOldFont = SelectObject32 (hdc, hFont);
263
264     left = rect.left;
265     
266     for (i = 0; i < infoPtr->uNumItem; i++)
267     {
268         if (wndPtr->dwStyle & TCS_BOTTOM) {
269         infoPtr->items[i].rect.bottom = rect.bottom;
270                 infoPtr->items[i].rect.top    = rect.bottom-20;
271         } else {
272                 infoPtr->items[i].rect.top    = rect.top;
273         infoPtr->items[i].rect.bottom = rect.top + 20;
274         }
275         infoPtr->items[i].rect.left = left;
276
277         GetTextExtentPoint32A(hdc, 
278                              infoPtr->items[i].pszText, 
279                              lstrlen32A(infoPtr->items[i].pszText), &size);
280         infoPtr->items[i].rect.right = left + size.cx+2*5;
281         TRACE(tab, "TextSize: %i\n ", size.cx);
282         TRACE(tab, "Rect: T %i, L %i, B %i, R %i\n", 
283               infoPtr->items[i].rect.top,
284               infoPtr->items[i].rect.left,
285               infoPtr->items[i].rect.bottom,
286               infoPtr->items[i].rect.right);    
287         left += (size.cx + 11);
288     }
289
290     SelectObject32 (hdc, hOldFont);
291     ReleaseDC32 (wndPtr->hwndSelf, hdc);
292 }
293                                  
294 static void
295 TAB_DrawItem (WND *wndPtr, HDC32 hdc, INT32 iItem)
296 {
297     TAB_INFO *infoPtr = TAB_GetInfoPtr(wndPtr);
298     TAB_ITEM *pti = &infoPtr->items[iItem];
299     RECT32 r;
300     INT32 oldBkMode,cx,cy;
301   HBRUSH32 hbr = CreateSolidBrush32 (COLOR_BACKGROUND);
302    
303     HPEN32      hwPen  = GetSysColorPen32 (COLOR_3DHILIGHT);
304     HPEN32      hbPen  = GetSysColorPen32 (COLOR_BTNSHADOW);
305     HPEN32      hsdPen = GetSysColorPen32 (COLOR_BTNTEXT);
306     HPEN32      htmpPen = (HPEN32)NULL;
307
308     CopyRect32(&r, &pti->rect);
309
310 /* demo */
311     FillRect32(hdc, &r, hbr);
312         
313         
314
315
316     htmpPen = hwPen;
317     htmpPen = SelectObject32 (hdc, htmpPen);
318         if (wndPtr->dwStyle & TCS_BOTTOM) {
319         MoveToEx32 (hdc, r.left, r.top, NULL);
320         LineTo32 (hdc, r.left, r.bottom - 2);
321         LineTo32 (hdc, r.left +2, r.bottom);
322         LineTo32 (hdc, r.right -1, r.bottom);
323         htmpPen = SelectObject32 (hdc, hbPen); 
324         MoveToEx32 (hdc, r.right-1, r.top, NULL);
325         LineTo32 (hdc,r.right-1, r.bottom-1);
326         hbPen = SelectObject32 (hdc, hsdPen);
327         MoveToEx32 (hdc, r.right, r.top+1, NULL);
328         LineTo32(hdc, r.right,r.bottom);
329     } else {
330         MoveToEx32 (hdc, r.left, r.bottom, NULL);
331         LineTo32 (hdc, r.left, r.top + 2);
332         LineTo32 (hdc, r.left +2, r.top);
333         LineTo32 (hdc, r.right -1, r.top);
334         htmpPen = SelectObject32 (hdc, hbPen); 
335         MoveToEx32 (hdc, r.right-1, r.bottom, NULL);
336         LineTo32 (hdc,r.right-1, r.top+1);
337         hbPen = SelectObject32 (hdc, hsdPen);
338         MoveToEx32 (hdc, r.right, r.bottom-1, NULL);
339         LineTo32(hdc, r.right,r.top);
340         }
341
342         hsdPen = SelectObject32(hdc,htmpPen); 
343
344     oldBkMode = SetBkMode32(hdc, TRANSPARENT); 
345     r.left += 3;
346     r.right -= 3;
347
348         if (infoPtr->himl) {
349                 ImageList_Draw (infoPtr->himl, iItem, hdc, 
350                                                 r.left, r.top+1, ILD_NORMAL);
351                 ImageList_GetIconSize (infoPtr->himl, &cx, &cy);
352                 r.left+=cx+3;
353                 }
354     SetTextColor32 (hdc, COLOR_BTNTEXT);
355     DrawText32A(hdc, pti->pszText, lstrlen32A(pti->pszText),
356         &r, DT_LEFT|DT_SINGLELINE|DT_VCENTER);
357     if (oldBkMode != TRANSPARENT)
358         SetBkMode32(hdc, oldBkMode);
359 }
360
361 static void
362 TAB_DrawBorder (WND *wndPtr, HDC32 hdc)
363 {
364     HPEN32 htmPen;
365     HPEN32 hwPen  = GetSysColorPen32 (COLOR_3DHILIGHT);
366     HPEN32 hbPen  = GetSysColorPen32 (COLOR_3DDKSHADOW);
367     HPEN32 hShade = GetSysColorPen32 (COLOR_BTNSHADOW);
368
369     RECT32 rect;
370
371     htmPen = SelectObject32 (hdc, hwPen);
372     GetClientRect32 (wndPtr->hwndSelf, &rect);
373
374     MoveToEx32 (hdc, rect.left, rect.bottom, NULL);
375     LineTo32 (hdc, rect.left, rect.top+20); 
376
377     LineTo32 (hdc, rect.right, rect.top+20);
378
379     hwPen = SelectObject32 (hdc, htmPen);
380     LineTo32 (hdc, rect.right, rect.bottom );
381     LineTo32 (hdc, rect.left, rect.bottom);
382     hbPen = SelectObject32 (hdc, hShade );
383     MoveToEx32 (hdc, rect.right-1, rect.top+20, NULL);
384     LineTo32 (hdc, rect.right-1, rect.bottom-1);
385     LineTo32 (hdc, rect.left, rect.bottom-1);
386     hShade = SelectObject32(hdc, hShade);
387 }
388
389     
390 static void
391 TAB_Refresh (WND *wndPtr, HDC32 hdc)
392 {
393     TAB_INFO *infoPtr = TAB_GetInfoPtr(wndPtr);
394     HFONT32 hOldFont;
395     INT32 i;
396
397         if (!infoPtr->DoRedraw) return;
398
399     TAB_DrawBorder (wndPtr, hdc);
400
401         hOldFont = SelectObject32 (hdc, infoPtr->hFont);
402     for (i = 0; i < infoPtr->uNumItem; i++) {
403         TAB_DrawItem (wndPtr, hdc, i);
404     }
405         SelectObject32 (hdc, hOldFont);
406 }
407
408 static LRESULT
409 TAB_SetRedraw (WND *wndPtr, WPARAM32 wParam)
410 {
411     TAB_INFO *infoPtr = TAB_GetInfoPtr(wndPtr);
412         
413         infoPtr->DoRedraw=(BOOL32) wParam;
414         return 0;
415 }
416
417 static LRESULT
418 TAB_Paint (WND *wndPtr, WPARAM32 wParam)
419 {
420     HDC32 hdc;
421     PAINTSTRUCT32 ps;
422     
423     hdc = wParam== 0 ? BeginPaint32 (wndPtr->hwndSelf, &ps) : (HDC32)wParam;
424     TAB_Refresh (wndPtr, hdc);
425     
426     if(!wParam)
427         EndPaint32 (wndPtr->hwndSelf, &ps);
428     return 0;
429 }
430
431 static LRESULT
432 TAB_InsertItem (WND *wndPtr, WPARAM32 wParam, LPARAM lParam)
433 {
434     TAB_INFO *infoPtr = TAB_GetInfoPtr(wndPtr);
435     TCITEM32A *pti;
436     HDC32  hdc;
437     INT32 iItem, len;
438     RECT32 rect;
439
440     GetClientRect32 (wndPtr->hwndSelf, &rect);
441         TRACE(tab, "Rect: %x T %i, L %i, B %i, R %i\n", wndPtr->hwndSelf,
442               rect.top, rect.left, rect.bottom, rect.right);    
443
444     pti = (TCITEM32A *)lParam;
445     iItem = (INT32)wParam;
446
447     if (iItem < 0) return -1;
448     if (iItem > infoPtr->uNumItem)
449         iItem = infoPtr->uNumItem;
450
451     if (infoPtr->uNumItem == 0) {
452         infoPtr->items = COMCTL32_Alloc (sizeof (TAB_ITEM));
453         infoPtr->uNumItem++;
454     }
455     else {
456         TAB_ITEM *oldItems = infoPtr->items;
457
458         infoPtr->uNumItem++;
459         infoPtr->items = COMCTL32_Alloc (sizeof (TAB_ITEM) * infoPtr->uNumItem);
460         
461         /* pre insert copy */
462         if (iItem > 0) {
463             memcpy (&infoPtr->items[0], &oldItems[0],
464                     iItem * sizeof(TAB_ITEM));
465         }
466
467         /* post insert copy */
468         if (iItem < infoPtr->uNumItem - 1) {
469             memcpy (&infoPtr->items[iItem+1], &oldItems[iItem],
470                     (infoPtr->uNumItem - iItem - 1) * sizeof(TAB_ITEM));
471
472         }
473         
474         COMCTL32_Free (oldItems);
475     }
476
477     infoPtr->items[iItem].mask = pti->mask;
478     if (pti->mask & TCIF_TEXT) {
479         len = lstrlen32A (pti->pszText);
480         infoPtr->items[iItem].pszText = COMCTL32_Alloc (len+1);
481         lstrcpy32A (infoPtr->items[iItem].pszText, pti->pszText);
482         infoPtr->items[iItem].cchTextMax = pti->cchTextMax;
483     }
484
485     if (pti->mask & TCIF_IMAGE)
486         infoPtr->items[iItem].iImage = pti->iImage;
487
488     if (pti->mask & TCIF_PARAM)
489         infoPtr->items[iItem].lParam = pti->lParam;
490
491     hdc = GetDC32 (wndPtr->hwndSelf);
492     TAB_Refresh (wndPtr, hdc);
493     ReleaseDC32 (wndPtr->hwndSelf, hdc);
494
495     TRACE(tab, "[%04x]: added item %d '%s'\n",
496                 wndPtr->hwndSelf, iItem, infoPtr->items[iItem].pszText);
497
498     TAB_SetItemBounds(wndPtr);
499     return iItem;
500 }
501
502 static LRESULT 
503 TAB_SetItem32A (WND *wndPtr, WPARAM32 wParam, LPARAM lParam)
504 {
505   TAB_INFO *infoPtr = TAB_GetInfoPtr(wndPtr);
506   TCITEM32A *tabItem; 
507   TAB_ITEM *wineItem; 
508   INT32    iItem,len;
509
510   iItem=(INT32) wParam;
511   tabItem=(LPTCITEM32A ) lParam;
512   TRACE (tab,"%d %p\n",iItem, tabItem);
513   if ((iItem<0) || (iItem>infoPtr->uNumItem)) return FALSE;
514
515   wineItem=& infoPtr->items[iItem];
516
517   if (tabItem->mask & TCIF_IMAGE) 
518                 wineItem->iImage=tabItem->iImage;
519
520   if (tabItem->mask & TCIF_PARAM) 
521                 wineItem->lParam=tabItem->lParam;
522
523   if (tabItem->mask & TCIF_RTLREADING) 
524                 FIXME (tab,"TCIF_RTLREADING\n");
525
526   if (tabItem->mask & TCIF_STATE) 
527                 wineItem->dwState=tabItem->dwState;
528
529   if (tabItem->mask & TCIF_TEXT) {
530          len=lstrlen32A (tabItem->pszText);
531          if (len>wineItem->cchTextMax) 
532                  wineItem->pszText= COMCTL32_ReAlloc (wineItem->pszText, len+1);
533          lstrcpyn32A (wineItem->pszText, tabItem->pszText, len);
534   }
535
536         return TRUE;
537 }
538
539 static LRESULT 
540 TAB_GetItemCount (WND *wndPtr, WPARAM32 wParam, LPARAM lParam)
541 {
542    TAB_INFO *infoPtr = TAB_GetInfoPtr(wndPtr);
543
544    return infoPtr->uNumItem;
545 }
546
547
548 static LRESULT 
549 TAB_GetItem32A (WND *wndPtr, WPARAM32 wParam, LPARAM lParam)
550 {
551    TAB_INFO *infoPtr = TAB_GetInfoPtr(wndPtr);
552    TCITEM32A *tabItem;
553    TAB_ITEM *wineItem;
554    INT32    iItem;
555
556   iItem=(INT32) wParam;
557   tabItem=(LPTCITEM32A) lParam;
558   TRACE (tab,"\n");
559   if ((iItem<0) || (iItem>infoPtr->uNumItem)) return FALSE;
560
561   wineItem=& infoPtr->items[iItem];
562
563   if (tabItem->mask & TCIF_IMAGE) 
564                 tabItem->iImage=wineItem->iImage;
565
566   if (tabItem->mask & TCIF_PARAM) 
567                 tabItem->lParam=wineItem->lParam;
568
569   if (tabItem->mask & TCIF_RTLREADING) 
570                 FIXME (tab, "TCIF_RTLREADING\n");
571
572   if (tabItem->mask & TCIF_STATE) 
573                 tabItem->dwState=wineItem->dwState;
574
575   if (tabItem->mask & TCIF_TEXT) 
576          lstrcpyn32A (tabItem->pszText, wineItem->pszText, tabItem->cchTextMax);
577
578         return TRUE;
579 }
580
581 static LRESULT 
582 TAB_DeleteItem (WND *wndPtr, WPARAM32 wParam, LPARAM lParam)
583 {
584         FIXME (tab,"stub \n");
585         return TRUE;
586 }
587
588 static LRESULT 
589 TAB_DeleteAllItems (WND *wndPtr, WPARAM32 wParam, LPARAM lParam)
590 {
591    TAB_INFO *infoPtr = TAB_GetInfoPtr(wndPtr);
592
593         COMCTL32_Free (infoPtr->items);
594         infoPtr->uNumItem=0;
595         
596         return TRUE;
597 }
598
599
600 static LRESULT
601 TAB_GetFont (WND *wndPtr, WPARAM32 wParam, LPARAM lParam)
602 {
603   TAB_INFO *infoPtr = TAB_GetInfoPtr(wndPtr);
604
605   TRACE (tab,"\n");
606   return (LRESULT)infoPtr->hFont;
607 }
608
609 static LRESULT
610 TAB_SetFont (WND *wndPtr, WPARAM32 wParam, LPARAM lParam)
611
612 {
613  TAB_INFO *infoPtr = TAB_GetInfoPtr(wndPtr);
614  TEXTMETRIC32A tm;
615  HFONT32 hFont, hOldFont;
616  HDC32 hdc;
617
618  TRACE (tab,"%x %lx\n",wParam, lParam);
619
620  infoPtr->hFont = (HFONT32)wParam;
621
622  hFont = infoPtr->hFont ? infoPtr->hFont : GetStockObject32 (SYSTEM_FONT);
623
624  hdc = GetDC32 (0);
625  hOldFont = SelectObject32 (hdc, hFont);
626  GetTextMetrics32A (hdc, &tm);
627  infoPtr->nHeight= tm.tmHeight + tm.tmExternalLeading;
628  SelectObject32 (hdc, hOldFont);
629
630  if (lParam) TAB_Refresh (wndPtr,hdc);
631  ReleaseDC32 (0, hdc);
632
633  return 0;
634 }
635
636
637 static LRESULT
638 TAB_GetImageList (WND *wndPtr, WPARAM32 wParam, LPARAM lParam)
639 {
640   TAB_INFO *infoPtr = TAB_GetInfoPtr(wndPtr);
641
642   TRACE (tab,"\n");
643   return (LRESULT)infoPtr->himl;
644 }
645
646 static LRESULT
647 TAB_SetImageList (WND *wndPtr, WPARAM32 wParam, LPARAM lParam)
648 {
649     TAB_INFO *infoPtr = TAB_GetInfoPtr(wndPtr);
650     HIMAGELIST himlPrev;
651
652     TRACE (tab,"\n");
653     himlPrev = infoPtr->himl;
654         infoPtr->himl= (HIMAGELIST)lParam;
655     return (LRESULT)himlPrev;
656 }
657
658
659 static LRESULT
660 TAB_Size (WND *wndPtr, WPARAM32 wParam, LPARAM lParam)
661
662 {
663   RECT32 parent_rect;
664   HWND32 parent;
665   HDC32 hdc;
666   UINT32 uPosFlags,cx,cy;
667
668   uPosFlags=0;
669   if (!wParam) {
670         parent = GetParent32 (wndPtr->hwndSelf);
671         GetClientRect32(parent, &parent_rect);
672         cx=LOWORD (lParam);
673         cy=HIWORD (lParam);
674         if (wndPtr->dwStyle & CCS_NORESIZE) 
675         uPosFlags |= (SWP_NOSIZE | SWP_NOMOVE);
676
677         SetWindowPos32 (wndPtr->hwndSelf, 0, parent_rect.left, parent_rect.top,
678             cx, cy, uPosFlags | SWP_NOZORDER);
679         } else {
680     FIXME (tab,"WM_SIZE flag %x %lx not handled\n", wParam, lParam);
681   } 
682
683   TAB_SetItemBounds (wndPtr);
684   hdc = GetDC32 (wndPtr->hwndSelf);
685   TAB_Refresh (wndPtr, hdc);
686   ReleaseDC32 (wndPtr->hwndSelf, hdc);
687
688   return 0;
689 }
690
691
692 static LRESULT 
693 TAB_Create (WND *wndPtr, WPARAM32 wParam, LPARAM lParam)
694 {
695     TAB_INFO *infoPtr;
696
697     infoPtr = (TAB_INFO *)COMCTL32_Alloc (sizeof(TAB_INFO));
698     wndPtr->wExtra[0] = (DWORD)infoPtr;
699    
700     infoPtr->uNumItem = 0;
701     infoPtr->hFont = 0;
702     infoPtr->items = 0;
703     infoPtr->hcurArrow = LoadCursor32A (0, IDC_ARROW32A);
704     infoPtr->iSelected = -1;  
705         infoPtr->hwndToolTip=0;
706   
707     TRACE(tab, "Created tab control, hwnd [%04x]\n", wndPtr->hwndSelf); 
708     if (wndPtr->dwStyle & TCS_TOOLTIPS) {
709     /* Create tooltip control */
710     infoPtr->hwndToolTip =
711         CreateWindowEx32A (0, TOOLTIPS_CLASS32A, NULL, 0,
712                    CW_USEDEFAULT32, CW_USEDEFAULT32,
713                    CW_USEDEFAULT32, CW_USEDEFAULT32,
714                    wndPtr->hwndSelf, 0, 0, 0);
715
716     /* Send NM_TOOLTIPSCREATED notification */
717     if (infoPtr->hwndToolTip) {
718         NMTOOLTIPSCREATED nmttc;
719
720         nmttc.hdr.hwndFrom = wndPtr->hwndSelf;
721         nmttc.hdr.idFrom = wndPtr->wIDmenu;
722         nmttc.hdr.code = NM_TOOLTIPSCREATED;
723         nmttc.hwndToolTips = infoPtr->hwndToolTip;
724
725         SendMessage32A (GetParent32 (wndPtr->hwndSelf), WM_NOTIFY,
726                 (WPARAM32)wndPtr->wIDmenu, (LPARAM)&nmttc);
727     }
728     }
729
730
731     return 0;
732 }
733
734 static LRESULT
735 TAB_Destroy (WND *wndPtr, WPARAM32 wParam, LPARAM lParam)
736 {
737     TAB_INFO *infoPtr = TAB_GetInfoPtr(wndPtr);
738     INT32 iItem;
739
740     if (infoPtr->items) {
741         for (iItem = 0; iItem < infoPtr->uNumItem; iItem++) {
742             if (infoPtr->items[iItem].pszText)
743                 COMCTL32_Free (infoPtr->items[iItem].pszText);
744         }
745         COMCTL32_Free (infoPtr->items);
746     }
747
748         if (infoPtr->hwndToolTip) 
749                   DestroyWindow32 (infoPtr->hwndToolTip);
750
751     COMCTL32_Free (infoPtr);
752     return 0;
753 }
754
755 LRESULT WINAPI
756 TAB_WindowProc (HWND32 hwnd, UINT32 uMsg, WPARAM32 wParam, LPARAM lParam)
757 {
758     WND *wndPtr = WIN_FindWndPtr(hwnd);
759
760     switch (uMsg)
761     {
762
763         case TCM_GETIMAGELIST:
764            return TAB_GetImageList (wndPtr, wParam, lParam);
765
766         case TCM_SETIMAGELIST:
767            return TAB_SetImageList (wndPtr, wParam, lParam);
768         
769         case TCM_GETITEMCOUNT:
770             return TAB_GetItemCount (wndPtr, wParam, lParam);
771
772         case TCM_GETITEM32A:
773            return TAB_GetItem32A (wndPtr, wParam, lParam);
774
775         case TCM_GETITEM32W:
776            FIXME (tab, "Unimplemented msg TCM_GETITEM32W\n");
777            return 0;
778
779         case TCM_SETITEM32A:
780            return TAB_SetItem32A (wndPtr, wParam, lParam);
781
782         case TCM_SETITEM32W:
783            FIXME (tab, "Unimplemented msg TCM_GETITEM32W\n");
784            return 0;
785
786         case TCM_DELETEITEM:
787            return TAB_DeleteItem (wndPtr, wParam, lParam);
788
789         case TCM_DELETEALLITEMS:
790            return TAB_DeleteAllItems (wndPtr, wParam, lParam);
791
792         case TCM_GETITEMRECT:
793            FIXME (tab, "Unimplemented msg TCM_GETITEMRECT\n");
794            return 0;
795
796         case TCM_GETCURSEL:
797            return TAB_GetCurSel (wndPtr);
798
799         case TCM_HITTEST:
800            return TAB_HitTest (wndPtr, wParam, lParam);
801
802         case TCM_SETCURSEL:
803            return TAB_SetCurSel (wndPtr, wParam);
804
805         case TCM_INSERTITEM32A:
806            return TAB_InsertItem (wndPtr, wParam, lParam);
807
808         case TCM_INSERTITEM32W:
809            FIXME (tab, "Unimplemented msg TCM_INSERTITEM32W\n");
810            return 0;
811
812         case TCM_SETITEMEXTRA:
813            FIXME (tab, "Unimplemented msg TCM_SETITEMEXTRA\n");
814            return 0;
815
816         case TCM_ADJUSTRECT:
817            return TAB_AdjustRect (wndPtr, wParam, lParam);
818
819         case TCM_SETITEMSIZE:
820            FIXME (tab, "Unimplemented msg TCM_SETITEMSIZE\n");
821            return 0;
822
823         case TCM_REMOVEIMAGE:
824            FIXME (tab, "Unimplemented msg TCM_REMOVEIMAGE\n");
825            return 0;
826
827         case TCM_SETPADDING:
828            FIXME (tab, "Unimplemented msg TCM_SETPADDING\n");
829            return 0;
830
831         case TCM_GETROWCOUNT:
832            FIXME (tab, "Unimplemented msg TCM_GETROWCOUNT\n");
833            return 0;
834
835         case TCM_GETTOOLTIPS:
836            return TAB_GetToolTips (wndPtr, wParam, lParam);
837
838         case TCM_SETTOOLTIPS:
839            return TAB_SetToolTips (wndPtr, wParam, lParam);
840
841         case TCM_GETCURFOCUS:
842         return TAB_GetCurFocus (wndPtr);
843
844         case TCM_SETCURFOCUS:
845         return TAB_SetCurFocus (wndPtr, wParam);
846
847         case TCM_SETMINTTABWIDTH:
848            FIXME (tab, "Unimplemented msg TCM_SETMINTTABWIDTH\n");
849            return 0;
850
851         case TCM_DESELECTALL:
852            FIXME (tab, "Unimplemented msg TCM_DESELECTALL\n");
853            return 0;
854
855         case WM_GETFONT:
856             return TAB_GetFont (wndPtr, wParam, lParam);
857
858         case WM_SETFONT:
859             return TAB_SetFont (wndPtr, wParam, lParam);
860
861         case WM_CREATE:
862             return TAB_Create (wndPtr, wParam, lParam);
863
864         case WM_DESTROY:
865             return TAB_Destroy (wndPtr, wParam, lParam);
866
867     case WM_GETDLGCODE:
868             return DLGC_WANTARROWS | DLGC_WANTCHARS;
869
870         case WM_LBUTTONDOWN:
871             return TAB_LButtonDown (wndPtr, wParam, lParam);
872
873         case WM_LBUTTONUP:
874             return TAB_LButtonUp (wndPtr, wParam, lParam);
875
876         case WM_RBUTTONDOWN:
877             return TAB_RButtonDown (wndPtr, wParam, lParam);
878
879         case WM_MOUSEMOVE:
880             return TAB_MouseMove (wndPtr, wParam, lParam);
881
882         case WM_PAINT:
883             return TAB_Paint (wndPtr, wParam);
884         case WM_SIZE:
885                 return TAB_Size (wndPtr, wParam, lParam);
886         
887         case WM_SETREDRAW:
888             return TAB_SetRedraw (wndPtr, wParam);
889         
890         
891         default:
892             if (uMsg >= WM_USER)
893                 ERR (tab, "unknown msg %04x wp=%08x lp=%08lx\n",
894                      uMsg, wParam, lParam);
895             return DefWindowProc32A (hwnd, uMsg, wParam, lParam);
896     }
897     return 0;
898 }
899
900
901 VOID
902 TAB_Register (VOID)
903 {
904     WNDCLASS32A wndClass;
905
906     if (GlobalFindAtom32A (WC_TABCONTROL32A)) return;
907
908     ZeroMemory (&wndClass, sizeof(WNDCLASS32A));
909     wndClass.style         = CS_GLOBALCLASS | CS_DBLCLKS | CS_SAVEBITS;
910     wndClass.lpfnWndProc   = (WNDPROC32)TAB_WindowProc;
911     wndClass.cbClsExtra    = 0;
912     wndClass.cbWndExtra    = sizeof(TAB_INFO *);
913     wndClass.hCursor       = LoadCursor32A (0, IDC_ARROW32A);
914     wndClass.hbrBackground = 0;
915     wndClass.lpszClassName = WC_TABCONTROL32A;
916  
917     RegisterClass32A (&wndClass);
918 }
919
920
921 VOID
922 TAB_Unregister (VOID)
923 {
924     if (GlobalFindAtom32A (WC_TABCONTROL32A))
925         UnregisterClass32A (WC_TABCONTROL32A, (HINSTANCE32)NULL);
926 }
927