From 2f58dc7d94ccfb790675201a794efab6a1403499 Mon Sep 17 00:00:00 2001 From: Max Maisel Date: Sun, 9 Feb 2020 14:55:23 +0100 Subject: [PATCH] Add combined slider and text box widget. This widgets will be used in the new Compresor2 effect but it is designed for use in other effects as well. Signed-off-by: Max Maisel --- src/CMakeLists.txt | 2 + src/ShuttleGui.cpp | 27 ++++++ src/ShuttleGui.h | 5 + src/widgets/SliderTextCtrl.cpp | 167 +++++++++++++++++++++++++++++++++ src/widgets/SliderTextCtrl.h | 77 +++++++++++++++ 5 files changed, 278 insertions(+) create mode 100644 src/widgets/SliderTextCtrl.cpp create mode 100644 src/widgets/SliderTextCtrl.h diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index cfa06880b..8ac44c420 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -956,6 +956,8 @@ list( APPEND SOURCES PRIVATE widgets/ReadOnlyText.h widgets/Ruler.cpp widgets/Ruler.h + widgets/SliderTextCtrl.cpp + widgets/SliderTextCtrl.h widgets/UnwritableLocationErrorDialog.cpp widgets/UnwritableLocationErrorDialog.h widgets/Warning.cpp diff --git a/src/ShuttleGui.cpp b/src/ShuttleGui.cpp index 82ab555c5..3328d80b2 100644 --- a/src/ShuttleGui.cpp +++ b/src/ShuttleGui.cpp @@ -121,6 +121,8 @@ for registering for changes. #include "widgets/wxTextCtrlWrapper.h" #include "AllThemeResources.h" +#include "widgets/SliderTextCtrl.h" + #if wxUSE_ACCESSIBILITY #include "widgets/WindowAccessible.h" #endif @@ -613,6 +615,31 @@ wxSlider * ShuttleGuiBase::AddSlider( return pSlider; } +SliderTextCtrl* ShuttleGuiBase::AddSliderTextCtrl( + const TranslatableString &Prompt, double pos, double Max, double Min, + int precision, double* value, double scale) +{ + HandleOptionality( Prompt ); + AddPrompt( Prompt ); + UseUpId(); + if( mShuttleMode != eIsCreating ) + return wxDynamicCast(wxWindow::FindWindowById( miId, mpDlg), SliderTextCtrl); + SliderTextCtrl * pSlider; + mpWind = pSlider = safenew SliderTextCtrl(GetParent(), miId, + pos, Min, Max, precision, scale, wxDefaultPosition, wxDefaultSize, + GetStyle( SliderTextCtrl::HORIZONTAL ), + value + ); +#if wxUSE_ACCESSIBILITY + // so that name can be set on a standard control + mpWind->SetAccessible(safenew WindowAccessible(mpWind)); +#endif + mpWind->SetName(wxStripMenuCodes(Prompt.Translation())); + miProp=1; + UpdateSizers(); + return pSlider; +} + wxSpinCtrl * ShuttleGuiBase::AddSpinCtrl( const TranslatableString &Prompt, int Value, int Max, int Min) { diff --git a/src/ShuttleGui.h b/src/ShuttleGui.h index d35d928cf..da01fa8d6 100644 --- a/src/ShuttleGui.h +++ b/src/ShuttleGui.h @@ -28,6 +28,7 @@ class ChoiceSetting; class wxArrayStringEx; +class SliderTextCtrl; const int nMaxNestedSizers = 20; @@ -263,6 +264,10 @@ public: int Value, int Max, int Min); wxTreeCtrl * AddTree(); + SliderTextCtrl* AddSliderTextCtrl( + const TranslatableString &Prompt, double pos, double Max, double Min = 0, + int precision = 2, double* value = NULL, double scale = 0); + // Pass the same initValue to the sequence of calls to AddRadioButton and // AddRadioButtonToGroup. // The radio button is filled if selector == initValue diff --git a/src/widgets/SliderTextCtrl.cpp b/src/widgets/SliderTextCtrl.cpp new file mode 100644 index 000000000..524d1a9f6 --- /dev/null +++ b/src/widgets/SliderTextCtrl.cpp @@ -0,0 +1,167 @@ +/********************************************************************** + + Audacity: A Digital Audio Editor + + SliderTextCtrl.cpp + + Max Maisel + +*******************************************************************//** + +\class SliderTextCtrl +\brief A slider with connected text box. + +*//*******************************************************************/ + + +#include "../Audacity.h" +#include "audacity/Types.h" +#include "SliderTextCtrl.h" + +#include +#include +#include +#include +#include +#include + +wxDEFINE_EVENT(cEVT_SLIDERTEXT, wxCommandEvent); + +SliderTextCtrl::SliderTextCtrl(wxWindow *parent, wxWindowID winid, + double value, double min, double max, int precision, double scale, + const wxPoint& pos, const wxSize& size, long style, double* varValue) + : wxPanelWrapper(parent, winid, pos, size, wxWS_EX_VALIDATE_RECURSIVELY) +{ + m_log = style & LOG; + m_int = style & INT; + m_value = value; + m_min = min; + m_max = max; + m_zero = -std::numeric_limits::infinity(); + + if(m_int) + { + precision = 0; + m_format = "%d"; + } + else + m_format = wxString::Format("%%.%df", precision); + + if(scale == 0) + m_scale = pow(10, precision); + else + m_scale = scale; + + wxFloatingPointValidator validator(precision, varValue); + + if(m_log) + { + if(min <= 0.0) + { + m_zero = -double(precision) - 1.0 / m_scale; + min = m_zero; + } + else + min = log10(min); + + if(value <= 0.0) + value = m_zero; + else + value = log10(value); + max = log10(max); + } + + m_sizer = safenew wxBoxSizer( + style & HORIZONTAL ? wxHORIZONTAL : wxVERTICAL); + m_slider = safenew wxSlider(this, ID_SLIDER, + round(value * m_scale), floor(min * m_scale), ceil(max * m_scale), + wxDefaultPosition, wxDefaultSize, + style & HORIZONTAL ? wxSL_HORIZONTAL : wxSL_VERTICAL); + m_textbox = safenew wxTextCtrl(this, ID_TEXTBOX, wxEmptyString, + wxDefaultPosition, wxDefaultSize, 0, validator); + + m_textbox->ChangeValue(FormatValue()); + m_textbox->Bind(wxEVT_KILL_FOCUS, &SliderTextCtrl::OnKillFocus, this); + + m_sizer->Add(m_slider, 1, wxEXPAND); + m_sizer->Add(m_textbox, 0, wxEXPAND); + + SetSizer(m_sizer); +} + +void SliderTextCtrl::SetMinTextboxWidth(int width) +{ + wxSize size = GetMinSize(); + size.SetWidth(width); + m_textbox->SetMinSize(size); +} + +double SliderTextCtrl::GetValue() const +{ + return m_value; +} + +void SliderTextCtrl::SetValue(double value) +{ + m_value = value; + m_textbox->ChangeValue(FormatValue()); +} + +void SliderTextCtrl::OnTextChange(wxCommandEvent& event) +{ + double value; + m_textbox->GetValue().ToDouble(&value); + m_value = std::min(value, m_max); + m_value = std::max(m_value, m_min); + if(m_log) + { + if(m_value == 0.0) + value = m_zero; + else + value = log10(m_value); + } + m_slider->SetValue(round(value * m_scale)); + event.SetEventType(cEVT_SLIDERTEXT); + event.Skip(); +} + +void SliderTextCtrl::OnSlider(wxCommandEvent& event) +{ + m_value = m_slider->GetValue() / m_scale; + if(m_log) + { + if(m_value <= m_zero) + m_value = 0.0; + else + { + m_value = pow(10.0, m_value); + m_value = std::max(m_min, m_value); + m_value = std::min(m_max, m_value); + } + } + m_textbox->ChangeValue(FormatValue()); + m_textbox->SetSelection(-1, -1); + event.SetEventType(cEVT_SLIDERTEXT); + event.Skip(); +} + +void SliderTextCtrl::OnKillFocus(wxFocusEvent& _) +{ + m_textbox->ChangeValue(FormatValue()); + wxCommandEvent event(cEVT_SLIDERTEXT, GetId()); + wxPostEvent(GetParent(), event); +} + +wxString SliderTextCtrl::FormatValue() const +{ + int v = m_value; + if(m_int) + return wxString::Format(m_format, v); + else + return wxString::Format(m_format, m_value); +} + +BEGIN_EVENT_TABLE(SliderTextCtrl, wxControl) + EVT_TEXT(ID_TEXTBOX, SliderTextCtrl::OnTextChange) + EVT_SLIDER(ID_SLIDER, SliderTextCtrl::OnSlider) +END_EVENT_TABLE() diff --git a/src/widgets/SliderTextCtrl.h b/src/widgets/SliderTextCtrl.h new file mode 100644 index 000000000..f8d27efa0 --- /dev/null +++ b/src/widgets/SliderTextCtrl.h @@ -0,0 +1,77 @@ +/********************************************************************** + + Audacity: A Digital Audio Editor + + SliderTextCtrl.h + + Max Maisel + + This class is a custom slider. + +**********************************************************************/ + +#ifndef __AUDACITY_SLIDERTEXTCTRL__ +#define __AUDACITY_SLIDERTEXTCTRL__ + +#include "wxPanelWrapper.h" // to inherit + +class wxSizer; +class wxSlider; +class wxTextCtrl; + +wxDECLARE_EVENT(cEVT_SLIDERTEXT, wxCommandEvent); + +#define EVT_SLIDERTEXT(winid, func) wx__DECLARE_EVT1( \ + cEVT_SLIDERTEXT, winid, wxCommandEventHandler(func)) + +class SliderTextCtrl : public wxPanelWrapper +{ + public: + enum Styles + { + HORIZONTAL = 1, + VERTICAL = 2, + LOG = 4, + INT = 8, + }; + + SliderTextCtrl(wxWindow *parent, wxWindowID winid, + double value, double min, double max, int precision = 2, + double scale = 0, const wxPoint& pos = wxDefaultPosition, + const wxSize& size = wxDefaultSize, long style = HORIZONTAL, + double* varValue = NULL); + + void SetMinTextboxWidth(int width); + + double GetValue() const; + void SetValue(double value); + + private: + void OnTextChange(wxCommandEvent& event); + void OnSlider(wxCommandEvent& event); + void OnKillFocus(wxFocusEvent& event); + wxString FormatValue() const; + + enum + { + ID_SLIDER = 1, + ID_TEXTBOX + }; + + wxSizer* m_sizer; + wxSlider* m_slider; + wxTextCtrl* m_textbox; + + bool m_log; + bool m_int; + double m_value; + double m_scale; + double m_min; + double m_max; + double m_zero; + wxString m_format; + + DECLARE_EVENT_TABLE() +}; + +#endif