Add a class to govern an "incrementing" text control
This class, INCREMENTAL_TEXT_CTRL, is used to provide a frameworks for classes that want to control a text control that can be incremented according to some scheme. Also provided is a wxWidgets implementation with spin buttons for control, as well as mousewheel support.
This commit is contained in:
parent
971f2db034
commit
061d659bb1
|
@ -230,6 +230,7 @@ set( COMMON_SRCS
|
|||
gr_basic.cpp
|
||||
hotkeys_basic.cpp
|
||||
html_messagebox.cpp
|
||||
incremental_text_ctrl.cpp
|
||||
kiface_i.cpp
|
||||
kiway.cpp
|
||||
kiway_express.cpp
|
||||
|
|
|
@ -0,0 +1,184 @@
|
|||
/*
|
||||
* This program source code file is part of KiCad, a free EDA CAD application.
|
||||
*
|
||||
* Copyright (C) 2015 Jean-Pierre Charras, jean-pierre.charras at wanadoo.fr
|
||||
* Copyright (C) 1992-2016 KiCad Developers, see AUTHORS.txt for contributors.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version 2
|
||||
* of the License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, you may find one here:
|
||||
* http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
|
||||
* or you may search the http://www.gnu.org website for the version 2 license,
|
||||
* or you may write to the Free Software Foundation, Inc.,
|
||||
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
|
||||
*/
|
||||
|
||||
#include <incremental_text_ctrl.h>
|
||||
|
||||
/**
|
||||
* Check that a string looks like a floating point number that can
|
||||
* be dealt with.
|
||||
*/
|
||||
static bool validateFloatField( const wxString& aStr )
|
||||
{
|
||||
// Skip empty fields
|
||||
if( aStr.size() == 0 )
|
||||
return false;
|
||||
|
||||
// a single . or , doesn't count as number, although valid in a float
|
||||
if( aStr.size() == 1 )
|
||||
{
|
||||
if( (aStr.compare( "." ) == 0) ||
|
||||
(aStr.compare( "," ) == 0) )
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
INCREMENTAL_TEXT_CTRL::INCREMENTAL_TEXT_CTRL() :
|
||||
m_minVal( 0.0 ),
|
||||
m_maxVal( 1.0 ),
|
||||
m_currentValue( 0.0 ),
|
||||
m_precision( 4 )
|
||||
{}
|
||||
|
||||
|
||||
void INCREMENTAL_TEXT_CTRL::SetStep( double aMin, double aMax,
|
||||
STEP_FUNCTION aStepFunc )
|
||||
{
|
||||
wxASSERT( aMin <= aMax );
|
||||
|
||||
m_minVal = std::min( aMin, aMax );
|
||||
m_maxVal = std::max( aMin, aMax );
|
||||
m_stepFunc = aStepFunc;
|
||||
|
||||
// finally, clamp the current value and re-display
|
||||
updateTextValue();
|
||||
}
|
||||
|
||||
|
||||
void INCREMENTAL_TEXT_CTRL::updateTextValue()
|
||||
{
|
||||
if( m_currentValue > m_maxVal )
|
||||
m_currentValue = m_maxVal;
|
||||
|
||||
if( m_currentValue < m_minVal )
|
||||
m_currentValue = m_minVal;
|
||||
|
||||
wxString fmt = wxString::Format( "%%.%df", m_precision );
|
||||
setTextCtrl( wxString::Format( fmt, m_currentValue ) );
|
||||
}
|
||||
|
||||
|
||||
void INCREMENTAL_TEXT_CTRL::incrementCtrlBy( double aInc )
|
||||
{
|
||||
const wxString txt = getCtrlText();
|
||||
if( !validateFloatField( txt ) )
|
||||
return;
|
||||
|
||||
txt.ToDouble( &m_currentValue );
|
||||
m_currentValue += aInc;
|
||||
|
||||
updateTextValue();
|
||||
}
|
||||
|
||||
|
||||
void INCREMENTAL_TEXT_CTRL::incrementCtrl( bool aUp )
|
||||
{
|
||||
incrementCtrlBy( m_stepFunc( aUp, m_currentValue ) );
|
||||
}
|
||||
|
||||
|
||||
void INCREMENTAL_TEXT_CTRL::SetPrecision( int aPrecision )
|
||||
{
|
||||
m_precision = aPrecision;
|
||||
}
|
||||
|
||||
|
||||
void INCREMENTAL_TEXT_CTRL::SetValue( double aValue )
|
||||
{
|
||||
m_currentValue = aValue;
|
||||
updateTextValue();
|
||||
}
|
||||
|
||||
|
||||
double INCREMENTAL_TEXT_CTRL::GetValue()
|
||||
{
|
||||
// sanitise before handing the value - if the user did something
|
||||
// like close a window with outstanding text changes, we need
|
||||
// to clamp the value and re-interpret the text
|
||||
incrementCtrlBy( 0.0 );
|
||||
|
||||
return m_currentValue;
|
||||
}
|
||||
|
||||
|
||||
SPIN_INCREMENTAL_TEXT_CTRL::SPIN_INCREMENTAL_TEXT_CTRL( wxSpinButton& aSpinBtn,
|
||||
wxTextCtrl& aTextCtrl ):
|
||||
m_spinBtn( aSpinBtn ),
|
||||
m_textCtrl( aTextCtrl )
|
||||
{
|
||||
// set always enabled, otherwise it's very hard to keep in sync
|
||||
aSpinBtn.SetRange( -INT_MAX, INT_MAX );
|
||||
|
||||
auto spinUpHandler = [this] ( wxSpinEvent& event )
|
||||
{
|
||||
incrementCtrl( true );
|
||||
};
|
||||
|
||||
// spin up/down if a single step of the field
|
||||
auto spinDownHandler = [this] ( wxSpinEvent& event )
|
||||
{
|
||||
incrementCtrl( false );
|
||||
};
|
||||
|
||||
auto mouseWheelHandler = [this] ( wxMouseEvent& aEvent )
|
||||
{
|
||||
incrementCtrl( aEvent.GetWheelRotation() >= 0 );
|
||||
};
|
||||
|
||||
aSpinBtn.Bind( wxEVT_SPIN_UP, spinUpHandler );
|
||||
aSpinBtn.Bind( wxEVT_SPIN_DOWN, spinDownHandler );
|
||||
|
||||
m_textCtrl.Bind( wxEVT_MOUSEWHEEL, mouseWheelHandler );
|
||||
|
||||
m_textCtrl.Bind( wxEVT_KILL_FOCUS, &SPIN_INCREMENTAL_TEXT_CTRL::onFocusLoss, this );
|
||||
}
|
||||
|
||||
SPIN_INCREMENTAL_TEXT_CTRL::~SPIN_INCREMENTAL_TEXT_CTRL()
|
||||
{
|
||||
// this must be unbound, as kill focus can arrive after the
|
||||
// text control is gone
|
||||
m_textCtrl.Unbind( wxEVT_KILL_FOCUS, &SPIN_INCREMENTAL_TEXT_CTRL::onFocusLoss, this );
|
||||
}
|
||||
|
||||
|
||||
void SPIN_INCREMENTAL_TEXT_CTRL::onFocusLoss( wxFocusEvent& aEvent )
|
||||
{
|
||||
// re-read the input and sanitize any user changes
|
||||
incrementCtrlBy( 0.0 );
|
||||
}
|
||||
|
||||
|
||||
void SPIN_INCREMENTAL_TEXT_CTRL::setTextCtrl( const wxString& val )
|
||||
{
|
||||
m_textCtrl.SetValue( val );
|
||||
}
|
||||
|
||||
|
||||
wxString SPIN_INCREMENTAL_TEXT_CTRL::getCtrlText() const
|
||||
{
|
||||
return m_textCtrl.GetValue();
|
||||
}
|
||||
|
|
@ -0,0 +1,188 @@
|
|||
/*
|
||||
* This program source code file is part of KiCad, a free EDA CAD application.
|
||||
*
|
||||
* Copyright (C) 2013 CERN
|
||||
* @author Maciej Suminski <maciej.suminski@cern.ch>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version 2
|
||||
* of the License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, you may find one here:
|
||||
* http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
|
||||
* or you may search the http://www.gnu.org website for the version 2 license,
|
||||
* or you may write to the Free Software Foundation, Inc.,
|
||||
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
|
||||
*/
|
||||
|
||||
#ifndef INCREMENTAL_TEXT_CTRL__H_
|
||||
#define INCREMENTAL_TEXT_CTRL__H_
|
||||
|
||||
#include <wx/wx.h>
|
||||
#include <wx/spinbutt.h>
|
||||
|
||||
#include <functional>
|
||||
|
||||
/**
|
||||
* Class that governs a textual control holding a number that can
|
||||
* be incremented/decremented according to some scheme (often just
|
||||
* a constant step).
|
||||
*/
|
||||
class INCREMENTAL_TEXT_CTRL
|
||||
{
|
||||
public:
|
||||
|
||||
/**
|
||||
* A callable object type that can be used to provide a step
|
||||
* value. Client can provide one of these to use for implementing
|
||||
* non-linear stepping, or stepping based on external parameters,
|
||||
* such as unit selection.
|
||||
*
|
||||
* @param aUp true if the next step is upwards
|
||||
* @param aCurrVal the current value of the control
|
||||
*/
|
||||
using STEP_FUNCTION = std::function<double(bool aUp, double aCurrVal)>;
|
||||
|
||||
INCREMENTAL_TEXT_CTRL();
|
||||
|
||||
virtual ~INCREMENTAL_TEXT_CTRL() {}
|
||||
|
||||
/**
|
||||
* Set the value of the text control, but obey the limits
|
||||
* currently set.
|
||||
*
|
||||
* @param aValue the control value to set
|
||||
*/
|
||||
void SetValue( double aValue );
|
||||
|
||||
/**
|
||||
* Get the current value of the control
|
||||
*/
|
||||
double GetValue();
|
||||
|
||||
/**
|
||||
* Function SetStep()
|
||||
*
|
||||
* Set the stepping parameters of the control. The range is
|
||||
* enforced by not allowing the scroll to exceed it, and on
|
||||
* loss of focus, the control is also clamped to the range.
|
||||
*
|
||||
* @param aMin the minium value allowed
|
||||
* @param aMax the maximum value allows
|
||||
* @param aNewfunc the step function used to calculate the next step
|
||||
*/
|
||||
void SetStep( double aMin, double aMax, STEP_FUNCTION aNewFunc );
|
||||
|
||||
/**
|
||||
* Function SetStep()
|
||||
*
|
||||
* Shortcut method to set step parameters when the step is constant
|
||||
*
|
||||
* @param aMin the minium value allowed
|
||||
* @param aMax the maximum value allows
|
||||
* @param aStep the constant step size
|
||||
*/
|
||||
void SetStep( double aMin, double aMax, double aStep )
|
||||
{
|
||||
SetStep( aMin, aMax,
|
||||
[aStep] ( bool aUp, double aCurrent ) { return aUp ? aStep : -aStep; } );
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the number of decimal places to display
|
||||
*/
|
||||
void SetPrecision( int aPrecision );
|
||||
|
||||
protected:
|
||||
|
||||
/**
|
||||
* Increment the control by the given amount
|
||||
*/
|
||||
void incrementCtrlBy( double aInc);
|
||||
|
||||
/**
|
||||
* Single increment up or down by one step
|
||||
*/
|
||||
void incrementCtrl( bool aUp );
|
||||
|
||||
/**
|
||||
* Update the text control value with the current value,
|
||||
* clamping to limits as needed
|
||||
*/
|
||||
void updateTextValue();
|
||||
|
||||
/*
|
||||
* Implementation-specific interfaces
|
||||
*/
|
||||
|
||||
/**
|
||||
* Set the text control string value after an increment.
|
||||
*/
|
||||
virtual void setTextCtrl( const wxString& aVal ) = 0;
|
||||
|
||||
/**
|
||||
* @return the current string value of the text control
|
||||
*/
|
||||
virtual wxString getCtrlText() const = 0;
|
||||
|
||||
private:
|
||||
|
||||
double m_minVal;
|
||||
double m_maxVal;
|
||||
|
||||
///< Current value of the control
|
||||
double m_currentValue;
|
||||
|
||||
///< Precision to display
|
||||
int m_precision;
|
||||
|
||||
///< The function used to determine the step
|
||||
STEP_FUNCTION m_stepFunc;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Class SPIN_INCREMENTING_TEXT_CTRL
|
||||
*
|
||||
* An incrementable text control, with WX spin buttons for clickable
|
||||
* control.
|
||||
*/
|
||||
class SPIN_INCREMENTAL_TEXT_CTRL: public INCREMENTAL_TEXT_CTRL
|
||||
{
|
||||
public:
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
*
|
||||
* @param aSpinBtn the spin button to control the value
|
||||
* @param aTextCtrl the text control that will display the value
|
||||
*/
|
||||
SPIN_INCREMENTAL_TEXT_CTRL( wxSpinButton& aSpinBtn,
|
||||
wxTextCtrl& aTextCtrl );
|
||||
|
||||
~SPIN_INCREMENTAL_TEXT_CTRL();
|
||||
|
||||
protected:
|
||||
|
||||
///> @copydoc INCREMENTAL_TEXT_CTRL::setTextCtrl()
|
||||
void setTextCtrl( const wxString& val ) override;
|
||||
|
||||
///> @copydoc INCREMENTAL_TEXT_CTRL::getCtrlText()
|
||||
wxString getCtrlText() const override;
|
||||
|
||||
private:
|
||||
|
||||
void onFocusLoss( wxFocusEvent& aEvent );
|
||||
|
||||
wxSpinButton& m_spinBtn;
|
||||
wxTextCtrl& m_textCtrl;
|
||||
};
|
||||
|
||||
#endif /* INCREMENTAL_TEXT_CTRL__H_ */
|
|
@ -205,6 +205,7 @@ DIALOG_DISPLAY_OPTIONS::DIALOG_DISPLAY_OPTIONS( PCB_EDIT_FRAME* parent ) :
|
|||
FinishDialogSettings();
|
||||
}
|
||||
|
||||
|
||||
void DIALOG_DISPLAY_OPTIONS::init()
|
||||
{
|
||||
SetFocus();
|
||||
|
|
Loading…
Reference in New Issue