Added xxx_Unregister() functions to all common controls.
[wine] / dlls / comctl32 / tab.c
1 /*
2  * Tab control
3  *
4  * Copyright 1998 Anders Carlsson
5  *
6  * TODO:
7  *  Image list support
8  *  Multiline support
9  *  Unicode support
10  *  Updown control support
11  *  Look and feel
12  *  Messages to be added in commctrl.h
13  *  ...
14  */
15
16 #include "windows.h"
17 #include "commctrl.h"
18 #include "tab.h"
19 #include "heap.h"
20 #include "win.h"
21 #include "debug.h"
22
23
24 #define TAB_GetInfoPtr(wndPtr) ((TAB_INFO *)wndPtr->wExtra[0])
25
26 static BOOL32
27 TAB_SendSimpleNotify (WND *wndPtr, UINT32 code)
28 {
29     NMHDR nmhdr;
30
31     nmhdr.hwndFrom = wndPtr->hwndSelf;
32     nmhdr.idFrom = wndPtr->wIDmenu;
33     nmhdr.code = code;
34
35     return (BOOL32) SendMessage32A (GetParent32 (wndPtr->hwndSelf), WM_NOTIFY,
36                                     (WPARAM32) nmhdr.idFrom, (LPARAM) &nmhdr);
37 }
38
39 static LRESULT
40 TAB_GetCurSel (WND *wndPtr)
41 {
42     TAB_INFO *infoPtr = TAB_GetInfoPtr(wndPtr);
43  
44     return infoPtr->iSelected;
45 }
46
47 static LRESULT
48 TAB_LButtonUp (WND *wndPtr, WPARAM32 wParam, LPARAM lParam)
49 {
50     TAB_INFO *infoPtr = TAB_GetInfoPtr(wndPtr);
51     POINT32 pt;
52     RECT32 rect;
53     INT32 iCount;
54
55     pt.x = (INT32)LOWORD(lParam);
56     pt.y = (INT32)HIWORD(lParam);
57
58     GetClientRect32 (wndPtr->hwndSelf, &rect);
59
60     if (PtInRect32 (&rect, pt))
61     {
62         for (iCount = 0; iCount < infoPtr->uNumItem; iCount++) {
63             rect = infoPtr->items[iCount].rect;
64             if (PtInRect32 (&rect, pt)) {
65                 TRACE(tab, "On Tab, item %d\n", iCount);
66                 
67                 if (infoPtr->iSelected != iCount) {
68                         infoPtr->iSelected = iCount;
69
70                         TAB_SendSimpleNotify(wndPtr, TCN_SELCHANGE);
71                 }
72                 
73                 return 0;
74             }
75         }
76     }
77
78     return 0;
79 }
80
81 static void 
82 TAB_SetItemBounds (WND *wndPtr)
83 {
84     TAB_INFO *infoPtr = TAB_GetInfoPtr(wndPtr);
85     RECT32 rect;
86     HFONT32 hFont, hOldFont;
87     INT32 i, left;
88     SIZE32 size;
89     HDC32 hdc;
90
91     /* FIXME: Is this needed? */
92     GetClientRect32 (wndPtr->hwndSelf, &rect);
93     
94     hdc = GetDC32(wndPtr->hwndSelf); 
95     
96     hFont = infoPtr->hFont ? infoPtr->hFont : GetStockObject32 (SYSTEM_FONT);
97     hOldFont = SelectObject32 (hdc, hFont);
98
99     left = rect.left;
100     
101     for (i = 0; i < infoPtr->uNumItem; i++)
102     {
103         infoPtr->items[i].rect.left = left;
104         infoPtr->items[i].rect.top = infoPtr->rect.top;
105
106         GetTextExtentPoint32A(hdc, 
107                              infoPtr->items[i].pszText, 
108                              lstrlen32A(infoPtr->items[i].pszText), &size);
109         infoPtr->items[i].rect.right = left + size.cx+2*5;
110         infoPtr->items[i].rect.bottom = infoPtr->rect.top + 20;
111         TRACE(tab, "TextSize: %i - ", size.cx);
112         TRACE(tab, "Rect: T %i, L %i, B %i, R %i\n", 
113               infoPtr->items[i].rect.top,
114               infoPtr->items[i].rect.left,
115               infoPtr->items[i].rect.bottom,
116               infoPtr->items[i].rect.right);    
117         left += (size.cx + 11);
118     }
119
120     SelectObject32 (hdc, hOldFont);
121     ReleaseDC32 (wndPtr->hwndSelf, hdc);
122 }
123                                  
124 static void
125 TAB_DrawItem (WND *wndPtr, HDC32 hdc, INT32 iItem)
126 {
127     TAB_INFO *infoPtr = TAB_GetInfoPtr(wndPtr);
128     TAB_ITEM *pti = &infoPtr->items[iItem];
129     RECT32 r;
130     INT32 oldBkMode;
131    
132     HPEN32      hwPen = CreatePen32 (PS_SOLID, 1, RGB (255, 255, 255 ));
133     HPEN32      hbPen = CreatePen32 (PS_SOLID, 1, GetSysColor32 (COLOR_BTNSHADOW));
134     HPEN32      hsdPen = CreatePen32(PS_SOLID, 1, GetSysColor32 (COLOR_BTNTEXT));
135     HPEN32      htmpPen = (HPEN32)NULL;
136
137     CopyRect32(&r, &pti->rect);
138
139     htmpPen = hwPen;
140     htmpPen = SelectObject32 (hdc, htmpPen);
141     MoveToEx32 (hdc, r.left, r.bottom, NULL);
142     LineTo32 (hdc, r.left, r.top + 2);
143     LineTo32 (hdc, r.left +2, r.top);
144
145     LineTo32 (hdc, r.right -1, r.top);
146     htmpPen = SelectObject32 (hdc, htmpPen);
147
148     htmpPen = SelectObject32 (hdc, hbPen);
149     MoveToEx32 (hdc, r.right-1, r.top, NULL);
150     LineTo32 (hdc,r.right-1, r.bottom-1);
151     hbPen = SelectObject32 (hdc, hsdPen);
152     MoveToEx32 (hdc, r.right, r.top+1, NULL);
153     LineTo32(hdc, r.right,r.bottom);
154     hsdPen = SelectObject32(hdc,htmpPen); 
155     DeleteObject32(hwPen);
156     DeleteObject32(hbPen);
157     DeleteObject32(hsdPen);
158
159     oldBkMode = SetBkMode32(hdc, TRANSPARENT);
160     r.left += 3;
161     r.right -= 3;
162     SetTextColor32 (hdc, COLOR_BTNTEXT);
163     DrawText32A(hdc, pti->pszText, lstrlen32A(pti->pszText),
164         &r, DT_LEFT|DT_SINGLELINE|DT_VCENTER);
165     if (oldBkMode != TRANSPARENT)
166         SetBkMode32(hdc, oldBkMode);
167 }
168
169 static void
170 TAB_DrawBorder (WND *wndPtr, HDC32 hdc)
171 {
172     HPEN32 htmPen;
173     HPEN32 hwPen = GetStockObject32(WHITE_PEN);
174     HPEN32 hbPen = GetStockObject32(BLACK_PEN);
175     HPEN32 hShade = CreatePen32 ( PS_SOLID, 1, GetSysColor32 (COLOR_BTNSHADOW));
176     RECT32 rect;
177
178     htmPen = SelectObject32 (hdc, hwPen);
179     GetClientRect32 (wndPtr->hwndSelf, &rect);
180
181     MoveToEx32 (hdc, rect.left, rect.bottom, NULL);
182     LineTo32 (hdc, rect.left, rect.top+20); 
183
184     LineTo32 (hdc, rect.right, rect.top+20);
185
186     hwPen = SelectObject32 (hdc, htmPen);
187     LineTo32 (hdc, rect.right, rect.bottom );
188     LineTo32 (hdc, rect.left, rect.bottom);
189     hbPen = SelectObject32 (hdc, hShade );
190     MoveToEx32 (hdc, rect.right-1, rect.top+20, NULL);
191     LineTo32 (hdc, rect.right-1, rect.bottom-1);
192     LineTo32 (hdc, rect.left, rect.bottom-1);
193     hShade = SelectObject32(hdc, hShade);
194     DeleteObject32 (hShade);
195 }
196
197     
198 static void
199 TAB_Refresh (WND *wndPtr, HDC32 hdc)
200 {
201     TAB_INFO *infoPtr = TAB_GetInfoPtr(wndPtr);
202     HFONT32 hFont, hOldFont;
203     RECT32 rect;
204     HBRUSH32 hbrBk;
205     INT32 i;
206
207     TAB_DrawBorder (wndPtr, hdc);
208
209     for (i = 0; i < infoPtr->uNumItem; i++) {
210         TAB_DrawItem (wndPtr, hdc, i);
211     }
212
213 }
214
215 static LRESULT
216 TAB_Paint (WND *wndPtr, WPARAM32 wParam)
217 {
218     HDC32 hdc;
219     PAINTSTRUCT32 ps;
220     
221     hdc = wParam== 0 ? BeginPaint32 (wndPtr->hwndSelf, &ps) : (HDC32)wParam;
222     TAB_Refresh (wndPtr, hdc);
223     
224     if(!wParam)
225         EndPaint32 (wndPtr->hwndSelf, &ps);
226     return 0;
227 }
228
229 static LRESULT
230 TAB_InsertItem (WND *wndPtr, WPARAM32 wParam, LPARAM lParam)
231 {
232     TAB_INFO *infoPtr = TAB_GetInfoPtr(wndPtr);
233     TCITEM *pti;
234     HDC32  hdc;
235     INT32 iItem, len;
236
237     pti = (TCITEM*)lParam;
238     iItem = (INT32)wParam;
239
240     if (iItem < 0) return -1;
241     if (iItem > infoPtr->uNumItem)
242         iItem = infoPtr->uNumItem;
243
244     if (infoPtr->uNumItem == 0) {
245         infoPtr->items = HeapAlloc (GetProcessHeap (), HEAP_ZERO_MEMORY,
246                                     sizeof (TAB_ITEM));
247         infoPtr->uNumItem++;
248     }
249     else {
250         TAB_ITEM *oldItems = infoPtr->items;
251
252         infoPtr->uNumItem++;
253         infoPtr->items = HeapAlloc (GetProcessHeap (), HEAP_ZERO_MEMORY,
254                                     sizeof (TAB_ITEM) * infoPtr->uNumItem);
255         
256         /* pre insert copy */
257         if (iItem > 0) {
258             memcpy (&infoPtr->items[0], &oldItems[0],
259                     iItem * sizeof(TAB_ITEM));
260         }
261
262         /* post insert copy */
263         if (iItem < infoPtr->uNumItem - 1) {
264             memcpy (&infoPtr->items[iItem+1], &oldItems[iItem],
265                     (infoPtr->uNumItem - iItem - 1) * sizeof(TAB_ITEM));
266
267         }
268         
269         HeapFree (GetProcessHeap (), 0, oldItems);
270     }
271
272     infoPtr->items[iItem].mask = pti->mask;
273     if (pti->mask & TCIF_TEXT) {
274         len = lstrlen32A (pti->pszText);
275         infoPtr->items[iItem].pszText = 
276             HeapAlloc (GetProcessHeap (), HEAP_ZERO_MEMORY, len+1);
277         lstrcpy32A (infoPtr->items[iItem].pszText, pti->pszText);
278         infoPtr->items[iItem].cchTextMax = pti->cchTextMax;
279     }
280
281     
282
283     if (pti->mask & TCIF_IMAGE)
284         infoPtr->items[iItem].iImage = pti->iImage;
285
286     if (pti->mask & TCIF_PARAM)
287         infoPtr->items[iItem].lParam = pti->lParam;
288
289     hdc = GetDC32 (wndPtr->hwndSelf);
290     TAB_Refresh (wndPtr, hdc);
291     ReleaseDC32 (wndPtr->hwndSelf, hdc);
292
293     TRACE(tab, "[%04x]: added item %d '%s'\n",
294                 wndPtr->hwndSelf, iItem, infoPtr->items[iItem].pszText);
295
296     TAB_SetItemBounds(wndPtr);
297     return iItem;
298 }
299
300 static LRESULT 
301 TAB_Create (WND *wndPtr, WPARAM32 wParam, LPARAM lParam)
302 {
303     TAB_INFO *infoPtr;
304
305     infoPtr = (TAB_INFO *)HeapAlloc (GetProcessHeap (), HEAP_ZERO_MEMORY,
306                                      sizeof(TAB_INFO));
307     wndPtr->wExtra[0] = (DWORD)infoPtr;
308    
309     infoPtr->uNumItem = 0;
310     infoPtr->hFont = 0;
311     infoPtr->items = 0;
312     infoPtr->hcurArrow = LoadCursor32A (0, IDC_ARROW32A);
313     infoPtr->iSelected = -1;  
314   
315     TRACE(tab, "Created tab control, hwnd [%04x]\n", wndPtr->hwndSelf); 
316     return 0;
317 }
318
319 static LRESULT
320 TAB_Destroy (WND *wndPtr, WPARAM32 wParam, LPARAM lParam)
321 {
322     TAB_INFO *infoPtr = TAB_GetInfoPtr(wndPtr);
323     INT32 iItem;
324
325     if (infoPtr->items) {
326         for (iItem = 0; iItem < infoPtr->uNumItem; iItem++) {
327             if (infoPtr->items[iItem].pszText)
328                 HeapFree (GetProcessHeap (), 0, infoPtr->items[iItem].pszText);
329         }
330         HeapFree (GetProcessHeap (), 0, infoPtr->items);
331     }
332
333     HeapFree (GetProcessHeap (), 0, infoPtr);
334  
335     return 0;
336 }
337
338 LRESULT WINAPI
339 TAB_WindowProc (HWND32 hwnd, UINT32 uMsg, WPARAM32 wParam, LPARAM lParam)
340 {
341     WND *wndPtr = WIN_FindWndPtr(hwnd);
342
343     switch (uMsg)
344     {
345
346         case TCM_GETCURSEL:
347            return TAB_GetCurSel (wndPtr);
348
349         case TCM_INSERTITEM:
350            return TAB_InsertItem (wndPtr, wParam, lParam);
351
352         case WM_CREATE:
353             return TAB_Create (wndPtr, wParam, lParam);
354
355         case WM_DESTROY:
356             return TAB_Destroy (wndPtr, wParam, lParam);
357
358         case WM_LBUTTONUP:
359             return TAB_LButtonUp (wndPtr, wParam, lParam);
360         case WM_PAINT:
361             return TAB_Paint (wndPtr, wParam);
362         
363         
364         default:
365             if (uMsg >= WM_USER)
366                 ERR (tab, "unknown msg %04x wp=%08x lp=%08lx\n",
367                      uMsg, wParam, lParam);
368             return DefWindowProc32A (hwnd, uMsg, wParam, lParam);
369     }
370     return 0;
371 }
372
373
374 VOID
375 TAB_Register (VOID)
376 {
377     WNDCLASS32A wndClass;
378
379     if (GlobalFindAtom32A (WC_TABCONTROL32A)) return;
380
381     ZeroMemory (&wndClass, sizeof(WNDCLASS32A));
382     wndClass.style         = CS_GLOBALCLASS | CS_DBLCLKS | CS_SAVEBITS;
383     wndClass.lpfnWndProc   = (WNDPROC32)TAB_WindowProc;
384     wndClass.cbClsExtra    = 0;
385     wndClass.cbWndExtra    = sizeof(TAB_INFO *);
386     wndClass.hCursor       = LoadCursor32A (0, IDC_ARROW32A);
387     wndClass.hbrBackground = 0;
388     wndClass.lpszClassName = WC_TABCONTROL32A;
389  
390     RegisterClass32A (&wndClass);
391 }
392
393
394 VOID
395 TAB_Unregister (VOID)
396 {
397     if (GlobalFindAtom32A (WC_TABCONTROL32A))
398         UnregisterClass32A (WC_TABCONTROL32A, (HINSTANCE32)NULL);
399 }
400