]>
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"
30 #include "wx/msw/dc.h" // for wxDCTemp
32 #include "wx/msw/uxtheme.h"
35 // no need to include tmschema.h
37 #define BP_PUSHBUTTON 1
42 #define PBS_DISABLED 4
43 #define PBS_DEFAULTED 5
45 #define TMT_CONTENTMARGINS 3602
47 #endif // wxUSE_UXTHEME
49 #ifndef ODS_NOFOCUSRECT
50 #define ODS_NOFOCUSRECT 0x0200
53 // ----------------------------------------------------------------------------
55 // ----------------------------------------------------------------------------
57 #if wxUSE_EXTENDED_RTTI
59 WX_DEFINE_FLAGS( wxBitmapButtonStyle
)
61 wxBEGIN_FLAGS( wxBitmapButtonStyle
)
62 // new style border flags, we put them first to
63 // use them for streaming out
64 wxFLAGS_MEMBER(wxBORDER_SIMPLE
)
65 wxFLAGS_MEMBER(wxBORDER_SUNKEN
)
66 wxFLAGS_MEMBER(wxBORDER_DOUBLE
)
67 wxFLAGS_MEMBER(wxBORDER_RAISED
)
68 wxFLAGS_MEMBER(wxBORDER_STATIC
)
69 wxFLAGS_MEMBER(wxBORDER_NONE
)
71 // old style border flags
72 wxFLAGS_MEMBER(wxSIMPLE_BORDER
)
73 wxFLAGS_MEMBER(wxSUNKEN_BORDER
)
74 wxFLAGS_MEMBER(wxDOUBLE_BORDER
)
75 wxFLAGS_MEMBER(wxRAISED_BORDER
)
76 wxFLAGS_MEMBER(wxSTATIC_BORDER
)
77 wxFLAGS_MEMBER(wxBORDER
)
79 // standard window styles
80 wxFLAGS_MEMBER(wxTAB_TRAVERSAL
)
81 wxFLAGS_MEMBER(wxCLIP_CHILDREN
)
82 wxFLAGS_MEMBER(wxTRANSPARENT_WINDOW
)
83 wxFLAGS_MEMBER(wxWANTS_CHARS
)
84 wxFLAGS_MEMBER(wxFULL_REPAINT_ON_RESIZE
)
85 wxFLAGS_MEMBER(wxALWAYS_SHOW_SB
)
86 wxFLAGS_MEMBER(wxVSCROLL
)
87 wxFLAGS_MEMBER(wxHSCROLL
)
89 wxFLAGS_MEMBER(wxBU_AUTODRAW
)
90 wxFLAGS_MEMBER(wxBU_LEFT
)
91 wxFLAGS_MEMBER(wxBU_RIGHT
)
92 wxFLAGS_MEMBER(wxBU_TOP
)
93 wxFLAGS_MEMBER(wxBU_BOTTOM
)
94 wxEND_FLAGS( wxBitmapButtonStyle
)
96 IMPLEMENT_DYNAMIC_CLASS_XTI(wxBitmapButton
, wxButton
,"wx/bmpbuttn.h")
98 wxBEGIN_PROPERTIES_TABLE(wxBitmapButton
)
99 wxPROPERTY_FLAGS( WindowStyle
, wxBitmapButtonStyle
, long , SetWindowStyleFlag
, GetWindowStyleFlag
, EMPTY_MACROVALUE
, 0 /*flags*/ , wxT("Helpstring") , wxT("group")) // style
100 wxEND_PROPERTIES_TABLE()
102 wxBEGIN_HANDLERS_TABLE(wxBitmapButton
)
103 wxEND_HANDLERS_TABLE()
105 wxCONSTRUCTOR_5( wxBitmapButton
, wxWindow
* , Parent
, wxWindowID
, Id
, wxBitmap
, Bitmap
, wxPoint
, Position
, wxSize
, Size
)
108 IMPLEMENT_DYNAMIC_CLASS(wxBitmapButton
, wxButton
)
111 BEGIN_EVENT_TABLE(wxBitmapButton
, wxBitmapButtonBase
)
112 EVT_SYS_COLOUR_CHANGED(wxBitmapButton::OnSysColourChanged
)
113 EVT_ENTER_WINDOW(wxBitmapButton::OnMouseEnterOrLeave
)
114 EVT_LEAVE_WINDOW(wxBitmapButton::OnMouseEnterOrLeave
)
120 long "style" , wxBU_AUTODRAW
127 bool wxBitmapButton::Create(wxWindow
*parent
,
129 const wxBitmap
& bitmap
,
131 const wxSize
& size
, long style
,
132 const wxValidator
& wxVALIDATOR_PARAM(validator
),
133 const wxString
& name
)
135 if ( !CreateControl(parent
, id
, pos
, size
, style
, validator
, name
) )
138 SetBitmapLabel(bitmap
);
140 if ( style
& wxBU_AUTODRAW
)
143 return MSWCreateControl(_T("BUTTON"), wxEmptyString
, pos
, size
);
146 WXDWORD
wxBitmapButton::MSWGetStyle(long style
, WXDWORD
*exstyle
) const
148 WXDWORD msStyle
= wxButton::MSWGetStyle(style
, exstyle
);
150 msStyle
|= BS_OWNERDRAW
;
152 if ( style
& wxBU_LEFT
)
154 if ( style
& wxBU_RIGHT
)
156 if ( style
& wxBU_TOP
)
158 if ( style
& wxBU_BOTTOM
)
159 msStyle
|= BS_BOTTOM
;
164 bool wxBitmapButton::SetBackgroundColour(const wxColour
& colour
)
166 if ( !wxBitmapButtonBase::SetBackgroundColour(colour
) )
172 // invalidate the brush, it will be recreated the next time it's needed
173 m_brushDisabled
= wxNullBrush
;
178 void wxBitmapButton::OnSysColourChanged(wxSysColourChangedEvent
& event
)
180 m_brushDisabled
= wxNullBrush
;
184 // this change affects our current state
191 void wxBitmapButton::OnMouseEnterOrLeave(wxMouseEvent
& event
)
193 if ( IsEnabled() && m_bmpHover
.Ok() )
199 void wxBitmapButton::SetBitmapLabel(const wxBitmap
& bitmap
)
202 if ( !HasFlag(wxBU_AUTODRAW
) && !m_disabledSetByUser
&& bitmap
.IsOk() )
204 m_bmpDisabled
= wxBitmap(bitmap
.ConvertToImage().ConvertToGreyscale());
206 #endif // wxUSE_IMAGE
208 wxBitmapButtonBase::SetBitmapLabel(bitmap
);
211 void wxBitmapButton::SetBitmapFocus(const wxBitmap
& focus
)
213 // if the focus bitmap is specified but hover one isn't, use the focus
214 // bitmap for hovering as well if this is consistent with the current
215 // Windows version look and feel
217 // rationale: this is compatible with the old wxGTK behaviour and also
218 // makes it much easier to do "the right thing" for all platforms (some of
219 // them, such as Windows XP, have "hot" buttons while others don't)
220 if ( focus
.Ok() && !m_hoverSetByUser
)
221 m_bmpHover
= m_bmpFocus
;
223 wxBitmapButtonBase::SetBitmapFocus(focus
);
226 void wxBitmapButton::SetBitmapDisabled(const wxBitmap
& disabled
)
228 if ( disabled
.IsOk() )
229 m_disabledSetByUser
= true;
231 wxBitmapButtonBase::SetBitmapDisabled(disabled
);
234 void wxBitmapButton::SetBitmapHover(const wxBitmap
& hover
)
237 m_hoverSetByUser
= true;
239 wxBitmapButtonBase::SetBitmapHover(hover
);
244 void MSWDrawXPBackground(wxButton
*button
, WXDRAWITEMSTRUCT
*wxdis
)
246 LPDRAWITEMSTRUCT lpDIS
= (LPDRAWITEMSTRUCT
)wxdis
;
247 HDC hdc
= lpDIS
->hDC
;
248 UINT state
= lpDIS
->itemState
;
250 CopyRect(&rectBtn
, &lpDIS
->rcItem
);
252 wxUxThemeHandle
theme(button
, L
"BUTTON");
255 if ( state
& ODS_SELECTED
)
257 iState
= PBS_PRESSED
;
259 else if ( button
->HasCapture() || button
->IsMouseInWindow() )
263 else if ( state
& ODS_FOCUS
)
265 iState
= PBS_DEFAULTED
;
267 else if ( state
& ODS_DISABLED
)
269 iState
= PBS_DISABLED
;
276 // draw parent background if needed
277 if ( wxUxThemeEngine::Get()->IsThemeBackgroundPartiallyTransparent(theme
,
281 wxUxThemeEngine::Get()->DrawThemeParentBackground(GetHwndOf(button
), hdc
, &rectBtn
);
285 wxUxThemeEngine::Get()->DrawThemeBackground(theme
, hdc
, BP_PUSHBUTTON
, iState
,
288 // calculate content area margins
290 wxUxThemeEngine::Get()->GetThemeMargins(theme
, hdc
, BP_PUSHBUTTON
, iState
,
291 TMT_CONTENTMARGINS
, &rectBtn
, &margins
);
293 ::CopyRect(&rectClient
, &rectBtn
);
294 ::InflateRect(&rectClient
, -margins
.cxLeftWidth
, -margins
.cyTopHeight
);
296 // if focused and !nofocus rect
297 if ( (state
& ODS_FOCUS
) && !(state
& ODS_NOFOCUSRECT
) )
299 DrawFocusRect(hdc
, &rectClient
);
302 if ( button
->UseBgCol() )
304 COLORREF colBg
= wxColourToRGB(button
->GetBackgroundColour());
305 HBRUSH hbrushBackground
= ::CreateSolidBrush(colBg
);
307 // don't overwrite the focus rect
308 ::InflateRect(&rectClient
, -1, -1);
309 FillRect(hdc
, &rectClient
, hbrushBackground
);
310 ::DeleteObject(hbrushBackground
);
313 #endif // wxUSE_UXTHEME
315 // VZ: should be at the very least less than wxDEFAULT_BUTTON_MARGIN
316 #define FOCUS_MARGIN 3
318 bool wxBitmapButton::MSWOnDraw(WXDRAWITEMSTRUCT
*item
)
321 long style
= GetWindowLong((HWND
) GetHWND(), GWL_STYLE
);
322 if (style
& BS_BITMAP
)
324 // Let default procedure draw the bitmap, which is defined
325 // in the Windows resource.
330 LPDRAWITEMSTRUCT lpDIS
= (LPDRAWITEMSTRUCT
) item
;
331 HDC hDC
= lpDIS
->hDC
;
332 UINT state
= lpDIS
->itemState
;
333 bool isSelected
= (state
& ODS_SELECTED
) != 0;
334 bool autoDraw
= (GetWindowStyleFlag() & wxBU_AUTODRAW
) != 0;
337 // choose the bitmap to use depending on the button state
340 if ( isSelected
&& m_bmpSelected
.Ok() )
341 bitmap
= &m_bmpSelected
;
342 else if ( m_bmpHover
.Ok() && IsMouseInWindow() )
343 bitmap
= &m_bmpHover
;
344 else if ((state
& ODS_FOCUS
) && m_bmpFocus
.Ok())
345 bitmap
= &m_bmpFocus
;
346 else if ((state
& ODS_DISABLED
) && m_bmpDisabled
.Ok())
347 bitmap
= &m_bmpDisabled
;
349 bitmap
= &m_bmpNormal
;
354 // centre the bitmap in the control area
355 int x
= lpDIS
->rcItem
.left
;
356 int y
= lpDIS
->rcItem
.top
;
357 int width
= lpDIS
->rcItem
.right
- x
;
358 int height
= lpDIS
->rcItem
.bottom
- y
;
359 int wBmp
= bitmap
->GetWidth();
360 int hBmp
= bitmap
->GetHeight();
363 if ( autoDraw
&& wxUxThemeEngine::GetIfActive() )
365 MSWDrawXPBackground(this, item
);
366 wxUxThemeHandle
theme(this, L
"BUTTON");
368 // calculate content area margins
369 // assuming here that each state is the same size
371 wxUxThemeEngine::Get()->GetThemeMargins(theme
, NULL
,
372 BP_PUSHBUTTON
, PBS_NORMAL
,
373 TMT_CONTENTMARGINS
, NULL
,
375 int marginX
= margins
.cxLeftWidth
+ 1;
376 int marginY
= margins
.cyTopHeight
+ 1;
379 if ( m_windowStyle
& wxBU_LEFT
)
383 else if ( m_windowStyle
& wxBU_RIGHT
)
385 x1
= x
+ (width
- wBmp
) - marginX
;
389 x1
= x
+ (width
- wBmp
) / 2;
392 if ( m_windowStyle
& wxBU_TOP
)
396 else if ( m_windowStyle
& wxBU_BOTTOM
)
398 y1
= y
+ (height
- hBmp
) - marginY
;
402 y1
= y
+ (height
- hBmp
) / 2;
406 wxDCTemp
dst((WXHDC
)hDC
);
407 dst
.DrawBitmap(*bitmap
, x1
, y1
, true);
411 #endif // wxUSE_UXTHEME
415 if(m_windowStyle
& wxBU_LEFT
)
416 x1
= x
+ (FOCUS_MARGIN
+1);
417 else if(m_windowStyle
& wxBU_RIGHT
)
418 x1
= x
+ (width
- wBmp
) - (FOCUS_MARGIN
+1);
420 x1
= x
+ (width
- wBmp
) / 2;
422 if(m_windowStyle
& wxBU_TOP
)
423 y1
= y
+ (FOCUS_MARGIN
+1);
424 else if(m_windowStyle
& wxBU_BOTTOM
)
425 y1
= y
+ (height
- hBmp
) - (FOCUS_MARGIN
+1);
427 y1
= y
+ (height
- hBmp
) / 2;
429 if ( isSelected
&& autoDraw
)
435 // draw the face, if auto-drawing
438 DrawFace((WXHDC
) hDC
,
439 lpDIS
->rcItem
.left
, lpDIS
->rcItem
.top
,
440 lpDIS
->rcItem
.right
, lpDIS
->rcItem
.bottom
,
445 wxDCTemp
dst((WXHDC
)hDC
);
446 dst
.DrawBitmap(*bitmap
, x1
, y1
, true);
448 // draw focus / disabled state, if auto-drawing
449 if ( (state
& ODS_DISABLED
) && autoDraw
)
451 DrawButtonDisable((WXHDC
) hDC
,
452 lpDIS
->rcItem
.left
, lpDIS
->rcItem
.top
,
453 lpDIS
->rcItem
.right
, lpDIS
->rcItem
.bottom
,
456 else if ( (state
& ODS_FOCUS
) && autoDraw
)
458 DrawButtonFocus((WXHDC
) hDC
,
462 lpDIS
->rcItem
.bottom
,
469 // GRG Feb/2000, support for bmp buttons with Win95/98 standard LNF
471 void wxBitmapButton::DrawFace( WXHDC dc
, int left
, int top
,
472 int right
, int bottom
, bool sel
)
481 // create needed pens and brush
482 penHiLight
= CreatePen(PS_SOLID
, 0, GetSysColor(COLOR_3DHILIGHT
));
483 penLight
= CreatePen(PS_SOLID
, 0, GetSysColor(COLOR_3DLIGHT
));
484 penShadow
= CreatePen(PS_SOLID
, 0, GetSysColor(COLOR_3DSHADOW
));
485 penDkShadow
= CreatePen(PS_SOLID
, 0, GetSysColor(COLOR_3DDKSHADOW
));
486 brushFace
= CreateSolidBrush(GetSysColor(COLOR_BTNFACE
));
488 // draw the rectangle
493 rect
.bottom
= bottom
;
494 FillRect((HDC
) dc
, &rect
, brushFace
);
497 oldp
= (HPEN
) SelectObject( (HDC
) dc
, sel
? penDkShadow
: penHiLight
);
499 wxDrawLine((HDC
) dc
, left
, top
, right
-1, top
);
500 wxDrawLine((HDC
) dc
, left
, top
+1, left
, bottom
-1);
502 SelectObject( (HDC
) dc
, sel
? penShadow
: penLight
);
503 wxDrawLine((HDC
) dc
, left
+1, top
+1, right
-2, top
+1);
504 wxDrawLine((HDC
) dc
, left
+1, top
+2, left
+1, bottom
-2);
506 SelectObject( (HDC
) dc
, sel
? penLight
: penShadow
);
507 wxDrawLine((HDC
) dc
, left
+1, bottom
-2, right
-1, bottom
-2);
508 wxDrawLine((HDC
) dc
, right
-2, bottom
-3, right
-2, top
);
510 SelectObject( (HDC
) dc
, sel
? penHiLight
: penDkShadow
);
511 wxDrawLine((HDC
) dc
, left
, bottom
-1, right
+2, bottom
-1);
512 wxDrawLine((HDC
) dc
, right
-1, bottom
-2, right
-1, top
-1);
514 // delete allocated resources
515 SelectObject((HDC
) dc
,oldp
);
516 DeleteObject(penHiLight
);
517 DeleteObject(penLight
);
518 DeleteObject(penShadow
);
519 DeleteObject(penDkShadow
);
520 DeleteObject(brushFace
);
523 void wxBitmapButton::DrawButtonFocus( WXHDC dc
, int left
, int top
, int right
,
524 int bottom
, bool WXUNUSED(sel
) )
530 rect
.bottom
= bottom
;
531 InflateRect( &rect
, - FOCUS_MARGIN
, - FOCUS_MARGIN
);
533 // GRG: the focus rectangle should not move when the button is pushed!
536 OffsetRect( &rect, 1, 1 );
539 DrawFocusRect( (HDC
) dc
, &rect
);
543 wxBitmapButton::DrawButtonDisable( WXHDC dc
,
544 int left
, int top
, int right
, int bottom
,
547 if ( !m_brushDisabled
.Ok() )
549 // draw a bitmap with two black and two background colour pixels
552 dc
.SelectObject(bmp
);
553 dc
.SetPen(*wxBLACK_PEN
);
556 dc
.SetPen(GetBackgroundColour());
560 m_brushDisabled
= wxBrush(bmp
);
563 SelectInHDC
selectBrush((HDC
)dc
, GetHbrushOf(m_brushDisabled
));
565 // ROP for "dest |= pattern" operation -- as it doesn't have a standard
566 // name, give it our own
567 static const DWORD PATTERNPAINT
= 0xFA0089UL
;
573 right
-= 2 * m_marginX
;
574 bottom
-= 2 * m_marginY
;
577 ::PatBlt( (HDC
) dc
, left
, top
, right
, bottom
, PATTERNPAINT
);
580 wxSize
wxBitmapButton::DoGetBestSize() const
582 if ( m_bmpNormal
.Ok() )
584 int width
= m_bmpNormal
.GetWidth(),
585 height
= m_bmpNormal
.GetHeight();
590 if ( wxUxThemeEngine::GetIfActive() )
592 wxUxThemeHandle
theme((wxBitmapButton
*)this, L
"BUTTON");
595 wxUxThemeEngine::Get()->GetThemeMargins(theme
, NULL
,
596 BP_PUSHBUTTON
, PBS_NORMAL
,
597 TMT_CONTENTMARGINS
, NULL
,
600 // XP doesn't draw themed buttons correctly when the client area is
601 // smaller than 8x8 - enforce this minimum size for small bitmaps
607 // don't add margins for the borderless buttons, they don't need
608 // them and it just makes them appear larger than needed
609 if ( !HasFlag(wxBORDER_NONE
) )
611 // we need 2 extra pixels for the focus rectangle, without them
612 // it's overwritten by the bitmap itself
613 marginH
= margins
.cxLeftWidth
+ margins
.cxRightWidth
+ 2;
614 marginV
= margins
.cyTopHeight
+ margins
.cyBottomHeight
+ 2;
618 #endif // wxUSE_UXTHEME
620 if ( !HasFlag(wxBORDER_NONE
) )
622 marginH
= 2*m_marginX
;
623 marginV
= 2*m_marginY
;
627 wxSize
best(width
+ marginH
, height
+ marginV
);
632 // no idea what our best size should be, defer to the base class
633 return wxBitmapButtonBase::DoGetBestSize();
636 #endif // wxUSE_BMPBUTTON