diff --git a/include/wx/msw/checkbox.h b/include/wx/msw/checkbox.h index 285fff555b..579e197f9d 100644 --- a/include/wx/msw/checkbox.h +++ b/include/wx/msw/checkbox.h @@ -11,8 +11,10 @@ #ifndef _WX_CHECKBOX_H_ #define _WX_CHECKBOX_H_ +#include "wx/msw/ownerdrawnbutton.h" + // Checkbox item (single checkbox) -class WXDLLIMPEXP_CORE wxCheckBox : public wxCheckBoxBase +class WXDLLIMPEXP_CORE wxCheckBox : public wxMSWOwnerDrawnButton { public: wxCheckBox() { } @@ -45,15 +47,10 @@ public: virtual bool MSWCommand(WXUINT param, WXWORD id); virtual void Command(wxCommandEvent& event); - virtual bool SetForegroundColour(const wxColour& colour); - virtual bool MSWOnDraw(WXDRAWITEMSTRUCT *item); // returns true if the platform should explicitly apply a theme border virtual bool CanApplyThemeBorder() const { return false; } - // make the checkbox owner drawn or reset it to normal style - void MSWMakeOwnerDrawn(bool ownerDrawn); - // implementation only from now on virtual WXDWORD MSWGetStyle(long flags, WXDWORD *exstyle = NULL) const; @@ -62,32 +59,21 @@ protected: virtual void DoSet3StateValue(wxCheckBoxState value); virtual wxCheckBoxState DoGet3StateValue() const; - virtual void MSWDrawButtonBitmap(wxWindow *win, wxDC& dc, - const wxRect& rect, int flags); - // return true if this checkbox is owner drawn - bool IsOwnerDrawn() const; + // Implement wxMSWOwnerDrawnButtonBase methods. + virtual int MSWGetButtonStyle() const wxOVERRIDE; + virtual void MSWOnButtonResetOwnerDrawn() wxOVERRIDE; + virtual int MSWGetButtonCheckedFlag() const wxOVERRIDE; + virtual void + MSWDrawButtonBitmap(wxDC& dc, const wxRect& rect, int flags) wxOVERRIDE; private: // common part of all ctors void Init(); - // event handlers used by owner-drawn checkbox - void OnMouseEnterOrLeave(wxMouseEvent& event); - void OnMouseLeft(wxMouseEvent& event); - void OnFocus(wxFocusEvent& event); - - // current state of the checkbox wxCheckBoxState m_state; - // true if the checkbox is currently pressed - bool m_isPressed; - - // true if mouse is currently over the control - bool m_isHot; - - DECLARE_DYNAMIC_CLASS_NO_COPY(wxCheckBox) }; diff --git a/include/wx/msw/control.h b/include/wx/msw/control.h index 113bc91352..f4969b3f0f 100644 --- a/include/wx/msw/control.h +++ b/include/wx/msw/control.h @@ -124,10 +124,6 @@ protected: // Look in our GetSubcontrols() for the windows with the given ID. virtual wxWindow *MSWFindItem(long id, WXHWND hWnd) const; - // For ownerdraw buttons - virtual bool MSWOwnerDrawnButton(const DRAWITEMSTRUCT *dis, int flags, bool isFocused); - virtual void MSWDrawButtonBitmap(wxWindow *WXUNUSED(win), wxDC& WXUNUSED(dc), - const wxRect& WXUNUSED(rect), int WXUNUSED(flags)) {} // for controls like radiobuttons which are really composite this array // holds the ids (not HWNDs!) of the sub controls diff --git a/include/wx/msw/ownerdrawnbutton.h b/include/wx/msw/ownerdrawnbutton.h new file mode 100644 index 0000000000..19a35031d6 --- /dev/null +++ b/include/wx/msw/ownerdrawnbutton.h @@ -0,0 +1,122 @@ +/////////////////////////////////////////////////////////////////////////////// +// Name: wx/msw/ownerdrawnbutton.h +// Purpose: Common base class for wxCheckBox and wxRadioButton +// Author: Vadim Zeitlin +// Created: 2014-05-04 +// Copyright: (c) 2014 Vadim Zeitlin +// Licence: wxWindows licence +/////////////////////////////////////////////////////////////////////////////// + +#ifndef _WX_MSW_OWNERDRAWNBUTTON_H_ +#define _WX_MSW_OWNERDRAWNBUTTON_H_ + +// ---------------------------------------------------------------------------- +// wxMSWOwnerDrawnButton: base class for any kind of Windows buttons +// ---------------------------------------------------------------------------- + +// This class contains the type-independent part of wxMSWOwnerDrawnButton and +// is implemented in src/msw/control.cpp. +// +// Notice that it is intentionally not exported, it is internal implementation +// detail only. +class wxMSWOwnerDrawnButtonBase +{ +protected: + // Ctor takes the back pointer to the real window, must be non-NULL. + wxMSWOwnerDrawnButtonBase(wxWindow* win) : + m_win(win) + { + m_isPressed = + m_isHot = false; + } + + // Make the control owner drawn if necessary to implement support for the + // given foreground colour. + void MSWMakeOwnerDrawnIfNecessary(const wxColour& colFg); + + // Return true if the control is currently owner drawn. + bool MSWIsOwnerDrawn() const; + + // Draw the button if the message information about which is provided in + // the given DRAWITEMSTRUCT asks us to do it, otherwise just return false. + bool MSWDrawButton(WXDRAWITEMSTRUCT *item); + + + // Methods which must be overridden in the derived concrete class. + + // Return the style to use for the non-owner-drawn button. + virtual int MSWGetButtonStyle() const = 0; + + // Called after reverting button to non-owner drawn state, provides a hook + // for wxCheckBox-specific hack. + virtual void MSWOnButtonResetOwnerDrawn() { } + + // Return the flags (such as wxCONTROL_CHECKED) to use for the control when + // drawing it. Notice that this class already takes care of the common + // logic and sets the other wxCONTROL_XXX flags on its own, this method + // really only needs to return the flags depending on the checked state. + virtual int MSWGetButtonCheckedFlag() const = 0; + + // Actually draw the check or radio bitmap, typically just by using the + // appropriate wxRendererNative method. + virtual void + MSWDrawButtonBitmap(wxDC& dc, const wxRect& rect, int flags) = 0; + + +private: + // Make the control owner drawn or reset it to normal style. + void MSWMakeOwnerDrawn(bool ownerDrawn); + + // Event handlers used to update the appearance of owner drawn button. + void OnMouseEnterOrLeave(wxMouseEvent& event); + void OnMouseLeft(wxMouseEvent& event); + void OnFocus(wxFocusEvent& event); + + + // The real window. + wxWindow* const m_win; + + // true if the checkbox is currently pressed + bool m_isPressed; + + // true if mouse is currently over the control + bool m_isHot; + + + wxDECLARE_NO_COPY_CLASS(wxMSWOwnerDrawnButtonBase); +}; + +// This class uses a weak version of CRTP, i.e. it's a template class taking +// the base class that the class deriving from it would normally derive from. +template +class wxMSWOwnerDrawnButton : public T, + private wxMSWOwnerDrawnButtonBase +{ +private: + typedef T Base; + +public: + wxMSWOwnerDrawnButton() : wxMSWOwnerDrawnButtonBase(this) + { + } + + virtual bool SetForegroundColour(const wxColour& colour) wxOVERRIDE + { + if ( !Base::SetForegroundColour(colour) ) + return false; + + MSWMakeOwnerDrawnIfNecessary(colour); + + return true; + } + + virtual bool MSWOnDraw(WXDRAWITEMSTRUCT *item) wxOVERRIDE + { + return MSWDrawButton(item) || Base::MSWOnDraw(item); + } + +protected: + bool IsOwnerDrawn() const { return MSWIsOwnerDrawn(); } +}; + +#endif // _WX_MSW_OWNERDRAWNBUTTON_H_ diff --git a/include/wx/msw/radiobut.h b/include/wx/msw/radiobut.h index cfc12b47b8..ad76fcf575 100644 --- a/include/wx/msw/radiobut.h +++ b/include/wx/msw/radiobut.h @@ -11,7 +11,9 @@ #ifndef _WX_RADIOBUT_H_ #define _WX_RADIOBUT_H_ -class WXDLLIMPEXP_CORE wxRadioButton: public wxControl +#include "wx/msw/ownerdrawnbutton.h" + +class WXDLLIMPEXP_CORE wxRadioButton : public wxMSWOwnerDrawnButton { public: // ctors and creation functions @@ -47,36 +49,26 @@ public: // implementation only from now on virtual bool MSWCommand(WXUINT param, WXWORD id); virtual void Command(wxCommandEvent& event); - virtual bool SetForegroundColour(const wxColour& colour); - virtual bool MSWOnDraw(WXDRAWITEMSTRUCT *item); virtual bool HasTransparentBackground() { return true; } - // make the radiobutton owner drawn or reset it to normal style - void MSWMakeOwnerDrawn(bool ownerDrawn); - virtual WXDWORD MSWGetStyle(long style, WXDWORD *exstyle) const; protected: virtual wxBorder GetDefaultBorder() const { return wxBORDER_NONE; } virtual wxSize DoGetBestSize() const; - virtual void MSWDrawButtonBitmap(wxWindow *win, wxDC& dc, - const wxRect& rect, int flags); - // return true if this checkbox is owner drawn - bool IsOwnerDrawn() const; + // Implement wxMSWOwnerDrawnButtonBase methods. + virtual int MSWGetButtonStyle() const wxOVERRIDE; + virtual int MSWGetButtonCheckedFlag() const wxOVERRIDE; + virtual void + MSWDrawButtonBitmap(wxDC& dc, const wxRect& rect, int flags) wxOVERRIDE; + private: // common part of all ctors void Init(); - // event handlers used by owner-drawn radiobutton - void OnMouseEnterOrLeave(wxMouseEvent& event); - void OnMouseLeft(wxMouseEvent& event); - void OnFocus(wxFocusEvent& event); - - // true if the radio button is currently pressed - bool m_isPressed; // we need to store the state internally as the result of GetValue() // sometimes gets out of sync in WM_COMMAND handler diff --git a/src/msw/checkbox.cpp b/src/msw/checkbox.cpp index 1029c74da0..d45e19a992 100644 --- a/src/msw/checkbox.cpp +++ b/src/msw/checkbox.cpp @@ -84,8 +84,6 @@ enum void wxCheckBox::Init() { m_state = wxCHK_UNCHECKED; - m_isPressed = - m_isHot = false; } bool wxCheckBox::Create(wxWindow *parent, @@ -269,145 +267,43 @@ bool wxCheckBox::MSWCommand(WXUINT cmd, WXWORD WXUNUSED(id)) } // ---------------------------------------------------------------------------- -// owner drawn checkboxes stuff +// owner drawn checkboxes support // ---------------------------------------------------------------------------- -bool wxCheckBox::SetForegroundColour(const wxColour& colour) +int wxCheckBox::MSWGetButtonStyle() const { - if ( !wxCheckBoxBase::SetForegroundColour(colour) ) - return false; - - // the only way to change the checkbox foreground colour under Windows XP - // is to owner draw it - if ( wxUxThemeEngine::GetIfActive() ) - MSWMakeOwnerDrawn(colour.IsOk()); - - return true; + return HasFlag(wxCHK_3STATE) ? BS_3STATE : BS_CHECKBOX; } -bool wxCheckBox::IsOwnerDrawn() const +void wxCheckBox::MSWOnButtonResetOwnerDrawn() { - return - (::GetWindowLong(GetHwnd(), GWL_STYLE) & BS_OWNERDRAW) == BS_OWNERDRAW; + // ensure that controls state is consistent with internal state + DoSet3StateValue(m_state); } -void wxCheckBox::MSWMakeOwnerDrawn(bool ownerDrawn) +int wxCheckBox::MSWGetButtonCheckedFlag() const { - long style = ::GetWindowLong(GetHwnd(), GWL_STYLE); - - // note that BS_CHECKBOX & BS_OWNERDRAW != 0 so we can't operate on - // them as on independent style bits - if ( ownerDrawn ) - { - style &= ~(BS_CHECKBOX | BS_3STATE); - style |= BS_OWNERDRAW; - - Connect(wxEVT_ENTER_WINDOW, - wxMouseEventHandler(wxCheckBox::OnMouseEnterOrLeave)); - Connect(wxEVT_LEAVE_WINDOW, - wxMouseEventHandler(wxCheckBox::OnMouseEnterOrLeave)); - Connect(wxEVT_LEFT_DOWN, wxMouseEventHandler(wxCheckBox::OnMouseLeft)); - Connect(wxEVT_LEFT_UP, wxMouseEventHandler(wxCheckBox::OnMouseLeft)); - Connect(wxEVT_SET_FOCUS, wxFocusEventHandler(wxCheckBox::OnFocus)); - Connect(wxEVT_KILL_FOCUS, wxFocusEventHandler(wxCheckBox::OnFocus)); - } - else // reset to default colour - { - style &= ~BS_OWNERDRAW; - style |= HasFlag(wxCHK_3STATE) ? BS_3STATE : BS_CHECKBOX; - - Disconnect(wxEVT_ENTER_WINDOW, - wxMouseEventHandler(wxCheckBox::OnMouseEnterOrLeave)); - Disconnect(wxEVT_LEAVE_WINDOW, - wxMouseEventHandler(wxCheckBox::OnMouseEnterOrLeave)); - Disconnect(wxEVT_LEFT_DOWN, wxMouseEventHandler(wxCheckBox::OnMouseLeft)); - Disconnect(wxEVT_LEFT_UP, wxMouseEventHandler(wxCheckBox::OnMouseLeft)); - Disconnect(wxEVT_SET_FOCUS, wxFocusEventHandler(wxCheckBox::OnFocus)); - Disconnect(wxEVT_KILL_FOCUS, wxFocusEventHandler(wxCheckBox::OnFocus)); - } - - ::SetWindowLong(GetHwnd(), GWL_STYLE, style); - - if ( !ownerDrawn ) - { - // ensure that controls state is consistent with internal state - DoSet3StateValue(m_state); - } -} - -void wxCheckBox::OnMouseEnterOrLeave(wxMouseEvent& event) -{ - m_isHot = event.GetEventType() == wxEVT_ENTER_WINDOW; - if ( !m_isHot ) - m_isPressed = false; - - Refresh(); - - event.Skip(); -} - -void wxCheckBox::OnMouseLeft(wxMouseEvent& event) -{ - // TODO: we should capture the mouse here to be notified about left up - // event but this interferes with BN_CLICKED generation so if we - // want to do this we'd need to generate them ourselves - m_isPressed = event.GetEventType() == wxEVT_LEFT_DOWN; - Refresh(); - - event.Skip(); -} - -void wxCheckBox::OnFocus(wxFocusEvent& event) -{ - Refresh(); - - event.Skip(); -} - -bool wxCheckBox::MSWOnDraw(WXDRAWITEMSTRUCT *item) -{ - DRAWITEMSTRUCT *dis = (DRAWITEMSTRUCT *)item; - - if ( !IsOwnerDrawn() || dis->CtlType != ODT_BUTTON ) - return wxCheckBoxBase::MSWOnDraw(item); - - // shall we draw a focus rect? - const bool isFocused = m_isPressed || FindFocus() == this; - - int flags = 0; - if ( !IsEnabled() ) - flags |= wxCONTROL_DISABLED; switch ( Get3StateValue() ) { case wxCHK_CHECKED: - flags |= wxCONTROL_CHECKED; - break; + return wxCONTROL_CHECKED; case wxCHK_UNDETERMINED: - flags |= wxCONTROL_PRESSED; - break; - - default: - wxFAIL_MSG( wxT("unexpected Get3StateValue() return value") ); - // fall through + return wxCONTROL_PRESSED; case wxCHK_UNCHECKED: // no extra styles needed - break; + return 0; } - if ( m_isPressed ) - flags |= wxCONTROL_PRESSED; + wxFAIL_MSG( wxT("unexpected Get3StateValue() return value") ); - if ( wxFindWindowAtPoint(wxGetMousePosition()) == this ) - flags |= wxCONTROL_CURRENT; - - return MSWOwnerDrawnButton(dis, flags, isFocused); + return 0; } -void wxCheckBox::MSWDrawButtonBitmap(wxWindow *win, wxDC& dc, const wxRect& rect, int flags) +void wxCheckBox::MSWDrawButtonBitmap(wxDC& dc, const wxRect& rect, int flags) { - wxRendererNative::Get().DrawCheckBox(win, dc, rect, flags); + wxRendererNative::Get().DrawCheckBox(this, dc, rect, flags); } #endif // wxUSE_CHECKBOX diff --git a/src/msw/control.cpp b/src/msw/control.cpp index 341bab00bc..077d09417b 100644 --- a/src/msw/control.cpp +++ b/src/msw/control.cpp @@ -45,6 +45,7 @@ #include "wx/treectrl.h" #endif // wxUSE_TREECTRL +#include "wx/renderer.h" #include "wx/msw/private.h" #include "wx/msw/uxtheme.h" #include "wx/msw/dc.h" // for wxDCTemp @@ -452,17 +453,139 @@ wxWindow* wxControl::MSWFindItem(long id, WXHWND hWnd) const return wxControlBase::MSWFindItem(id, hWnd); } -bool wxControl::MSWOwnerDrawnButton(const DRAWITEMSTRUCT *dis, int flags, bool isFocused) +// ---------------------------------------------------------------------------- +// Owner drawn buttons support. +// ---------------------------------------------------------------------------- + +void +wxMSWOwnerDrawnButtonBase::MSWMakeOwnerDrawnIfNecessary(const wxColour& colFg) { + // The only way to change the checkbox foreground colour when using + // themes is to owner draw it. + if ( wxUxThemeEngine::GetIfActive() ) + MSWMakeOwnerDrawn(colFg.IsOk()); +} + +bool wxMSWOwnerDrawnButtonBase::MSWIsOwnerDrawn() const +{ + return + (::GetWindowLong(GetHwndOf(m_win), GWL_STYLE) & BS_OWNERDRAW) == BS_OWNERDRAW; +} + +void wxMSWOwnerDrawnButtonBase::MSWMakeOwnerDrawn(bool ownerDrawn) +{ + long style = ::GetWindowLong(GetHwndOf(m_win), GWL_STYLE); + + // note that BS_CHECKBOX & BS_OWNERDRAW != 0 so we can't operate on + // them as on independent style bits + if ( ownerDrawn ) + { + style &= ~BS_TYPEMASK; + style |= BS_OWNERDRAW; + + m_win->Bind(wxEVT_ENTER_WINDOW, + &wxMSWOwnerDrawnButtonBase::OnMouseEnterOrLeave, this); + m_win->Bind(wxEVT_LEAVE_WINDOW, + &wxMSWOwnerDrawnButtonBase::OnMouseEnterOrLeave, this); + + m_win->Bind(wxEVT_LEFT_DOWN, + &wxMSWOwnerDrawnButtonBase::OnMouseLeft, this); + m_win->Bind(wxEVT_LEFT_UP, + &wxMSWOwnerDrawnButtonBase::OnMouseLeft, this); + + m_win->Bind(wxEVT_SET_FOCUS, + &wxMSWOwnerDrawnButtonBase::OnFocus, this); + + m_win->Bind(wxEVT_KILL_FOCUS, + &wxMSWOwnerDrawnButtonBase::OnFocus, this); + } + else // reset to default colour + { + style &= ~BS_OWNERDRAW; + style |= MSWGetButtonStyle(); + + m_win->Unbind(wxEVT_ENTER_WINDOW, + &wxMSWOwnerDrawnButtonBase::OnMouseEnterOrLeave, this); + m_win->Unbind(wxEVT_LEAVE_WINDOW, + &wxMSWOwnerDrawnButtonBase::OnMouseEnterOrLeave, this); + + m_win->Unbind(wxEVT_LEFT_DOWN, + &wxMSWOwnerDrawnButtonBase::OnMouseLeft, this); + m_win->Unbind(wxEVT_LEFT_UP, + &wxMSWOwnerDrawnButtonBase::OnMouseLeft, this); + + m_win->Unbind(wxEVT_SET_FOCUS, + &wxMSWOwnerDrawnButtonBase::OnFocus, this); + m_win->Unbind(wxEVT_KILL_FOCUS, + &wxMSWOwnerDrawnButtonBase::OnFocus, this); + } + + ::SetWindowLong(GetHwndOf(m_win), GWL_STYLE, style); + + if ( !ownerDrawn ) + MSWOnButtonResetOwnerDrawn(); +} + +void wxMSWOwnerDrawnButtonBase::OnMouseEnterOrLeave(wxMouseEvent& event) +{ + if ( event.GetEventType() == wxEVT_LEAVE_WINDOW ) + m_isPressed = false; + + m_win->Refresh(); + + event.Skip(); +} + +void wxMSWOwnerDrawnButtonBase::OnMouseLeft(wxMouseEvent& event) +{ + // TODO: we should capture the mouse here to be notified about left up + // event but this interferes with BN_CLICKED generation so if we + // want to do this we'd need to generate them ourselves + m_isPressed = event.GetEventType() == wxEVT_LEFT_DOWN; + m_win->Refresh(); + + event.Skip(); +} + +void wxMSWOwnerDrawnButtonBase::OnFocus(wxFocusEvent& event) +{ + m_win->Refresh(); + + event.Skip(); +} + +bool wxMSWOwnerDrawnButtonBase::MSWDrawButton(WXDRAWITEMSTRUCT *item) +{ + DRAWITEMSTRUCT *dis = (DRAWITEMSTRUCT *)item; + + if ( !MSWIsOwnerDrawn() || dis->CtlType != ODT_BUTTON ) + return false; + + // shall we draw a focus rect? + const bool isFocused = m_isPressed || m_win->HasFocus(); + + int flags = MSWGetButtonCheckedFlag(); + + if ( !m_win->IsEnabled() ) + flags |= wxCONTROL_DISABLED; + + if ( m_isPressed ) + flags |= wxCONTROL_PRESSED; + + if ( wxFindWindowAtPoint(wxGetMousePosition()) == m_win ) + flags |= wxCONTROL_CURRENT; + + // calculate the rectangles for the button itself and the label HDC hdc = dis->hDC; const RECT& rect = dis->rcItem; // calculate the rectangles for the button itself and the label + const wxSize bestSize = m_win->GetBestSize(); RECT rectButton, rectLabel; - rectLabel.top = rect.top + (rect.bottom - rect.top - GetBestSize().y) / 2; - rectLabel.bottom = rectLabel.top + GetBestSize().y; + rectLabel.top = rect.top + (rect.bottom - rect.top - bestSize.y) / 2; + rectLabel.bottom = rectLabel.top + bestSize.y; // choose the values consistent with those used for native, non // owner-drawn, buttons @@ -475,11 +598,11 @@ bool wxControl::MSWOwnerDrawnButton(const DRAWITEMSTRUCT *dis, int flags, bool i // The space between the button and the label // is included in the button bitmap. - const int buttonSize = wxMin(CXMENUCHECK - MARGIN, GetSize().y); + const int buttonSize = wxMin(CXMENUCHECK - MARGIN, m_win->GetSize().y); rectButton.top = rect.top + (rect.bottom - rect.top - buttonSize) / 2; rectButton.bottom = rectButton.top + buttonSize; - const bool isRightAligned = HasFlag(wxALIGN_RIGHT); + const bool isRightAligned = m_win->HasFlag(wxALIGN_RIGHT); if ( isRightAligned ) { rectLabel.right = rect.right - CXMENUCHECK; @@ -500,10 +623,10 @@ bool wxControl::MSWOwnerDrawnButton(const DRAWITEMSTRUCT *dis, int flags, bool i // draw the button itself wxDCTemp dc(hdc); - MSWDrawButtonBitmap(this, dc, wxRectFromRECT(rectButton), flags); + MSWDrawButtonBitmap(dc, wxRectFromRECT(rectButton), flags); // draw the text - const wxString& label = GetLabel(); + const wxString& label = m_win->GetLabel(); // first we need to measure it UINT fmt = DT_NOCLIP; @@ -537,7 +660,7 @@ bool wxControl::MSWOwnerDrawnButton(const DRAWITEMSTRUCT *dis, int flags, bool i } } - if ( !IsEnabled() ) + if ( flags & wxCONTROL_DISABLED ) { ::SetTextColor(hdc, ::GetSysColor(COLOR_GRAYTEXT)); } diff --git a/src/msw/radiobut.cpp b/src/msw/radiobut.cpp index 2e28facb61..cbb286bcf0 100644 --- a/src/msw/radiobut.cpp +++ b/src/msw/radiobut.cpp @@ -48,7 +48,6 @@ void wxRadioButton::Init() { m_isChecked = false; - m_isPressed = false; } bool wxRadioButton::Create(wxWindow *parent, @@ -306,122 +305,19 @@ WXDWORD wxRadioButton::MSWGetStyle(long style, WXDWORD *exstyle) const // owner drawn radio button stuff // ---------------------------------------------------------------------------- -bool wxRadioButton::SetForegroundColour(const wxColour& colour) +int wxRadioButton::MSWGetButtonStyle() const { - if ( !wxControl::SetForegroundColour(colour) ) - return false; - - // the only way to change the radiobox foreground colour if themes are enablad - // is to owner draw it - if ( wxUxThemeEngine::GetIfActive() ) - MSWMakeOwnerDrawn(colour.IsOk()); - - return true; + return BS_RADIOBUTTON; } -bool wxRadioButton::IsOwnerDrawn() const +int wxRadioButton::MSWGetButtonCheckedFlag() const { - return - (::GetWindowLong(GetHwnd(), GWL_STYLE) & BS_OWNERDRAW) == BS_OWNERDRAW; + return m_isChecked ? wxCONTROL_CHECKED : 0; } -void wxRadioButton::MSWMakeOwnerDrawn(bool ownerDrawn) +void wxRadioButton::MSWDrawButtonBitmap(wxDC& dc, const wxRect& rect, int flags) { - long style = ::GetWindowLong(GetHwnd(), GWL_STYLE); - - // note that BS_RADIOBUTTON & BS_OWNERDRAW != 0 so we can't operate on - // them as on independent style bits - - if ( ownerDrawn ) - { - style &= ~BS_RADIOBUTTON; - style |= BS_OWNERDRAW; - - Connect(wxEVT_ENTER_WINDOW, - wxMouseEventHandler(wxRadioButton::OnMouseEnterOrLeave)); - Connect(wxEVT_LEAVE_WINDOW, - wxMouseEventHandler(wxRadioButton::OnMouseEnterOrLeave)); - Connect(wxEVT_LEFT_DOWN, wxMouseEventHandler(wxRadioButton::OnMouseLeft)); - Connect(wxEVT_LEFT_UP, wxMouseEventHandler(wxRadioButton::OnMouseLeft)); - Connect(wxEVT_SET_FOCUS, wxFocusEventHandler(wxRadioButton::OnFocus)); - Connect(wxEVT_KILL_FOCUS, wxFocusEventHandler(wxRadioButton::OnFocus)); - } - else // reset to default colour - { - style &= ~BS_OWNERDRAW; - style |= BS_RADIOBUTTON; - - Disconnect(wxEVT_ENTER_WINDOW, - wxMouseEventHandler(wxRadioButton::OnMouseEnterOrLeave)); - Disconnect(wxEVT_LEAVE_WINDOW, - wxMouseEventHandler(wxRadioButton::OnMouseEnterOrLeave)); - Disconnect(wxEVT_LEFT_DOWN, wxMouseEventHandler(wxRadioButton::OnMouseLeft)); - Disconnect(wxEVT_LEFT_UP, wxMouseEventHandler(wxRadioButton::OnMouseLeft)); - Disconnect(wxEVT_SET_FOCUS, wxFocusEventHandler(wxRadioButton::OnFocus)); - Disconnect(wxEVT_KILL_FOCUS, wxFocusEventHandler(wxRadioButton::OnFocus)); - } - - ::SetWindowLong(GetHwnd(), GWL_STYLE, style); -} - -void wxRadioButton::OnMouseEnterOrLeave(wxMouseEvent& event) -{ - const bool isHot = event.GetEventType() == wxEVT_ENTER_WINDOW; - if ( !isHot ) - m_isPressed = false; - - Refresh(); - - event.Skip(); -} - -void wxRadioButton::OnMouseLeft(wxMouseEvent& event) -{ - // TODO: we should capture the mouse here to be notified about left up - // event but this interferes with BN_CLICKED generation so if we - // want to do this we'd need to generate them ourselves - m_isPressed = event.GetEventType() == wxEVT_LEFT_DOWN; - Refresh(); - - event.Skip(); -} - -void wxRadioButton::OnFocus(wxFocusEvent& event) -{ - Refresh(); - - event.Skip(); -} - -bool wxRadioButton::MSWOnDraw(WXDRAWITEMSTRUCT *item) -{ - DRAWITEMSTRUCT *dis = (DRAWITEMSTRUCT *)item; - - if ( !IsOwnerDrawn() || dis->CtlType != ODT_BUTTON ) - return wxControl::MSWOnDraw(item); - - // shall we draw a focus rect? - const bool isFocused = m_isPressed || FindFocus() == this; - - int flags = 0; - if ( !IsEnabled() ) - flags |= wxCONTROL_DISABLED; - - if ( m_isChecked ) - flags |= wxCONTROL_CHECKED; - - if ( m_isPressed ) - flags |= wxCONTROL_PRESSED; - - if ( wxFindWindowAtPoint(wxGetMousePosition()) == this ) - flags |= wxCONTROL_CURRENT; - - return MSWOwnerDrawnButton(dis, flags, isFocused); -} - -void wxRadioButton::MSWDrawButtonBitmap(wxWindow *win, wxDC& dc, const wxRect& rect, int flags) -{ - wxRendererNative::Get().DrawRadioBitmap(win, dc, rect, flags); + wxRendererNative::Get().DrawRadioBitmap(this, dc, rect, flags); } #endif // wxUSE_RADIOBTN