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