2015-02-17 23:35:18 +00:00
|
|
|
/*
|
|
|
|
* This program source code file is part of KiCad, a free EDA CAD application.
|
|
|
|
*
|
|
|
|
* Copyright (C) 2014-2015 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
|
|
|
|
*/
|
|
|
|
|
2019-09-07 23:00:15 +00:00
|
|
|
#include <wx/clipbrd.h>
|
2015-02-17 23:35:18 +00:00
|
|
|
#include <wx/stattext.h>
|
2017-08-25 14:46:49 +00:00
|
|
|
#include <wx/textentry.h>
|
2015-02-17 23:35:18 +00:00
|
|
|
#include <limits>
|
|
|
|
#include <base_units.h>
|
2018-02-03 09:09:53 +00:00
|
|
|
#include <draw_frame.h>
|
|
|
|
#include <confirm.h>
|
2015-02-17 23:35:18 +00:00
|
|
|
|
2017-11-10 23:27:46 +00:00
|
|
|
#include "widgets/unit_binder.h"
|
2015-02-17 23:35:18 +00:00
|
|
|
|
2018-11-23 14:58:38 +00:00
|
|
|
wxDEFINE_EVENT( DELAY_FOCUS, wxCommandEvent );
|
|
|
|
|
2018-02-03 09:09:53 +00:00
|
|
|
UNIT_BINDER::UNIT_BINDER( EDA_DRAW_FRAME* aParent,
|
2018-03-07 12:48:08 +00:00
|
|
|
wxStaticText* aLabel, wxWindow* aValue, wxStaticText* aUnitLabel,
|
2018-11-29 18:59:38 +00:00
|
|
|
bool aUseMils, bool allowEval ) :
|
2018-02-03 09:09:53 +00:00
|
|
|
m_label( aLabel ),
|
2018-03-07 12:48:08 +00:00
|
|
|
m_value( aValue ),
|
2015-03-11 16:04:20 +00:00
|
|
|
m_unitLabel( aUnitLabel ),
|
2018-02-03 09:09:53 +00:00
|
|
|
m_eval( aParent->GetUserUnits(), aUseMils )
|
2015-02-17 23:35:18 +00:00
|
|
|
{
|
2018-02-03 09:09:53 +00:00
|
|
|
// Fix the units (to the current units) for the life of the binder
|
|
|
|
m_units = aParent->GetUserUnits();
|
|
|
|
m_useMils = aUseMils;
|
2018-03-07 12:48:08 +00:00
|
|
|
m_allowEval = allowEval && dynamic_cast<wxTextEntry*>( m_value );
|
2018-10-08 11:58:10 +00:00
|
|
|
m_needsEval = false;
|
2019-09-07 23:00:15 +00:00
|
|
|
m_selStart = 0;
|
|
|
|
m_selEnd = 0;
|
2018-02-03 09:09:53 +00:00
|
|
|
|
2018-03-07 12:48:08 +00:00
|
|
|
auto textEntry = dynamic_cast<wxTextEntry*>( m_value );
|
|
|
|
if( textEntry )
|
2018-07-21 08:41:38 +00:00
|
|
|
{
|
|
|
|
// Use ChangeValue() instead of SetValue() so we don't generate events.
|
|
|
|
textEntry->ChangeValue( wxT( "0" ) );
|
|
|
|
}
|
2015-02-17 23:35:18 +00:00
|
|
|
|
2020-12-09 18:38:35 +00:00
|
|
|
if( m_unitLabel )
|
|
|
|
m_unitLabel->SetLabel( GetAbbreviatedUnitsLabel( m_units, m_useMils ) );
|
2015-02-17 23:35:18 +00:00
|
|
|
|
2018-03-07 12:48:08 +00:00
|
|
|
m_value->Connect( wxEVT_SET_FOCUS, wxFocusEventHandler( UNIT_BINDER::onSetFocus ), NULL, this );
|
|
|
|
m_value->Connect( wxEVT_KILL_FOCUS, wxFocusEventHandler( UNIT_BINDER::onKillFocus ), NULL, this );
|
2018-11-23 14:58:38 +00:00
|
|
|
Connect( DELAY_FOCUS, wxCommandEventHandler( UNIT_BINDER::delayedFocusHandler ), NULL, this );
|
2015-02-17 23:35:18 +00:00
|
|
|
}
|
|
|
|
|
2015-02-18 16:53:46 +00:00
|
|
|
|
2018-05-23 06:11:47 +00:00
|
|
|
void UNIT_BINDER::SetUnits( EDA_UNITS_T aUnits, bool aUseMils )
|
|
|
|
{
|
|
|
|
m_units = aUnits;
|
|
|
|
m_useMils = aUseMils;
|
2020-12-09 18:38:35 +00:00
|
|
|
|
|
|
|
if( m_unitLabel )
|
|
|
|
m_unitLabel->SetLabel( GetAbbreviatedUnitsLabel( m_units, m_useMils ) );
|
2018-05-23 06:11:47 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2018-02-03 09:09:53 +00:00
|
|
|
void UNIT_BINDER::onSetFocus( wxFocusEvent& aEvent )
|
|
|
|
{
|
2018-03-07 12:48:08 +00:00
|
|
|
auto textEntry = dynamic_cast<wxTextEntry*>( m_value );
|
|
|
|
|
|
|
|
if( m_allowEval && textEntry )
|
2018-02-03 09:09:53 +00:00
|
|
|
{
|
2018-02-25 16:14:24 +00:00
|
|
|
wxString oldStr = m_eval.OriginalText();
|
2018-02-03 09:09:53 +00:00
|
|
|
|
2018-02-25 16:14:24 +00:00
|
|
|
if( oldStr.length() )
|
2019-09-07 23:00:15 +00:00
|
|
|
{
|
2018-03-07 12:48:08 +00:00
|
|
|
textEntry->SetValue( oldStr );
|
2019-09-07 23:00:15 +00:00
|
|
|
textEntry->SetSelection( m_selStart, m_selEnd );
|
|
|
|
}
|
2018-10-08 11:58:10 +00:00
|
|
|
|
|
|
|
m_needsEval = true;
|
2018-02-03 09:09:53 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
aEvent.Skip();
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void UNIT_BINDER::onKillFocus( wxFocusEvent& aEvent )
|
|
|
|
{
|
2018-11-29 18:59:38 +00:00
|
|
|
auto textEntry = dynamic_cast<wxTextEntry*>( m_value );
|
2018-10-08 11:58:10 +00:00
|
|
|
|
2018-11-29 18:59:38 +00:00
|
|
|
if( m_allowEval && textEntry )
|
|
|
|
{
|
|
|
|
if( m_eval.Process( textEntry->GetValue() ) )
|
2019-09-07 23:00:15 +00:00
|
|
|
{
|
|
|
|
textEntry->GetSelection( &m_selStart, &m_selEnd );
|
|
|
|
wxString sel = textEntry->GetStringSelection();
|
|
|
|
|
2018-11-29 18:59:38 +00:00
|
|
|
textEntry->ChangeValue( m_eval.Result() );
|
2018-11-27 17:08:11 +00:00
|
|
|
|
2019-09-07 23:00:15 +00:00
|
|
|
#ifdef __WXGTK__
|
|
|
|
// Manually copy the selected text to the primary selection clipboard
|
|
|
|
if( wxTheClipboard->Open() )
|
|
|
|
{
|
|
|
|
bool clipTarget = wxTheClipboard->IsUsingPrimarySelection();
|
|
|
|
wxTheClipboard->UsePrimarySelection( true );
|
|
|
|
wxTheClipboard->SetData( new wxTextDataObject( sel ) );
|
|
|
|
wxTheClipboard->UsePrimarySelection( clipTarget );
|
|
|
|
wxTheClipboard->Close();
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
}
|
|
|
|
|
2018-11-29 18:59:38 +00:00
|
|
|
m_needsEval = false;
|
2018-11-27 17:08:11 +00:00
|
|
|
}
|
2018-03-07 12:48:08 +00:00
|
|
|
|
2018-10-08 11:58:10 +00:00
|
|
|
aEvent.Skip();
|
2018-02-03 09:09:53 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
wxString valueDescriptionFromLabel( wxStaticText* aLabel )
|
|
|
|
{
|
|
|
|
wxString desc = aLabel->GetLabel();
|
|
|
|
|
|
|
|
desc.EndsWith( wxT( ":" ), &desc );
|
|
|
|
return desc;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2018-11-23 14:58:38 +00:00
|
|
|
void UNIT_BINDER::delayedFocusHandler( wxCommandEvent& )
|
2018-02-03 09:09:53 +00:00
|
|
|
{
|
2018-10-30 23:12:55 +00:00
|
|
|
if( !m_errorMessage.IsEmpty() )
|
|
|
|
DisplayError( m_value->GetParent(), m_errorMessage );
|
|
|
|
|
|
|
|
m_errorMessage = wxEmptyString;
|
2018-03-07 12:48:08 +00:00
|
|
|
m_value->SetFocus();
|
2018-02-03 09:09:53 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2018-11-29 18:59:38 +00:00
|
|
|
bool UNIT_BINDER::Validate( int aMin, int aMax, bool setFocusOnError )
|
2018-02-03 09:09:53 +00:00
|
|
|
{
|
2018-03-07 12:48:08 +00:00
|
|
|
auto textEntry = dynamic_cast<wxTextEntry*>( m_value );
|
|
|
|
|
|
|
|
if( !textEntry || textEntry->GetValue() == INDETERMINATE )
|
|
|
|
return true;
|
2018-02-03 09:09:53 +00:00
|
|
|
|
2018-11-29 18:59:38 +00:00
|
|
|
if( GetValue() < aMin )
|
2018-02-03 09:09:53 +00:00
|
|
|
{
|
2018-11-29 18:59:38 +00:00
|
|
|
m_errorMessage = wxString::Format( _( "%s must be at least %s." ),
|
2018-10-30 23:12:55 +00:00
|
|
|
valueDescriptionFromLabel( m_label ),
|
2018-11-29 18:59:38 +00:00
|
|
|
StringFromValue( m_units, aMin, true ) );
|
2018-02-03 09:09:53 +00:00
|
|
|
|
|
|
|
if( setFocusOnError )
|
|
|
|
{
|
2018-03-07 12:48:08 +00:00
|
|
|
textEntry->SelectAll();
|
2018-02-03 09:09:53 +00:00
|
|
|
// Don't focus directly; we might be inside a KillFocus event handler
|
2018-11-23 14:58:38 +00:00
|
|
|
wxPostEvent( this, wxCommandEvent( DELAY_FOCUS ) );
|
2018-02-03 09:09:53 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2018-11-29 18:59:38 +00:00
|
|
|
if( GetValue() > aMax )
|
2018-02-03 09:09:53 +00:00
|
|
|
{
|
2018-11-29 18:59:38 +00:00
|
|
|
m_errorMessage = wxString::Format( _( "%s must be less than %s." ),
|
2018-10-30 23:12:55 +00:00
|
|
|
valueDescriptionFromLabel( m_label ),
|
2018-11-29 18:59:38 +00:00
|
|
|
StringFromValue( m_units, aMax, true ) );
|
2018-02-03 09:09:53 +00:00
|
|
|
|
|
|
|
if( setFocusOnError )
|
|
|
|
{
|
2018-03-07 12:48:08 +00:00
|
|
|
textEntry->SelectAll();
|
2018-02-03 09:09:53 +00:00
|
|
|
// Don't focus directly; we might be inside a KillFocus event handler
|
2018-11-23 14:58:38 +00:00
|
|
|
wxPostEvent( this, wxCommandEvent( DELAY_FOCUS ) );
|
2018-02-03 09:09:53 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2017-11-10 23:27:46 +00:00
|
|
|
void UNIT_BINDER::SetValue( int aValue )
|
2015-02-17 23:35:18 +00:00
|
|
|
{
|
2018-02-03 09:09:53 +00:00
|
|
|
SetValue( StringFromValue( m_units, aValue, false, m_useMils ) );
|
|
|
|
}
|
2015-02-17 23:35:18 +00:00
|
|
|
|
2015-07-09 11:35:50 +00:00
|
|
|
|
2018-02-03 09:09:53 +00:00
|
|
|
void UNIT_BINDER::SetValue( wxString aValue )
|
|
|
|
{
|
2018-10-08 11:58:10 +00:00
|
|
|
auto textEntry = dynamic_cast<wxTextEntry*>( m_value );
|
|
|
|
auto staticText = dynamic_cast<wxStaticText*>( m_value );
|
|
|
|
|
|
|
|
if( textEntry )
|
|
|
|
textEntry->SetValue( aValue );
|
|
|
|
else if( staticText )
|
|
|
|
staticText->SetLabel( aValue );
|
2018-02-03 09:09:53 +00:00
|
|
|
|
|
|
|
if( m_allowEval )
|
2018-09-09 18:04:10 +00:00
|
|
|
m_eval.Clear();
|
|
|
|
|
2020-12-09 18:38:35 +00:00
|
|
|
if( m_unitLabel )
|
|
|
|
m_unitLabel->SetLabel( GetAbbreviatedUnitsLabel( m_units, m_useMils ) );
|
2018-09-09 18:04:10 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void UNIT_BINDER::ChangeValue( int aValue )
|
|
|
|
{
|
|
|
|
ChangeValue( StringFromValue( m_units, aValue, false, m_useMils ) );
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void UNIT_BINDER::ChangeValue( wxString aValue )
|
|
|
|
{
|
2018-10-08 11:58:10 +00:00
|
|
|
auto textEntry = dynamic_cast<wxTextEntry*>( m_value );
|
|
|
|
auto staticText = dynamic_cast<wxStaticText*>( m_value );
|
|
|
|
|
|
|
|
if( textEntry )
|
|
|
|
textEntry->ChangeValue( aValue );
|
|
|
|
else if( staticText )
|
|
|
|
staticText->SetLabel( aValue );
|
2018-09-09 18:04:10 +00:00
|
|
|
|
|
|
|
if( m_allowEval )
|
2018-02-25 16:14:24 +00:00
|
|
|
m_eval.Clear();
|
2018-02-03 09:09:53 +00:00
|
|
|
|
2020-12-09 18:38:35 +00:00
|
|
|
if( m_unitLabel )
|
|
|
|
m_unitLabel->SetLabel( GetAbbreviatedUnitsLabel( m_units, m_useMils ) );
|
2015-02-17 23:35:18 +00:00
|
|
|
}
|
|
|
|
|
2015-02-18 16:53:46 +00:00
|
|
|
|
2018-10-08 11:58:10 +00:00
|
|
|
int UNIT_BINDER::GetValue()
|
2015-02-17 23:35:18 +00:00
|
|
|
{
|
2018-10-08 11:58:10 +00:00
|
|
|
auto textEntry = dynamic_cast<wxTextEntry*>( m_value );
|
|
|
|
auto staticText = dynamic_cast<wxStaticText*>( m_value );
|
2018-10-30 22:56:52 +00:00
|
|
|
wxString value;
|
2018-03-07 12:48:08 +00:00
|
|
|
|
2018-10-30 22:56:52 +00:00
|
|
|
if( textEntry )
|
2018-10-08 11:58:10 +00:00
|
|
|
{
|
2018-10-30 22:56:52 +00:00
|
|
|
if( m_needsEval && m_eval.Process( textEntry->GetValue() ) )
|
|
|
|
value = m_eval.Result();
|
|
|
|
else
|
|
|
|
value = textEntry->GetValue();
|
2018-10-08 11:58:10 +00:00
|
|
|
}
|
|
|
|
else if( staticText )
|
2018-10-30 22:56:52 +00:00
|
|
|
value = staticText->GetLabel();
|
2018-10-08 11:58:10 +00:00
|
|
|
else
|
|
|
|
return 0;
|
2018-10-30 22:56:52 +00:00
|
|
|
|
|
|
|
return ValueFromString( m_units, value, m_useMils );
|
2015-02-17 23:35:18 +00:00
|
|
|
}
|
|
|
|
|
2015-02-18 16:53:46 +00:00
|
|
|
|
2018-02-03 09:09:53 +00:00
|
|
|
bool UNIT_BINDER::IsIndeterminate() const
|
2015-07-09 11:35:50 +00:00
|
|
|
{
|
2018-10-08 11:58:10 +00:00
|
|
|
auto textEntry = dynamic_cast<wxTextEntry*>( m_value );
|
|
|
|
|
|
|
|
if( textEntry )
|
|
|
|
return textEntry->GetValue() == INDETERMINATE;
|
2018-03-07 12:48:08 +00:00
|
|
|
|
|
|
|
return false;
|
2015-07-09 11:35:50 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2018-06-12 07:36:35 +00:00
|
|
|
void UNIT_BINDER::SetLabel( const wxString& aLabel )
|
|
|
|
{
|
|
|
|
m_label->SetLabel( aLabel );
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2017-11-10 23:27:46 +00:00
|
|
|
void UNIT_BINDER::Enable( bool aEnable )
|
2015-02-17 23:35:18 +00:00
|
|
|
{
|
2018-02-03 09:09:53 +00:00
|
|
|
m_label->Enable( aEnable );
|
2018-03-07 12:48:08 +00:00
|
|
|
m_value->Enable( aEnable );
|
2020-12-09 18:38:35 +00:00
|
|
|
|
|
|
|
if( m_unitLabel )
|
|
|
|
m_unitLabel->Enable( aEnable );
|
2015-03-11 16:04:20 +00:00
|
|
|
}
|
2017-08-25 14:46:49 +00:00
|
|
|
|
2018-05-23 06:11:47 +00:00
|
|
|
|
|
|
|
void UNIT_BINDER::Show( bool aShow )
|
|
|
|
{
|
|
|
|
m_label->Show( aShow );
|
|
|
|
m_value->Show( aShow );
|
2020-12-09 18:38:35 +00:00
|
|
|
|
|
|
|
if( m_unitLabel )
|
|
|
|
m_unitLabel->Show( aShow );
|
2018-05-23 06:11:47 +00:00
|
|
|
}
|
|
|
|
|