From 43be3c33f3b35fb72affcaa959002cc60e1c0acd Mon Sep 17 00:00:00 2001 From: Julian Smart Date: Tue, 23 May 2006 17:53:50 +0000 Subject: [PATCH] Applied patch 1489656: support for wxToggleButton under wxUniversal git-svn-id: https://svn.wxwidgets.org/svn/wx/wxWidgets/trunk@39293 c3d73ce0-8a6f-49c7-b76d-6d57e0e08775 --- build/bakefiles/files.bkl | 1 + include/wx/tglbtn.h | 4 +- include/wx/univ/tglbtn.h | 163 ++++++++++++++ src/univ/tglbtn.cpp | 437 ++++++++++++++++++++++++++++++++++++++ src/univ/themes/gtk.cpp | 16 +- src/univ/themes/win32.cpp | 16 +- 6 files changed, 630 insertions(+), 7 deletions(-) create mode 100644 include/wx/univ/tglbtn.h create mode 100644 src/univ/tglbtn.cpp diff --git a/build/bakefiles/files.bkl b/build/bakefiles/files.bkl index a3e6c83451..6cbb90f34f 100644 --- a/build/bakefiles/files.bkl +++ b/build/bakefiles/files.bkl @@ -2457,6 +2457,7 @@ IMPORTANT: please read docs/tech/tn0016.txt before modifying this file! src/univ/stattext.cpp src/univ/statusbr.cpp src/univ/textctrl.cpp + src/univ/tglbtn.cpp src/univ/theme.cpp src/univ/toolbar.cpp src/univ/topluniv.cpp diff --git a/include/wx/tglbtn.h b/include/wx/tglbtn.h index 2972d5f04a..7ac6ec9840 100644 --- a/include/wx/tglbtn.h +++ b/include/wx/tglbtn.h @@ -27,7 +27,9 @@ END_DECLARE_EVENT_TYPES() #define EVT_TOGGLEBUTTON(id, fn) \ wx__DECLARE_EVT1(wxEVT_COMMAND_TOGGLEBUTTON_CLICKED, id, wxCommandEventHandler(fn)) -#if defined(__WXMSW__) +#if defined(__WXUNIVERSAL__) + #include "wx/univ/tglbtn.h" +#elif defined(__WXMSW__) #include "wx/msw/tglbtn.h" #elif defined(__WXGTK20__) #include "wx/gtk/tglbtn.h" diff --git a/include/wx/univ/tglbtn.h b/include/wx/univ/tglbtn.h new file mode 100644 index 0000000000..1fcdd76c7c --- /dev/null +++ b/include/wx/univ/tglbtn.h @@ -0,0 +1,163 @@ +/////////////////////////////////////////////////////////////////////////////// +// Name: wx/univ/button.h +// Purpose: wxToggleButton for wxUniversal +// Author: Vadim Zeitlin +// Modified by: David Bjorkevik +// Created: 16.05.06 +// RCS-ID: $Id$ +// Copyright: (c) 2000 SciTech Software, Inc. (www.scitechsoft.com) +// Licence: wxWindows licence +/////////////////////////////////////////////////////////////////////////////// + +#ifndef _WX_UNIV_TGLBTN_H_ +#define _WX_UNIV_TGLBTN_H_ + +class WXDLLEXPORT wxInputHandler; + +#include "wx/bitmap.h" +#include "wx/checkbox.h" + +// ---------------------------------------------------------------------------- +// the actions supported by this control +// ---------------------------------------------------------------------------- + +#define wxACTION_BUTTON_TOGGLE _T("toggle") // press/release the button +#define wxACTION_BUTTON_PRESS _T("press") // press the button +#define wxACTION_BUTTON_RELEASE _T("release") // release the button +#define wxACTION_BUTTON_CLICK _T("click") // generate button click event + +// ---------------------------------------------------------------------------- +// wxToggleButton: a push button +// ---------------------------------------------------------------------------- + +class WXDLLIMPEXP_CORE wxToggleButton: public wxControl +{ +public: + wxToggleButton() { Init(); } + wxToggleButton(wxWindow *parent, + wxWindowID id, + const wxBitmap& bitmap, + const wxString& label = wxEmptyString, + const wxPoint& pos = wxDefaultPosition, + const wxSize& size = wxDefaultSize, + long style = 0, + const wxValidator& validator = wxDefaultValidator, + const wxString& name = wxCheckBoxNameStr) + { + Init(); + + Create(parent, id, bitmap, label, pos, size, style, validator, name); + } + + wxToggleButton(wxWindow *parent, + wxWindowID id, + const wxString& label = wxEmptyString, + const wxPoint& pos = wxDefaultPosition, + const wxSize& size = wxDefaultSize, + long style = 0, + const wxValidator& validator = wxDefaultValidator, + const wxString& name = wxCheckBoxNameStr) + { + Init(); + + Create(parent, id, label, pos, size, style, validator, name); + } + + bool Create(wxWindow *parent, + wxWindowID id, + const wxString& label = wxEmptyString, + const wxPoint& pos = wxDefaultPosition, + const wxSize& size = wxDefaultSize, + long style = 0, + const wxValidator& validator = wxDefaultValidator, + const wxString& name = wxCheckBoxNameStr) + { + return Create(parent, id, wxNullBitmap, label, + pos, size, style, validator, name); + } + + bool Create(wxWindow *parent, + wxWindowID id, + const wxBitmap& bitmap, + const wxString& label = wxEmptyString, + const wxPoint& pos = wxDefaultPosition, + const wxSize& size = wxDefaultSize, + long style = 0, + const wxValidator& validator = wxDefaultValidator, + const wxString& name = wxCheckBoxNameStr); + + virtual ~wxToggleButton(); + + virtual void SetImageLabel(const wxBitmap& bitmap); + virtual void SetImageMargins(wxCoord x, wxCoord y); + + virtual bool IsPressed() const { return m_isPressed || m_value; } + + // wxToggleButton actions + void Toggle(); + virtual void Press(); + virtual void Release(); + virtual void Click(); + + // Get/set the value + void SetValue(bool state); + bool GetValue() const { return m_value; } + + // returns the default button size for this platform + static wxSize GetDefaultSize(); + +protected: + virtual bool PerformAction(const wxControlAction& action, + long numArg = -1, + const wxString& strArg = wxEmptyString); + virtual wxSize DoGetBestClientSize() const; + + virtual bool DoDrawBackground(wxDC& dc); + virtual void DoDraw(wxControlRenderer *renderer); + + virtual bool CanBeHighlighted() const { return true; } + + // common part of all ctors + void Init(); + + // current state - is the user currently pressing the button + bool m_isPressed; + + // the current value + bool m_value; + + // the (optional) image to show and the margins around it + wxBitmap m_bitmap; + wxCoord m_marginBmpX, + m_marginBmpY; + +private: + DECLARE_DYNAMIC_CLASS(wxToggleButton) +}; +// wxStdToggleButtonInputHandler: translates SPACE and ENTER keys and the left mouse +// click into button press/release actions +// ---------------------------------------------------------------------------- + +class WXDLLEXPORT wxStdToggleButtonInputHandler : public wxStdInputHandler +{ +public: + wxStdToggleButtonInputHandler(wxInputHandler *inphand); + + virtual bool HandleKey(wxInputConsumer *consumer, + const wxKeyEvent& event, + bool pressed); + virtual bool HandleMouse(wxInputConsumer *consumer, + const wxMouseEvent& event); + virtual bool HandleMouseMove(wxInputConsumer *consumer, const wxMouseEvent& event); + virtual bool HandleFocus(wxInputConsumer *consumer, const wxFocusEvent& event); + virtual bool HandleActivation(wxInputConsumer *consumer, bool activated); + +private: + // the window (button) which has capture or NULL and the flag telling if + // the mouse is inside the button which captured it or not + wxWindow *m_winCapture; + bool m_winHasMouse; +}; + +#endif // _WX_UNIV_TGLBTN_H_ + diff --git a/src/univ/tglbtn.cpp b/src/univ/tglbtn.cpp new file mode 100644 index 0000000000..6a13b3ff72 --- /dev/null +++ b/src/univ/tglbtn.cpp @@ -0,0 +1,437 @@ +///////////////////////////////////////////////////////////////////////////// +// Name: univ/tglbtn.cpp +// Purpose: wxToggleButton +// Author: Vadim Zeitlin +// Modified by: David Bjorkevik +// Created: 16.05.06 +// RCS-ID: $Id$ +// Copyright: (c) 2000 SciTech Software, Inc. (www.scitechsoft.com) +// Licence: wxWindows licence +///////////////////////////////////////////////////////////////////////////// + +// ============================================================================ +// declarations +// ============================================================================ + +// ---------------------------------------------------------------------------- +// headers +// ---------------------------------------------------------------------------- + +#include "wx/wxprec.h" + +#ifdef __BORLANDC__ + #pragma hdrstop +#endif + +#if wxUSE_TOGGLEBTN + +#ifndef WX_PRECOMP + #include "wx/dcclient.h" + #include "wx/dcscreen.h" + #include "wx/button.h" + #include "wx/validate.h" + #include "wx/settings.h" +#endif + +#include "wx/univ/renderer.h" +#include "wx/univ/inphand.h" +#include "wx/univ/theme.h" +#include "wx/univ/colschem.h" +#include "wx/stockitem.h" +#include "wx/tglbtn.h" + +// ---------------------------------------------------------------------------- +// constants +// ---------------------------------------------------------------------------- +DEFINE_EVENT_TYPE(wxEVT_COMMAND_TOGGLEBUTTON_CLICKED) + +// default margins around the image +static const wxCoord DEFAULT_BTN_MARGIN_X = 0; // We should give space for the border, at least. +static const wxCoord DEFAULT_BTN_MARGIN_Y = 0; + +// ============================================================================ +// implementation +// ============================================================================ + +IMPLEMENT_DYNAMIC_CLASS(wxToggleButton, wxControl) + +// ---------------------------------------------------------------------------- +// creation +// ---------------------------------------------------------------------------- + +void wxToggleButton::Init() +{ + m_isPressed = false; + m_value = false; +} + +bool wxToggleButton::Create(wxWindow *parent, + wxWindowID id, + const wxBitmap& bitmap, + const wxString &lbl, + const wxPoint &pos, + const wxSize &size, + long style, + const wxValidator& validator, + const wxString &name) +{ + wxString label(lbl); + if (label.empty() && wxIsStockID(id)) + label = wxGetStockLabel(id); + + long ctrl_style = style & ~wxBU_ALIGN_MASK; + + wxASSERT_MSG( (ctrl_style & wxALIGN_MASK) == 0, + _T("Some style conflicts with align flags") ); + + if((style & wxBU_RIGHT) == wxBU_RIGHT) + ctrl_style |= wxALIGN_RIGHT; + else if((style & wxBU_LEFT) == wxBU_LEFT) + ctrl_style |= wxALIGN_LEFT; + else + ctrl_style |= wxALIGN_CENTRE_HORIZONTAL; + + if((style & wxBU_TOP) == wxBU_TOP) + ctrl_style |= wxALIGN_TOP; + else if((style & wxBU_BOTTOM) == wxBU_BOTTOM) + ctrl_style |= wxALIGN_BOTTOM; + else + ctrl_style |= wxALIGN_CENTRE_VERTICAL; + + if ( !wxControl::Create(parent, id, pos, size, ctrl_style, validator, name) ) + return false; + + SetLabel(label); + SetImageLabel(bitmap); + // SetBestSize(size); -- called by SetImageLabel() + + CreateInputHandler(wxINP_HANDLER_BUTTON); + + return true; +} + +wxToggleButton::~wxToggleButton() +{ +} + +// ---------------------------------------------------------------------------- +// size management +// ---------------------------------------------------------------------------- + +/* static */ +wxSize wxToggleButton::GetDefaultSize() +{ + static wxSize s_sizeBtn; + + if ( s_sizeBtn.x == 0 ) + { + wxScreenDC dc; + + // this corresponds more or less to wxMSW standard in Win32 theme (see + // wxWin32Renderer::AdjustSize()) +// s_sizeBtn.x = 8*dc.GetCharWidth(); +// s_sizeBtn.y = (11*dc.GetCharHeight())/10 + 2; + // Otto Wyss, Patch 664399 + s_sizeBtn.x = dc.GetCharWidth()*10 + 2; + s_sizeBtn.y = dc.GetCharHeight()*11/10 + 2; + } + + return s_sizeBtn; +} + +wxSize wxToggleButton::DoGetBestClientSize() const +{ + wxClientDC dc(wxConstCast(this, wxToggleButton)); + wxCoord width, height; + dc.GetMultiLineTextExtent(GetLabel(), &width, &height); + + if ( m_bitmap.Ok() ) + { + // allocate extra space for the bitmap + wxCoord heightBmp = m_bitmap.GetHeight() + 2*m_marginBmpY; + if ( height < heightBmp ) + height = heightBmp; + + width += m_bitmap.GetWidth() + 2*m_marginBmpX; + } + + // The default size should not be adjusted, so the code is moved into the + // renderer. This is conceptual wrong but currently the only solution. + // (Otto Wyss, Patch 664399) + +/* + // for compatibility with other ports, the buttons default size is never + // less than the standard one, but not when display not PDAs. + if (wxSystemSettings::GetScreenType() > wxSYS_SCREEN_PDA) + { + if ( !(GetWindowStyle() & wxBU_EXACTFIT) ) + { + wxSize szDef = GetDefaultSize(); + if ( width < szDef.x ) + width = szDef.x; + } + } +*/ + return wxSize(width, height); +} + +// ---------------------------------------------------------------------------- +// drawing +// ---------------------------------------------------------------------------- + +void wxToggleButton::DoDraw(wxControlRenderer *renderer) +{ + if ( !(GetWindowStyle() & wxBORDER_NONE) ) + { + renderer->DrawButtonBorder(); + } + + renderer->DrawLabel(m_bitmap, m_marginBmpX, m_marginBmpY); +} + +bool wxToggleButton::DoDrawBackground(wxDC& dc) +{ + wxRect rect; + wxSize size = GetSize(); + rect.width = size.x; + rect.height = size.y; + + if ( GetBackgroundBitmap().Ok() ) + { + // get the bitmap and the flags + int alignment; + wxStretch stretch; + wxBitmap bmp = GetBackgroundBitmap(&alignment, &stretch); + wxControlRenderer::DrawBitmap(dc, bmp, rect, alignment, stretch); + } + else + { + m_renderer->DrawButtonSurface(dc, wxTHEME_BG_COLOUR(this), + rect, GetStateFlags()); + } + + return true; +} + +// ---------------------------------------------------------------------------- +// input processing +// ---------------------------------------------------------------------------- + +void wxToggleButton::Press() +{ + if ( !m_isPressed ) + { + m_isPressed = true; + + Refresh(); + } +} + +void wxToggleButton::Release() +{ + if ( m_isPressed ) + { + m_isPressed = false; + + Refresh(); + } +} + +void wxToggleButton::Toggle() +{ + if ( m_isPressed ) + Release(); + else + Press(); + + if ( !m_isPressed ) + { + // releasing button after it had been pressed generates a click event + // and toggles value + m_value = !m_value; + Click(); + } +} + +void wxToggleButton::Click() +{ + wxCommandEvent event(wxEVT_COMMAND_TOGGLEBUTTON_CLICKED, GetId()); + InitCommandEvent(event); + event.SetInt(GetValue()); + Command(event); +} + +bool wxToggleButton::PerformAction(const wxControlAction& action, + long numArg, + const wxString& strArg) +{ + if ( action == wxACTION_BUTTON_TOGGLE ) + Toggle(); + else if ( action == wxACTION_BUTTON_CLICK ) + Click(); + else if ( action == wxACTION_BUTTON_PRESS ) + Press(); + else if ( action == wxACTION_BUTTON_RELEASE ) + Release(); + else + return wxControl::PerformAction(action, numArg, strArg); + + return true; +} + +// ---------------------------------------------------------------------------- +// misc +// ---------------------------------------------------------------------------- + +void wxToggleButton::SetImageLabel(const wxBitmap& bitmap) +{ + m_bitmap = bitmap; + + SetImageMargins(DEFAULT_BTN_MARGIN_X, DEFAULT_BTN_MARGIN_Y); +} + +void wxToggleButton::SetImageMargins(wxCoord x, wxCoord y) +{ + m_marginBmpX = x + 2; + m_marginBmpY = y + 2; + + SetBestSize(wxDefaultSize); +} + +// void SetValue(bool state) +// Set the value of the toggle button. +void wxToggleButton::SetValue(bool state) +{ + m_value = state; + Refresh(); +} + +// ============================================================================ +// wxStdButtonInputHandler +// ============================================================================ + +wxStdToggleButtonInputHandler::wxStdToggleButtonInputHandler(wxInputHandler *handler) + : wxStdInputHandler(handler) +{ + m_winCapture = NULL; + m_winHasMouse = false; +} + +bool wxStdToggleButtonInputHandler::HandleKey(wxInputConsumer *consumer, + const wxKeyEvent& event, + bool pressed) +{ + int keycode = event.GetKeyCode(); + if ( keycode == WXK_SPACE || keycode == WXK_RETURN ) + { + consumer->PerformAction(wxACTION_BUTTON_TOGGLE); + + return true; + } + + return wxStdInputHandler::HandleKey(consumer, event, pressed); +} + +bool wxStdToggleButtonInputHandler::HandleMouse(wxInputConsumer *consumer, + const wxMouseEvent& event) +{ + // the button has 2 states: pressed and normal with the following + // transitions between them: + // + // normal -> left down -> capture mouse and go to pressed state + // pressed -> left up inside -> generate click -> go to normal + // outside ------------------> + // + // the other mouse buttons are ignored + if ( event.Button(1) ) + { + if ( event.LeftDown() || event.LeftDClick() ) + { + m_winCapture = consumer->GetInputWindow(); + m_winCapture->CaptureMouse(); + m_winHasMouse = true; + + consumer->PerformAction(wxACTION_BUTTON_PRESS); + + return true; + } + else if ( event.LeftUp() ) + { + if ( m_winCapture ) + { + m_winCapture->ReleaseMouse(); + m_winCapture = NULL; + } + + if ( m_winHasMouse ) + { + // this will generate a click event + consumer->PerformAction(wxACTION_BUTTON_TOGGLE); + + return true; + } + //else: the mouse was released outside the window, this doesn't + // count as a click + } + //else: don't do anything special about the double click + } + + return wxStdInputHandler::HandleMouse(consumer, event); +} + +bool wxStdToggleButtonInputHandler::HandleMouseMove(wxInputConsumer *consumer, + const wxMouseEvent& event) +{ + // we only have to do something when the mouse leaves/enters the pressed + // button and don't care about the other ones + if ( event.GetEventObject() == m_winCapture ) + { + // leaving the button should remove its pressed state + if ( event.Leaving() ) + { + // remember that the mouse is now outside + m_winHasMouse = false; + + // we do have a pressed button, so release it + consumer->GetInputWindow()->SetCurrent(false); + consumer->PerformAction(wxACTION_BUTTON_RELEASE); + + return true; + } + // and entering it back should make it pressed again if it had been + // pressed + else if ( event.Entering() ) + { + // the mouse is (back) inside the button + m_winHasMouse = true; + + // we did have a pressed button which we released when leaving the + // window, press it again + consumer->GetInputWindow()->SetCurrent(true); + consumer->PerformAction(wxACTION_BUTTON_PRESS); + + return true; + } + } + + return wxStdInputHandler::HandleMouseMove(consumer, event); +} + +bool wxStdToggleButtonInputHandler::HandleFocus(wxInputConsumer * WXUNUSED(consumer), + const wxFocusEvent& WXUNUSED(event)) +{ + // buttons change appearance when they get/lose focus, so return true to + // refresh + return true; +} + +bool wxStdToggleButtonInputHandler::HandleActivation(wxInputConsumer *consumer, + bool WXUNUSED(activated)) +{ + // the default button changes appearance when the app is [de]activated, so + // return true to refresh + return wxStaticCast(consumer->GetInputWindow(), wxToggleButton)->IsDefault(); +} + +#endif // wxUSE_TOGGLEBTN + diff --git a/src/univ/themes/gtk.cpp b/src/univ/themes/gtk.cpp index a721afbb6d..fceabaa12a 100644 --- a/src/univ/themes/gtk.cpp +++ b/src/univ/themes/gtk.cpp @@ -52,6 +52,9 @@ #include "wx/toplevel.h" #include "wx/artprov.h" #include "wx/image.h" +#ifdef wxUSE_TOGGLEBTN +#include "wx/tglbtn.h" +#endif // wxUSE_TOGGLEBTN #include "wx/univ/renderer.h" #include "wx/univ/inphand.h" @@ -2815,8 +2818,15 @@ void wxGTKRenderer::AdjustSize(wxSize *size, const wxWindow *window) size->y += 4; } else #endif // wxUSE_BMPBUTTON -#if wxUSE_BUTTON - if ( wxDynamicCast(window, wxButton) ) +#if wxUSE_BUTTON || wxUSE_TOGGLEBTN + if ( 0 +# if wxUSE_BUTTON + || wxDynamicCast(window, wxButton) +# endif // wxUSE_BUTTON +# if wxUSE_TOGGLEBTN + || wxDynamicCast(window, wxToggleButton) +# endif // wxUSE_TOGGLEBTN + ) { if ( !(window->GetWindowStyle() & wxBU_EXACTFIT) ) { @@ -2830,7 +2840,7 @@ void wxGTKRenderer::AdjustSize(wxSize *size, const wxWindow *window) size->y += 4; } } else -#endif //wxUSE_BUTTON +#endif // wxUSE_BUTTON || wxUSE_TOGGLEBTN if ( wxDynamicCast(window, wxScrollBar) ) { // we only set the width of vert scrollbars and height of the diff --git a/src/univ/themes/win32.cpp b/src/univ/themes/win32.cpp index 2465b06995..823d14827b 100644 --- a/src/univ/themes/win32.cpp +++ b/src/univ/themes/win32.cpp @@ -57,6 +57,9 @@ #include "wx/artprov.h" #include "wx/toplevel.h" #include "wx/image.h" +#ifdef wxUSE_TOGGLEBTN +#include "wx/tglbtn.h" +#endif // wxUSE_TOGGLEBTN #include "wx/univ/scrtimer.h" #include "wx/univ/renderer.h" @@ -4341,8 +4344,15 @@ void wxWin32Renderer::AdjustSize(wxSize *size, const wxWindow *window) // do nothing } else #endif // wxUSE_BMPBUTTON -#if wxUSE_BUTTON - if ( wxDynamicCast(window, wxButton) ) +#if wxUSE_BUTTON || wxUSE_TOGGLEBTN + if ( 0 +# if wxUSE_BUTTON + || wxDynamicCast(window, wxButton) +# endif // wxUSE_BUTTON +# if wxUSE_TOGGLEBTN + || wxDynamicCast(window, wxToggleButton) +# endif // wxUSE_TOGGLEBTN + ) { if ( !(window->GetWindowStyle() & wxBU_EXACTFIT) ) { @@ -4371,7 +4381,7 @@ void wxWin32Renderer::AdjustSize(wxSize *size, const wxWindow *window) // no border width adjustments for buttons return; } -#endif // wxUSE_BUTTON +#endif // wxUSE_BUTTON || wxUSE_TOGGLEBTN // take into account the border width wxRect rectBorder = GetBorderDimensions(window->GetBorder()); -- 2.45.2