xref: /reactos/win32ss/user/user32/controls/static.c (revision 019f21ee)
1 /*
2  * Static control
3  *
4  * Copyright  David W. Metcalfe, 1993
5  *
6  * This library is free software; you can redistribute it and/or
7  * modify it under the terms of the GNU Lesser General Public
8  * License as published by the Free Software Foundation; either
9  * version 2.1 of the License, or (at your option) any later version.
10  *
11  * This library is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14  * Lesser General Public License for more details.
15  *
16  * You should have received a copy of the GNU Lesser General Public
17  * License along with this library; if not, write to the Free Software
18  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
19  *
20  * Notes:
21  *   - Controls with SS_SIMPLE but without SS_NOPREFIX:
22  *     The text should not be changed. Windows doesn't clear the
23  *     client rectangle, so the new text must be larger than the old one.
24  *   - The SS_RIGHTJUST style is currently not implemented by Windows
25  *     (or it does something different than documented).
26  *
27  * TODO:
28  *   - Animated cursors
29  */
30 
31 #include <user32.h>
32 
33 WINE_DEFAULT_DEBUG_CHANNEL(static);
34 
35 static void STATIC_PaintOwnerDrawfn( HWND hwnd, HDC hdc, DWORD style );
36 static void STATIC_PaintTextfn( HWND hwnd, HDC hdc, DWORD style );
37 static void STATIC_PaintRectfn( HWND hwnd, HDC hdc, DWORD style );
38 static void STATIC_PaintIconfn( HWND hwnd, HDC hdc, DWORD style );
39 static void STATIC_PaintBitmapfn( HWND hwnd, HDC hdc, DWORD style );
40 static void STATIC_PaintEnhMetafn( HWND hwnd, HDC hdc, DWORD style );
41 static void STATIC_PaintEtchedfn( HWND hwnd, HDC hdc, DWORD style );
42 
43 static COLORREF color_3dshadow, color_3ddkshadow, color_3dhighlight;
44 
45 /* offsets for GetWindowLong for static private information */
46 #define HFONT_GWL_OFFSET    0
47 #define HICON_GWL_OFFSET    (sizeof(HFONT))
48 #define UISTATE_GWL_OFFSET (HICON_GWL_OFFSET+sizeof(HICON)) // ReactOS: keep in sync with STATIC_UISTATE_GWL_OFFSET
49 #define STATIC_EXTRA_BYTES  (UISTATE_GWL_OFFSET + sizeof(LONG))
50 
51 typedef void (*pfPaint)( HWND hwnd, HDC hdc, DWORD style );
52 
53 static const pfPaint staticPaintFunc[SS_TYPEMASK+1] =
54 {
55     STATIC_PaintTextfn,      /* SS_LEFT */
56     STATIC_PaintTextfn,      /* SS_CENTER */
57     STATIC_PaintTextfn,      /* SS_RIGHT */
58     STATIC_PaintIconfn,      /* SS_ICON */
59     STATIC_PaintRectfn,      /* SS_BLACKRECT */
60     STATIC_PaintRectfn,      /* SS_GRAYRECT */
61     STATIC_PaintRectfn,      /* SS_WHITERECT */
62     STATIC_PaintRectfn,      /* SS_BLACKFRAME */
63     STATIC_PaintRectfn,      /* SS_GRAYFRAME */
64     STATIC_PaintRectfn,      /* SS_WHITEFRAME */
65     NULL,                    /* SS_USERITEM */
66     STATIC_PaintTextfn,      /* SS_SIMPLE */
67     STATIC_PaintTextfn,      /* SS_LEFTNOWORDWRAP */
68     STATIC_PaintOwnerDrawfn, /* SS_OWNERDRAW */
69     STATIC_PaintBitmapfn,    /* SS_BITMAP */
70     STATIC_PaintEnhMetafn,   /* SS_ENHMETAFILE */
71     STATIC_PaintEtchedfn,    /* SS_ETCHEDHORZ */
72     STATIC_PaintEtchedfn,    /* SS_ETCHEDVERT */
73     STATIC_PaintEtchedfn,    /* SS_ETCHEDFRAME */
74 };
75 
76 
77 /*********************************************************************
78  * static class descriptor
79  */
80 static const WCHAR staticW[] = {'S','t','a','t','i','c',0};
81 const struct builtin_class_descr STATIC_builtin_class =
82 {
83     staticW,             /* name */
84     CS_DBLCLKS | CS_PARENTDC, /* style  */
85     StaticWndProcA,      /* procA */
86     StaticWndProcW,      /* procW */
87     STATIC_EXTRA_BYTES,  /* extra */
88     IDC_ARROW,           /* cursor */
89     0                    /* brush */
90 };
91 
92 /***********************************************************************
93  *           STATIC_SetIcon
94  *
95  * Set the icon for an SS_ICON control.
96  */
97 static HICON STATIC_SetIcon( HWND hwnd, HICON hicon, DWORD style )
98 {
99     HICON prevIcon;
100     SIZE size;
101 
102     if ((style & SS_TYPEMASK) != SS_ICON) return 0;
103     if (hicon && !get_icon_size( hicon, &size ))
104     {
105         WARN("hicon != 0, but invalid\n");
106         return 0;
107     }
108     prevIcon = (HICON)SetWindowLongPtrW( hwnd, HICON_GWL_OFFSET, (LONG_PTR)hicon );
109     if (hicon && !(style & SS_CENTERIMAGE) && !(style & SS_REALSIZECONTROL))
110     {
111         /* Windows currently doesn't implement SS_RIGHTJUST */
112         /*
113         if ((style & SS_RIGHTJUST) != 0)
114         {
115             RECT wr;
116             GetWindowRect(hwnd, &wr);
117             SetWindowPos( hwnd, 0, wr.right - info->nWidth, wr.bottom - info->nHeight,
118                           info->nWidth, info->nHeight, SWP_NOACTIVATE | SWP_NOZORDER );
119         }
120         else */
121         {
122             SetWindowPos( hwnd, 0, 0, 0, size.cx, size.cy, SWP_NOACTIVATE | SWP_NOMOVE | SWP_NOZORDER );
123         }
124     }
125     return prevIcon;
126 }
127 
128 /***********************************************************************
129  *           STATIC_SetBitmap
130  *
131  * Set the bitmap for an SS_BITMAP control.
132  */
133 static HBITMAP STATIC_SetBitmap( HWND hwnd, HBITMAP hBitmap, DWORD style )
134 {
135     HBITMAP hOldBitmap;
136 
137     if ((style & SS_TYPEMASK) != SS_BITMAP) return 0;
138     if (hBitmap && GetObjectType(hBitmap) != OBJ_BITMAP) {
139         WARN("hBitmap != 0, but it's not a bitmap\n");
140         return 0;
141     }
142     hOldBitmap = (HBITMAP)SetWindowLongPtrW( hwnd, HICON_GWL_OFFSET, (LONG_PTR)hBitmap );
143     if (hBitmap && !(style & SS_CENTERIMAGE) && !(style & SS_REALSIZECONTROL))
144     {
145         BITMAP bm;
146         GetObjectW(hBitmap, sizeof(bm), &bm);
147         /* Windows currently doesn't implement SS_RIGHTJUST */
148         /*
149         if ((style & SS_RIGHTJUST) != 0)
150         {
151             RECT wr;
152             GetWindowRect(hwnd, &wr);
153             SetWindowPos( hwnd, 0, wr.right - bm.bmWidth, wr.bottom - bm.bmHeight,
154                           bm.bmWidth, bm.bmHeight, SWP_NOACTIVATE | SWP_NOZORDER );
155         }
156         else */
157         {
158             SetWindowPos( hwnd, 0, 0, 0, bm.bmWidth, bm.bmHeight,
159                           SWP_NOACTIVATE | SWP_NOMOVE | SWP_NOZORDER );
160         }
161 
162     }
163     return hOldBitmap;
164 }
165 
166 /***********************************************************************
167  *           STATIC_SetEnhMetaFile
168  *
169  * Set the enhanced metafile for an SS_ENHMETAFILE control.
170  */
171 static HENHMETAFILE STATIC_SetEnhMetaFile( HWND hwnd, HENHMETAFILE hEnhMetaFile, DWORD style )
172 {
173     if ((style & SS_TYPEMASK) != SS_ENHMETAFILE) return 0;
174     if (hEnhMetaFile && GetObjectType(hEnhMetaFile) != OBJ_ENHMETAFILE) {
175         WARN("hEnhMetaFile != 0, but it's not an enhanced metafile\n");
176         return 0;
177     }
178     return (HENHMETAFILE)SetWindowLongPtrW( hwnd, HICON_GWL_OFFSET, (LONG_PTR)hEnhMetaFile );
179 }
180 
181 /***********************************************************************
182  *           STATIC_GetImage
183  *
184  * Gets the bitmap for an SS_BITMAP control, the icon/cursor for an
185  * SS_ICON control or the enhanced metafile for an SS_ENHMETAFILE control.
186  */
187 static HANDLE STATIC_GetImage( HWND hwnd, WPARAM wParam, DWORD style )
188 {
189     switch(style & SS_TYPEMASK)
190     {
191         case SS_ICON:
192             if ((wParam != IMAGE_ICON) &&
193                 (wParam != IMAGE_CURSOR)) return NULL;
194             break;
195         case SS_BITMAP:
196             if (wParam != IMAGE_BITMAP) return NULL;
197             break;
198         case SS_ENHMETAFILE:
199             if (wParam != IMAGE_ENHMETAFILE) return NULL;
200             break;
201         default:
202             return NULL;
203     }
204     return (HANDLE)GetWindowLongPtrW( hwnd, HICON_GWL_OFFSET );
205 }
206 
207 /***********************************************************************
208  *           STATIC_LoadIconA
209  *
210  * Load the icon for an SS_ICON control.
211  */
212 static HICON STATIC_LoadIconA( HINSTANCE hInstance, LPCSTR name, DWORD style )
213 {
214     HICON hicon = 0;
215 
216     if (hInstance && ((ULONG_PTR)hInstance >> 16))
217     {
218         if ((style & SS_REALSIZEIMAGE) != 0)
219             hicon = LoadImageA(hInstance, name, IMAGE_ICON, 0, 0, LR_SHARED);
220         else
221         {
222             hicon = LoadIconA( hInstance, name );
223             if (!hicon) hicon = LoadCursorA( hInstance, name );
224         }
225     }
226     if (!hicon) hicon = LoadIconA( 0, name );
227     /* Windows doesn't try to load a standard cursor,
228        probably because most IDs for standard cursors conflict
229        with the IDs for standard icons anyway */
230     return hicon;
231 }
232 
233 /***********************************************************************
234  *           STATIC_LoadIconW
235  *
236  * Load the icon for an SS_ICON control.
237  */
238 static HICON STATIC_LoadIconW( HINSTANCE hInstance, LPCWSTR name, DWORD style )
239 {
240     HICON hicon = 0;
241 
242     if (hInstance && ((ULONG_PTR)hInstance >> 16))
243     {
244         if ((style & SS_REALSIZEIMAGE) != 0)
245             hicon = LoadImageW(hInstance, name, IMAGE_ICON, 0, 0, LR_SHARED);
246         else
247         {
248             hicon = LoadIconW( hInstance, name );
249             if (!hicon) hicon = LoadCursorW( hInstance, name );
250         }
251     }
252     if (!hicon) hicon = LoadIconW( 0, name );
253     /* Windows doesn't try to load a standard cursor,
254        probably because most IDs for standard cursors conflict
255        with the IDs for standard icons anyway */
256     return hicon;
257 }
258 
259 /***********************************************************************
260  *           STATIC_TryPaintFcn
261  *
262  * Try to immediately paint the control.
263  */
264 static VOID STATIC_TryPaintFcn(HWND hwnd, LONG full_style)
265 {
266     LONG style = full_style & SS_TYPEMASK;
267     RECT rc;
268 
269     GetClientRect( hwnd, &rc );
270     if (!IsRectEmpty(&rc) && IsWindowVisible(hwnd) && staticPaintFunc[style])
271     {
272 	HDC hdc;
273         HRGN hrgn;
274 
275 	hdc = GetDC( hwnd );
276         hrgn = set_control_clipping( hdc, &rc );
277 	(staticPaintFunc[style])( hwnd, hdc, full_style );
278         SelectClipRgn( hdc, hrgn );
279         if (hrgn) DeleteObject( hrgn );
280 	ReleaseDC( hwnd, hdc );
281     }
282 }
283 
284 static HBRUSH STATIC_SendWmCtlColorStatic(HWND hwnd, HDC hdc)
285 {
286 #ifdef __REACTOS__
287     return GetControlBrush( hwnd, hdc, WM_CTLCOLORSTATIC);
288 #else
289     HBRUSH hBrush;
290     HWND parent = GetParent(hwnd);
291 
292     if (!parent) parent = hwnd;
293     hBrush = (HBRUSH) SendMessageW( parent,
294                     WM_CTLCOLORSTATIC, (WPARAM)hdc, (LPARAM)hwnd );
295     if (!hBrush) /* did the app forget to call DefWindowProc ? */
296     {
297         /* FIXME: DefWindowProc should return different colors if a
298                   manifest is present */
299         hBrush = (HBRUSH)DefWindowProcW( parent, WM_CTLCOLORSTATIC,
300                                         (WPARAM)hdc, (LPARAM)hwnd);
301     }
302     return hBrush;
303 #endif
304 }
305 
306 static VOID STATIC_InitColours(void)
307 {
308     color_3ddkshadow  = GetSysColor(COLOR_3DDKSHADOW);
309     color_3dshadow    = GetSysColor(COLOR_3DSHADOW);
310     color_3dhighlight = GetSysColor(COLOR_3DHIGHLIGHT);
311 }
312 
313 /***********************************************************************
314  *           hasTextStyle
315  *
316  * Tests if the control displays text.
317  */
318 static BOOL hasTextStyle( DWORD style )
319 {
320     switch(style & SS_TYPEMASK)
321     {
322         case SS_SIMPLE:
323         case SS_LEFT:
324         case SS_LEFTNOWORDWRAP:
325         case SS_CENTER:
326         case SS_RIGHT:
327         case SS_OWNERDRAW:
328             return TRUE;
329     }
330 
331     return FALSE;
332 }
333 
334 /***********************************************************************
335  *           StaticWndProc_common
336  */
337 LRESULT WINAPI StaticWndProc_common( HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL unicode ) // ReactOS
338 {
339     LRESULT lResult = 0;
340     LONG full_style = GetWindowLongW( hwnd, GWL_STYLE );
341     LONG style = full_style & SS_TYPEMASK;
342 #ifdef __REACTOS__
343     PWND pWnd;
344 
345     pWnd = ValidateHwnd(hwnd);
346     if (pWnd)
347     {
348        if (!pWnd->fnid)
349        {
350           NtUserSetWindowFNID(hwnd, FNID_STATIC);
351        }
352        else
353        {
354           if (pWnd->fnid != FNID_STATIC)
355           {
356              ERR("Wrong window class for Static! fnId 0x%x\n",pWnd->fnid);
357              return 0;
358           }
359        }
360     }
361 #endif
362 
363     if (!IsWindow( hwnd )) return 0;
364 
365     switch (uMsg)
366     {
367     case WM_CREATE:
368         if (style < 0L || style > SS_TYPEMASK)
369         {
370             ERR("Unknown style 0x%02lx\n", style );
371             return -1;
372         }
373         STATIC_update_uistate(hwnd, unicode); // ReactOS r30727
374         STATIC_InitColours();
375         break;
376 
377     case WM_NCDESTROY:
378 #ifdef __REACTOS__
379         NtUserSetWindowFNID(hwnd, FNID_DESTROY);
380 #endif
381         if (style == SS_ICON) {
382 /*
383  * FIXME
384  *           DestroyIcon32( STATIC_SetIcon( wndPtr, 0 ) );
385  *
386  * We don't want to do this yet because DestroyIcon32 is broken. If the icon
387  * had already been loaded by the application the last thing we want to do is
388  * GlobalFree16 the handle.
389  */
390             break;
391         }
392         else return unicode ? DefWindowProcW(hwnd, uMsg, wParam, lParam) :
393                               DefWindowProcA(hwnd, uMsg, wParam, lParam);
394 
395     case WM_ERASEBKGND:
396         /* do all painting in WM_PAINT like Windows does */
397         return 1;
398 
399     case WM_PRINTCLIENT:
400     case WM_PAINT:
401         {
402             PAINTSTRUCT ps;
403             RECT rect;
404             HDC hdc = wParam ? (HDC)wParam : BeginPaint(hwnd, &ps);
405             GetClientRect( hwnd, &rect );
406             if (staticPaintFunc[style])
407             {
408                 HRGN hrgn = set_control_clipping( hdc, &rect );
409                 (staticPaintFunc[style])( hwnd, hdc, full_style );
410                 SelectClipRgn( hdc, hrgn );
411                 if (hrgn) DeleteObject( hrgn );
412             }
413             if (!wParam) EndPaint(hwnd, &ps);
414         }
415         break;
416 
417     case WM_ENABLE:
418         STATIC_TryPaintFcn( hwnd, full_style );
419         if (full_style & SS_NOTIFY) {
420             if (wParam) {
421                 SendMessageW( GetParent(hwnd), WM_COMMAND,
422                               MAKEWPARAM( GetWindowLongPtrW(hwnd,GWLP_ID), STN_ENABLE ), (LPARAM)hwnd);
423             }
424             else {
425                 SendMessageW( GetParent(hwnd), WM_COMMAND,
426                               MAKEWPARAM( GetWindowLongPtrW(hwnd,GWLP_ID), STN_DISABLE ), (LPARAM)hwnd);
427             }
428         }
429         break;
430 
431     case WM_SYSCOLORCHANGE:
432         STATIC_InitColours();
433         STATIC_TryPaintFcn( hwnd, full_style );
434         break;
435 
436     case WM_NCCREATE:
437         {
438             CREATESTRUCTW *cs = (CREATESTRUCTW *)lParam;
439 
440             if (full_style & SS_SUNKEN)
441                 SetWindowLongW( hwnd, GWL_EXSTYLE,
442                                 GetWindowLongW( hwnd, GWL_EXSTYLE ) | WS_EX_STATICEDGE );
443 
444             switch (style) {
445             case SS_ICON:
446                 {
447                     HICON hIcon;
448                     if (unicode || IS_INTRESOURCE(cs->lpszName))
449                        hIcon = STATIC_LoadIconW(cs->hInstance, cs->lpszName, full_style);
450                     else
451                        hIcon = STATIC_LoadIconA(cs->hInstance, (LPCSTR)cs->lpszName, full_style);
452                     STATIC_SetIcon(hwnd, hIcon, full_style);
453                 }
454                 break;
455             case SS_BITMAP:
456                 if ((ULONG_PTR)cs->hInstance >> 16)
457                 {
458                     HBITMAP hBitmap;
459                     if (unicode || IS_INTRESOURCE(cs->lpszName))
460                         hBitmap = LoadBitmapW(cs->hInstance, cs->lpszName);
461                     else
462                         hBitmap = LoadBitmapA(cs->hInstance, (LPCSTR)cs->lpszName);
463                     STATIC_SetBitmap(hwnd, hBitmap, full_style);
464                 }
465                 break;
466             }
467             /* SS_ENHMETAFILE: Despite what MSDN says, Windows does not load
468                the enhanced metafile that was specified as the window text. */
469         }
470         return unicode ? DefWindowProcW(hwnd, uMsg, wParam, lParam) :
471                          DefWindowProcA(hwnd, uMsg, wParam, lParam);
472 
473     case WM_SETTEXT:
474         if (hasTextStyle( full_style ))
475         {
476             if (unicode)
477                 lResult = DefWindowProcW( hwnd, uMsg, wParam, lParam );
478             else
479                 lResult = DefWindowProcA( hwnd, uMsg, wParam, lParam );
480             STATIC_TryPaintFcn( hwnd, full_style );
481         }
482         break;
483 
484     case WM_SETFONT:
485         if (hasTextStyle( full_style ))
486         {
487             SetWindowLongPtrW( hwnd, HFONT_GWL_OFFSET, wParam );
488             if (LOWORD(lParam))
489                 RedrawWindow( hwnd, NULL, 0, RDW_INVALIDATE | RDW_ERASE | RDW_UPDATENOW | RDW_ALLCHILDREN );
490         }
491         break;
492 
493     case WM_GETFONT:
494         return GetWindowLongPtrW( hwnd, HFONT_GWL_OFFSET );
495 
496     case WM_NCHITTEST:
497         if (full_style & SS_NOTIFY)
498            return HTCLIENT;
499         else
500            return HTTRANSPARENT;
501 
502     case WM_GETDLGCODE:
503         return DLGC_STATIC;
504 
505     case WM_LBUTTONDOWN:
506     case WM_NCLBUTTONDOWN:
507         if (full_style & SS_NOTIFY)
508             SendMessageW( GetParent(hwnd), WM_COMMAND,
509                           MAKEWPARAM( GetWindowLongPtrW(hwnd,GWLP_ID), STN_CLICKED ), (LPARAM)hwnd);
510         return 0;
511 
512     case WM_LBUTTONDBLCLK:
513     case WM_NCLBUTTONDBLCLK:
514         if (full_style & SS_NOTIFY)
515             SendMessageW( GetParent(hwnd), WM_COMMAND,
516                           MAKEWPARAM( GetWindowLongPtrW(hwnd,GWLP_ID), STN_DBLCLK ), (LPARAM)hwnd);
517         return 0;
518 
519     case STM_GETIMAGE:
520         return (LRESULT)STATIC_GetImage( hwnd, wParam, full_style );
521 
522     case STM_GETICON:
523         return (LRESULT)STATIC_GetImage( hwnd, IMAGE_ICON, full_style );
524 
525     case STM_SETIMAGE:
526         switch(wParam) {
527 	case IMAGE_BITMAP:
528 	    if (style != SS_BITMAP) return 0; // ReactOS r43158
529 	    lResult = (LRESULT)STATIC_SetBitmap( hwnd, (HBITMAP)lParam, full_style );
530 	    break;
531 	case IMAGE_ENHMETAFILE:
532 	    if (style != SS_ENHMETAFILE) return 0; // ReactOS r43158
533 	    lResult = (LRESULT)STATIC_SetEnhMetaFile( hwnd, (HENHMETAFILE)lParam, full_style );
534 	    break;
535 	case IMAGE_ICON:
536 	case IMAGE_CURSOR:
537 	    if (style != SS_ICON) return 0; // ReactOS r43158
538 	    lResult = (LRESULT)STATIC_SetIcon( hwnd, (HICON)lParam, full_style );
539 	    break;
540 	default:
541 	    FIXME("STM_SETIMAGE: Unhandled type %lx\n", wParam);
542 	    break;
543 	}
544         STATIC_TryPaintFcn( hwnd, full_style );
545 	break;
546 
547     case STM_SETICON:
548         lResult = (LRESULT)STATIC_SetIcon( hwnd, (HICON)wParam, full_style );
549         STATIC_TryPaintFcn( hwnd, full_style );
550         break;
551 
552 #ifdef __REACTOS__
553     case WM_UPDATEUISTATE:
554         if (unicode)
555             DefWindowProcW(hwnd, uMsg, wParam, lParam);
556         else
557             DefWindowProcA(hwnd, uMsg, wParam, lParam);
558 
559         if (STATIC_update_uistate(hwnd, unicode) && hasTextStyle( full_style ))
560         {
561             RedrawWindow( hwnd, NULL, 0, RDW_INVALIDATE | RDW_ERASE | RDW_UPDATENOW | RDW_ALLCHILDREN );
562         }
563         break;
564 #endif
565 
566     default:
567         return unicode ? DefWindowProcW(hwnd, uMsg, wParam, lParam) :
568                          DefWindowProcA(hwnd, uMsg, wParam, lParam);
569     }
570     return lResult;
571 }
572 
573 /***********************************************************************
574  *           StaticWndProcA
575  */
576 LRESULT WINAPI StaticWndProcA( HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam )
577 {
578     if (!IsWindow( hWnd )) return 0;
579     return StaticWndProc_common(hWnd, uMsg, wParam, lParam, FALSE);
580 }
581 
582 /***********************************************************************
583  *           StaticWndProcW
584  */
585 LRESULT WINAPI StaticWndProcW( HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam )
586 {
587     if (!IsWindow( hWnd )) return 0;
588     return StaticWndProc_common(hWnd, uMsg, wParam, lParam, TRUE);
589 }
590 
591 static void STATIC_PaintOwnerDrawfn( HWND hwnd, HDC hdc, DWORD style )
592 {
593   DRAWITEMSTRUCT dis;
594   HFONT font, oldFont = NULL;
595   UINT id = (UINT)GetWindowLongPtrW( hwnd, GWLP_ID );
596 
597   dis.CtlType    = ODT_STATIC;
598   dis.CtlID      = id;
599   dis.itemID     = 0;
600   dis.itemAction = ODA_DRAWENTIRE;
601   dis.itemState  = IsWindowEnabled(hwnd) ? 0 : ODS_DISABLED;
602   dis.hwndItem   = hwnd;
603   dis.hDC        = hdc;
604   dis.itemData   = 0;
605   GetClientRect( hwnd, &dis.rcItem );
606 
607   font = (HFONT)GetWindowLongPtrW( hwnd, HFONT_GWL_OFFSET );
608   if (font) oldFont = SelectObject( hdc, font );
609   /* hBrush = */ STATIC_SendWmCtlColorStatic(hwnd, hdc);
610   SendMessageW( GetParent(hwnd), WM_DRAWITEM, id, (LPARAM)&dis );
611   if (font) SelectObject( hdc, oldFont );
612 }
613 
614 static void STATIC_PaintTextfn( HWND hwnd, HDC hdc, DWORD style )
615 {
616     RECT rc;
617     HBRUSH hBrush;
618     HFONT hFont, hOldFont = NULL;
619     WORD wFormat;
620     INT len, buf_size;
621     WCHAR *text;
622 
623     GetClientRect( hwnd, &rc);
624 
625     switch (style & SS_TYPEMASK)
626     {
627     case SS_LEFT:
628 	wFormat = DT_LEFT | DT_EXPANDTABS | DT_WORDBREAK;
629 	break;
630 
631     case SS_CENTER:
632 	wFormat = DT_CENTER | DT_EXPANDTABS | DT_WORDBREAK;
633 	break;
634 
635     case SS_RIGHT:
636 	wFormat = DT_RIGHT | DT_EXPANDTABS | DT_WORDBREAK;
637 	break;
638 
639     case SS_SIMPLE:
640         wFormat = DT_LEFT | DT_SINGLELINE;
641 	break;
642 
643     case SS_LEFTNOWORDWRAP:
644         wFormat = DT_LEFT | DT_EXPANDTABS;
645 	break;
646 
647     default:
648         return;
649     }
650 
651     if (GetWindowLongW( hwnd, GWL_EXSTYLE ) & WS_EX_RIGHT)
652         wFormat = DT_RIGHT | (wFormat & ~(DT_LEFT | DT_CENTER));
653 
654     if (style & SS_NOPREFIX)
655         wFormat |= DT_NOPREFIX;
656     else if (GetWindowLongW(hwnd, UISTATE_GWL_OFFSET) & UISF_HIDEACCEL) // ReactOS r30727
657         wFormat |= DT_HIDEPREFIX;
658 
659     if ((style & SS_TYPEMASK) != SS_SIMPLE)
660     {
661         if (style & SS_CENTERIMAGE)
662             wFormat |= DT_SINGLELINE | DT_VCENTER;
663         if (style & SS_EDITCONTROL)
664             wFormat |= DT_EDITCONTROL;
665         if (style & SS_ENDELLIPSIS)
666             wFormat |= DT_SINGLELINE | DT_END_ELLIPSIS;
667         if (style & SS_PATHELLIPSIS)
668             wFormat |= DT_SINGLELINE | DT_PATH_ELLIPSIS;
669         if (style & SS_WORDELLIPSIS)
670             wFormat |= DT_SINGLELINE | DT_WORD_ELLIPSIS;
671     }
672 
673     if ((hFont = (HFONT)GetWindowLongPtrW( hwnd, HFONT_GWL_OFFSET )))
674         hOldFont = SelectObject( hdc, hFont );
675 
676     /* SS_SIMPLE controls: WM_CTLCOLORSTATIC is sent, but the returned
677                            brush is not used */
678     hBrush = STATIC_SendWmCtlColorStatic(hwnd, hdc);
679 
680     if ((style & SS_TYPEMASK) != SS_SIMPLE)
681     {
682         FillRect( hdc, &rc, hBrush );
683         if (!IsWindowEnabled(hwnd)) SetTextColor(hdc, GetSysColor(COLOR_GRAYTEXT));
684     }
685 
686     buf_size = 256;
687     if (!(text = HeapAlloc( GetProcessHeap(), 0, buf_size * sizeof(WCHAR) )))
688         goto no_TextOut;
689 
690     while ((len = InternalGetWindowText( hwnd, text, buf_size )) == buf_size - 1)
691     {
692         buf_size *= 2;
693         if (!(text = HeapReAlloc( GetProcessHeap(), 0, text, buf_size * sizeof(WCHAR) )))
694             goto no_TextOut;
695     }
696 
697     if (!len) goto no_TextOut;
698 
699     if (((style & SS_TYPEMASK) == SS_SIMPLE) && (style & SS_NOPREFIX))
700     {
701         /* Windows uses the faster ExtTextOut() to draw the text and
702            to paint the whole client rectangle with the text background
703            color. Reference: "Static Controls" by Kyle Marsh, 1992 */
704         ExtTextOutW( hdc, rc.left, rc.top, ETO_CLIPPED | ETO_OPAQUE,
705                      &rc, text, len, NULL );
706     }
707     else
708     {
709         DrawTextW( hdc, text, -1, &rc, wFormat );
710     }
711 
712 no_TextOut:
713     HeapFree( GetProcessHeap(), 0, text );
714 
715     if (hFont)
716         SelectObject( hdc, hOldFont );
717 }
718 
719 static void STATIC_PaintRectfn( HWND hwnd, HDC hdc, DWORD style )
720 {
721     RECT rc;
722     HBRUSH hBrush;
723 
724     GetClientRect( hwnd, &rc);
725 
726     /* FIXME: send WM_CTLCOLORSTATIC */
727 #ifdef __REACTOS__
728     hBrush = STATIC_SendWmCtlColorStatic(hwnd, hdc); // Always sent....
729 #endif
730     switch (style & SS_TYPEMASK)
731     {
732     case SS_BLACKRECT:
733 	hBrush = CreateSolidBrush(color_3ddkshadow);
734         FillRect( hdc, &rc, hBrush );
735 	break;
736     case SS_GRAYRECT:
737 	hBrush = CreateSolidBrush(color_3dshadow);
738         FillRect( hdc, &rc, hBrush );
739 	break;
740     case SS_WHITERECT:
741 	hBrush = CreateSolidBrush(color_3dhighlight);
742         FillRect( hdc, &rc, hBrush );
743 	break;
744     case SS_BLACKFRAME:
745 	hBrush = CreateSolidBrush(color_3ddkshadow);
746         FrameRect( hdc, &rc, hBrush );
747 	break;
748     case SS_GRAYFRAME:
749 	hBrush = CreateSolidBrush(color_3dshadow);
750         FrameRect( hdc, &rc, hBrush );
751 	break;
752     case SS_WHITEFRAME:
753 	hBrush = CreateSolidBrush(color_3dhighlight);
754         FrameRect( hdc, &rc, hBrush );
755 	break;
756     default:
757         return;
758     }
759     DeleteObject( hBrush );
760 }
761 
762 
763 static void STATIC_PaintIconfn( HWND hwnd, HDC hdc, DWORD style )
764 {
765     RECT rc, iconRect;
766     HBRUSH hbrush;
767     HICON hIcon;
768     SIZE size;
769 
770     GetClientRect( hwnd, &rc );
771     hbrush = STATIC_SendWmCtlColorStatic(hwnd, hdc);
772     hIcon = (HICON)GetWindowLongPtrW( hwnd, HICON_GWL_OFFSET );
773     if (!hIcon || !get_icon_size( hIcon, &size ))
774     {
775         FillRect(hdc, &rc, hbrush);
776     }
777     else
778     {
779         if (style & SS_CENTERIMAGE)
780         {
781             iconRect.left = (rc.right - rc.left) / 2 - size.cx / 2;
782             iconRect.top = (rc.bottom - rc.top) / 2 - size.cy / 2;
783             iconRect.right = iconRect.left + size.cx;
784             iconRect.bottom = iconRect.top + size.cy;
785         }
786         else
787             iconRect = rc;
788         FillRect( hdc, &rc, hbrush );
789         DrawIconEx( hdc, iconRect.left, iconRect.top, hIcon, iconRect.right - iconRect.left,
790                     iconRect.bottom - iconRect.top, 0, NULL, DI_NORMAL );
791     }
792 }
793 
794 static void STATIC_PaintBitmapfn(HWND hwnd, HDC hdc, DWORD style )
795 {
796     HDC hMemDC;
797     HBITMAP hBitmap, oldbitmap;
798 
799     /* message is still sent, even if the returned brush is not used */
800     STATIC_SendWmCtlColorStatic(hwnd, hdc);
801 
802     if ((hBitmap = (HBITMAP)GetWindowLongPtrW( hwnd, HICON_GWL_OFFSET ))
803          && (GetObjectType(hBitmap) == OBJ_BITMAP)
804          && (hMemDC = CreateCompatibleDC( hdc )))
805     {
806         BITMAP bm;
807         RECT rcClient;
808 
809         GetObjectW(hBitmap, sizeof(bm), &bm);
810         oldbitmap = SelectObject(hMemDC, hBitmap);
811 
812         GetClientRect(hwnd, &rcClient);
813         if (style & SS_CENTERIMAGE)
814         {
815             HBRUSH hbrush = CreateSolidBrush(GetPixel(hMemDC, 0, 0));
816 
817             FillRect( hdc, &rcClient, hbrush );
818 
819             rcClient.left = (rcClient.right - rcClient.left)/2 - bm.bmWidth/2;
820             rcClient.top = (rcClient.bottom - rcClient.top)/2 - bm.bmHeight/2;
821             rcClient.right = rcClient.left + bm.bmWidth;
822             rcClient.bottom = rcClient.top + bm.bmHeight;
823 
824             DeleteObject(hbrush);
825         }
826         StretchBlt(hdc, rcClient.left, rcClient.top, rcClient.right - rcClient.left,
827                    rcClient.bottom - rcClient.top, hMemDC,
828                    0, 0, bm.bmWidth, bm.bmHeight, SRCCOPY);
829         SelectObject(hMemDC, oldbitmap);
830         DeleteDC(hMemDC);
831     }
832 }
833 
834 
835 static void STATIC_PaintEnhMetafn(HWND hwnd, HDC hdc, DWORD style )
836 {
837     HENHMETAFILE hEnhMetaFile;
838     RECT rc;
839     HBRUSH hbrush;
840 
841     GetClientRect(hwnd, &rc);
842     hbrush = STATIC_SendWmCtlColorStatic(hwnd, hdc);
843     FillRect(hdc, &rc, hbrush);
844     if ((hEnhMetaFile = (HENHMETAFILE)GetWindowLongPtrW( hwnd, HICON_GWL_OFFSET )))
845     {
846         /* The control's current font is not selected into the
847            device context! */
848         if (GetObjectType(hEnhMetaFile) == OBJ_ENHMETAFILE)
849             PlayEnhMetaFile(hdc, hEnhMetaFile, &rc);
850     }
851 }
852 
853 
854 static void STATIC_PaintEtchedfn( HWND hwnd, HDC hdc, DWORD style )
855 {
856     RECT rc;
857 
858     /* FIXME: sometimes (not always) sends WM_CTLCOLORSTATIC */
859     GetClientRect( hwnd, &rc );
860     switch (style & SS_TYPEMASK)
861     {
862 	case SS_ETCHEDHORZ:
863 	    DrawEdge(hdc,&rc,EDGE_ETCHED,BF_TOP|BF_BOTTOM);
864 	    break;
865 	case SS_ETCHEDVERT:
866 	    DrawEdge(hdc,&rc,EDGE_ETCHED,BF_LEFT|BF_RIGHT);
867 	    break;
868 	case SS_ETCHEDFRAME:
869 	    DrawEdge (hdc, &rc, EDGE_ETCHED, BF_RECT);
870 	    break;
871     }
872 }
873