//************************************************************************************************** // PnlTxtSpn.cpp * // --------------- * // Started : 2004-03-20 * // Last Update : 2015-08-10 * // Copyright : (C) 2004-2016 MSWaters * //************************************************************************************************** //************************************************************************************************** // * // 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 3 of the License, or (at your option) any later version. * // * //************************************************************************************************** #include "PnlTxtSpn.hpp" //************************************************************************************************** // Allocate storage for static data members. uint PnlTxtSpn::m_uiSpnPeriod = SPN_PERIOD_DEF; //************************************************************************************************** // Implement an event table. wxBEGIN_EVENT_TABLE( PnlTxtSpn, wxPanel ) EVT_CHAR ( PnlTxtSpn::OnTxtChar ) EVT_TEXT_MAXLEN( PnlTxtSpn::ID_TXTCTRL, PnlTxtSpn::OnTxtMaxLen ) EVT_SPIN_UP ( PnlTxtSpn::ID_SPINBTN, PnlTxtSpn::OnSbnInc ) EVT_SPIN_DOWN ( PnlTxtSpn::ID_SPINBTN, PnlTxtSpn::OnSbnDec ) wxEND_EVENT_TABLE( ) //************************************************************************************************** // Constructor. PnlTxtSpn::PnlTxtSpn( void ) : wxPanel( ) { bClear( ); } //************************************************************************************************** // Destructor. PnlTxtSpn::~PnlTxtSpn( ) { } //************************************************************************************************** // Layout the display objects. void PnlTxtSpn::DoLayout( void ) { wxBoxSizer * poSzr; wxSizerFlags oFlags; // Create and set the sizer for the panel poSzr = new wxBoxSizer( wxHORIZONTAL ); SetSizer( poSzr ); #if !wxCHECK_VERSION( 3,0,0 ) oFlags.Expand( ); #endif // Add the text control oFlags.Proportion( 1 ); poSzr->Add( &m_oTxtValue, oFlags ); // Add the spin control oFlags.Proportion( 0 ); poSzr->Add( &m_oSbnValue, oFlags ); // Set the panel sizer and the min. & init. sizes as calculated by the sizer poSzr->SetSizeHints( this ); } //************************************************************************************************** // Create an instance of this object. // // Argument List : // poWin - The parent window // oWinID - The window identifier // iWidth - The width the spin control in pixels // // Return Values : // true - Success // false - Failure bool PnlTxtSpn::bCreate( wxWindow * poWin, wxWindowID oWinID, int iWidth ) { int i1; if( bIsCreated( ) ) return( true ); // Subtract 15 (pixels) from iWidth to allow for the spin control width i1 = iWidth - 15; if( i1 <= 0 ) i1 = -1; // Create the base class (wxPanel) if( ! wxPanel::Create( poWin, oWinID ) ) return( false ); // Create the text control m_oTxtValue.Create( this, ID_TXTCTRL, wxT(""), wxDefaultPosition, wxSize( i1, -1 ), wxTE_RIGHT ); // Create the spin control m_oSbnValue.Create( this, ID_SPINBTN, wxDefaultPosition, wxDefaultSize, wxSP_VERTICAL | wxSP_ARROW_KEYS ); // Set the display object attributes m_oTxtValue.SetMaxLength( SPN_MAXLEN ); m_oSbnValue.SetRange( -0x8000, 0x7FFF ); bSetValDef( m_dfDefValue ); bSetRange( m_dfMinValue, m_dfMaxValue ); bSetIncSz( m_dfMinIncSz, m_dfMaxIncSz ); bSetValue( m_dfDefValue ); // Layout the display objects DoLayout( ); return( true ); } //************************************************************************************************** // Clear the object attributes. // // Return Values : // true - Success // false - Failure bool PnlTxtSpn::bClear( void ) { bool bRtn=true; if( ! bSetValType( eVALUE_FLT ) ) bRtn = false; if( ! bSetValDef( 0.0 ) ) bRtn = false; if( ! bSetRange( -10000.0, 10000.0 ) ) bRtn = false; if( ! bSetIncSz( 1.0, 100.0 ) ) bRtn = false; if( m_oTxtValue.GetParent( ) != NULL ) m_oTxtValue.Clear( ); return( bRtn ); } //************************************************************************************************** // Set the variable type to be displayed by the spin control. // // Argument List : // eVType - The variable type specifier // // Return Values : // true - Success // false - Failure bool PnlTxtSpn::bSetValType( eTypeValue eVType ) { double df1; // Argument validity checks if( m_eValType == eVType ) return( true ); if( eVType!=eVALUE_INT && eVType!=eVALUE_FLT && eVType!=eVALUE_SCI && eVType!=eVALUE_ENG ) return( false ); // Set the new variable type m_eValType = eVType; // Display the new variable type if( bIsCreated( ) ) { if( ! rosGetValue( ).IsEmpty( ) ) { // Attempt to display the current value using the new format df1 = dfGetValue( ); bSetValue( df1 ); } } return( true ); } //************************************************************************************************** // Set the current value of the spin control. // // Argument List : // dfValue - The float value // // Return Values : // true - Success // false - Failure bool PnlTxtSpn::bSetValue( double dfValue ) { wxString osValue; double df1; long li1; int i1; // Argument validity checks if( ! bIsCreated( ) ) return( false ); if( dfValuem_dfMaxValue && !CnvtType::bIsEqual( dfValue, m_dfMaxValue ) ) return( false ); // Format the string to load into the control switch( m_eValType ) { case eVALUE_HEX : if( dfValue < 0.0 ) return( false ); li1 = lround( dfValue ); osValue.Printf( wxT("%X"), (ulong) li1 ); break; case eVALUE_INT : li1 = lround( dfValue ); osValue.Printf( wxT("%li"), li1 ); break; case eVALUE_FLT : osValue.Printf( wxT("%#.2f"), dfValue ); break; case eVALUE_SCI : osValue.Printf( wxT("%#.2E"), dfValue ); break; case eVALUE_ENG : if( ! CnvtType::bParseFlt( dfValue, &df1, &i1 ) ) return( false ); for( ; i1%3!=0; i1-- ) df1 *= 10.0; osValue.Printf( wxT("%#.2fE%02i"), df1, i1 ); break; default: return( false ); } // Load the new value osValue.Append( wxT(" ") ); m_oTxtValue.SetValue( osValue ); return( true ); } //************************************************************************************************** // Set the current value of the spin control. // // Argument List : // rosValue - The string value // // Return Values : // true - Success // false - Failure bool PnlTxtSpn::bSetValue( const wxString & rosValue ) { double dfValue; if( ! CnvtType::bStrToFlt( rosValue, &dfValue ) ) return( false ); if( ! bSetValue( dfValue ) ) return( false ); return( true ); } //************************************************************************************************** // Set the initial value of the spin control. // // Argument List : // dfDefValue - The spin control default value // // Return Values : // true - Success // false - Failure bool PnlTxtSpn::bSetValDef( double dfDefValue ) { if( dfDefValue == NOVAL_DBL ) return( bSetValue( m_dfDefValue ) ); if( dfDefValuem_dfMaxValue && !CnvtType::bIsEqual( dfDefValue, m_dfMaxValue ) ) return( false ); m_dfDefValue = dfDefValue; return( true ); } //************************************************************************************************** // Set the increment sizes of the spin control. // // This spin control can be incremented using two different approaches, // constant or variable step sizes. A constant step size means that the spin // control is incremented by the same amount throughout it's range. A variable // step size means that the spin control is incremented by an amount dependent // on it's current value. // // Argument List : // dfMinIncSz - The minimum spin control increment size // dfMaxIncSz - The maximum spin control increment size // // Return Values : // true - Success // false - Failure bool PnlTxtSpn::bSetIncSz( double dfMinIncSz, double dfMaxIncSz ) { // Constant or variable incrementing? if( dfMinIncSz < 0.0 ) return( false ); if( dfMaxIncSz < 0.0 ) dfMaxIncSz = dfMinIncSz; // Do some validity checks on the arguments if( dfMinIncSz > dfMaxIncSz ) return( false ); // Check that the new increment sizes fit within the current range if( dfMaxIncSz > (m_dfMaxValue - m_dfMinValue) ) return( false ); m_dfMinIncSz = dfMinIncSz; // Set increment sizes m_dfMaxIncSz = dfMaxIncSz; return( true ); } //************************************************************************************************** // Set the spin control range. // // Argument List : // dfMinValue - The spin control minimum value // dfMaxValue - The spin control maximum value // // Return Values : // true - Success // false - Failure bool PnlTxtSpn::bSetRange( double dfMinValue, double dfMaxValue ) { wxString os1; double df1; // Check argument validity if( dfMinValue >= dfMaxValue ) return( false ); // Set new parameter values m_dfMinValue = dfMinValue; m_dfMaxValue = dfMaxValue; // Update the text control if necessary if( bIsCreated( ) ) { os1 = m_oTxtValue.GetValue( ); CnvtType::bStrToFlt( os1, &df1 ); if( df1 < m_dfMinValue ) bSetValue( m_dfMinValue ); else if( df1 > m_dfMaxValue ) bSetValue( m_dfMaxValue ); } return( true ); } //************************************************************************************************** // Get the current spin control value as an integer. // // Return Values : // Success - The integer value // Failure - NOVAL_LONG long PnlTxtSpn::liGetValue( void ) { double df1; long li1; // Get the value as a float df1 = dfGetValue( ); if( df1 == NOVAL_DBL ) return( NOVAL_LNG ); // Round the value li1 = lround( df1 ); return( li1 ); } //************************************************************************************************** // Get the current spin control value as a float. // // Return Values : // Success - The float value // Failure - NOVAL_DBL double PnlTxtSpn::dfGetValue( void ) { wxString os1; double df1; // Has the control been created? if( ! bIsCreated( ) ) return( NOVAL_DBL ); // Get the value as a float os1 = m_oTxtValue.GetValue( ); if( ! CnvtType::bStrToFlt( os1, &df1 ) ) return( NOVAL_DBL ); return( df1 ); } //************************************************************************************************** // Get the current spin control value as a string. // // Return Values : // Success - The string value // Failure - An empty string const wxString & PnlTxtSpn::rosGetValue( void ) { static wxString osValue; osValue.Empty( ); if( dfGetValue( ) != NOVAL_DBL ) { osValue = m_oTxtValue.GetValue( ); osValue.Trim( ); } return( osValue ); } //************************************************************************************************** // Set the spin control repeat rate. // // Argument List : // uiPeriod - The period between successive spin control updates (in mSec) // // Return Values : // Success - true // Failure - false bool PnlTxtSpn::bSetSpnPeriod( uint uiPeriod ) { if( uiPeriodSPN_PERIOD_MAX ) return( false ); m_uiSpnPeriod = uiPeriod; return( true ); } //************************************************************************************************** // Print the object attributes. // // Argument List : // rosPrefix - A prefix to every line displayed (usually just spaces) void PnlTxtSpn::Print( const wxString & rosPrefix ) { std::cout << rosPrefix.mb_str( ) << "m_eValType : "; switch( m_eValType ) { case eVALUE_BIN : std::cout << "eVALUE_BIN"; break; case eVALUE_OCT : std::cout << "eVALUE_OCT"; break; case eVALUE_HEX : std::cout << "eVALUE_HEX"; break; case eVALUE_INT : std::cout << "eVALUE_INT"; break; case eVALUE_FLT : std::cout << "eVALUE_FLT"; break; case eVALUE_SCI : std::cout << "eVALUE_SCI"; break; case eVALUE_ENG : std::cout << "eVALUE_ENG"; break; case eVALUE_NONE : std::cout << "eVALUE_NONE"; break; default : std::cout << "Invalid"; } std::cout << '\n'; std::cout << rosPrefix.mb_str( ) << "m_dfDefValue : " << m_dfDefValue << '\n'; std::cout << rosPrefix.mb_str( ) << "m_dfMinValue : " << m_dfMinValue << '\n'; std::cout << rosPrefix.mb_str( ) << "m_dfMaxValue : " << m_dfMaxValue << '\n'; std::cout << rosPrefix.mb_str( ) << "m_dfMinIncSz : " << m_dfMinIncSz << '\n'; std::cout << rosPrefix.mb_str( ) << "m_dfMaxIncSz : " << m_dfMaxIncSz << '\n'; } //************************************************************************************************** // Event Handlers * //************************************************************************************************** // Key press event handler. // // Argument List : // roEvtKey - An object holding information about the event void PnlTxtSpn::OnTxtChar( wxKeyEvent & roEvtKey ) { wxSpinEvent oEvtSpn; int iKeyCode; // Look for the modifier keys and if( roEvtKey.HasModifiers( ) ) return; // Get the key code iKeyCode = roEvtKey.GetKeyCode( ); // Process arrow keys etc. if( iKeyCode == WXK_UP ) { OnSbnInc( oEvtSpn ); return; } else if( iKeyCode == WXK_DOWN ) { OnSbnDec( oEvtSpn ); return; } // Test that the key code is valid and reject invalid characters // ??? (2007-07-07) This doesn't work but it would be good if it did. Only up // and down arrow keys get through to this function, don't know why. switch( iKeyCode ) { case (int) '.' : case (int) '0' : case (int) '1' : case (int) '2' : case (int) '3' : case (int) '4' : case (int) '5' : case (int) '6' : case (int) '7' : case (int) '8' : case (int) '9' : case (int) '+' : case (int) '-' : case (int) 'e' : case (int) 'E' : case WXK_BACK : case WXK_DELETE : break; default : wxBell( ); // Sound the system bell } } //************************************************************************************************** // Text control maximum length reached event handler. // // Argument List : // roEvtCmd - An object holding information about the event void PnlTxtSpn::OnTxtMaxLen( wxCommandEvent & roEvtCmd ) { wxBell( ); // Sound the system bell } //************************************************************************************************** // Spin button scroll up event handler. // // Argument List : // roEvtSpn - An object holding information about the event void PnlTxtSpn::OnSbnInc( wxSpinEvent & roEvtSpn ) { static uint ui_msec=0; double dfValue, dfIncSz; wxString os1; double df1, df2; uint ui1; int i1; // Allow additional event handlers to be called roEvtSpn.Skip( ); // Increment the text control SPN_RPTRATE times per second ui1 = (uint) wxGetLocalTimeMillis( ).GetLo( ); if( ui1>ui_msec && (ui1-ui_msec) m_dfMaxIncSz ) dfIncSz = m_dfMaxIncSz; } // Determine if the text control value is a whole multiple of the increment size if( ! CnvtType::bIsEqual( fmod( dfValue, dfIncSz ), 0.0 ) ) dfIncSz = ceil( dfValue / dfIncSz ) * dfIncSz - dfValue; // Increment the value and check it against the minimum and maximum limits dfValue += dfIncSz; if( dfValue > m_dfMaxValue ) dfValue = m_dfMaxValue; else if( dfValue < m_dfMinValue ) dfValue = m_dfMinValue; // Set the text control value bSetValue( dfValue ); } //************************************************************************************************** // Spin button scroll down event handler. // // Argument List : // roEvtSpn - An object holding information about the event void PnlTxtSpn::OnSbnDec( wxSpinEvent & roEvtSpn ) { static uint ui_msec=0; double dfValue, dfDecSz; wxString os1; double df1, df2; uint ui1; int i1; // Allow additional event handlers to be called roEvtSpn.Skip( ); // Decrement the text control SPN_RPTRATE times per second ui1 = (uint) wxGetLocalTimeMillis( ).GetLo( ); if( ui1>ui_msec && (ui1-ui_msec) m_dfMaxIncSz ) dfDecSz = m_dfMaxIncSz; } // Determine if the text control value is a whole multiple of the decrement size if( ! CnvtType::bIsEqual( round( dfValue / dfDecSz ), dfValue / dfDecSz ) ) dfDecSz = dfValue - floor( dfValue / dfDecSz ) * dfDecSz; // Decrement the value and check it against the minimum and maximum limits dfValue -= dfDecSz; if( dfValue < m_dfMinValue ) { // The following makes zero a valid value even if the allowable limits don't include it if( m_eValType==eVALUE_SCI || m_eValType==eVALUE_ENG ) dfValue = 0.0; else dfValue = m_dfMinValue; } else if( dfValue > m_dfMaxValue ) dfValue = m_dfMaxValue; // Set the text control value bSetValue( dfValue ); } //**************************************************************************************************