]>
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 SetBitmapLabel(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
187 SetInitialSize(size
);
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::SetBitmapLabel(const wxBitmap
& bitmap
)
230 if ( !HasFlag(wxBU_AUTODRAW
) && !m_disabledSetByUser
&& bitmap
.IsOk() )
232 m_bmpDisabled
= wxBitmap(bitmap
.ConvertToImage().ConvertToGreyscale());
234 #endif // wxUSE_IMAGE
236 wxBitmapButtonBase::SetBitmapLabel(bitmap
);
239 void wxBitmapButton::SetBitmapFocus(const wxBitmap
& focus
)
241 // if the focus bitmap is specified but hover one isn't, use the focus
242 // bitmap for hovering as well if this is consistent with the current
243 // Windows version look and feel
245 // rationale: this is compatible with the old wxGTK behaviour and also
246 // makes it much easier to do "the right thing" for all platforms (some of
247 // them, such as Windows XP, have "hot" buttons while others don't)
248 if ( focus
.Ok() && !m_hoverSetByUser
)
249 m_bmpHover
= m_bmpFocus
;
251 wxBitmapButtonBase::SetBitmapFocus(focus
);
254 void wxBitmapButton::SetBitmapDisabled(const wxBitmap
& disabled
)
256 if ( disabled
.IsOk() )
257 m_disabledSetByUser
= true;
259 wxBitmapButtonBase::SetBitmapDisabled(disabled
);
262 void wxBitmapButton::SetBitmapHover(const wxBitmap
& hover
)
265 m_hoverSetByUser
= true;
267 wxBitmapButtonBase::SetBitmapHover(hover
);
272 void MSWDrawXPBackground(wxButton
*button
, WXDRAWITEMSTRUCT
*wxdis
)
274 LPDRAWITEMSTRUCT lpDIS
= (LPDRAWITEMSTRUCT
)wxdis
;
275 HDC hdc
= lpDIS
->hDC
;
276 UINT state
= lpDIS
->itemState
;
278 CopyRect(&rectBtn
, &lpDIS
->rcItem
);
280 wxUxThemeHandle
theme(button
, L
"BUTTON");
283 if ( state
& ODS_SELECTED
)
285 iState
= PBS_PRESSED
;
287 else if ( button
->HasCapture() || button
->IsMouseInWindow() )
291 else if ( state
& ODS_FOCUS
)
293 iState
= PBS_DEFAULTED
;
295 else if ( state
& ODS_DISABLED
)
297 iState
= PBS_DISABLED
;
304 // draw parent background if needed
305 if ( wxUxThemeEngine::Get()->IsThemeBackgroundPartiallyTransparent(theme
,
309 wxUxThemeEngine::Get()->DrawThemeParentBackground(GetHwndOf(button
), hdc
, &rectBtn
);
313 wxUxThemeEngine::Get()->DrawThemeBackground(theme
, hdc
, BP_PUSHBUTTON
, iState
,
316 // calculate content area margins
318 wxUxThemeEngine::Get()->GetThemeMargins(theme
, hdc
, BP_PUSHBUTTON
, iState
,
319 TMT_CONTENTMARGINS
, &rectBtn
, &margins
);
321 ::CopyRect(&rectClient
, &rectBtn
);
322 ::InflateRect(&rectClient
, -margins
.cxLeftWidth
, -margins
.cyTopHeight
);
324 // if focused and !nofocus rect
325 if ( (state
& ODS_FOCUS
) && !(state
& ODS_NOFOCUSRECT
) )
327 DrawFocusRect(hdc
, &rectClient
);
330 if ( button
->UseBgCol() )
332 COLORREF colBg
= wxColourToRGB(button
->GetBackgroundColour());
333 HBRUSH hbrushBackground
= ::CreateSolidBrush(colBg
);
335 // don't overwrite the focus rect
336 ::InflateRect(&rectClient
, -1, -1);
337 FillRect(hdc
, &rectClient
, hbrushBackground
);
338 ::DeleteObject(hbrushBackground
);
341 #endif // wxUSE_UXTHEME
343 // VZ: should be at the very least less than wxDEFAULT_BUTTON_MARGIN
344 #define FOCUS_MARGIN 3
346 bool wxBitmapButton::MSWOnDraw(WXDRAWITEMSTRUCT
*item
)
349 long style
= GetWindowLong((HWND
) GetHWND(), GWL_STYLE
);
350 if (style
& BS_BITMAP
)
352 // Let default procedure draw the bitmap, which is defined
353 // in the Windows resource.
358 LPDRAWITEMSTRUCT lpDIS
= (LPDRAWITEMSTRUCT
) item
;
359 HDC hDC
= lpDIS
->hDC
;
360 UINT state
= lpDIS
->itemState
;
361 bool isSelected
= (state
& ODS_SELECTED
) != 0;
362 bool autoDraw
= (GetWindowStyleFlag() & wxBU_AUTODRAW
) != 0;
365 // choose the bitmap to use depending on the button state
368 if ( isSelected
&& m_bmpSelected
.Ok() )
369 bitmap
= &m_bmpSelected
;
370 else if ( m_bmpHover
.Ok() && IsMouseInWindow() )
371 bitmap
= &m_bmpHover
;
372 else if ((state
& ODS_FOCUS
) && m_bmpFocus
.Ok())
373 bitmap
= &m_bmpFocus
;
374 else if ((state
& ODS_DISABLED
) && m_bmpDisabled
.Ok())
375 bitmap
= &m_bmpDisabled
;
377 bitmap
= &m_bmpNormal
;
382 // centre the bitmap in the control area
383 int x
= lpDIS
->rcItem
.left
;
384 int y
= lpDIS
->rcItem
.top
;
385 int width
= lpDIS
->rcItem
.right
- x
;
386 int height
= lpDIS
->rcItem
.bottom
- y
;
387 int wBmp
= bitmap
->GetWidth();
388 int hBmp
= bitmap
->GetHeight();
391 if ( autoDraw
&& wxUxThemeEngine::GetIfActive() )
393 MSWDrawXPBackground(this, item
);
394 wxUxThemeHandle
theme(this, L
"BUTTON");
396 // calculate content area margins
397 // assuming here that each state is the same size
399 wxUxThemeEngine::Get()->GetThemeMargins(theme
, NULL
,
400 BP_PUSHBUTTON
, PBS_NORMAL
,
401 TMT_CONTENTMARGINS
, NULL
,
403 int marginX
= margins
.cxLeftWidth
+ 1;
404 int marginY
= margins
.cyTopHeight
+ 1;
407 if ( m_windowStyle
& wxBU_LEFT
)
411 else if ( m_windowStyle
& wxBU_RIGHT
)
413 x1
= x
+ (width
- wBmp
) - marginX
;
417 x1
= x
+ (width
- wBmp
) / 2;
420 if ( m_windowStyle
& wxBU_TOP
)
424 else if ( m_windowStyle
& wxBU_BOTTOM
)
426 y1
= y
+ (height
- hBmp
) - marginY
;
430 y1
= y
+ (height
- hBmp
) / 2;
434 wxDCTemp
dst((WXHDC
)hDC
);
435 dst
.DrawBitmap(*bitmap
, x1
, y1
, true);
439 #endif // wxUSE_UXTHEME
443 if(m_windowStyle
& wxBU_LEFT
)
444 x1
= x
+ (FOCUS_MARGIN
+1);
445 else if(m_windowStyle
& wxBU_RIGHT
)
446 x1
= x
+ (width
- wBmp
) - (FOCUS_MARGIN
+1);
448 x1
= x
+ (width
- wBmp
) / 2;
450 if(m_windowStyle
& wxBU_TOP
)
451 y1
= y
+ (FOCUS_MARGIN
+1);
452 else if(m_windowStyle
& wxBU_BOTTOM
)
453 y1
= y
+ (height
- hBmp
) - (FOCUS_MARGIN
+1);
455 y1
= y
+ (height
- hBmp
) / 2;
457 if ( isSelected
&& autoDraw
)
463 // draw the face, if auto-drawing
466 DrawFace((WXHDC
) hDC
,
467 lpDIS
->rcItem
.left
, lpDIS
->rcItem
.top
,
468 lpDIS
->rcItem
.right
, lpDIS
->rcItem
.bottom
,
473 wxDCTemp
dst((WXHDC
)hDC
);
474 dst
.DrawBitmap(*bitmap
, x1
, y1
, true);
476 // draw focus / disabled state, if auto-drawing
477 if ( (state
& ODS_DISABLED
) && autoDraw
)
479 DrawButtonDisable((WXHDC
) hDC
,
480 lpDIS
->rcItem
.left
, lpDIS
->rcItem
.top
,
481 lpDIS
->rcItem
.right
, lpDIS
->rcItem
.bottom
,
484 else if ( (state
& ODS_FOCUS
) && autoDraw
)
486 DrawButtonFocus((WXHDC
) hDC
,
490 lpDIS
->rcItem
.bottom
,
497 // GRG Feb/2000, support for bmp buttons with Win95/98 standard LNF
499 void wxBitmapButton::DrawFace( WXHDC dc
, int left
, int top
,
500 int right
, int bottom
, bool sel
)
509 // create needed pens and brush
510 penHiLight
= CreatePen(PS_SOLID
, 0, GetSysColor(COLOR_3DHILIGHT
));
511 penLight
= CreatePen(PS_SOLID
, 0, GetSysColor(COLOR_3DLIGHT
));
512 penShadow
= CreatePen(PS_SOLID
, 0, GetSysColor(COLOR_3DSHADOW
));
513 penDkShadow
= CreatePen(PS_SOLID
, 0, GetSysColor(COLOR_3DDKSHADOW
));
514 brushFace
= CreateSolidBrush(GetSysColor(COLOR_BTNFACE
));
516 // draw the rectangle
521 rect
.bottom
= bottom
;
522 FillRect((HDC
) dc
, &rect
, brushFace
);
525 oldp
= (HPEN
) SelectObject( (HDC
) dc
, sel
? penDkShadow
: penHiLight
);
527 wxDrawLine((HDC
) dc
, left
, top
, right
-1, top
);
528 wxDrawLine((HDC
) dc
, left
, top
+1, left
, bottom
-1);
530 SelectObject( (HDC
) dc
, sel
? penShadow
: penLight
);
531 wxDrawLine((HDC
) dc
, left
+1, top
+1, right
-2, top
+1);
532 wxDrawLine((HDC
) dc
, left
+1, top
+2, left
+1, bottom
-2);
534 SelectObject( (HDC
) dc
, sel
? penLight
: penShadow
);
535 wxDrawLine((HDC
) dc
, left
+1, bottom
-2, right
-1, bottom
-2);
536 wxDrawLine((HDC
) dc
, right
-2, bottom
-3, right
-2, top
);
538 SelectObject( (HDC
) dc
, sel
? penHiLight
: penDkShadow
);
539 wxDrawLine((HDC
) dc
, left
, bottom
-1, right
+2, bottom
-1);
540 wxDrawLine((HDC
) dc
, right
-1, bottom
-2, right
-1, top
-1);
542 // delete allocated resources
543 SelectObject((HDC
) dc
,oldp
);
544 DeleteObject(penHiLight
);
545 DeleteObject(penLight
);
546 DeleteObject(penShadow
);
547 DeleteObject(penDkShadow
);
548 DeleteObject(brushFace
);
551 void wxBitmapButton::DrawButtonFocus( WXHDC dc
, int left
, int top
, int right
,
552 int bottom
, bool WXUNUSED(sel
) )
558 rect
.bottom
= bottom
;
559 InflateRect( &rect
, - FOCUS_MARGIN
, - FOCUS_MARGIN
);
561 // GRG: the focus rectangle should not move when the button is pushed!
564 OffsetRect( &rect, 1, 1 );
567 DrawFocusRect( (HDC
) dc
, &rect
);
571 wxBitmapButton::DrawButtonDisable( WXHDC dc
,
572 int left
, int top
, int right
, int bottom
,
575 if ( !m_brushDisabled
.Ok() )
577 // draw a bitmap with two black and two background colour pixels
580 dc
.SelectObject(bmp
);
581 dc
.SetPen(*wxBLACK_PEN
);
584 dc
.SetPen(GetBackgroundColour());
588 m_brushDisabled
= wxBrush(bmp
);
591 SelectInHDC
selectBrush((HDC
)dc
, GetHbrushOf(m_brushDisabled
));
593 // ROP for "dest |= pattern" operation -- as it doesn't have a standard
594 // name, give it our own
595 static const DWORD PATTERNPAINT
= 0xFA0089UL
;
601 right
-= 2 * m_marginX
;
602 bottom
-= 2 * m_marginY
;
605 ::PatBlt( (HDC
) dc
, left
, top
, right
, bottom
, PATTERNPAINT
);
608 wxSize
wxBitmapButton::DoGetBestSize() const
610 if ( m_bmpNormal
.Ok() )
612 int width
= m_bmpNormal
.GetWidth(),
613 height
= m_bmpNormal
.GetHeight();
618 if ( wxUxThemeEngine::GetIfActive() )
620 wxUxThemeHandle
theme((wxBitmapButton
*)this, L
"BUTTON");
623 wxUxThemeEngine::Get()->GetThemeMargins(theme
, NULL
,
624 BP_PUSHBUTTON
, PBS_NORMAL
,
625 TMT_CONTENTMARGINS
, NULL
,
628 // XP doesn't draw themed buttons correctly when the client area is
629 // smaller than 8x8 - enforce this minimum size for small bitmaps
635 // don't add margins for the borderless buttons, they don't need
636 // them and it just makes them appear larger than needed
637 if ( !HasFlag(wxBORDER_NONE
) )
639 // we need 2 extra pixels for the focus rectangle, without them
640 // it's overwritten by the bitmap itself
641 marginH
= margins
.cxLeftWidth
+ margins
.cxRightWidth
+ 2;
642 marginV
= margins
.cyTopHeight
+ margins
.cyBottomHeight
+ 2;
646 #endif // wxUSE_UXTHEME
648 if ( !HasFlag(wxBORDER_NONE
) )
650 marginH
= 2*m_marginX
;
651 marginV
= 2*m_marginY
;
655 wxSize
best(width
+ marginH
, height
+ marginV
);
660 // no idea what our best size should be, defer to the base class
661 return wxBitmapButtonBase::DoGetBestSize();
664 #endif // wxUSE_BMPBUTTON