dinput: Factor out IDirectInputDevice ansi vtable.
[wine.git] / dlls / comctl32 / static.c
blob2bd2b22bc2001cd2bc72f762fb09279941937013
1 /*
2 * Static control
4 * Copyright David W. Metcalfe, 1993
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.
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.
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
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).
27 * TODO:
28 * - Animated cursors
31 #include <stdarg.h>
33 #include "windef.h"
34 #include "winbase.h"
35 #include "wingdi.h"
36 #include "winuser.h"
37 #include "commctrl.h"
39 #include "wine/heap.h"
40 #include "wine/debug.h"
42 #include "comctl32.h"
44 WINE_DEFAULT_DEBUG_CHANNEL(static);
46 static void STATIC_PaintOwnerDrawfn( HWND hwnd, HDC hdc, DWORD style );
47 static void STATIC_PaintTextfn( HWND hwnd, HDC hdc, DWORD style );
48 static void STATIC_PaintRectfn( HWND hwnd, HDC hdc, DWORD style );
49 static void STATIC_PaintIconfn( HWND hwnd, HDC hdc, DWORD style );
50 static void STATIC_PaintBitmapfn( HWND hwnd, HDC hdc, DWORD style );
51 static void STATIC_PaintEnhMetafn( HWND hwnd, HDC hdc, DWORD style );
52 static void STATIC_PaintEtchedfn( HWND hwnd, HDC hdc, DWORD style );
54 struct static_extra_info
56 HFONT hfont;
57 union
59 HICON hicon;
60 HBITMAP hbitmap;
61 HENHMETAFILE hemf;
62 } image;
63 BOOL image_has_alpha;
66 typedef void (*pfPaint)( HWND hwnd, HDC hdc, DWORD style );
68 static const pfPaint staticPaintFunc[SS_TYPEMASK+1] =
70 STATIC_PaintTextfn, /* SS_LEFT */
71 STATIC_PaintTextfn, /* SS_CENTER */
72 STATIC_PaintTextfn, /* SS_RIGHT */
73 STATIC_PaintIconfn, /* SS_ICON */
74 STATIC_PaintRectfn, /* SS_BLACKRECT */
75 STATIC_PaintRectfn, /* SS_GRAYRECT */
76 STATIC_PaintRectfn, /* SS_WHITERECT */
77 STATIC_PaintRectfn, /* SS_BLACKFRAME */
78 STATIC_PaintRectfn, /* SS_GRAYFRAME */
79 STATIC_PaintRectfn, /* SS_WHITEFRAME */
80 NULL, /* SS_USERITEM */
81 STATIC_PaintTextfn, /* SS_SIMPLE */
82 STATIC_PaintTextfn, /* SS_LEFTNOWORDWRAP */
83 STATIC_PaintOwnerDrawfn, /* SS_OWNERDRAW */
84 STATIC_PaintBitmapfn, /* SS_BITMAP */
85 STATIC_PaintEnhMetafn, /* SS_ENHMETAFILE */
86 STATIC_PaintEtchedfn, /* SS_ETCHEDHORZ */
87 STATIC_PaintEtchedfn, /* SS_ETCHEDVERT */
88 STATIC_PaintEtchedfn, /* SS_ETCHEDFRAME */
91 static struct static_extra_info *get_extra_ptr( HWND hwnd, BOOL force )
93 struct static_extra_info *extra = (struct static_extra_info *)GetWindowLongPtrW( hwnd, 0 );
94 if (!extra && force)
96 extra = heap_alloc_zero( sizeof(*extra) );
97 if (extra)
98 SetWindowLongPtrW( hwnd, 0, (ULONG_PTR)extra );
100 return extra;
103 static BOOL get_icon_size( HICON handle, SIZE *size )
105 ICONINFO info;
106 BITMAP bmp;
107 int ret;
109 if (!GetIconInfo(handle, &info))
110 return FALSE;
112 ret = GetObjectW(info.hbmColor, sizeof(bmp), &bmp);
113 if (ret)
115 size->cx = bmp.bmWidth;
116 size->cy = bmp.bmHeight;
119 DeleteObject(info.hbmMask);
120 DeleteObject(info.hbmColor);
122 return !!ret;
125 /***********************************************************************
126 * STATIC_SetIcon
128 * Set the icon for an SS_ICON control.
130 static HICON STATIC_SetIcon( HWND hwnd, HICON hicon, DWORD style )
132 HICON prevIcon;
133 SIZE size;
134 struct static_extra_info *extra;
136 if ((style & SS_TYPEMASK) != SS_ICON) return 0;
137 if (hicon && !get_icon_size( hicon, &size ))
139 WARN("hicon != 0, but invalid\n");
140 return 0;
143 extra = get_extra_ptr( hwnd, TRUE );
144 if (!extra) return 0;
146 prevIcon = extra->image.hicon;
147 extra->image.hicon = hicon;
148 if (hicon && !(style & SS_CENTERIMAGE) && !(style & SS_REALSIZECONTROL))
150 /* Windows currently doesn't implement SS_RIGHTJUST */
152 if ((style & SS_RIGHTJUST) != 0)
154 RECT wr;
155 GetWindowRect(hwnd, &wr);
156 SetWindowPos( hwnd, 0, wr.right - info->nWidth, wr.bottom - info->nHeight,
157 info->nWidth, info->nHeight, SWP_NOACTIVATE | SWP_NOZORDER );
159 else */
161 SetWindowPos( hwnd, 0, 0, 0, size.cx, size.cy, SWP_NOACTIVATE | SWP_NOMOVE | SWP_NOZORDER );
164 return prevIcon;
167 static HBITMAP create_alpha_bitmap( HBITMAP hbitmap )
169 BITMAP bm;
170 HBITMAP alpha;
171 BITMAPINFO info;
172 HDC hdc;
173 void *bits;
174 DWORD i;
175 BYTE *ptr;
176 BOOL has_alpha = FALSE;
178 GetObjectW( hbitmap, sizeof(bm), &bm );
179 if (bm.bmBitsPixel != 32) return 0;
181 if (!(hdc = CreateCompatibleDC( 0 ))) return 0;
183 info.bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
184 info.bmiHeader.biWidth = bm.bmWidth;
185 info.bmiHeader.biHeight = -bm.bmHeight;
186 info.bmiHeader.biPlanes = 1;
187 info.bmiHeader.biBitCount = 32;
188 info.bmiHeader.biCompression = BI_RGB;
189 info.bmiHeader.biSizeImage = bm.bmWidth * bm.bmHeight * 4;
190 info.bmiHeader.biXPelsPerMeter = 0;
191 info.bmiHeader.biYPelsPerMeter = 0;
192 info.bmiHeader.biClrUsed = 0;
193 info.bmiHeader.biClrImportant = 0;
194 if ((alpha = CreateDIBSection( hdc, &info, DIB_RGB_COLORS, &bits, NULL, 0 )))
196 GetDIBits( hdc, hbitmap, 0, bm.bmHeight, bits, &info, DIB_RGB_COLORS );
198 for (i = 0, ptr = bits; i < bm.bmWidth * bm.bmHeight; i++, ptr += 4)
199 if ((has_alpha = (ptr[3] != 0))) break;
201 if (!has_alpha)
203 DeleteObject( alpha );
204 alpha = 0;
208 DeleteDC( hdc );
210 return alpha;
213 /***********************************************************************
214 * STATIC_SetBitmap
216 * Set the bitmap for an SS_BITMAP control.
218 static HBITMAP STATIC_SetBitmap( HWND hwnd, HBITMAP hBitmap, DWORD style )
220 HBITMAP hOldBitmap, alpha;
221 struct static_extra_info *extra;
223 if ((style & SS_TYPEMASK) != SS_BITMAP) return 0;
224 if (hBitmap && GetObjectType(hBitmap) != OBJ_BITMAP)
226 WARN("hBitmap != 0, but it's not a bitmap\n");
227 return 0;
230 extra = get_extra_ptr( hwnd, TRUE );
231 if (!extra) return 0;
233 hOldBitmap = extra->image.hbitmap;
234 extra->image.hbitmap = hBitmap;
235 extra->image_has_alpha = FALSE;
237 if (hBitmap)
239 alpha = create_alpha_bitmap( hBitmap );
240 if (alpha)
242 extra->image.hbitmap = alpha;
243 extra->image_has_alpha = TRUE;
247 if (hBitmap && !(style & SS_CENTERIMAGE) && !(style & SS_REALSIZECONTROL))
249 BITMAP bm;
250 GetObjectW(hBitmap, sizeof(bm), &bm);
252 /* Windows currently doesn't implement SS_RIGHTJUST */
254 if ((style & SS_RIGHTJUST) != 0)
256 RECT wr;
257 GetWindowRect(hwnd, &wr);
258 SetWindowPos( hwnd, 0, wr.right - bm.bmWidth, wr.bottom - bm.bmHeight,
259 bm.bmWidth, bm.bmHeight, SWP_NOACTIVATE | SWP_NOZORDER );
261 else */
263 SetWindowPos( hwnd, 0, 0, 0, bm.bmWidth, bm.bmHeight,
264 SWP_NOACTIVATE | SWP_NOMOVE | SWP_NOZORDER );
267 return hOldBitmap;
270 /***********************************************************************
271 * STATIC_SetEnhMetaFile
273 * Set the enhanced metafile for an SS_ENHMETAFILE control.
275 static HENHMETAFILE STATIC_SetEnhMetaFile( HWND hwnd, HENHMETAFILE hEnhMetaFile, DWORD style )
277 HENHMETAFILE old_hemf;
278 struct static_extra_info *extra;
280 if ((style & SS_TYPEMASK) != SS_ENHMETAFILE) return 0;
281 if (hEnhMetaFile && GetObjectType(hEnhMetaFile) != OBJ_ENHMETAFILE)
283 WARN("hEnhMetaFile != 0, but it's not an enhanced metafile\n");
284 return 0;
287 extra = get_extra_ptr( hwnd, TRUE );
288 if (!extra) return 0;
290 old_hemf = extra->image.hemf;
291 extra->image.hemf = hEnhMetaFile;
293 return old_hemf;
296 /***********************************************************************
297 * STATIC_GetImage
299 * Gets the bitmap for an SS_BITMAP control, the icon/cursor for an
300 * SS_ICON control or the enhanced metafile for an SS_ENHMETAFILE control.
302 static HANDLE STATIC_GetImage( HWND hwnd, WPARAM wParam, DWORD style )
304 struct static_extra_info *extra;
306 switch (style & SS_TYPEMASK)
308 case SS_ICON:
309 if ((wParam != IMAGE_ICON) &&
310 (wParam != IMAGE_CURSOR)) return NULL;
311 break;
312 case SS_BITMAP:
313 if (wParam != IMAGE_BITMAP) return NULL;
314 break;
315 case SS_ENHMETAFILE:
316 if (wParam != IMAGE_ENHMETAFILE) return NULL;
317 break;
318 default:
319 return NULL;
322 extra = get_extra_ptr( hwnd, FALSE );
323 return extra ? extra->image.hbitmap : 0;
326 static void STATIC_SetFont( HWND hwnd, HFONT hfont )
328 struct static_extra_info *extra = get_extra_ptr( hwnd, TRUE );
329 if (extra)
330 extra->hfont = hfont;
333 static HFONT STATIC_GetFont( HWND hwnd )
335 struct static_extra_info *extra = get_extra_ptr( hwnd, FALSE );
336 return extra ? extra->hfont : 0;
339 /***********************************************************************
340 * STATIC_LoadIconW
342 * Load the icon for an SS_ICON control.
344 static HICON STATIC_LoadIconW( HINSTANCE hInstance, LPCWSTR name, DWORD style )
346 HICON hicon = 0;
348 if (hInstance && ((ULONG_PTR)hInstance >> 16))
350 if ((style & SS_REALSIZEIMAGE) != 0)
351 hicon = LoadImageW(hInstance, name, IMAGE_ICON, 0, 0, LR_SHARED);
352 else
354 hicon = LoadIconW( hInstance, name );
355 if (!hicon) hicon = LoadCursorW( hInstance, name );
358 if (!hicon) hicon = LoadIconW( 0, name );
359 /* Windows doesn't try to load a standard cursor,
360 probably because most IDs for standard cursors conflict
361 with the IDs for standard icons anyway */
362 return hicon;
365 /***********************************************************************
366 * STATIC_TryPaintFcn
368 * Try to immediately paint the control.
370 static VOID STATIC_TryPaintFcn(HWND hwnd, LONG full_style)
372 LONG style = full_style & SS_TYPEMASK;
373 RECT rc;
375 GetClientRect( hwnd, &rc );
376 if (!IsRectEmpty(&rc) && IsWindowVisible(hwnd) && staticPaintFunc[style])
378 HDC hdc;
379 HRGN hrgn;
381 hdc = GetDC( hwnd );
382 hrgn = set_control_clipping( hdc, &rc );
383 (staticPaintFunc[style])( hwnd, hdc, full_style );
384 SelectClipRgn( hdc, hrgn );
385 if (hrgn) DeleteObject( hrgn );
386 ReleaseDC( hwnd, hdc );
390 static HBRUSH STATIC_SendWmCtlColorStatic(HWND hwnd, HDC hdc)
392 HBRUSH hBrush;
393 HWND parent = GetParent(hwnd);
395 if (!parent) parent = hwnd;
396 hBrush = (HBRUSH) SendMessageW( parent, WM_CTLCOLORSTATIC, (WPARAM)hdc, (LPARAM)hwnd );
397 if (!hBrush) /* did the app forget to call DefWindowProc ? */
399 /* FIXME: DefWindowProc should return different colors if a
400 manifest is present */
401 hBrush = (HBRUSH)DefWindowProcW( parent, WM_CTLCOLORSTATIC, (WPARAM)hdc, (LPARAM)hwnd);
403 return hBrush;
406 /***********************************************************************
407 * hasTextStyle
409 * Tests if the control displays text.
411 static BOOL hasTextStyle( DWORD style )
413 switch (style & SS_TYPEMASK)
415 case SS_SIMPLE:
416 case SS_LEFT:
417 case SS_LEFTNOWORDWRAP:
418 case SS_CENTER:
419 case SS_RIGHT:
420 case SS_OWNERDRAW:
421 return TRUE;
424 return FALSE;
427 static LRESULT CALLBACK STATIC_WindowProc( HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam )
429 LRESULT lResult = 0;
430 LONG full_style = GetWindowLongW( hwnd, GWL_STYLE );
431 LONG style = full_style & SS_TYPEMASK;
433 if (!IsWindow( hwnd )) return 0;
435 switch (uMsg)
437 case WM_CREATE:
438 if (style < 0L || style > SS_TYPEMASK)
440 ERR("Unknown style 0x%02x\n", style );
441 return -1;
443 break;
445 case WM_NCDESTROY:
446 if (style == SS_ICON)
448 struct static_extra_info *extra = get_extra_ptr( hwnd, FALSE );
449 if (extra)
451 if (extra->image_has_alpha)
452 DeleteObject( extra->image.hbitmap );
453 heap_free( extra );
456 * FIXME
457 * DestroyIcon32( STATIC_SetIcon( wndPtr, 0 ) );
459 * We don't want to do this yet because DestroyIcon32 is broken. If the icon
460 * had already been loaded by the application the last thing we want to do is
461 * GlobalFree16 the handle.
463 break;
465 else
466 return DefWindowProcW(hwnd, uMsg, wParam, lParam);
468 case WM_ERASEBKGND:
469 /* do all painting in WM_PAINT like Windows does */
470 return 1;
472 case WM_PRINTCLIENT:
473 case WM_PAINT:
475 PAINTSTRUCT ps;
476 RECT rect;
477 HDC hdc = wParam ? (HDC)wParam : BeginPaint(hwnd, &ps);
478 GetClientRect( hwnd, &rect );
479 if (staticPaintFunc[style])
481 HRGN hrgn = set_control_clipping( hdc, &rect );
482 (staticPaintFunc[style])( hwnd, hdc, full_style );
483 SelectClipRgn( hdc, hrgn );
484 if (hrgn) DeleteObject( hrgn );
486 if (!wParam) EndPaint(hwnd, &ps);
488 break;
490 case WM_ENABLE:
491 STATIC_TryPaintFcn( hwnd, full_style );
492 if (full_style & SS_NOTIFY)
494 if (wParam)
495 SendMessageW( GetParent(hwnd), WM_COMMAND,
496 MAKEWPARAM( GetWindowLongPtrW(hwnd,GWLP_ID), STN_ENABLE ), (LPARAM)hwnd);
497 else
498 SendMessageW( GetParent(hwnd), WM_COMMAND,
499 MAKEWPARAM( GetWindowLongPtrW(hwnd,GWLP_ID), STN_DISABLE ), (LPARAM)hwnd);
501 break;
503 case WM_SYSCOLORCHANGE:
504 COMCTL32_RefreshSysColors();
505 STATIC_TryPaintFcn( hwnd, full_style );
506 break;
508 case WM_THEMECHANGED:
509 InvalidateRect( hwnd, 0, TRUE );
510 break;
512 case WM_NCCREATE:
514 CREATESTRUCTW *cs = (CREATESTRUCTW *)lParam;
516 if (full_style & SS_SUNKEN)
517 SetWindowLongW( hwnd, GWL_EXSTYLE,
518 GetWindowLongW( hwnd, GWL_EXSTYLE ) | WS_EX_STATICEDGE );
520 switch (style)
522 case SS_ICON:
524 HICON hIcon;
526 hIcon = STATIC_LoadIconW(cs->hInstance, cs->lpszName, full_style);
527 STATIC_SetIcon(hwnd, hIcon, full_style);
529 break;
530 case SS_BITMAP:
531 if ((ULONG_PTR)cs->hInstance >> 16)
533 HBITMAP hBitmap;
534 hBitmap = LoadBitmapW(cs->hInstance, cs->lpszName);
535 STATIC_SetBitmap(hwnd, hBitmap, full_style);
537 break;
539 /* SS_ENHMETAFILE: Despite what MSDN says, Windows does not load
540 the enhanced metafile that was specified as the window text. */
542 return DefWindowProcW(hwnd, uMsg, wParam, lParam);
544 case WM_SETTEXT:
545 if (hasTextStyle( full_style ))
547 lResult = DefWindowProcW( hwnd, uMsg, wParam, lParam );
548 STATIC_TryPaintFcn( hwnd, full_style );
550 break;
552 case WM_SETFONT:
553 if (hasTextStyle( full_style ))
555 STATIC_SetFont( hwnd, (HFONT)wParam );
556 if (LOWORD(lParam))
557 RedrawWindow( hwnd, NULL, 0, RDW_INVALIDATE | RDW_ERASE | RDW_UPDATENOW | RDW_ALLCHILDREN );
559 break;
561 case WM_GETFONT:
562 return (LRESULT)STATIC_GetFont( hwnd );
564 case WM_NCHITTEST:
565 if (full_style & SS_NOTIFY)
566 return HTCLIENT;
567 else
568 return HTTRANSPARENT;
570 case WM_GETDLGCODE:
571 return DLGC_STATIC;
573 case WM_LBUTTONDOWN:
574 case WM_NCLBUTTONDOWN:
575 if (full_style & SS_NOTIFY)
576 SendMessageW( GetParent(hwnd), WM_COMMAND,
577 MAKEWPARAM( GetWindowLongPtrW(hwnd,GWLP_ID), STN_CLICKED ), (LPARAM)hwnd);
578 return 0;
580 case WM_LBUTTONDBLCLK:
581 case WM_NCLBUTTONDBLCLK:
582 if (full_style & SS_NOTIFY)
583 SendMessageW( GetParent(hwnd), WM_COMMAND,
584 MAKEWPARAM( GetWindowLongPtrW(hwnd,GWLP_ID), STN_DBLCLK ), (LPARAM)hwnd);
585 return 0;
587 case STM_GETIMAGE:
588 return (LRESULT)STATIC_GetImage( hwnd, wParam, full_style );
590 case STM_GETICON:
591 return (LRESULT)STATIC_GetImage( hwnd, IMAGE_ICON, full_style );
593 case STM_SETIMAGE:
594 switch (wParam)
596 case IMAGE_BITMAP:
597 lResult = (LRESULT)STATIC_SetBitmap( hwnd, (HBITMAP)lParam, full_style );
598 break;
599 case IMAGE_ENHMETAFILE:
600 lResult = (LRESULT)STATIC_SetEnhMetaFile( hwnd, (HENHMETAFILE)lParam, full_style );
601 break;
602 case IMAGE_ICON:
603 case IMAGE_CURSOR:
604 lResult = (LRESULT)STATIC_SetIcon( hwnd, (HICON)lParam, full_style );
605 break;
606 default:
607 FIXME("STM_SETIMAGE: Unhandled type %lx\n", wParam);
608 break;
610 STATIC_TryPaintFcn( hwnd, full_style );
611 break;
613 case STM_SETICON:
614 lResult = (LRESULT)STATIC_SetIcon( hwnd, (HICON)wParam, full_style );
615 STATIC_TryPaintFcn( hwnd, full_style );
616 break;
618 default:
619 return DefWindowProcW(hwnd, uMsg, wParam, lParam);
621 return lResult;
624 static void STATIC_PaintOwnerDrawfn( HWND hwnd, HDC hdc, DWORD style )
626 DRAWITEMSTRUCT dis;
627 HFONT font, oldFont = NULL;
628 UINT id = (UINT)GetWindowLongPtrW( hwnd, GWLP_ID );
630 dis.CtlType = ODT_STATIC;
631 dis.CtlID = id;
632 dis.itemID = 0;
633 dis.itemAction = ODA_DRAWENTIRE;
634 dis.itemState = IsWindowEnabled(hwnd) ? 0 : ODS_DISABLED;
635 dis.hwndItem = hwnd;
636 dis.hDC = hdc;
637 dis.itemData = 0;
638 GetClientRect( hwnd, &dis.rcItem );
640 font = STATIC_GetFont( hwnd );
641 if (font) oldFont = SelectObject( hdc, font );
642 SendMessageW( GetParent(hwnd), WM_CTLCOLORSTATIC, (WPARAM)hdc, (LPARAM)hwnd );
643 SendMessageW( GetParent(hwnd), WM_DRAWITEM, id, (LPARAM)&dis );
644 if (font) SelectObject( hdc, oldFont );
647 static void STATIC_PaintTextfn( HWND hwnd, HDC hdc, DWORD style )
649 RECT rc;
650 HBRUSH hBrush;
651 HFONT hFont, hOldFont = NULL;
652 UINT format;
653 INT len, buf_size;
654 WCHAR *text;
656 GetClientRect( hwnd, &rc);
658 switch (style & SS_TYPEMASK)
660 case SS_LEFT:
661 format = DT_LEFT | DT_EXPANDTABS | DT_WORDBREAK;
662 break;
664 case SS_CENTER:
665 format = DT_CENTER | DT_EXPANDTABS | DT_WORDBREAK;
666 break;
668 case SS_RIGHT:
669 format = DT_RIGHT | DT_EXPANDTABS | DT_WORDBREAK;
670 break;
672 case SS_SIMPLE:
673 format = DT_LEFT | DT_SINGLELINE;
674 break;
676 case SS_LEFTNOWORDWRAP:
677 format = DT_LEFT | DT_EXPANDTABS;
678 break;
680 default:
681 return;
684 if (GetWindowLongW( hwnd, GWL_EXSTYLE ) & WS_EX_RIGHT)
685 format = DT_RIGHT | (format & ~(DT_LEFT | DT_CENTER));
687 if (style & SS_NOPREFIX)
688 format |= DT_NOPREFIX;
690 if ((style & SS_TYPEMASK) != SS_SIMPLE)
692 if (style & SS_CENTERIMAGE)
693 format |= DT_SINGLELINE | DT_VCENTER;
694 if (style & SS_EDITCONTROL)
695 format |= DT_EDITCONTROL;
696 if (style & SS_ENDELLIPSIS)
697 format |= DT_SINGLELINE | DT_END_ELLIPSIS;
698 if (style & SS_PATHELLIPSIS)
699 format |= DT_SINGLELINE | DT_PATH_ELLIPSIS;
700 if (style & SS_WORDELLIPSIS)
701 format |= DT_SINGLELINE | DT_WORD_ELLIPSIS;
704 if ((hFont = STATIC_GetFont( hwnd )))
705 hOldFont = SelectObject( hdc, hFont );
707 /* SS_SIMPLE controls: WM_CTLCOLORSTATIC is sent, but the returned
708 brush is not used */
709 hBrush = STATIC_SendWmCtlColorStatic(hwnd, hdc);
711 if ((style & SS_TYPEMASK) != SS_SIMPLE)
713 FillRect( hdc, &rc, hBrush );
714 if (!IsWindowEnabled(hwnd)) SetTextColor(hdc, GetSysColor(COLOR_GRAYTEXT));
717 buf_size = 256;
718 if (!(text = HeapAlloc( GetProcessHeap(), 0, buf_size * sizeof(WCHAR) )))
719 goto no_TextOut;
721 while ((len = InternalGetWindowText( hwnd, text, buf_size )) == buf_size - 1)
723 buf_size *= 2;
724 if (!(text = HeapReAlloc( GetProcessHeap(), 0, text, buf_size * sizeof(WCHAR) )))
725 goto no_TextOut;
728 if (!len) goto no_TextOut;
730 if (((style & SS_TYPEMASK) == SS_SIMPLE) && (style & SS_NOPREFIX))
732 /* Windows uses the faster ExtTextOut() to draw the text and
733 to paint the whole client rectangle with the text background
734 color. Reference: "Static Controls" by Kyle Marsh, 1992 */
735 ExtTextOutW( hdc, rc.left, rc.top, ETO_CLIPPED | ETO_OPAQUE,
736 &rc, text, len, NULL );
738 else
740 DrawTextW( hdc, text, -1, &rc, format );
743 no_TextOut:
744 HeapFree( GetProcessHeap(), 0, text );
746 if (hFont)
747 SelectObject( hdc, hOldFont );
750 static void STATIC_PaintRectfn( HWND hwnd, HDC hdc, DWORD style )
752 RECT rc;
753 HBRUSH hBrush;
755 GetClientRect( hwnd, &rc);
757 /* FIXME: send WM_CTLCOLORSTATIC */
758 switch (style & SS_TYPEMASK)
760 case SS_BLACKRECT:
761 hBrush = CreateSolidBrush(comctl32_color.clr3dDkShadow);
762 FillRect( hdc, &rc, hBrush );
763 break;
764 case SS_GRAYRECT:
765 hBrush = CreateSolidBrush(comctl32_color.clr3dShadow);
766 FillRect( hdc, &rc, hBrush );
767 break;
768 case SS_WHITERECT:
769 hBrush = CreateSolidBrush(comctl32_color.clr3dHilight);
770 FillRect( hdc, &rc, hBrush );
771 break;
772 case SS_BLACKFRAME:
773 hBrush = CreateSolidBrush(comctl32_color.clr3dDkShadow);
774 FrameRect( hdc, &rc, hBrush );
775 break;
776 case SS_GRAYFRAME:
777 hBrush = CreateSolidBrush(comctl32_color.clr3dShadow);
778 FrameRect( hdc, &rc, hBrush );
779 break;
780 case SS_WHITEFRAME:
781 hBrush = CreateSolidBrush(comctl32_color.clr3dHilight);
782 FrameRect( hdc, &rc, hBrush );
783 break;
784 default:
785 return;
787 DeleteObject( hBrush );
791 static void STATIC_PaintIconfn( HWND hwnd, HDC hdc, DWORD style )
793 RECT rc, iconRect;
794 HBRUSH hbrush;
795 HICON hIcon;
796 SIZE size;
798 GetClientRect( hwnd, &rc );
799 hbrush = STATIC_SendWmCtlColorStatic(hwnd, hdc);
800 hIcon = STATIC_GetImage( hwnd, IMAGE_ICON, style );
801 if (!hIcon || !get_icon_size( hIcon, &size ))
803 FillRect(hdc, &rc, hbrush);
805 else
807 if (style & SS_CENTERIMAGE)
809 iconRect.left = (rc.right - rc.left) / 2 - size.cx / 2;
810 iconRect.top = (rc.bottom - rc.top) / 2 - size.cy / 2;
811 iconRect.right = iconRect.left + size.cx;
812 iconRect.bottom = iconRect.top + size.cy;
814 else
815 iconRect = rc;
816 FillRect( hdc, &rc, hbrush );
817 DrawIconEx( hdc, iconRect.left, iconRect.top, hIcon, iconRect.right - iconRect.left,
818 iconRect.bottom - iconRect.top, 0, NULL, DI_NORMAL );
822 static void STATIC_PaintBitmapfn(HWND hwnd, HDC hdc, DWORD style )
824 HDC hMemDC;
825 HBITMAP hBitmap, oldbitmap;
826 HBRUSH hbrush;
828 hbrush = STATIC_SendWmCtlColorStatic(hwnd, hdc);
830 if ((hBitmap = STATIC_GetImage( hwnd, IMAGE_BITMAP, style ))
831 && (GetObjectType(hBitmap) == OBJ_BITMAP)
832 && (hMemDC = CreateCompatibleDC( hdc )))
834 BITMAP bm;
835 RECT rcClient;
836 LOGBRUSH brush;
837 BLENDFUNCTION blend = { AC_SRC_OVER, 0, 255, AC_SRC_ALPHA };
838 struct static_extra_info *extra = get_extra_ptr( hwnd, FALSE );
840 GetObjectW(hBitmap, sizeof(bm), &bm);
841 oldbitmap = SelectObject(hMemDC, hBitmap);
843 /* Set the background color for monochrome bitmaps
844 to the color of the background brush */
845 if (GetObjectW( hbrush, sizeof(brush), &brush ))
847 if (brush.lbStyle == BS_SOLID)
848 SetBkColor(hdc, brush.lbColor);
850 GetClientRect(hwnd, &rcClient);
851 if (style & SS_CENTERIMAGE)
853 FillRect( hdc, &rcClient, hbrush );
854 rcClient.left = (rcClient.right - rcClient.left)/2 - bm.bmWidth/2;
855 rcClient.top = (rcClient.bottom - rcClient.top)/2 - bm.bmHeight/2;
856 rcClient.right = rcClient.left + bm.bmWidth;
857 rcClient.bottom = rcClient.top + bm.bmHeight;
860 if (extra->image_has_alpha)
861 GdiAlphaBlend(hdc, rcClient.left, rcClient.top, rcClient.right - rcClient.left,
862 rcClient.bottom - rcClient.top, hMemDC,
863 0, 0, bm.bmWidth, bm.bmHeight, blend);
864 else
865 StretchBlt(hdc, rcClient.left, rcClient.top, rcClient.right - rcClient.left,
866 rcClient.bottom - rcClient.top, hMemDC,
867 0, 0, bm.bmWidth, bm.bmHeight, SRCCOPY);
868 SelectObject(hMemDC, oldbitmap);
869 DeleteDC(hMemDC);
873 static void STATIC_PaintEnhMetafn(HWND hwnd, HDC hdc, DWORD style )
875 HENHMETAFILE hEnhMetaFile;
876 RECT rc;
877 HBRUSH hbrush;
879 GetClientRect(hwnd, &rc);
880 hbrush = STATIC_SendWmCtlColorStatic(hwnd, hdc);
881 FillRect(hdc, &rc, hbrush);
882 if ((hEnhMetaFile = STATIC_GetImage( hwnd, IMAGE_ENHMETAFILE, style )))
884 /* The control's current font is not selected into the
885 device context! */
886 if (GetObjectType(hEnhMetaFile) == OBJ_ENHMETAFILE)
887 PlayEnhMetaFile(hdc, hEnhMetaFile, &rc);
891 static void STATIC_PaintEtchedfn( HWND hwnd, HDC hdc, DWORD style )
893 RECT rc;
895 /* FIXME: sometimes (not always) sends WM_CTLCOLORSTATIC */
896 GetClientRect( hwnd, &rc );
897 switch (style & SS_TYPEMASK)
899 case SS_ETCHEDHORZ:
900 DrawEdge(hdc, &rc, EDGE_ETCHED, BF_TOP | BF_BOTTOM);
901 break;
902 case SS_ETCHEDVERT:
903 DrawEdge(hdc, &rc, EDGE_ETCHED, BF_LEFT | BF_RIGHT);
904 break;
905 case SS_ETCHEDFRAME:
906 DrawEdge(hdc, &rc, EDGE_ETCHED, BF_RECT);
907 break;
911 void STATIC_Register(void)
913 WNDCLASSW wndClass;
915 memset(&wndClass, 0, sizeof(wndClass));
916 wndClass.style = CS_DBLCLKS | CS_PARENTDC | CS_GLOBALCLASS;
917 wndClass.lpfnWndProc = STATIC_WindowProc;
918 wndClass.cbClsExtra = 0;
919 wndClass.cbWndExtra = sizeof(struct static_extra_info *);
920 wndClass.hCursor = LoadCursorW(0, (LPWSTR)IDC_ARROW);
921 wndClass.hbrBackground = NULL;
922 wndClass.lpszClassName = WC_STATICW;
923 RegisterClassW(&wndClass);