]>
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_bitmaps
[State_Current
].IsOk() )
199 void wxBitmapButton::DoSetBitmap(const wxBitmap
& bitmap
, State which
)
207 if ( !HasFlag(wxBU_AUTODRAW
) && !m_disabledSetByUser
)
209 wxImage
img(bitmap
.ConvertToImage().ConvertToGreyscale());
210 m_bitmaps
[State_Disabled
] = wxBitmap(img
);
213 #endif // wxUSE_IMAGE
216 // if the focus bitmap is specified but current one isn't, use
217 // the focus bitmap for hovering as well if this is consistent
218 // with the current Windows version look and feel
220 // rationale: this is compatible with the old wxGTK behaviour
221 // and also makes it much easier to do "the right thing" for
222 // all platforms (some of them, such as Windows XP, have "hot"
223 // buttons while others don't)
224 if ( !m_hoverSetByUser
)
225 m_bitmaps
[State_Current
] = bitmap
;
229 // don't overwrite it with the focused bitmap
230 m_hoverSetByUser
= true;
234 // don't overwrite it with the version automatically created
235 // from the normal one
236 m_disabledSetByUser
= true;
241 wxBitmapButtonBase::DoSetBitmap(bitmap
, which
);
246 void MSWDrawXPBackground(wxButton
*button
, WXDRAWITEMSTRUCT
*wxdis
)
248 LPDRAWITEMSTRUCT lpDIS
= (LPDRAWITEMSTRUCT
)wxdis
;
249 HDC hdc
= lpDIS
->hDC
;
250 UINT state
= lpDIS
->itemState
;
252 CopyRect(&rectBtn
, &lpDIS
->rcItem
);
254 wxUxThemeHandle
theme(button
, L
"BUTTON");
257 if ( state
& ODS_SELECTED
)
259 iState
= PBS_PRESSED
;
261 else if ( button
->HasCapture() || button
->IsMouseInWindow() )
265 else if ( state
& ODS_FOCUS
)
267 iState
= PBS_DEFAULTED
;
269 else if ( state
& ODS_DISABLED
)
271 iState
= PBS_DISABLED
;
278 // draw parent background if needed
279 if ( wxUxThemeEngine::Get()->IsThemeBackgroundPartiallyTransparent(theme
,
283 wxUxThemeEngine::Get()->DrawThemeParentBackground(GetHwndOf(button
), hdc
, &rectBtn
);
287 wxUxThemeEngine::Get()->DrawThemeBackground(theme
, hdc
, BP_PUSHBUTTON
, iState
,
290 // calculate content area margins
292 wxUxThemeEngine::Get()->GetThemeMargins(theme
, hdc
, BP_PUSHBUTTON
, iState
,
293 TMT_CONTENTMARGINS
, &rectBtn
, &margins
);
295 ::CopyRect(&rectClient
, &rectBtn
);
296 ::InflateRect(&rectClient
, -margins
.cxLeftWidth
, -margins
.cyTopHeight
);
298 // if focused and !nofocus rect
299 if ( (state
& ODS_FOCUS
) && !(state
& ODS_NOFOCUSRECT
) )
301 DrawFocusRect(hdc
, &rectClient
);
304 if ( button
->UseBgCol() )
306 COLORREF colBg
= wxColourToRGB(button
->GetBackgroundColour());
307 HBRUSH hbrushBackground
= ::CreateSolidBrush(colBg
);
309 // don't overwrite the focus rect
310 ::InflateRect(&rectClient
, -1, -1);
311 FillRect(hdc
, &rectClient
, hbrushBackground
);
312 ::DeleteObject(hbrushBackground
);
315 #endif // wxUSE_UXTHEME
317 // VZ: should be at the very least less than wxDEFAULT_BUTTON_MARGIN
318 #define FOCUS_MARGIN 3
320 bool wxBitmapButton::MSWOnDraw(WXDRAWITEMSTRUCT
*item
)
323 long style
= GetWindowLong((HWND
) GetHWND(), GWL_STYLE
);
324 if (style
& BS_BITMAP
)
326 // Let default procedure draw the bitmap, which is defined
327 // in the Windows resource.
332 LPDRAWITEMSTRUCT lpDIS
= (LPDRAWITEMSTRUCT
) item
;
333 HDC hDC
= lpDIS
->hDC
;
334 UINT state
= lpDIS
->itemState
;
335 bool isSelected
= (state
& ODS_SELECTED
) != 0;
336 bool autoDraw
= HasFlag(wxBU_AUTODRAW
);
339 // choose the bitmap to use depending on the button state
343 bitmap
= GetBitmapSelected();
344 else if ( IsMouseInWindow() )
345 bitmap
= GetBitmapCurrent();
346 else if ( state
& ODS_DISABLED
)
347 bitmap
= GetBitmapDisabled();
349 if ( !bitmap
.IsOk() )
351 if ( state
& ODS_FOCUS
)
352 bitmap
= GetBitmapFocus();
354 if ( !bitmap
.IsOk() )
355 bitmap
= GetBitmapLabel();
357 if ( !bitmap
.IsOk() )
361 // centre the bitmap in the control area
362 int x
= lpDIS
->rcItem
.left
;
363 int y
= lpDIS
->rcItem
.top
;
364 int width
= lpDIS
->rcItem
.right
- x
;
365 int height
= lpDIS
->rcItem
.bottom
- y
;
366 int wBmp
= bitmap
.GetWidth();
367 int hBmp
= bitmap
.GetHeight();
370 if ( autoDraw
&& wxUxThemeEngine::GetIfActive() )
372 MSWDrawXPBackground(this, item
);
373 wxUxThemeHandle
theme(this, L
"BUTTON");
375 // calculate content area margins
376 // assuming here that each state is the same size
378 wxUxThemeEngine::Get()->GetThemeMargins(theme
, NULL
,
379 BP_PUSHBUTTON
, PBS_NORMAL
,
380 TMT_CONTENTMARGINS
, NULL
,
382 int marginX
= margins
.cxLeftWidth
+ 1;
383 int marginY
= margins
.cyTopHeight
+ 1;
386 if ( m_windowStyle
& wxBU_LEFT
)
390 else if ( m_windowStyle
& wxBU_RIGHT
)
392 x1
= x
+ (width
- wBmp
) - marginX
;
396 x1
= x
+ (width
- wBmp
) / 2;
399 if ( m_windowStyle
& wxBU_TOP
)
403 else if ( m_windowStyle
& wxBU_BOTTOM
)
405 y1
= y
+ (height
- hBmp
) - marginY
;
409 y1
= y
+ (height
- hBmp
) / 2;
413 wxDCTemp
dst((WXHDC
)hDC
);
414 dst
.DrawBitmap(bitmap
, x1
, y1
, true);
418 #endif // wxUSE_UXTHEME
422 if(m_windowStyle
& wxBU_LEFT
)
423 x1
= x
+ (FOCUS_MARGIN
+1);
424 else if(m_windowStyle
& wxBU_RIGHT
)
425 x1
= x
+ (width
- wBmp
) - (FOCUS_MARGIN
+1);
427 x1
= x
+ (width
- wBmp
) / 2;
429 if(m_windowStyle
& wxBU_TOP
)
430 y1
= y
+ (FOCUS_MARGIN
+1);
431 else if(m_windowStyle
& wxBU_BOTTOM
)
432 y1
= y
+ (height
- hBmp
) - (FOCUS_MARGIN
+1);
434 y1
= y
+ (height
- hBmp
) / 2;
436 if ( isSelected
&& autoDraw
)
442 // draw the face, if auto-drawing
445 DrawFace((WXHDC
) hDC
,
446 lpDIS
->rcItem
.left
, lpDIS
->rcItem
.top
,
447 lpDIS
->rcItem
.right
, lpDIS
->rcItem
.bottom
,
452 wxDCTemp
dst((WXHDC
)hDC
);
453 dst
.DrawBitmap(bitmap
, x1
, y1
, true);
455 // draw focus / disabled state, if auto-drawing
456 if ( (state
& ODS_DISABLED
) && autoDraw
)
458 DrawButtonDisable((WXHDC
) hDC
,
459 lpDIS
->rcItem
.left
, lpDIS
->rcItem
.top
,
460 lpDIS
->rcItem
.right
, lpDIS
->rcItem
.bottom
,
463 else if ( (state
& ODS_FOCUS
) && autoDraw
)
465 DrawButtonFocus((WXHDC
) hDC
,
469 lpDIS
->rcItem
.bottom
,
476 // GRG Feb/2000, support for bmp buttons with Win95/98 standard LNF
478 void wxBitmapButton::DrawFace( WXHDC dc
, int left
, int top
,
479 int right
, int bottom
, bool sel
)
488 // create needed pens and brush
489 penHiLight
= CreatePen(PS_SOLID
, 0, GetSysColor(COLOR_3DHILIGHT
));
490 penLight
= CreatePen(PS_SOLID
, 0, GetSysColor(COLOR_3DLIGHT
));
491 penShadow
= CreatePen(PS_SOLID
, 0, GetSysColor(COLOR_3DSHADOW
));
492 penDkShadow
= CreatePen(PS_SOLID
, 0, GetSysColor(COLOR_3DDKSHADOW
));
493 brushFace
= CreateSolidBrush(GetSysColor(COLOR_BTNFACE
));
495 // draw the rectangle
500 rect
.bottom
= bottom
;
501 FillRect((HDC
) dc
, &rect
, brushFace
);
504 oldp
= (HPEN
) SelectObject( (HDC
) dc
, sel
? penDkShadow
: penHiLight
);
506 wxDrawLine((HDC
) dc
, left
, top
, right
-1, top
);
507 wxDrawLine((HDC
) dc
, left
, top
+1, left
, bottom
-1);
509 SelectObject( (HDC
) dc
, sel
? penShadow
: penLight
);
510 wxDrawLine((HDC
) dc
, left
+1, top
+1, right
-2, top
+1);
511 wxDrawLine((HDC
) dc
, left
+1, top
+2, left
+1, bottom
-2);
513 SelectObject( (HDC
) dc
, sel
? penLight
: penShadow
);
514 wxDrawLine((HDC
) dc
, left
+1, bottom
-2, right
-1, bottom
-2);
515 wxDrawLine((HDC
) dc
, right
-2, bottom
-3, right
-2, top
);
517 SelectObject( (HDC
) dc
, sel
? penHiLight
: penDkShadow
);
518 wxDrawLine((HDC
) dc
, left
, bottom
-1, right
+2, bottom
-1);
519 wxDrawLine((HDC
) dc
, right
-1, bottom
-2, right
-1, top
-1);
521 // delete allocated resources
522 SelectObject((HDC
) dc
,oldp
);
523 DeleteObject(penHiLight
);
524 DeleteObject(penLight
);
525 DeleteObject(penShadow
);
526 DeleteObject(penDkShadow
);
527 DeleteObject(brushFace
);
530 void wxBitmapButton::DrawButtonFocus( WXHDC dc
, int left
, int top
, int right
,
531 int bottom
, bool WXUNUSED(sel
) )
537 rect
.bottom
= bottom
;
538 InflateRect( &rect
, - FOCUS_MARGIN
, - FOCUS_MARGIN
);
540 // GRG: the focus rectangle should not move when the button is pushed!
543 OffsetRect( &rect, 1, 1 );
546 DrawFocusRect( (HDC
) dc
, &rect
);
550 wxBitmapButton::DrawButtonDisable( WXHDC dc
,
551 int left
, int top
, int right
, int bottom
,
554 if ( !m_brushDisabled
.IsOk() )
556 // draw a bitmap with two black and two background colour pixels
559 dc
.SelectObject(bmp
);
560 dc
.SetPen(*wxBLACK_PEN
);
563 dc
.SetPen(GetBackgroundColour());
567 m_brushDisabled
= wxBrush(bmp
);
570 SelectInHDC
selectBrush((HDC
)dc
, GetHbrushOf(m_brushDisabled
));
572 // ROP for "dest |= pattern" operation -- as it doesn't have a standard
573 // name, give it our own
574 static const DWORD PATTERNPAINT
= 0xFA0089UL
;
580 right
-= 2 * m_marginX
;
581 bottom
-= 2 * m_marginY
;
584 ::PatBlt( (HDC
) dc
, left
, top
, right
, bottom
, PATTERNPAINT
);
587 wxSize
wxBitmapButton::DoGetBestSize() const
589 if ( GetBitmapLabel().IsOk() )
591 int width
= GetBitmapLabel().GetWidth(),
592 height
= GetBitmapLabel().GetHeight();
597 if ( wxUxThemeEngine::GetIfActive() )
599 wxUxThemeHandle
theme((wxBitmapButton
*)this, L
"BUTTON");
602 wxUxThemeEngine::Get()->GetThemeMargins(theme
, NULL
,
603 BP_PUSHBUTTON
, PBS_NORMAL
,
604 TMT_CONTENTMARGINS
, NULL
,
607 // XP doesn't draw themed buttons correctly when the client area is
608 // smaller than 8x8 - enforce this minimum size for small bitmaps
614 // don't add margins for the borderless buttons, they don't need
615 // them and it just makes them appear larger than needed
616 if ( !HasFlag(wxBORDER_NONE
) )
618 // we need 2 extra pixels for the focus rectangle, without them
619 // it's overwritten by the bitmap itself
620 marginH
= margins
.cxLeftWidth
+ margins
.cxRightWidth
+ 2;
621 marginV
= margins
.cyTopHeight
+ margins
.cyBottomHeight
+ 2;
625 #endif // wxUSE_UXTHEME
627 if ( !HasFlag(wxBORDER_NONE
) )
629 marginH
= 2*m_marginX
;
630 marginV
= 2*m_marginY
;
634 wxSize
best(width
+ marginH
, height
+ marginV
);
639 // no idea what our best size should be, defer to the base class
640 return wxBitmapButtonBase::DoGetBestSize();
643 #endif // wxUSE_BMPBUTTON