Don't write to buffer with zero length.
[wine] / controls / static.c
1 /*
2  * Static control
3  *
4  * Copyright  David W. Metcalfe, 1993
5  *
6  */
7
8 #include "windef.h"
9 #include "wingdi.h"
10 #include "wine/winuser16.h"
11 #include "win.h"
12 #include "cursoricon.h"
13 #include "controls.h"
14 #include "heap.h"
15 #include "debugtools.h"
16 #include "tweak.h"
17
18 DEFAULT_DEBUG_CHANNEL(static);
19
20 static void STATIC_PaintOwnerDrawfn( WND *wndPtr, HDC hdc );
21 static void STATIC_PaintTextfn( WND *wndPtr, HDC hdc );
22 static void STATIC_PaintRectfn( WND *wndPtr, HDC hdc );
23 static void STATIC_PaintIconfn( WND *wndPtr, HDC hdc );
24 static void STATIC_PaintBitmapfn( WND *wndPtr, HDC hdc );
25 static void STATIC_PaintEtchedfn( WND *wndPtr, HDC hdc );
26 static LRESULT WINAPI StaticWndProcA( HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam );
27
28 static COLORREF color_windowframe, color_background, color_window;
29
30 typedef struct
31 {
32     HFONT16  hFont;   /* Control font (or 0 for system font) */
33     WORD     dummy;   /* Don't know what MS-Windows puts in there */
34     HICON16  hIcon;   /* Icon handle for SS_ICON controls */
35 } STATICINFO;
36
37 typedef void (*pfPaint)( WND *, HDC );
38
39 static pfPaint staticPaintFunc[SS_TYPEMASK+1] =
40 {
41     STATIC_PaintTextfn,      /* SS_LEFT */
42     STATIC_PaintTextfn,      /* SS_CENTER */
43     STATIC_PaintTextfn,      /* SS_RIGHT */
44     STATIC_PaintIconfn,      /* SS_ICON */
45     STATIC_PaintRectfn,      /* SS_BLACKRECT */
46     STATIC_PaintRectfn,      /* SS_GRAYRECT */
47     STATIC_PaintRectfn,      /* SS_WHITERECT */
48     STATIC_PaintRectfn,      /* SS_BLACKFRAME */
49     STATIC_PaintRectfn,      /* SS_GRAYFRAME */
50     STATIC_PaintRectfn,      /* SS_WHITEFRAME */
51     NULL,                    /* Not defined */
52     STATIC_PaintTextfn,      /* SS_SIMPLE */
53     STATIC_PaintTextfn,      /* SS_LEFTNOWORDWRAP */
54     STATIC_PaintOwnerDrawfn, /* SS_OWNERDRAW */
55     STATIC_PaintBitmapfn,    /* SS_BITMAP */
56     NULL,                    /* SS_ENHMETAFILE */
57     STATIC_PaintEtchedfn,    /* SS_ETCHEDHORIZ */
58     STATIC_PaintEtchedfn,    /* SS_ETCHEDVERT */
59     STATIC_PaintEtchedfn,    /* SS_ETCHEDFRAME */
60 };
61
62
63 /*********************************************************************
64  * static class descriptor
65  */
66 const struct builtin_class_descr STATIC_builtin_class =
67 {
68     "Static",            /* name */
69     CS_GLOBALCLASS | CS_DBLCLKS | CS_PARENTDC, /* style  */
70     StaticWndProcA,      /* procA */
71     NULL,                /* procW (FIXME) */
72     sizeof(STATICINFO),  /* extra */
73     IDC_ARROWA,          /* cursor */
74     0                    /* brush */
75 };
76
77
78 /***********************************************************************
79  *           STATIC_SetIcon
80  *
81  * Set the icon for an SS_ICON control.
82  */
83 static HICON16 STATIC_SetIcon( WND *wndPtr, HICON16 hicon )
84 {
85     HICON16 prevIcon;
86     STATICINFO *infoPtr = (STATICINFO *)wndPtr->wExtra;
87     CURSORICONINFO *info = hicon?(CURSORICONINFO *) GlobalLock16( hicon ):NULL;
88
89     if ((wndPtr->dwStyle & SS_TYPEMASK) != SS_ICON) return 0;
90     if (hicon && !info) {
91         ERR("huh? hicon!=0, but info=0???\n");
92         return 0;
93     }
94     prevIcon = infoPtr->hIcon;
95     infoPtr->hIcon = hicon;
96     if (hicon)
97     {
98         SetWindowPos( wndPtr->hwndSelf, 0, 0, 0, info->nWidth, info->nHeight,
99                         SWP_NOACTIVATE | SWP_NOMOVE | SWP_NOZORDER );
100         GlobalUnlock16( hicon );
101     }
102     return prevIcon;
103 }
104
105 /***********************************************************************
106  *           STATIC_SetBitmap
107  *
108  * Set the bitmap for an SS_BITMAP control.
109  */
110 static HBITMAP16 STATIC_SetBitmap( WND *wndPtr, HBITMAP16 hBitmap )
111 {
112     HBITMAP16 hOldBitmap;
113     STATICINFO *infoPtr = (STATICINFO *)wndPtr->wExtra;
114
115     if ((wndPtr->dwStyle & SS_TYPEMASK) != SS_BITMAP) return 0;
116     if (hBitmap && GetObjectType(hBitmap) != OBJ_BITMAP) {
117         ERR("huh? hBitmap!=0, but not bitmap\n");
118         return 0;
119     }
120     hOldBitmap = infoPtr->hIcon;
121     infoPtr->hIcon = hBitmap;
122     if (hBitmap)
123     {
124         BITMAP bm;
125         GetObjectA(hBitmap, sizeof(bm), &bm);
126         SetWindowPos( wndPtr->hwndSelf, 0, 0, 0, bm.bmWidth, bm.bmHeight,
127                       SWP_NOACTIVATE | SWP_NOMOVE | SWP_NOZORDER );
128     }
129     return hOldBitmap;
130 }
131
132
133 /***********************************************************************
134  *           STATIC_LoadIcon
135  *
136  * Load the icon for an SS_ICON control.
137  */
138 static HICON STATIC_LoadIcon( WND *wndPtr, LPCSTR name )
139 {
140     HICON hicon = LoadIconA( wndPtr->hInstance, name );
141     if (!hicon) hicon = LoadIconA( 0, name );
142     return hicon;
143 }
144
145 /***********************************************************************
146  *           STATIC_LoadBitmap
147  *
148  * Load the bitmap for an SS_BITMAP control.
149  */
150 static HBITMAP STATIC_LoadBitmap( WND *wndPtr, LPCSTR name )
151 {
152     HBITMAP hbitmap = LoadBitmapA( wndPtr->hInstance, name );
153     if (!hbitmap)  /* Try OEM icon (FIXME: is this right?) */
154         hbitmap = LoadBitmapA( 0, name );
155     return hbitmap;
156 }
157
158
159 /***********************************************************************
160  *           StaticWndProcA
161  */
162 static LRESULT WINAPI StaticWndProcA( HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam )
163 {
164     LRESULT lResult = 0;
165     WND *wndPtr = WIN_FindWndPtr(hWnd);
166     LONG style = wndPtr->dwStyle & SS_TYPEMASK;
167     STATICINFO *infoPtr = (STATICINFO *)wndPtr->wExtra;
168
169     switch (uMsg)
170     {
171     case WM_NCCREATE: {
172         CREATESTRUCTA *cs = (CREATESTRUCTA *)lParam;
173
174         if ((TWEAK_WineLook > WIN31_LOOK) && (wndPtr->dwStyle & SS_SUNKEN))
175             wndPtr->dwExStyle |= WS_EX_STATICEDGE;
176
177         if (style == SS_ICON)
178         {
179             if (cs->lpszName)
180             {
181                 if (!HIWORD(cs->lpszName) || cs->lpszName[0])
182                     STATIC_SetIcon( wndPtr,
183                                 STATIC_LoadIcon( wndPtr, cs->lpszName ));
184             }
185             lResult = 1;
186             goto END;
187         }
188         if (style == SS_BITMAP)
189         {
190             if (cs->lpszName)
191                 STATIC_SetBitmap( wndPtr,
192                                 STATIC_LoadBitmap( wndPtr, cs->lpszName ));
193             WARN("style SS_BITMAP, dwStyle is 0x%08lx\n",
194                         wndPtr->dwStyle);
195             lResult = 1;
196             goto END;
197         }
198         if (!HIWORD(cs->lpszName) && (cs->lpszName))
199         {
200                 FIXME("windowName is 0x%04x, not doing DefWindowProc\n",
201                     LOWORD(cs->lpszName));
202                 lResult = 1;
203                 goto END;
204         }
205         lResult = DefWindowProcA( hWnd, uMsg, wParam, lParam );
206         goto END;
207     }
208     case WM_CREATE:
209         if (style < 0L || style > SS_TYPEMASK)
210         {
211             ERR("Unknown style 0x%02lx\n", style );
212             lResult = -1L;
213             break;
214         }
215         /* initialise colours */
216         color_windowframe  = GetSysColor(COLOR_WINDOWFRAME);
217         color_background   = GetSysColor(COLOR_BACKGROUND);
218         color_window       = GetSysColor(COLOR_WINDOW);
219         break;
220
221     case WM_NCDESTROY:
222         if (style == SS_ICON) {
223 /*
224  * FIXME
225  *           DestroyIcon32( STATIC_SetIcon( wndPtr, 0 ) );
226  * 
227  * We don't want to do this yet because DestroyIcon32 is broken. If the icon
228  * had already been loaded by the application the last thing we want to do is
229  * GlobalFree16 the handle.
230  */
231         } else {
232             lResult = DefWindowProcA( hWnd, uMsg, wParam, lParam );
233         }
234         break;
235
236     case WM_PAINT:
237         {
238             PAINTSTRUCT ps;
239             BeginPaint( hWnd, &ps );
240             if (staticPaintFunc[style])
241                 (staticPaintFunc[style])( wndPtr, ps.hdc );
242             EndPaint( hWnd, &ps );
243         }
244         break;
245
246     case WM_ENABLE:
247         InvalidateRect( hWnd, NULL, FALSE );
248         break;
249
250     case WM_SYSCOLORCHANGE:
251         color_windowframe  = GetSysColor(COLOR_WINDOWFRAME);
252         color_background   = GetSysColor(COLOR_BACKGROUND);
253         color_window       = GetSysColor(COLOR_WINDOW);
254         InvalidateRect( hWnd, NULL, TRUE );
255         break;
256
257     case WM_SETTEXT:
258         if (style == SS_ICON)
259             /* FIXME : should we also return the previous hIcon here ??? */
260             STATIC_SetIcon( wndPtr, STATIC_LoadIcon( wndPtr, (LPCSTR)lParam ));
261         else if (style == SS_BITMAP) 
262             STATIC_SetBitmap(wndPtr,STATIC_LoadBitmap(wndPtr,(LPCSTR)lParam ));
263         else
264             DEFWND_SetTextA( wndPtr, (LPCSTR)lParam );
265         InvalidateRect( hWnd, NULL, FALSE );
266         lResult = 1; /* success. FIXME: check text length */
267         break;
268
269     case WM_SETFONT:
270         if (style == SS_ICON)
271         {
272             lResult = 0;
273             goto END;
274         }
275         if (style == SS_BITMAP)
276         {
277             lResult = 0;
278             goto END;
279         }
280         infoPtr->hFont = (HFONT16)wParam;
281         if (LOWORD(lParam))
282         {
283             InvalidateRect( hWnd, NULL, FALSE );
284             UpdateWindow( hWnd );
285         }
286         break;
287
288     case WM_GETFONT:
289         lResult = infoPtr->hFont;
290         goto END;
291
292     case WM_NCHITTEST:
293         if (wndPtr->dwStyle & SS_NOTIFY)
294            lResult = HTCLIENT;
295         else
296            lResult = HTTRANSPARENT;
297         goto END;
298
299     case WM_GETDLGCODE:
300         lResult = DLGC_STATIC;
301         goto END;
302
303     case STM_GETIMAGE:
304     case STM_GETICON16:
305     case STM_GETICON:
306         lResult = infoPtr->hIcon;
307         goto END;
308
309     case STM_SETIMAGE:
310         switch(wParam) {
311         case IMAGE_BITMAP:
312             lResult = STATIC_SetBitmap( wndPtr, (HBITMAP)lParam );
313             break;
314         case IMAGE_ICON:
315             lResult = STATIC_SetIcon( wndPtr, (HICON16)lParam );
316             break;
317         default:
318             FIXME("STM_SETIMAGE: Unhandled type %x\n", wParam);
319             break;
320         }
321         InvalidateRect( hWnd, NULL, FALSE );
322         UpdateWindow( hWnd );
323         break;
324
325     case STM_SETICON16:
326     case STM_SETICON:
327         lResult = STATIC_SetIcon( wndPtr, (HICON16)wParam );
328         InvalidateRect( hWnd, NULL, FALSE );
329         UpdateWindow( hWnd );
330         break;
331
332     default:
333         lResult = DefWindowProcA(hWnd, uMsg, wParam, lParam);
334         break;
335     }
336     
337 END:
338     WIN_ReleaseWndPtr(wndPtr);
339     return lResult;
340 }
341
342 static void STATIC_PaintOwnerDrawfn( WND *wndPtr, HDC hdc )
343 {
344   DRAWITEMSTRUCT dis;
345
346   dis.CtlType    = ODT_STATIC;
347   dis.CtlID      = wndPtr->wIDmenu;
348   dis.itemID     = 0;
349   dis.itemAction = ODA_DRAWENTIRE;
350   dis.itemState  = 0;
351   dis.hwndItem   = wndPtr->hwndSelf;
352   dis.hDC        = hdc;
353   dis.itemData   = 0;
354   GetClientRect( wndPtr->hwndSelf, &dis.rcItem );
355
356   SendMessageA( GetParent(wndPtr->hwndSelf), WM_CTLCOLORSTATIC, 
357                 hdc, wndPtr->hwndSelf );    
358   SendMessageA( GetParent(wndPtr->hwndSelf), WM_DRAWITEM,
359                 wndPtr->wIDmenu, (LPARAM)&dis );
360 }
361
362 static void STATIC_PaintTextfn( WND *wndPtr, HDC hdc )
363 {
364     RECT rc;
365     HBRUSH hBrush;
366     WORD wFormat;
367
368     LONG style = wndPtr->dwStyle;
369     STATICINFO *infoPtr = (STATICINFO *)wndPtr->wExtra;
370
371     GetClientRect( wndPtr->hwndSelf, &rc);
372
373     switch (style & SS_TYPEMASK)
374     {
375     case SS_LEFT:
376         wFormat = DT_LEFT | DT_EXPANDTABS | DT_WORDBREAK | DT_NOCLIP;
377         break;
378
379     case SS_CENTER:
380         wFormat = DT_CENTER | DT_EXPANDTABS | DT_WORDBREAK | DT_NOCLIP;
381         break;
382
383     case SS_RIGHT:
384         wFormat = DT_RIGHT | DT_EXPANDTABS | DT_WORDBREAK | DT_NOCLIP;
385         break;
386
387     case SS_SIMPLE:
388         wFormat = DT_LEFT | DT_SINGLELINE | DT_VCENTER | DT_NOCLIP;
389         break;
390
391     case SS_LEFTNOWORDWRAP:
392         wFormat = DT_LEFT | DT_EXPANDTABS | DT_VCENTER;
393         break;
394
395     default:
396         return;
397     }
398
399     if (style & SS_NOPREFIX)
400         wFormat |= DT_NOPREFIX;
401
402     if (infoPtr->hFont) SelectObject( hdc, infoPtr->hFont );
403
404     if ((style & SS_NOPREFIX) || ((style & SS_TYPEMASK) != SS_SIMPLE))
405     {
406         hBrush = SendMessageA( GetParent(wndPtr->hwndSelf), WM_CTLCOLORSTATIC,
407                              hdc, wndPtr->hwndSelf );
408         if (!hBrush) hBrush = GetStockObject(WHITE_BRUSH);
409         FillRect( hdc, &rc, hBrush );    
410     }
411     if (!IsWindowEnabled(wndPtr->hwndSelf))
412         SetTextColor(hdc, GetSysColor(COLOR_GRAYTEXT));
413
414     if (wndPtr->text) DrawTextW( hdc, wndPtr->text, -1, &rc, wFormat );
415 }
416
417 static void STATIC_PaintRectfn( WND *wndPtr, HDC hdc )
418 {
419     RECT rc;
420     HBRUSH hBrush;
421
422     GetClientRect( wndPtr->hwndSelf, &rc);
423     
424     switch (wndPtr->dwStyle & SS_TYPEMASK)
425     {
426     case SS_BLACKRECT:
427         hBrush = CreateSolidBrush(color_windowframe);
428         FillRect( hdc, &rc, hBrush );
429         break;
430     case SS_GRAYRECT:
431         hBrush = CreateSolidBrush(color_background);
432         FillRect( hdc, &rc, hBrush );
433         break;
434     case SS_WHITERECT:
435         hBrush = CreateSolidBrush(color_window);
436         FillRect( hdc, &rc, hBrush );
437         break;
438     case SS_BLACKFRAME:
439         hBrush = CreateSolidBrush(color_windowframe);
440         FrameRect( hdc, &rc, hBrush );
441         break;
442     case SS_GRAYFRAME:
443         hBrush = CreateSolidBrush(color_background);
444         FrameRect( hdc, &rc, hBrush );
445         break;
446     case SS_WHITEFRAME:
447         hBrush = CreateSolidBrush(color_window);
448         FrameRect( hdc, &rc, hBrush );
449         break;
450     default:
451         return;
452     }
453     DeleteObject( hBrush );
454 }
455
456
457 static void STATIC_PaintIconfn( WND *wndPtr, HDC hdc )
458 {
459     RECT rc;
460     HBRUSH hbrush;
461     STATICINFO *infoPtr = (STATICINFO *)wndPtr->wExtra;
462
463     GetClientRect( wndPtr->hwndSelf, &rc );
464     hbrush = SendMessageA( GetParent(wndPtr->hwndSelf), WM_CTLCOLORSTATIC,
465                              hdc, wndPtr->hwndSelf );
466     FillRect( hdc, &rc, hbrush );
467     if (infoPtr->hIcon) DrawIcon( hdc, rc.left, rc.top, infoPtr->hIcon );
468 }
469
470 static void STATIC_PaintBitmapfn(WND *wndPtr, HDC hdc )
471 {
472     RECT rc;
473     HBRUSH hbrush;
474     STATICINFO *infoPtr = (STATICINFO *)wndPtr->wExtra;
475     HDC hMemDC;
476     HBITMAP oldbitmap;
477
478     GetClientRect( wndPtr->hwndSelf, &rc );
479     hbrush = SendMessageA( GetParent(wndPtr->hwndSelf), WM_CTLCOLORSTATIC,
480                              hdc, wndPtr->hwndSelf );
481     FillRect( hdc, &rc, hbrush );
482
483     if (infoPtr->hIcon) {
484         BITMAP bm;
485         SIZE sz;
486
487         if(GetObjectType(infoPtr->hIcon) != OBJ_BITMAP)
488             return;
489         if (!(hMemDC = CreateCompatibleDC( hdc ))) return;
490         GetObjectA(infoPtr->hIcon, sizeof(bm), &bm);
491         GetBitmapDimensionEx(infoPtr->hIcon, &sz);
492         oldbitmap = SelectObject(hMemDC, infoPtr->hIcon);
493         BitBlt(hdc, sz.cx, sz.cy, bm.bmWidth, bm.bmHeight, hMemDC, 0, 0,
494                SRCCOPY);
495         SelectObject(hMemDC, oldbitmap);
496         DeleteDC(hMemDC);
497     }
498 }
499
500
501 static void STATIC_PaintEtchedfn( WND *wndPtr, HDC hdc )
502 {
503     RECT rc;
504
505     if (TWEAK_WineLook == WIN31_LOOK)
506         return;
507
508     GetClientRect( wndPtr->hwndSelf, &rc );
509     switch (wndPtr->dwStyle & SS_TYPEMASK)
510     {
511         case SS_ETCHEDHORZ:
512             DrawEdge(hdc,&rc,EDGE_ETCHED,BF_TOP|BF_BOTTOM);
513             break;
514         case SS_ETCHEDVERT:
515             DrawEdge(hdc,&rc,EDGE_ETCHED,BF_LEFT|BF_RIGHT);
516             break;
517         case SS_ETCHEDFRAME:
518             DrawEdge (hdc, &rc, EDGE_ETCHED, BF_RECT);
519             break;
520     }
521 }
522