Changed some treeview related definitions.
[wine] / dlls / comctl32 / status.c
1 /*
2  * Interface code to StatusWindow widget/control
3  *
4  * Copyright 1996 Bruce Milner
5  * Copyright 1998 Eric Kohl
6  */
7
8 #include "windows.h"
9 #include "commctrl.h"
10 #include "status.h"
11 #include "win.h"
12 #include "debug.h"
13
14 /*
15  * Run tests using Waite Group Windows95 API Bible Vol. 1&2
16  * The second cdrom contains executables drawstat.exe,gettext.exe,
17  * simple.exe, getparts.exe, setparts.exe, statwnd.exe
18  */
19
20 /*
21  * Fixme/Todo
22  * 1) Don't hard code bar to bottom of window, allow CCS_TOP also.
23  * 2) Tooltip support (almost done).
24  */
25
26 #define _MAX(a,b) (((a)>(b))?(a):(b))
27 #define _MIN(a,b) (((a)>(b))?(b):(a))
28
29 #define HORZ_BORDER 0
30 #define VERT_BORDER 2
31 #define HORZ_GAP    2
32
33 #define STATUSBAR_GetInfoPtr(wndPtr) ((STATUSWINDOWINFO *)wndPtr->wExtra[0])
34
35
36 static void
37 STATUSBAR_DrawSizeGrip (HDC32 hdc, LPRECT32 lpRect)
38 {
39     HPEN32 hOldPen;
40     POINT32 pt;
41     INT32 i;
42
43     pt.x = lpRect->right - 1;
44     pt.y = lpRect->bottom - 1;
45
46     hOldPen = SelectObject32 (hdc, GetSysColorPen32 (COLOR_3DFACE));
47     MoveToEx32 (hdc, pt.x - 12, pt.y, NULL);
48     LineTo32 (hdc, pt.x, pt.y);
49     LineTo32 (hdc, pt.x, pt.y - 12);
50
51     pt.x--;
52     pt.y--;
53
54     SelectObject32 (hdc, GetSysColorPen32 (COLOR_3DSHADOW));
55     for (i = 1; i < 11; i += 4) {
56         MoveToEx32 (hdc, pt.x - i, pt.y, NULL);
57         LineTo32 (hdc, pt.x, pt.y - i);
58
59         MoveToEx32 (hdc, pt.x - i-1, pt.y, NULL);
60         LineTo32 (hdc, pt.x, pt.y - i-1);
61     }
62
63     SelectObject32 (hdc, GetSysColorPen32 (COLOR_3DHIGHLIGHT));
64     for (i = 3; i < 13; i += 4) {
65         MoveToEx32 (hdc, pt.x - i, pt.y, NULL);
66         LineTo32 (hdc, pt.x, pt.y - i);
67     }
68
69     SelectObject32 (hdc, hOldPen);
70 }
71
72
73 static void 
74 STATUSBAR_DrawPart (HDC32 hdc, STATUSWINDOWPART *part)
75 {
76     RECT32 r = part->bound;
77     UINT32 border = BDR_SUNKENOUTER;
78
79     if (part->style==SBT_POPOUT)
80       border = BDR_RAISEDOUTER;
81     else if (part->style==SBT_NOBORDERS)
82       border = 0;
83
84     DrawEdge32(hdc, &r, border, BF_RECT|BF_ADJUST);
85
86     /* draw the icon */
87     if (part->hIcon) {
88         INT32 cy = r.bottom - r.top;
89
90         r.left += 2;
91         DrawIconEx32 (hdc, r.left, r.top, part->hIcon, cy, cy, 0, 0, DI_NORMAL);
92         r.left += cy;
93     }
94
95     /* now draw text */
96     if (part->text) {
97       int oldbkmode = SetBkMode32(hdc, TRANSPARENT);
98       LPWSTR p = (LPWSTR)part->text;
99       UINT32 align = DT_LEFT;
100       if (*p == L'\t') {
101         p++;
102         align = DT_CENTER;
103
104         if (*p == L'\t') {
105           p++;
106           align = DT_RIGHT;
107         }
108       }
109       r.left += 3;
110       DrawText32W (hdc, p, lstrlen32W (p), &r, align|DT_VCENTER|DT_SINGLELINE);
111       if (oldbkmode != TRANSPARENT)
112         SetBkMode32(hdc, oldbkmode);
113     }
114 }
115
116
117 static VOID
118 STATUSBAR_RefreshPart (WND *wndPtr, STATUSWINDOWPART *part, HDC32 hdc)
119 {
120     STATUSWINDOWINFO *self = STATUSBAR_GetInfoPtr (wndPtr);
121     HBRUSH32 hbrBk;
122     HFONT32  hOldFont;
123
124     if (!IsWindowVisible32(wndPtr->hwndSelf))
125         return;
126
127     if (self->clrBk != CLR_DEFAULT)
128         hbrBk = CreateSolidBrush32 (self->clrBk);
129     else
130         hbrBk = GetSysColorBrush32 (COLOR_3DFACE);
131     FillRect32(hdc, &part->bound, hbrBk);
132
133     hOldFont = SelectObject32 (hdc, self->hFont ? self->hFont : self->hDefaultFont);
134
135     if (part->style == SBT_OWNERDRAW) {
136         DRAWITEMSTRUCT32 dis;
137
138         dis.CtlID = wndPtr->wIDmenu;
139         dis.itemID = -1;
140         dis.hwndItem = wndPtr->hwndSelf;
141         dis.hDC = hdc;
142         dis.rcItem = part->bound;
143         dis.itemData = (INT32)part->text;
144         SendMessage32A (GetParent32 (wndPtr->hwndSelf), WM_DRAWITEM,
145                         (WPARAM32)wndPtr->wIDmenu, (LPARAM)&dis);
146     }
147     else
148         STATUSBAR_DrawPart (hdc, part);
149
150     SelectObject32 (hdc, hOldFont);
151
152     if (self->clrBk != CLR_DEFAULT)
153         DeleteObject32 (hbrBk);
154
155     if (wndPtr->dwStyle & SBARS_SIZEGRIP) {
156         RECT32 rect;
157
158         GetClientRect32 (wndPtr->hwndSelf, &rect);
159         STATUSBAR_DrawSizeGrip (hdc, &rect);
160     }
161 }
162
163
164 static BOOL32
165 STATUSBAR_Refresh (WND *wndPtr, HDC32 hdc)
166 {
167     STATUSWINDOWINFO *self = STATUSBAR_GetInfoPtr (wndPtr);
168     int      i;
169     RECT32   rect;
170     HBRUSH32 hbrBk;
171     HFONT32  hOldFont;
172
173     if (!IsWindowVisible32(wndPtr->hwndSelf))
174         return (TRUE);
175
176     GetClientRect32 (wndPtr->hwndSelf, &rect);
177
178     if (self->clrBk != CLR_DEFAULT)
179         hbrBk = CreateSolidBrush32 (self->clrBk);
180     else
181         hbrBk = GetSysColorBrush32 (COLOR_3DFACE);
182     FillRect32(hdc, &rect, hbrBk);
183
184     hOldFont = SelectObject32 (hdc, self->hFont ? self->hFont : self->hDefaultFont);
185
186     if (self->simple) {
187         STATUSBAR_DrawPart (hdc, &self->part0);
188     }
189     else {
190         for (i = 0; i < self->numParts; i++) {
191             if (self->parts[i].style == SBT_OWNERDRAW) {
192                 DRAWITEMSTRUCT32 dis;
193
194                 dis.CtlID = wndPtr->wIDmenu;
195                 dis.itemID = -1;
196                 dis.hwndItem = wndPtr->hwndSelf;
197                 dis.hDC = hdc;
198                 dis.rcItem = self->parts[i].bound;
199                 dis.itemData = (INT32)self->parts[i].text;
200                 SendMessage32A (GetParent32 (wndPtr->hwndSelf), WM_DRAWITEM,
201                                 (WPARAM32)wndPtr->wIDmenu, (LPARAM)&dis);
202             }
203             else
204                 STATUSBAR_DrawPart (hdc, &self->parts[i]);
205         }
206     }
207
208     SelectObject32 (hdc, hOldFont);
209
210     if (self->clrBk != CLR_DEFAULT)
211         DeleteObject32 (hbrBk);
212
213     if (wndPtr->dwStyle & SBARS_SIZEGRIP)
214         STATUSBAR_DrawSizeGrip (hdc, &rect);
215
216     return TRUE;
217 }
218
219
220 static void
221 STATUSBAR_SetPartBounds (WND *wndPtr)
222 {
223     STATUSWINDOWINFO *self = STATUSBAR_GetInfoPtr (wndPtr);
224     STATUSWINDOWPART *part;
225     RECT32 rect, *r;
226     int i;
227
228     /* get our window size */
229     GetClientRect32 (wndPtr->hwndSelf, &rect);
230
231     rect.top += VERT_BORDER;
232
233     /* set bounds for simple rectangle */
234     self->part0.bound = rect;
235
236     /* set bounds for non-simple rectangles */
237     for (i = 0; i < self->numParts; i++) {
238         part = &self->parts[i];
239         r = &self->parts[i].bound;
240         r->top = rect.top;
241         r->bottom = rect.bottom;
242         if (i == 0)
243             r->left = 0;
244         else
245             r->left = self->parts[i-1].bound.right + HORZ_GAP;
246         if (part->x == -1)
247             r->right = rect.right;
248         else
249             r->right = part->x;
250
251         if (self->hwndToolTip) {
252             TTTOOLINFO32A ti;
253
254             ti.cbSize = sizeof(TTTOOLINFO32A);
255             ti.hwnd = wndPtr->hwndSelf;
256             ti.uId = i;
257             ti.rect = *r;
258             SendMessage32A (self->hwndToolTip, TTM_NEWTOOLRECT32A,
259                             0, (LPARAM)&ti);
260         }
261     }
262 }
263
264
265 static VOID
266 STATUSBAR_RelayEvent (HWND32 hwndTip, HWND32 hwndMsg, UINT32 uMsg,
267                       WPARAM32 wParam, LPARAM lParam)
268 {
269     MSG32 msg;
270
271     msg.hwnd = hwndMsg;
272     msg.message = uMsg;
273     msg.wParam = wParam;
274     msg.lParam = lParam;
275     msg.time = GetMessageTime ();
276     msg.pt.x = LOWORD(GetMessagePos ());
277     msg.pt.y = HIWORD(GetMessagePos ());
278
279     SendMessage32A (hwndTip, TTM_RELAYEVENT, 0, (LPARAM)&msg);
280 }
281
282
283 __inline__ static LRESULT
284 STATUSBAR_GetBorders (LPARAM lParam)
285 {
286     LPINT32 out = (LPINT32) lParam;
287
288     out[0] = HORZ_BORDER; /* horizontal border width */
289     out[1] = VERT_BORDER; /* vertical border width */
290     out[2] = HORZ_GAP; /* width of border between rectangles */
291
292     return TRUE;
293 }
294
295
296 static LRESULT
297 STATUSBAR_GetIcon (WND *wndPtr, WPARAM32 wParam)
298 {
299     STATUSWINDOWINFO *self = STATUSBAR_GetInfoPtr (wndPtr);
300     INT32 nPart;
301
302     nPart = (INT32)wParam & 0x00ff;
303     if ((nPart < -1) || (nPart >= self->numParts)) return 0;
304
305     if (nPart == -1)
306         return (self->part0.hIcon);
307     else
308         return (self->parts[nPart].hIcon);
309 }
310
311
312 static LRESULT
313 STATUSBAR_GetParts (WND *wndPtr, WPARAM32 wParam, LPARAM lParam)
314 {
315     STATUSWINDOWINFO *self = STATUSBAR_GetInfoPtr (wndPtr);
316     LPINT32 parts;
317     INT32   num_parts;
318     int     i;
319
320     num_parts = (INT32) wParam;
321     parts = (LPINT32) lParam;
322     if (parts) {
323         return (self->numParts);
324         for (i = 0; i < num_parts; i++) {
325             parts[i] = self->parts[i].x;
326         }
327     }
328     return (self->numParts);
329 }
330
331
332 static LRESULT
333 STATUSBAR_GetRect (WND *wndPtr, WPARAM32 wParam, LPARAM lParam)
334 {
335     STATUSWINDOWINFO *infoPtr = STATUSBAR_GetInfoPtr (wndPtr);
336     int part_num;
337     LPRECT32  rect;
338
339     part_num = ((INT32) wParam) & 0x00ff;
340     rect = (LPRECT32) lParam;
341     if (infoPtr->simple)
342         *rect = infoPtr->part0.bound;
343     else
344         *rect = infoPtr->parts[part_num].bound;
345     return TRUE;
346 }
347
348
349 static LRESULT
350 STATUSBAR_GetText32A (WND *wndPtr, WPARAM32 wParam, LPARAM lParam)
351 {
352     STATUSWINDOWINFO *self = STATUSBAR_GetInfoPtr (wndPtr);
353     STATUSWINDOWPART *part;
354     INT32   nPart;
355     LRESULT result;
356
357     nPart = ((INT32) wParam) & 0x00ff;
358     if (self->simple)
359         part = &self->part0;
360     else
361         part = &self->parts[nPart];
362
363     if (part->style == SBT_OWNERDRAW)
364         result = (LRESULT)part->text;
365     else {
366         result = part->text ? lstrlen32W (part->text) : 0;
367         result |= (part->style << 16);
368         if (lParam && LOWORD(result))
369             lstrcpyWtoA ((LPSTR)lParam, part->text);
370     }
371     return result;
372 }
373
374
375 static LRESULT
376 STATUSBAR_GetText32W (WND *wndPtr, WPARAM32 wParam, LPARAM lParam)
377 {
378     STATUSWINDOWINFO *self = STATUSBAR_GetInfoPtr (wndPtr);
379     STATUSWINDOWPART *part;
380     INT32   nPart;
381     LRESULT result;
382
383     nPart = ((INT32)wParam) & 0x00ff;
384     if (self->simple)
385         part = &self->part0;
386     else
387         part = &self->parts[nPart];
388
389     if (part->style == SBT_OWNERDRAW)
390         result = (LRESULT)part->text;
391     else {
392         result = part->text ? lstrlen32W (part->text) : 0;
393         result |= (part->style << 16);
394         if (lParam)
395             lstrcpy32W ((LPWSTR)lParam, part->text);
396     }
397     return result;
398 }
399
400
401 static LRESULT
402 STATUSBAR_GetTextLength (WND *wndPtr, WPARAM32 wParam)
403 {
404     STATUSWINDOWINFO *infoPtr = STATUSBAR_GetInfoPtr (wndPtr);
405     STATUSWINDOWPART *part;
406     INT32 part_num;
407     DWORD result;
408
409     part_num = ((INT32) wParam) & 0x00ff;
410
411     if (infoPtr->simple)
412         part = &infoPtr->part0;
413     else
414         part = &infoPtr->parts[part_num];
415
416     if (part->text)
417         result = lstrlen32W(part->text);
418     else
419         result = 0;
420
421     result |= (part->style << 16);
422     return result;
423 }
424
425
426 static LRESULT
427 STATUSBAR_GetTipText32A (WND *wndPtr, WPARAM32 wParam, LPARAM lParam)
428 {
429     STATUSWINDOWINFO *infoPtr = STATUSBAR_GetInfoPtr (wndPtr);
430
431     if (infoPtr->hwndToolTip) {
432         TTTOOLINFO32A ti;
433         ti.cbSize = sizeof(TTTOOLINFO32A);
434         ti.hwnd = wndPtr->hwndSelf;
435         ti.uId = LOWORD(wParam);
436         SendMessage32A (infoPtr->hwndToolTip, TTM_GETTEXT32A, 0, (LPARAM)&ti);
437
438         if (ti.lpszText)
439             lstrcpyn32A ((LPSTR)lParam, ti.lpszText, HIWORD(wParam));
440     }
441
442     return 0;
443 }
444
445
446 static LRESULT
447 STATUSBAR_GetTipText32W (WND *wndPtr, WPARAM32 wParam, LPARAM lParam)
448 {
449     STATUSWINDOWINFO *infoPtr = STATUSBAR_GetInfoPtr (wndPtr);
450
451     if (infoPtr->hwndToolTip) {
452         TTTOOLINFO32W ti;
453         ti.cbSize = sizeof(TTTOOLINFO32W);
454         ti.hwnd = wndPtr->hwndSelf;
455         ti.uId = LOWORD(wParam);
456         SendMessage32W (infoPtr->hwndToolTip, TTM_GETTEXT32W, 0, (LPARAM)&ti);
457
458         if (ti.lpszText)
459             lstrcpyn32W ((LPWSTR)lParam, ti.lpszText, HIWORD(wParam));
460     }
461
462     return 0;
463 }
464
465
466 __inline__ static LRESULT
467 STATUSBAR_GetUnicodeFormat (WND *wndPtr)
468 {
469     STATUSWINDOWINFO *infoPtr = STATUSBAR_GetInfoPtr (wndPtr);
470     return infoPtr->bUnicode;
471 }
472
473
474 __inline__ static LRESULT
475 STATUSBAR_IsSimple (WND *wndPtr)
476 {
477     STATUSWINDOWINFO *infoPtr = STATUSBAR_GetInfoPtr (wndPtr);
478     return infoPtr->simple;
479 }
480
481
482 static LRESULT
483 STATUSBAR_SetBkColor (WND *wndPtr, WPARAM32 wParam, LPARAM lParam)
484 {
485     STATUSWINDOWINFO *self = STATUSBAR_GetInfoPtr (wndPtr);
486     COLORREF oldBkColor;
487     HDC32    hdc;
488
489     oldBkColor = self->clrBk;
490     self->clrBk = (COLORREF)lParam;
491     hdc = GetDC32 (wndPtr->hwndSelf);
492     STATUSBAR_Refresh (wndPtr, hdc);
493     ReleaseDC32 (wndPtr->hwndSelf, hdc);
494
495     return oldBkColor;
496 }
497
498
499 static LRESULT
500 STATUSBAR_SetIcon (WND *wndPtr, WPARAM32 wParam, LPARAM lParam)
501 {
502     STATUSWINDOWINFO *self = STATUSBAR_GetInfoPtr (wndPtr);
503     INT32 nPart = (INT32)wParam & 0x00ff;
504     HDC32 hdc; 
505
506     if ((nPart < -1) || (nPart >= self->numParts))
507         return FALSE;
508
509     hdc = GetDC32 (wndPtr->hwndSelf);
510     if (nPart == -1) {
511         self->part0.hIcon = (HICON32)lParam;
512         if (self->simple)
513             STATUSBAR_RefreshPart (wndPtr, &self->part0, hdc);
514     }
515     else {
516         self->parts[nPart].hIcon = (HICON32)lParam;
517         if (!(self->simple))
518             STATUSBAR_RefreshPart (wndPtr, &self->parts[nPart], hdc);
519     }
520     ReleaseDC32 (wndPtr->hwndSelf, hdc);
521
522     return TRUE;
523 }
524
525
526 static LRESULT
527 STATUSBAR_SetMinHeight (WND *wndPtr, WPARAM32 wParam, LPARAM lParam)
528 {
529     STATUSWINDOWINFO *self = STATUSBAR_GetInfoPtr (wndPtr);
530
531     if (IsWindowVisible32 (wndPtr->hwndSelf)) {
532         HWND32 parent = GetParent32 (wndPtr->hwndSelf);
533         INT32  width, x, y;
534         RECT32 parent_rect;
535
536         GetClientRect32 (parent, &parent_rect);
537         self->height = (INT32)wParam + VERT_BORDER;
538         width = parent_rect.right - parent_rect.left;
539         x = parent_rect.left;
540         y = parent_rect.bottom - self->height;
541         MoveWindow32 (wndPtr->hwndSelf, parent_rect.left,
542                       parent_rect.bottom - self->height,
543                       width, self->height, TRUE);
544         STATUSBAR_SetPartBounds (wndPtr);
545     }
546
547     return TRUE;
548 }
549
550
551 static LRESULT
552 STATUSBAR_SetParts (WND *wndPtr, WPARAM32 wParam, LPARAM lParam)
553 {
554     STATUSWINDOWINFO *self = STATUSBAR_GetInfoPtr (wndPtr);
555     STATUSWINDOWPART *tmp;
556     HDC32       hdc;
557     LPINT32 parts;
558     int i;
559     int oldNumParts;
560
561     if (self->simple)
562         self->simple = FALSE;
563
564     oldNumParts = self->numParts;
565     self->numParts = (INT32) wParam;
566     parts = (LPINT32) lParam;
567     if (oldNumParts > self->numParts) {
568         for (i = self->numParts ; i < oldNumParts; i++) {
569             if (self->parts[i].text && (self->parts[i].style != SBT_OWNERDRAW))
570                 COMCTL32_Free (self->parts[i].text);
571         }
572     }
573     else if (oldNumParts < self->numParts) {
574         tmp = COMCTL32_Alloc (sizeof(STATUSWINDOWPART) * self->numParts);
575         for (i = 0; i < oldNumParts; i++) {
576             tmp[i] = self->parts[i];
577         }
578         if (self->parts)
579             COMCTL32_Free (self->parts);
580         self->parts = tmp;
581     }
582     
583     for (i = 0; i < self->numParts; i++) {
584         self->parts[i].x = parts[i];
585     }
586
587     if (self->hwndToolTip) {
588         INT32 nTipCount =
589             SendMessage32A (self->hwndToolTip, TTM_GETTOOLCOUNT, 0, 0);
590
591         if (nTipCount < self->numParts) {
592             /* add tools */
593             TTTOOLINFO32A ti;
594             INT32 i;
595
596             ZeroMemory (&ti, sizeof(TTTOOLINFO32A));
597             ti.cbSize = sizeof(TTTOOLINFO32A);
598             ti.hwnd = wndPtr->hwndSelf;
599             for (i = nTipCount; i < self->numParts; i++) {
600                 TRACE (statusbar, "add tool %d\n", i);
601                 ti.uId = i;
602                 SendMessage32A (self->hwndToolTip, TTM_ADDTOOL32A,
603                                 0, (LPARAM)&ti);
604             }
605         }
606         else if (nTipCount > self->numParts) {
607             /* delete tools */
608             INT32 i;
609
610             for (i = nTipCount - 1; i >= self->numParts; i--) {
611
612                 FIXME (statusbar, "delete tool %d\n", i);
613
614             }
615         }
616     }
617
618     STATUSBAR_SetPartBounds (wndPtr);
619
620     hdc = GetDC32 (wndPtr->hwndSelf);
621     STATUSBAR_Refresh (wndPtr, hdc);
622     ReleaseDC32 (wndPtr->hwndSelf, hdc);
623
624     return TRUE;
625 }
626
627
628 static LRESULT
629 STATUSBAR_SetText32A (WND *wndPtr, WPARAM32 wParam, LPARAM lParam)
630 {
631     STATUSWINDOWINFO *self = STATUSBAR_GetInfoPtr (wndPtr);
632     STATUSWINDOWPART *part;
633     int part_num;
634     int style;
635     LPSTR text;
636     int len;
637     HDC32 hdc;
638
639     text = (LPSTR) lParam;
640     part_num = ((INT32) wParam) & 0x00ff;
641     style = ((INT32) wParam) & 0xff00;
642
643     if ((self->simple) || (self->parts==NULL) || (part_num==255))
644         part = &self->part0;
645     else
646         part = &self->parts[part_num];
647     if (!part) return FALSE;
648     part->style = style;
649     if (style == SBT_OWNERDRAW) {
650         part->text = (LPWSTR)text;
651     }
652     else {
653         /* duplicate string */
654         if (part->text)
655             COMCTL32_Free (part->text);
656         part->text = 0;
657         if (text && (len = lstrlen32A(text))) {
658             part->text = COMCTL32_Alloc ((len+1)*sizeof(WCHAR));
659             lstrcpyAtoW (part->text, text);
660         }
661     }
662
663     hdc = GetDC32 (wndPtr->hwndSelf);
664     STATUSBAR_RefreshPart (wndPtr, part, hdc);
665     ReleaseDC32 (wndPtr->hwndSelf, hdc);
666
667     return TRUE;
668 }
669
670
671 static LRESULT
672 STATUSBAR_SetText32W (WND *wndPtr, WPARAM32 wParam, LPARAM lParam)
673 {
674     STATUSWINDOWINFO *self = STATUSBAR_GetInfoPtr (wndPtr);
675     STATUSWINDOWPART *part;
676     INT32  part_num, style, len;
677     LPWSTR text;
678     HDC32  hdc;
679
680     text = (LPWSTR) lParam;
681     part_num = ((INT32) wParam) & 0x00ff;
682     style = ((INT32) wParam) & 0xff00;
683
684     if ((self->simple) || (self->parts==NULL) || (part_num==255))
685         part = &self->part0;
686     else
687         part = &self->parts[part_num];
688     if (!part) return FALSE;
689     part->style = style;
690     if (style == SBT_OWNERDRAW) {
691         part->text = text;
692     }
693     else {
694         /* duplicate string */
695         if (part->text)
696             COMCTL32_Free (part->text);
697         part->text = 0;
698         if (text && (len = lstrlen32W(text))) {
699             part->text = COMCTL32_Alloc ((len+1)*sizeof(WCHAR));
700             lstrcpy32W(part->text, text);
701         }
702     }
703
704     hdc = GetDC32 (wndPtr->hwndSelf);
705     STATUSBAR_RefreshPart (wndPtr, part, hdc);
706     ReleaseDC32 (wndPtr->hwndSelf, hdc);
707
708     return TRUE;
709 }
710
711
712 static LRESULT
713 STATUSBAR_SetTipText32A (WND *wndPtr, WPARAM32 wParam, LPARAM lParam)
714 {
715     STATUSWINDOWINFO *infoPtr = STATUSBAR_GetInfoPtr (wndPtr);
716
717     TRACE (statusbar, "part %d: \"%s\"\n", (INT32)wParam, (LPSTR)lParam);
718     if (infoPtr->hwndToolTip) {
719         TTTOOLINFO32A ti;
720         ti.cbSize = sizeof(TTTOOLINFO32A);
721         ti.hwnd = wndPtr->hwndSelf;
722         ti.uId = (INT32)wParam;
723         ti.hinst = 0;
724         ti.lpszText = (LPSTR)lParam;
725         SendMessage32A (infoPtr->hwndToolTip, TTM_UPDATETIPTEXT32A,
726                         0, (LPARAM)&ti);
727     }
728
729     return 0;
730 }
731
732
733 static LRESULT
734 STATUSBAR_SetTipText32W (WND *wndPtr, WPARAM32 wParam, LPARAM lParam)
735 {
736     STATUSWINDOWINFO *infoPtr = STATUSBAR_GetInfoPtr (wndPtr);
737
738     TRACE (statusbar, "part %d: \"%s\"\n", (INT32)wParam, (LPSTR)lParam);
739     if (infoPtr->hwndToolTip) {
740         TTTOOLINFO32W ti;
741         ti.cbSize = sizeof(TTTOOLINFO32W);
742         ti.hwnd = wndPtr->hwndSelf;
743         ti.uId = (INT32)wParam;
744         ti.hinst = 0;
745         ti.lpszText = (LPWSTR)lParam;
746         SendMessage32W (infoPtr->hwndToolTip, TTM_UPDATETIPTEXT32W,
747                         0, (LPARAM)&ti);
748     }
749
750     return 0;
751 }
752
753
754 __inline__ static LRESULT
755 STATUSBAR_SetUnicodeFormat (WND *wndPtr, WPARAM32 wParam)
756 {
757     STATUSWINDOWINFO *infoPtr = STATUSBAR_GetInfoPtr (wndPtr);
758     BOOL32 bTemp = infoPtr->bUnicode;
759
760     TRACE (statusbar, "(0x%x)\n", (BOOL32)wParam);
761     infoPtr->bUnicode = (BOOL32)wParam;
762
763     return bTemp;
764 }
765
766
767 static LRESULT
768 STATUSBAR_Simple (WND *wndPtr, WPARAM32 wParam, LPARAM lParam)
769 {
770     STATUSWINDOWINFO *infoPtr = STATUSBAR_GetInfoPtr (wndPtr);
771     HDC32  hdc;
772     NMHDR  nmhdr;
773
774     infoPtr->simple = (BOOL32)wParam;
775
776     /* send notification */
777     nmhdr.hwndFrom = wndPtr->hwndSelf;
778     nmhdr.idFrom = wndPtr->wIDmenu;
779     nmhdr.code = SBN_SIMPLEMODECHANGE;
780     SendMessage32A (GetParent32 (wndPtr->hwndSelf), WM_NOTIFY,
781                     0, (LPARAM)&nmhdr);
782
783     hdc = GetDC32 (wndPtr->hwndSelf);
784     STATUSBAR_Refresh (wndPtr, hdc);
785     ReleaseDC32 (wndPtr->hwndSelf, hdc);
786
787     return TRUE;
788 }
789
790
791 static LRESULT
792 STATUSBAR_WMCreate (WND *wndPtr, WPARAM32 wParam, LPARAM lParam)
793 {
794     LPCREATESTRUCT32A lpCreate = (LPCREATESTRUCT32A)lParam;
795     NONCLIENTMETRICS32A nclm;
796     RECT32      rect;
797     int         width, len;
798     HDC32       hdc;
799     STATUSWINDOWINFO *self;
800
801     self = (STATUSWINDOWINFO*)COMCTL32_Alloc (sizeof(STATUSWINDOWINFO));
802     wndPtr->wExtra[0] = (DWORD)self;
803
804     self->numParts = 1;
805     self->parts = 0;
806     self->simple = FALSE;
807     self->clrBk = CLR_DEFAULT;
808     self->hFont = 0;
809     GetClientRect32 (wndPtr->hwndSelf, &rect);
810
811     nclm.cbSize = sizeof(NONCLIENTMETRICS32A);
812     SystemParametersInfo32A (SPI_GETNONCLIENTMETRICS, 0, &nclm, 0);
813     self->hDefaultFont = CreateFontIndirect32A (&nclm.lfStatusFont);
814
815     /* initialize simple case */
816     self->part0.bound = rect;
817     self->part0.text = 0;
818     self->part0.x = 0;
819     self->part0.style = 0;
820     self->part0.hIcon = 0;
821
822     /* initialize first part */
823     self->parts = COMCTL32_Alloc (sizeof(STATUSWINDOWPART));
824     self->parts[0].bound = rect;
825     self->parts[0].text = 0;
826     self->parts[0].x = -1;
827     self->parts[0].style = 0;
828     self->parts[0].hIcon = 0;
829
830     if (IsWindowUnicode (wndPtr->hwndSelf)) {
831         self->bUnicode = TRUE;
832         if ((len = lstrlen32W ((LPCWSTR)lpCreate->lpszName))) {
833             self->parts[0].text = COMCTL32_Alloc ((len + 1)*sizeof(WCHAR));
834             lstrcpy32W (self->parts[0].text, (LPCWSTR)lpCreate->lpszName);
835         }
836     }
837     else {
838         if ((len = lstrlen32A ((LPCSTR)lpCreate->lpszName))) {
839             self->parts[0].text = COMCTL32_Alloc ((len + 1)*sizeof(WCHAR));
840             lstrcpyAtoW (self->parts[0].text, (LPCSTR)lpCreate->lpszName);
841         }
842     }
843
844     if ((hdc = GetDC32 (0))) {
845         TEXTMETRIC32A tm;
846         HFONT32 hOldFont;
847
848         hOldFont = SelectObject32 (hdc,self->hDefaultFont);
849         GetTextMetrics32A(hdc, &tm);
850         self->textHeight = tm.tmHeight;
851         SelectObject32 (hdc, hOldFont);
852         ReleaseDC32(0, hdc);
853     }
854
855     if (wndPtr->dwStyle & SBT_TOOLTIPS) {
856         self->hwndToolTip =
857             CreateWindowEx32A (0, TOOLTIPS_CLASS32A, NULL, 0,
858                                CW_USEDEFAULT32, CW_USEDEFAULT32,
859                                CW_USEDEFAULT32, CW_USEDEFAULT32,
860                                wndPtr->hwndSelf, 0,
861                                wndPtr->hInstance, NULL);
862
863         if (self->hwndToolTip) {
864             NMTOOLTIPSCREATED nmttc;
865
866             nmttc.hdr.hwndFrom = wndPtr->hwndSelf;
867             nmttc.hdr.idFrom = wndPtr->wIDmenu;
868             nmttc.hdr.code = NM_TOOLTIPSCREATED;
869             nmttc.hwndToolTips = self->hwndToolTip;
870
871             SendMessage32A (GetParent32 (wndPtr->hwndSelf), WM_NOTIFY,
872                             (WPARAM32)wndPtr->wIDmenu, (LPARAM)&nmttc);
873         }
874     }
875
876     GetClientRect32 (GetParent32 (wndPtr->hwndSelf), &rect);
877     width = rect.right - rect.left;
878     self->height = self->textHeight + 4 + VERT_BORDER;
879     MoveWindow32 (wndPtr->hwndSelf, lpCreate->x, lpCreate->y-1,
880                   width, self->height, FALSE);
881     STATUSBAR_SetPartBounds (wndPtr);
882
883     return 0;
884 }
885
886
887 static LRESULT
888 STATUSBAR_WMDestroy (WND *wndPtr)
889 {
890     STATUSWINDOWINFO *self = STATUSBAR_GetInfoPtr (wndPtr);
891     int i;
892
893     for (i = 0; i < self->numParts; i++) {
894         if (self->parts[i].text && (self->parts[i].style != SBT_OWNERDRAW))
895             COMCTL32_Free (self->parts[i].text);
896     }
897     if (self->part0.text && (self->part0.style != SBT_OWNERDRAW))
898         COMCTL32_Free (self->part0.text);
899     COMCTL32_Free (self->parts);
900
901     /* delete default font */
902     if (self->hDefaultFont)
903         DeleteObject32 (self->hDefaultFont);
904
905     /* delete tool tip control */
906     if (self->hwndToolTip)
907         DestroyWindow32 (self->hwndToolTip);
908
909     COMCTL32_Free (self);
910
911     return 0;
912 }
913
914
915 static __inline__ LRESULT
916 STATUSBAR_WMGetFont (WND *wndPtr)
917 {
918     STATUSWINDOWINFO *infoPtr = STATUSBAR_GetInfoPtr (wndPtr);
919     return infoPtr->hFont;
920 }
921
922
923 static LRESULT
924 STATUSBAR_WMGetText (WND *wndPtr, WPARAM32 wParam, LPARAM lParam)
925 {
926     STATUSWINDOWINFO *infoPtr = STATUSBAR_GetInfoPtr (wndPtr);
927     INT32 len;
928
929     if (!(infoPtr->parts[0].text))
930         return 0;
931     len = lstrlen32W (infoPtr->parts[0].text);
932     if (wParam > len) {
933         if (infoPtr->bUnicode)
934             lstrcpy32W ((LPWSTR)lParam, infoPtr->parts[0].text);
935         else
936             lstrcpyWtoA ((LPSTR)lParam, infoPtr->parts[0].text);
937         return len;
938     }
939
940     return -1;
941 }
942
943
944 __inline__ static LRESULT
945 STATUSBAR_WMMouseMove (WND *wndPtr, WPARAM32 wParam, LPARAM lParam)
946 {
947     STATUSWINDOWINFO *infoPtr = STATUSBAR_GetInfoPtr (wndPtr);
948
949     if (infoPtr->hwndToolTip)
950         STATUSBAR_RelayEvent (infoPtr->hwndToolTip, wndPtr->hwndSelf,
951                               WM_MOUSEMOVE, wParam, lParam);
952     return 0;
953 }
954
955
956 static LRESULT
957 STATUSBAR_WMNCHitTest (WND *wndPtr, WPARAM32 wParam, LPARAM lParam)
958 {
959     if (wndPtr->dwStyle & SBARS_SIZEGRIP) {
960         RECT32  rect;
961         POINT32 pt;
962
963         GetClientRect32 (wndPtr->hwndSelf, &rect);
964
965         pt.x = (INT32)LOWORD(lParam);
966         pt.y = (INT32)HIWORD(lParam);
967         ScreenToClient32 (wndPtr->hwndSelf, &pt);
968
969         rect.left = rect.right - 13;
970         rect.top += 2;
971
972         if (PtInRect32 (&rect, pt))
973             return HTBOTTOMRIGHT;
974     }
975
976     return DefWindowProc32A (wndPtr->hwndSelf, WM_NCHITTEST, wParam, lParam);
977 }
978
979
980 static __inline__ LRESULT
981 STATUSBAR_WMNCLButtonDown (WND *wndPtr, WPARAM32 wParam, LPARAM lParam)
982 {
983     PostMessage32A (wndPtr->parent->hwndSelf, WM_NCLBUTTONDOWN,
984                     wParam, lParam);
985     return 0;
986 }
987
988
989 static __inline__ LRESULT
990 STATUSBAR_WMNCLButtonUp (WND *wndPtr, WPARAM32 wParam, LPARAM lParam)
991 {
992     PostMessage32A (wndPtr->parent->hwndSelf, WM_NCLBUTTONUP,
993                     wParam, lParam);
994     return 0;
995 }
996
997
998 static LRESULT
999 STATUSBAR_WMPaint (WND *wndPtr, WPARAM32 wParam)
1000 {
1001     HDC32 hdc;
1002     PAINTSTRUCT32 ps;
1003
1004     hdc = wParam==0 ? BeginPaint32 (wndPtr->hwndSelf, &ps) : (HDC32)wParam;
1005     STATUSBAR_Refresh (wndPtr, hdc);
1006     if (!wParam)
1007         EndPaint32 (wndPtr->hwndSelf, &ps);
1008
1009     return 0;
1010 }
1011
1012
1013 static LRESULT
1014 STATUSBAR_WMSetFont (WND *wndPtr, WPARAM32 wParam, LPARAM lParam)
1015 {
1016     STATUSWINDOWINFO *infoPtr = STATUSBAR_GetInfoPtr (wndPtr);
1017
1018     infoPtr->hFont = (HFONT32)wParam;
1019     if (LOWORD(lParam) == TRUE) {
1020         HDC32 hdc = GetDC32 (wndPtr->hwndSelf);
1021         STATUSBAR_Refresh (wndPtr, hdc);
1022         ReleaseDC32 (wndPtr->hwndSelf, hdc);
1023     }
1024
1025     return 0;
1026 }
1027
1028
1029 static LRESULT
1030 STATUSBAR_WMSetText (WND *wndPtr, WPARAM32 wParam, LPARAM lParam)
1031 {
1032     STATUSWINDOWINFO *infoPtr = STATUSBAR_GetInfoPtr (wndPtr);
1033     STATUSWINDOWPART *part;
1034     int len;
1035     HDC32 hdc;
1036
1037     if (infoPtr->numParts == 0)
1038         return FALSE;
1039
1040     part = &infoPtr->parts[0];
1041     /* duplicate string */
1042     if (part->text)
1043         COMCTL32_Free (part->text);
1044     part->text = 0;
1045     if (infoPtr->bUnicode) {
1046         if (lParam && (len = lstrlen32W((LPCWSTR)lParam))) {
1047             part->text = COMCTL32_Alloc ((len+1)*sizeof(WCHAR));
1048             lstrcpy32W (part->text, (LPCWSTR)lParam);
1049         }
1050     }
1051     else {
1052         if (lParam && (len = lstrlen32A((LPCSTR)lParam))) {
1053             part->text = COMCTL32_Alloc ((len+1)*sizeof(WCHAR));
1054             lstrcpyAtoW (part->text, (LPCSTR)lParam);
1055         }
1056     }
1057
1058     hdc = GetDC32 (wndPtr->hwndSelf);
1059     STATUSBAR_RefreshPart (wndPtr, part, hdc);
1060     ReleaseDC32 (wndPtr->hwndSelf, hdc);
1061
1062     return TRUE;
1063 }
1064
1065
1066 static LRESULT
1067 STATUSBAR_WMSize (WND *wndPtr, WPARAM32 wParam, LPARAM lParam)
1068 {
1069     STATUSWINDOWINFO *infoPtr = STATUSBAR_GetInfoPtr (wndPtr);
1070     INT32  width, x, y, flags;
1071     RECT32 parent_rect;
1072     HWND32 parent;
1073
1074     /* Need to resize width to match parent */
1075     flags = (INT32) wParam;
1076
1077     /* FIXME for flags =
1078      * SIZE_MAXIMIZED, SIZE_MAXSHOW, SIZE_MINIMIZED, SIZE_RESTORED
1079      */
1080
1081     if (flags == SIZE_RESTORED) {
1082         /* width and height don't apply */
1083         parent = GetParent32 (wndPtr->hwndSelf);
1084         GetClientRect32 (parent, &parent_rect);
1085         width = parent_rect.right - parent_rect.left;
1086         x = parent_rect.left;
1087         y = parent_rect.bottom - infoPtr->height;
1088         MoveWindow32 (wndPtr->hwndSelf, parent_rect.left, 
1089                       parent_rect.bottom - infoPtr->height,
1090                       width, infoPtr->height, TRUE);
1091         STATUSBAR_SetPartBounds (wndPtr);
1092     }
1093     return 0;
1094 }
1095
1096
1097 static LRESULT
1098 STATUSBAR_SendNotify (WND *wndPtr, UINT32 code)
1099 {
1100     NMHDR  nmhdr;
1101
1102     nmhdr.hwndFrom = wndPtr->hwndSelf;
1103     nmhdr.idFrom = wndPtr->wIDmenu;
1104     nmhdr.code = code;
1105     SendMessage32A (GetParent32 (wndPtr->hwndSelf), WM_NOTIFY,
1106                     0, (LPARAM)&nmhdr);
1107     return 0;
1108 }
1109
1110
1111
1112 LRESULT WINAPI
1113 StatusWindowProc (HWND32 hwnd, UINT32 msg, WPARAM32 wParam, LPARAM lParam)
1114 {
1115     WND *wndPtr = WIN_FindWndPtr (hwnd);
1116
1117     switch (msg) {
1118         case SB_GETBORDERS:
1119             return STATUSBAR_GetBorders (lParam);
1120
1121         case SB_GETICON:
1122             return STATUSBAR_GetIcon (wndPtr, wParam);
1123
1124         case SB_GETPARTS:
1125             return STATUSBAR_GetParts (wndPtr, wParam, lParam);
1126
1127         case SB_GETRECT:
1128             return STATUSBAR_GetRect (wndPtr, wParam, lParam);
1129
1130         case SB_GETTEXT32A:
1131             return STATUSBAR_GetText32A (wndPtr, wParam, lParam);
1132
1133         case SB_GETTEXT32W:
1134             return STATUSBAR_GetText32W (wndPtr, wParam, lParam);
1135
1136         case SB_GETTEXTLENGTH32A:
1137         case SB_GETTEXTLENGTH32W:
1138             return STATUSBAR_GetTextLength (wndPtr, wParam);
1139
1140         case SB_GETTIPTEXT32A:
1141             return STATUSBAR_GetTipText32A (wndPtr, wParam, lParam);
1142
1143         case SB_GETTIPTEXT32W:
1144             return STATUSBAR_GetTipText32W (wndPtr, wParam, lParam);
1145
1146         case SB_GETUNICODEFORMAT:
1147             return STATUSBAR_GetUnicodeFormat (wndPtr);
1148
1149         case SB_ISSIMPLE:
1150             return STATUSBAR_IsSimple (wndPtr);
1151
1152         case SB_SETBKCOLOR:
1153             return STATUSBAR_SetBkColor (wndPtr, wParam, lParam);
1154
1155         case SB_SETICON:
1156             return STATUSBAR_SetIcon (wndPtr, wParam, lParam);
1157
1158         case SB_SETMINHEIGHT:
1159             return STATUSBAR_SetMinHeight (wndPtr, wParam, lParam);
1160
1161         case SB_SETPARTS:       
1162             return STATUSBAR_SetParts (wndPtr, wParam, lParam);
1163
1164         case SB_SETTEXT32A:
1165             return STATUSBAR_SetText32A (wndPtr, wParam, lParam);
1166
1167         case SB_SETTEXT32W:
1168             return STATUSBAR_SetText32W (wndPtr, wParam, lParam);
1169
1170         case SB_SETTIPTEXT32A:
1171             return STATUSBAR_SetTipText32A (wndPtr, wParam, lParam);
1172
1173         case SB_SETTIPTEXT32W:
1174             return STATUSBAR_SetTipText32W (wndPtr, wParam, lParam);
1175
1176         case SB_SETUNICODEFORMAT:
1177             return STATUSBAR_SetUnicodeFormat (wndPtr, wParam);
1178
1179         case SB_SIMPLE:
1180             return STATUSBAR_Simple (wndPtr, wParam, lParam);
1181
1182
1183         case WM_CREATE:
1184             return STATUSBAR_WMCreate (wndPtr, wParam, lParam);
1185
1186         case WM_DESTROY:
1187             return STATUSBAR_WMDestroy (wndPtr);
1188
1189         case WM_GETFONT:
1190             return STATUSBAR_WMGetFont (wndPtr);
1191
1192         case WM_GETTEXT:
1193             return STATUSBAR_WMGetText (wndPtr, wParam, lParam);
1194
1195         case WM_GETTEXTLENGTH:
1196             return STATUSBAR_GetTextLength (wndPtr, 0);
1197
1198         case WM_LBUTTONDBLCLK:
1199             return STATUSBAR_SendNotify (wndPtr, NM_DBLCLK);
1200
1201         case WM_LBUTTONUP:
1202             return STATUSBAR_SendNotify (wndPtr, NM_CLICK);
1203
1204         case WM_MOUSEMOVE:
1205             return STATUSBAR_WMMouseMove (wndPtr, wParam, lParam);
1206
1207         case WM_NCHITTEST:
1208             return STATUSBAR_WMNCHitTest (wndPtr, wParam, lParam);
1209
1210         case WM_NCLBUTTONDOWN:
1211             return STATUSBAR_WMNCLButtonDown (wndPtr, wParam, lParam);
1212
1213         case WM_NCLBUTTONUP:
1214             return STATUSBAR_WMNCLButtonUp (wndPtr, wParam, lParam);
1215
1216         case WM_PAINT:
1217             return STATUSBAR_WMPaint (wndPtr, wParam);
1218
1219         case WM_RBUTTONDBLCLK:
1220             return STATUSBAR_SendNotify (wndPtr, NM_RDBLCLK);
1221
1222         case WM_RBUTTONUP:
1223             return STATUSBAR_SendNotify (wndPtr, NM_RCLICK);
1224
1225         case WM_SETFONT:
1226             return STATUSBAR_WMSetFont (wndPtr, wParam, lParam);
1227
1228         case WM_SETTEXT:
1229             return STATUSBAR_WMSetText (wndPtr, wParam, lParam);
1230
1231         case WM_SIZE:
1232             return STATUSBAR_WMSize (wndPtr, wParam, lParam);
1233
1234         default:
1235             if (msg >= WM_USER)
1236                 ERR (statusbar, "unknown msg %04x wp=%04x lp=%08lx\n",
1237                      msg, wParam, lParam);
1238             return DefWindowProc32A (hwnd, msg, wParam, lParam);
1239     }
1240     return 0;
1241 }
1242
1243
1244 /***********************************************************************
1245  * STATUS_Register [Internal]
1246  *
1247  * Registers the status window class.
1248  */
1249
1250 VOID
1251 STATUS_Register (VOID)
1252 {
1253     WNDCLASS32A wndClass;
1254
1255     if (GlobalFindAtom32A (STATUSCLASSNAME32A)) return;
1256
1257     ZeroMemory (&wndClass, sizeof(WNDCLASS32A));
1258     wndClass.style         = CS_GLOBALCLASS | CS_DBLCLKS | CS_VREDRAW;
1259     wndClass.lpfnWndProc   = (WNDPROC32)StatusWindowProc;
1260     wndClass.cbClsExtra    = 0;
1261     wndClass.cbWndExtra    = sizeof(STATUSWINDOWINFO *);
1262     wndClass.hCursor       = LoadCursor32A (0, IDC_ARROW32A);
1263     wndClass.hbrBackground = (HBRUSH32)(COLOR_3DFACE + 1);
1264     wndClass.lpszClassName = STATUSCLASSNAME32A;
1265  
1266     RegisterClass32A (&wndClass);
1267 }
1268
1269
1270 /***********************************************************************
1271  * STATUS_Unregister [Internal]
1272  *
1273  * Unregisters the status window class.
1274  */
1275
1276 VOID
1277 STATUS_Unregister (VOID)
1278 {
1279     if (GlobalFindAtom32A (STATUSCLASSNAME32A))
1280         UnregisterClass32A (STATUSCLASSNAME32A, (HINSTANCE32)NULL);
1281 }
1282