]>
git.saurik.com Git - wxWidgets.git/blob - src/msw/bmpbuttn.cpp
1 /////////////////////////////////////////////////////////////////////////////
2 // Name: src/msw/bmpbuttn.cpp
3 // Purpose: wxBitmapButton
4 // Author: Julian Smart
8 // Copyright: (c) Julian Smart
9 // Licence: wxWindows licence
10 /////////////////////////////////////////////////////////////////////////////
12 // For compilers that support precompilation, includes "wx.h".
13 #include "wx/wxprec.h"
21 #include "wx/bmpbuttn.h"
25 #include "wx/dcmemory.h"
29 #include "wx/msw/private.h"
31 #include "wx/msw/uxtheme.h"
34 // no need to include tmschema.h
36 #define BP_PUSHBUTTON 1
41 #define PBS_DISABLED 4
42 #define PBS_DEFAULTED 5
44 #define TMT_CONTENTMARGINS 3602
46 #endif // wxUSE_UXTHEME
48 #ifndef ODS_NOFOCUSRECT
49 #define ODS_NOFOCUSRECT 0x0200
52 // ----------------------------------------------------------------------------
54 // ----------------------------------------------------------------------------
56 #if wxUSE_EXTENDED_RTTI
58 WX_DEFINE_FLAGS( wxBitmapButtonStyle
)
60 wxBEGIN_FLAGS( wxBitmapButtonStyle
)
61 // new style border flags, we put them first to
62 // use them for streaming out
63 wxFLAGS_MEMBER(wxBORDER_SIMPLE
)
64 wxFLAGS_MEMBER(wxBORDER_SUNKEN
)
65 wxFLAGS_MEMBER(wxBORDER_DOUBLE
)
66 wxFLAGS_MEMBER(wxBORDER_RAISED
)
67 wxFLAGS_MEMBER(wxBORDER_STATIC
)
68 wxFLAGS_MEMBER(wxBORDER_NONE
)
70 // old style border flags
71 wxFLAGS_MEMBER(wxSIMPLE_BORDER
)
72 wxFLAGS_MEMBER(wxSUNKEN_BORDER
)
73 wxFLAGS_MEMBER(wxDOUBLE_BORDER
)
74 wxFLAGS_MEMBER(wxRAISED_BORDER
)
75 wxFLAGS_MEMBER(wxSTATIC_BORDER
)
76 wxFLAGS_MEMBER(wxBORDER
)
78 // standard window styles
79 wxFLAGS_MEMBER(wxTAB_TRAVERSAL
)
80 wxFLAGS_MEMBER(wxCLIP_CHILDREN
)
81 wxFLAGS_MEMBER(wxTRANSPARENT_WINDOW
)
82 wxFLAGS_MEMBER(wxWANTS_CHARS
)
83 wxFLAGS_MEMBER(wxFULL_REPAINT_ON_RESIZE
)
84 wxFLAGS_MEMBER(wxALWAYS_SHOW_SB
)
85 wxFLAGS_MEMBER(wxVSCROLL
)
86 wxFLAGS_MEMBER(wxHSCROLL
)
88 wxFLAGS_MEMBER(wxBU_AUTODRAW
)
89 wxFLAGS_MEMBER(wxBU_LEFT
)
90 wxFLAGS_MEMBER(wxBU_RIGHT
)
91 wxFLAGS_MEMBER(wxBU_TOP
)
92 wxFLAGS_MEMBER(wxBU_BOTTOM
)
93 wxEND_FLAGS( wxBitmapButtonStyle
)
95 IMPLEMENT_DYNAMIC_CLASS_XTI(wxBitmapButton
, wxButton
,"wx/bmpbuttn.h")
97 wxBEGIN_PROPERTIES_TABLE(wxBitmapButton
)
98 wxPROPERTY_FLAGS( WindowStyle
, wxBitmapButtonStyle
, long , SetWindowStyleFlag
, GetWindowStyleFlag
, EMPTY_MACROVALUE
, 0 /*flags*/ , wxT("Helpstring") , wxT("group")) // style
99 wxEND_PROPERTIES_TABLE()
101 wxBEGIN_HANDLERS_TABLE(wxBitmapButton
)
102 wxEND_HANDLERS_TABLE()
104 wxCONSTRUCTOR_5( wxBitmapButton
, wxWindow
* , Parent
, wxWindowID
, Id
, wxBitmap
, Bitmap
, wxPoint
, Position
, wxSize
, Size
)
107 IMPLEMENT_DYNAMIC_CLASS(wxBitmapButton
, wxButton
)
110 BEGIN_EVENT_TABLE(wxBitmapButton
, wxBitmapButtonBase
)
111 EVT_SYS_COLOUR_CHANGED(wxBitmapButton::OnSysColourChanged
)
112 EVT_ENTER_WINDOW(wxBitmapButton::OnMouseEnterOrLeave
)
113 EVT_LEAVE_WINDOW(wxBitmapButton::OnMouseEnterOrLeave
)
119 long "style" , wxBU_AUTODRAW
126 bool wxBitmapButton::Create(wxWindow
*parent
, wxWindowID id
,
127 const wxBitmap
& bitmap
,
129 const wxSize
& size
, long style
,
130 const wxValidator
& wxVALIDATOR_PARAM(validator
),
131 const wxString
& name
)
133 m_bmpNormal
= bitmap
;
137 SetValidator(validator
);
138 #endif // wxUSE_VALIDATORS
140 parent
->AddChild(this);
142 m_windowStyle
= style
;
144 if ( style
& wxBU_AUTODRAW
)
151 m_windowId
= NewControlId();
155 long msStyle
= WS_VISIBLE
| WS_TABSTOP
| WS_CHILD
| BS_OWNERDRAW
;
157 if ( m_windowStyle
& wxCLIP_SIBLINGS
)
158 msStyle
|= WS_CLIPSIBLINGS
;
161 if(m_windowStyle
& wxBU_LEFT
)
163 if(m_windowStyle
& wxBU_RIGHT
)
165 if(m_windowStyle
& wxBU_TOP
)
167 if(m_windowStyle
& wxBU_BOTTOM
)
168 msStyle
|= BS_BOTTOM
;
171 m_hWnd
= (WXHWND
) CreateWindowEx(
183 // Subclass again for purposes of dialog editing mode
192 bool wxBitmapButton::SetBackgroundColour(const wxColour
& colour
)
194 if ( !wxBitmapButtonBase::SetBackgroundColour(colour
) )
200 // invalidate the brush, it will be recreated the next time it's needed
201 m_brushDisabled
= wxNullBrush
;
206 void wxBitmapButton::OnSysColourChanged(wxSysColourChangedEvent
& event
)
208 m_brushDisabled
= wxNullBrush
;
212 // this change affects our current state
219 void wxBitmapButton::OnMouseEnterOrLeave(wxMouseEvent
& event
)
221 if ( IsEnabled() && m_bmpHover
.Ok() )
227 void wxBitmapButton::OnSetBitmap()
229 // if the focus bitmap is specified but hover one isn't, use the focus
230 // bitmap for hovering as well if this is consistent with the current
231 // Windows version look and feel
233 // rationale: this is compatible with the old wxGTK behaviour and also
234 // makes it much easier to do "the right thing" for all platforms (some of
235 // them, such as Windows XP, have "hot" buttons while others don't)
236 if ( !m_bmpHover
.Ok() &&
238 wxUxThemeEngine::GetIfActive() )
240 m_bmpHover
= m_bmpFocus
;
243 // this will redraw us
244 wxBitmapButtonBase::OnSetBitmap();
249 void MSWDrawXPBackground(wxButton
*button
, WXDRAWITEMSTRUCT
*wxdis
)
251 LPDRAWITEMSTRUCT lpDIS
= (LPDRAWITEMSTRUCT
)wxdis
;
252 HDC hdc
= lpDIS
->hDC
;
253 UINT state
= lpDIS
->itemState
;
255 CopyRect(&rectBtn
, &lpDIS
->rcItem
);
257 wxUxThemeHandle
theme(button
, L
"BUTTON");
260 if ( state
& ODS_SELECTED
)
262 iState
= PBS_PRESSED
;
264 else if ( button
->HasCapture() || button
->IsMouseInWindow() )
268 else if ( state
& ODS_FOCUS
)
270 iState
= PBS_DEFAULTED
;
272 else if ( state
& ODS_DISABLED
)
274 iState
= PBS_DISABLED
;
281 // draw parent background if needed
282 if ( wxUxThemeEngine::Get()->IsThemeBackgroundPartiallyTransparent(theme
,
286 wxUxThemeEngine::Get()->DrawThemeParentBackground(GetHwndOf(button
), hdc
, &rectBtn
);
290 wxUxThemeEngine::Get()->DrawThemeBackground(theme
, hdc
, BP_PUSHBUTTON
, iState
,
293 // calculate content area margins
295 wxUxThemeEngine::Get()->GetThemeMargins(theme
, hdc
, BP_PUSHBUTTON
, iState
,
296 TMT_CONTENTMARGINS
, &rectBtn
, &margins
);
298 ::CopyRect(&rectClient
, &rectBtn
);
299 ::InflateRect(&rectClient
, -margins
.cxLeftWidth
, -margins
.cyTopHeight
);
301 // if focused and !nofocus rect
302 if ( (state
& ODS_FOCUS
) && !(state
& ODS_NOFOCUSRECT
) )
304 DrawFocusRect(hdc
, &rectClient
);
307 if ( button
->UseBgCol() )
309 COLORREF colBg
= wxColourToRGB(button
->GetBackgroundColour());
310 HBRUSH hbrushBackground
= ::CreateSolidBrush(colBg
);
312 // don't overwrite the focus rect
313 ::InflateRect(&rectClient
, -1, -1);
314 FillRect(hdc
, &rectClient
, hbrushBackground
);
315 ::DeleteObject(hbrushBackground
);
318 #endif // wxUSE_UXTHEME
320 // VZ: should be at the very least less than wxDEFAULT_BUTTON_MARGIN
321 #define FOCUS_MARGIN 3
323 bool wxBitmapButton::MSWOnDraw(WXDRAWITEMSTRUCT
*item
)
326 long style
= GetWindowLong((HWND
) GetHWND(), GWL_STYLE
);
327 if (style
& BS_BITMAP
)
329 // Let default procedure draw the bitmap, which is defined
330 // in the Windows resource.
335 LPDRAWITEMSTRUCT lpDIS
= (LPDRAWITEMSTRUCT
) item
;
336 HDC hDC
= lpDIS
->hDC
;
337 UINT state
= lpDIS
->itemState
;
338 bool isSelected
= (state
& ODS_SELECTED
) != 0;
339 bool autoDraw
= (GetWindowStyleFlag() & wxBU_AUTODRAW
) != 0;
342 // choose the bitmap to use depending on the button state
345 if ( isSelected
&& m_bmpSelected
.Ok() )
346 bitmap
= &m_bmpSelected
;
347 else if ( m_bmpHover
.Ok() && IsMouseInWindow() )
348 bitmap
= &m_bmpHover
;
349 else if ((state
& ODS_FOCUS
) && m_bmpFocus
.Ok())
350 bitmap
= &m_bmpFocus
;
351 else if ((state
& ODS_DISABLED
) && m_bmpDisabled
.Ok())
352 bitmap
= &m_bmpDisabled
;
354 bitmap
= &m_bmpNormal
;
359 // centre the bitmap in the control area
360 int x
= lpDIS
->rcItem
.left
;
361 int y
= lpDIS
->rcItem
.top
;
362 int width
= lpDIS
->rcItem
.right
- x
;
363 int height
= lpDIS
->rcItem
.bottom
- y
;
364 int wBmp
= bitmap
->GetWidth();
365 int hBmp
= bitmap
->GetHeight();
368 if ( autoDraw
&& wxUxThemeEngine::GetIfActive() )
370 MSWDrawXPBackground(this, item
);
371 wxUxThemeHandle
theme(this, L
"BUTTON");
373 // calculate content area margins
374 // assuming here that each state is the same size
376 wxUxThemeEngine::Get()->GetThemeMargins(theme
, NULL
,
377 BP_PUSHBUTTON
, PBS_NORMAL
,
378 TMT_CONTENTMARGINS
, NULL
,
380 int marginX
= margins
.cxLeftWidth
+ 1;
381 int marginY
= margins
.cyTopHeight
+ 1;
384 if ( m_windowStyle
& wxBU_LEFT
)
388 else if ( m_windowStyle
& wxBU_RIGHT
)
390 x1
= x
+ (width
- wBmp
) - marginX
;
394 x1
= x
+ (width
- wBmp
) / 2;
397 if ( m_windowStyle
& wxBU_TOP
)
401 else if ( m_windowStyle
& wxBU_BOTTOM
)
403 y1
= y
+ (height
- hBmp
) - marginY
;
407 y1
= y
+ (height
- hBmp
) / 2;
411 wxDCTemp
dst((WXHDC
)hDC
);
412 dst
.DrawBitmap(*bitmap
, x1
, y1
, true);
416 #endif // wxUSE_UXTHEME
420 if(m_windowStyle
& wxBU_LEFT
)
421 x1
= x
+ (FOCUS_MARGIN
+1);
422 else if(m_windowStyle
& wxBU_RIGHT
)
423 x1
= x
+ (width
- wBmp
) - (FOCUS_MARGIN
+1);
425 x1
= x
+ (width
- wBmp
) / 2;
427 if(m_windowStyle
& wxBU_TOP
)
428 y1
= y
+ (FOCUS_MARGIN
+1);
429 else if(m_windowStyle
& wxBU_BOTTOM
)
430 y1
= y
+ (height
- hBmp
) - (FOCUS_MARGIN
+1);
432 y1
= y
+ (height
- hBmp
) / 2;
434 if ( isSelected
&& autoDraw
)
440 // draw the face, if auto-drawing
443 DrawFace((WXHDC
) hDC
,
444 lpDIS
->rcItem
.left
, lpDIS
->rcItem
.top
,
445 lpDIS
->rcItem
.right
, lpDIS
->rcItem
.bottom
,
450 wxDCTemp
dst((WXHDC
)hDC
);
451 dst
.DrawBitmap(*bitmap
, x1
, y1
, true);
453 // draw focus / disabled state, if auto-drawing
454 if ( (state
& ODS_DISABLED
) && autoDraw
)
456 DrawButtonDisable((WXHDC
) hDC
,
457 lpDIS
->rcItem
.left
, lpDIS
->rcItem
.top
,
458 lpDIS
->rcItem
.right
, lpDIS
->rcItem
.bottom
,
461 else if ( (state
& ODS_FOCUS
) && autoDraw
)
463 DrawButtonFocus((WXHDC
) hDC
,
467 lpDIS
->rcItem
.bottom
,
474 // GRG Feb/2000, support for bmp buttons with Win95/98 standard LNF
476 void wxBitmapButton::DrawFace( WXHDC dc
, int left
, int top
,
477 int right
, int bottom
, bool sel
)
486 // create needed pens and brush
487 penHiLight
= CreatePen(PS_SOLID
, 0, GetSysColor(COLOR_3DHILIGHT
));
488 penLight
= CreatePen(PS_SOLID
, 0, GetSysColor(COLOR_3DLIGHT
));
489 penShadow
= CreatePen(PS_SOLID
, 0, GetSysColor(COLOR_3DSHADOW
));
490 penDkShadow
= CreatePen(PS_SOLID
, 0, GetSysColor(COLOR_3DDKSHADOW
));
491 brushFace
= CreateSolidBrush(GetSysColor(COLOR_BTNFACE
));
493 // draw the rectangle
498 rect
.bottom
= bottom
;
499 FillRect((HDC
) dc
, &rect
, brushFace
);
502 oldp
= (HPEN
) SelectObject( (HDC
) dc
, sel
? penDkShadow
: penHiLight
);
504 wxDrawLine((HDC
) dc
, left
, top
, right
-1, top
);
505 wxDrawLine((HDC
) dc
, left
, top
+1, left
, bottom
-1);
507 SelectObject( (HDC
) dc
, sel
? penShadow
: penLight
);
508 wxDrawLine((HDC
) dc
, left
+1, top
+1, right
-2, top
+1);
509 wxDrawLine((HDC
) dc
, left
+1, top
+2, left
+1, bottom
-2);
511 SelectObject( (HDC
) dc
, sel
? penLight
: penShadow
);
512 wxDrawLine((HDC
) dc
, left
+1, bottom
-2, right
-1, bottom
-2);
513 wxDrawLine((HDC
) dc
, right
-2, bottom
-3, right
-2, top
);
515 SelectObject( (HDC
) dc
, sel
? penHiLight
: penDkShadow
);
516 wxDrawLine((HDC
) dc
, left
, bottom
-1, right
+2, bottom
-1);
517 wxDrawLine((HDC
) dc
, right
-1, bottom
-2, right
-1, top
-1);
519 // delete allocated resources
520 SelectObject((HDC
) dc
,oldp
);
521 DeleteObject(penHiLight
);
522 DeleteObject(penLight
);
523 DeleteObject(penShadow
);
524 DeleteObject(penDkShadow
);
525 DeleteObject(brushFace
);
528 void wxBitmapButton::DrawButtonFocus( WXHDC dc
, int left
, int top
, int right
,
529 int bottom
, bool WXUNUSED(sel
) )
535 rect
.bottom
= bottom
;
536 InflateRect( &rect
, - FOCUS_MARGIN
, - FOCUS_MARGIN
);
538 // GRG: the focus rectangle should not move when the button is pushed!
541 OffsetRect( &rect, 1, 1 );
544 DrawFocusRect( (HDC
) dc
, &rect
);
548 wxBitmapButton::DrawButtonDisable( WXHDC dc
,
549 int left
, int top
, int right
, int bottom
,
552 if ( !m_brushDisabled
.Ok() )
554 // draw a bitmap with two black and two background colour pixels
557 dc
.SelectObject(bmp
);
558 dc
.SetPen(*wxBLACK_PEN
);
561 dc
.SetPen(GetBackgroundColour());
565 m_brushDisabled
= wxBrush(bmp
);
568 SelectInHDC
selectBrush((HDC
)dc
, GetHbrushOf(m_brushDisabled
));
570 // ROP for "dest |= pattern" operation -- as it doesn't have a standard
571 // name, give it our own
572 static const DWORD PATTERNPAINT
= 0xFA0089UL
;
578 right
-= 2 * m_marginX
;
579 bottom
-= 2 * m_marginY
;
582 ::PatBlt( (HDC
) dc
, left
, top
, right
, bottom
, PATTERNPAINT
);
585 void wxBitmapButton::SetDefault()
587 wxButton::SetDefault();
590 wxSize
wxBitmapButton::DoGetBestSize() const
592 if ( m_bmpNormal
.Ok() )
594 int width
= m_bmpNormal
.GetWidth(),
595 height
= m_bmpNormal
.GetHeight();
600 if ( wxUxThemeEngine::GetIfActive() )
602 wxUxThemeHandle
theme((wxBitmapButton
*)this, L
"BUTTON");
605 wxUxThemeEngine::Get()->GetThemeMargins(theme
, NULL
,
606 BP_PUSHBUTTON
, PBS_NORMAL
,
607 TMT_CONTENTMARGINS
, NULL
,
610 // XP doesn't draw themed buttons correctly when the client area is
611 // smaller than 8x8 - enforce this minimum size for small bitmaps
617 // don't add margins for the borderless buttons, they don't need
618 // them and it just makes them appear larger than needed
619 if ( !HasFlag(wxBORDER_NONE
) )
621 // we need 2 extra pixels for the focus rectangle, without them
622 // it's overwritten by the bitmap itself
623 marginH
= margins
.cxLeftWidth
+ margins
.cxRightWidth
+ 2;
624 marginV
= margins
.cyTopHeight
+ margins
.cyBottomHeight
+ 2;
628 #endif // wxUSE_UXTHEME
630 if ( !HasFlag(wxBORDER_NONE
) )
632 marginH
= 2*m_marginX
;
633 marginV
= 2*m_marginY
;
637 wxSize
best(width
+ marginH
, height
+ marginV
);
642 // no idea what our best size should be, defer to the base class
643 return wxBitmapButtonBase::DoGetBestSize();
646 #endif // wxUSE_BMPBUTTON