You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

727 lines
20 KiB

7 months ago
3 years ago
3 years ago
11 years ago
7 months ago
7 months ago
7 months ago
7 months ago
7 months ago
7 months ago
7 months ago
7 months ago
7 months ago
7 months ago
7 months ago
7 months ago
11 years ago
7 months ago
11 years ago
7 months ago
7 months ago
7 months ago
3 years ago
  1. /*
  2. * This program source code file is part of KiCad, a free EDA CAD application.
  3. *
  4. * Copyright (C) 2014-2015 CERN
  5. * Copyright The KiCad Developers, see AUTHORS.txt for contributors.
  6. * Author: Maciej Suminski <maciej.suminski@cern.ch>
  7. *
  8. * This program is free software; you can redistribute it and/or
  9. * modify it under the terms of the GNU General Public License
  10. * as published by the Free Software Foundation; either version 2
  11. * of the License, or (at your option) any later version.
  12. *
  13. * This program is distributed in the hope that it will be useful,
  14. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  15. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  16. * GNU General Public License for more details.
  17. *
  18. * You should have received a copy of the GNU General Public License
  19. * along with this program; if not, you may find one here:
  20. * http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
  21. * or you may search the http://www.gnu.org website for the version 2 license,
  22. * or you may write to the Free Software Foundation, Inc.,
  23. * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
  24. */
  25. #include <wx/clipbrd.h>
  26. #include <wx/combobox.h>
  27. #include <wx/stattext.h>
  28. #include <wx/textentry.h>
  29. #include <eda_units.h>
  30. #include <eda_draw_frame.h>
  31. #include <confirm.h>
  32. #include "widgets/unit_binder.h"
  33. #include "wx/dcclient.h"
  34. using namespace EDA_UNIT_UTILS::UI;
  35. wxDEFINE_EVENT( DELAY_FOCUS, wxCommandEvent );
  36. UNIT_BINDER::UNIT_BINDER( EDA_DRAW_FRAME* aParent, wxStaticText* aLabel, wxWindow* aValueCtrl,
  37. wxStaticText* aUnitLabel, bool allowEval, bool aBindFrameEvents ) :
  38. UNIT_BINDER( aParent, aParent, aLabel, aValueCtrl, aUnitLabel, allowEval, aBindFrameEvents )
  39. {
  40. }
  41. UNIT_BINDER::UNIT_BINDER( UNITS_PROVIDER* aUnitsProvider, wxWindow* aEventSource,
  42. wxStaticText* aLabel, wxWindow* aValueCtrl, wxStaticText* aUnitLabel,
  43. bool aAllowEval, bool aBindFocusEvent ) :
  44. m_bindFocusEvent( aBindFocusEvent ),
  45. m_label( aLabel ),
  46. m_valueCtrl( aValueCtrl ),
  47. m_eventSource( aEventSource ),
  48. m_unitLabel( aUnitLabel ),
  49. m_iuScale( &aUnitsProvider->GetIuScale() ),
  50. m_negativeZero( false ),
  51. m_dataType( EDA_DATA_TYPE::DISTANCE ),
  52. m_precision( 0 ),
  53. m_eval( aUnitsProvider->GetUserUnits() ),
  54. m_unitsInValue( false ),
  55. m_originTransforms( aUnitsProvider->GetOriginTransforms() ),
  56. m_coordType( ORIGIN_TRANSFORMS::NOT_A_COORD )
  57. {
  58. init( aUnitsProvider );
  59. m_allowEval = aAllowEval && ( !m_valueCtrl || dynamic_cast<wxTextEntry*>( m_valueCtrl ) );
  60. wxTextEntry* textEntry = dynamic_cast<wxTextEntry*>( m_valueCtrl );
  61. if( textEntry )
  62. {
  63. wxClientDC dc( m_valueCtrl );
  64. // Gives enough room to display a value in inches in textEntry
  65. // 3 digits + '.' + 10 digits
  66. wxSize minSize = m_valueCtrl->GetMinSize();
  67. int minWidth = dc.GetTextExtent( wxT( "XXX.XXXXXXXXXX" ) ).GetWidth();
  68. if( minSize.GetWidth() < minWidth )
  69. m_valueCtrl->SetMinSize( wxSize( minWidth, minSize.GetHeight() ) );
  70. // Use ChangeValue() instead of SetValue() so we don't generate events.
  71. if( m_negativeZero )
  72. textEntry->ChangeValue( wxT( "-0" ) );
  73. else
  74. textEntry->ChangeValue( wxT( "0" ) );
  75. }
  76. if( m_unitLabel )
  77. m_unitLabel->SetLabel( EDA_UNIT_UTILS::GetLabel( m_units, m_dataType ) );
  78. if( m_valueCtrl )
  79. {
  80. m_valueCtrl->Connect( wxEVT_SET_FOCUS, wxFocusEventHandler( UNIT_BINDER::onSetFocus ), nullptr, this );
  81. m_valueCtrl->Connect( wxEVT_KILL_FOCUS, wxFocusEventHandler( UNIT_BINDER::onKillFocus ), nullptr, this );
  82. m_valueCtrl->Connect( wxEVT_LEFT_UP, wxMouseEventHandler( UNIT_BINDER::onClick ), nullptr, this );
  83. m_valueCtrl->Connect( wxEVT_COMBOBOX, wxCommandEventHandler( UNIT_BINDER::onComboBox ), nullptr, this );
  84. }
  85. if( m_bindFocusEvent )
  86. Connect( DELAY_FOCUS, wxCommandEventHandler( UNIT_BINDER::delayedFocusHandler ), nullptr, this );
  87. if( m_eventSource )
  88. {
  89. m_eventSource->Connect( EDA_EVT_UNITS_CHANGED, wxCommandEventHandler( UNIT_BINDER::onUnitsChanged ),
  90. nullptr, this );
  91. }
  92. }
  93. UNIT_BINDER::~UNIT_BINDER()
  94. {
  95. if( m_valueCtrl )
  96. {
  97. m_valueCtrl->Disconnect( wxEVT_SET_FOCUS, wxFocusEventHandler( UNIT_BINDER::onSetFocus ), nullptr, this );
  98. m_valueCtrl->Disconnect( wxEVT_KILL_FOCUS, wxFocusEventHandler( UNIT_BINDER::onKillFocus ), nullptr, this );
  99. m_valueCtrl->Disconnect( wxEVT_LEFT_UP, wxMouseEventHandler( UNIT_BINDER::onClick ), nullptr, this );
  100. m_valueCtrl->Disconnect( wxEVT_COMBOBOX, wxCommandEventHandler( UNIT_BINDER::onComboBox ), nullptr, this );
  101. }
  102. if( m_bindFocusEvent )
  103. Disconnect( DELAY_FOCUS, wxCommandEventHandler( UNIT_BINDER::delayedFocusHandler ), nullptr, this );
  104. if( m_eventSource )
  105. {
  106. m_eventSource->Disconnect( EDA_EVT_UNITS_CHANGED, wxCommandEventHandler( UNIT_BINDER::onUnitsChanged ),
  107. nullptr, this );
  108. }
  109. }
  110. void UNIT_BINDER::init( UNITS_PROVIDER* aProvider )
  111. {
  112. m_units = aProvider->GetUserUnits();
  113. m_needsEval = false;
  114. m_selStart = 0;
  115. m_selEnd = 0;
  116. }
  117. void UNIT_BINDER::SetUnits( EDA_UNITS aUnits )
  118. {
  119. m_units = aUnits;
  120. m_eval.SetDefaultUnits( m_units );
  121. m_eval.LocaleChanged(); // In case locale changed since last run
  122. if( m_unitLabel )
  123. m_unitLabel->SetLabel( EDA_UNIT_UTILS::GetLabel( m_units, m_dataType ) );
  124. }
  125. void UNIT_BINDER::SetPrecision( int aLength )
  126. {
  127. m_precision = std::min( aLength, 6 );
  128. }
  129. void UNIT_BINDER::SetDataType( EDA_DATA_TYPE aDataType )
  130. {
  131. m_dataType = aDataType;
  132. if( m_unitLabel )
  133. m_unitLabel->SetLabel( EDA_UNIT_UTILS::GetLabel( m_units, m_dataType ) );
  134. }
  135. void UNIT_BINDER::onUnitsChanged( wxCommandEvent& aEvent )
  136. {
  137. EDA_BASE_FRAME* provider = static_cast<EDA_BASE_FRAME*>( aEvent.GetClientData() );
  138. if( m_units != EDA_UNITS::UNSCALED
  139. && m_units != EDA_UNITS::DEGREES
  140. && m_units != EDA_UNITS::PERCENT )
  141. {
  142. int temp = GetIntValue();
  143. wxComboBox* const combo = dynamic_cast<wxComboBox*>( m_valueCtrl );
  144. std::vector<long long int> comboValues;
  145. // Read out the current values
  146. if( combo )
  147. {
  148. for( unsigned int i = 0; i < combo->GetCount(); i++ )
  149. {
  150. const wxString value = combo->GetString( i );
  151. long long int conv = ValueFromString( *m_iuScale, m_units, value, m_dataType );
  152. comboValues.push_back( conv );
  153. }
  154. }
  155. SetUnits( provider->GetUserUnits() );
  156. m_iuScale = &provider->GetIuScale();
  157. // Re-populate the combo box with updated values
  158. if( combo )
  159. {
  160. SetOptionsList( comboValues );
  161. }
  162. if( !IsIndeterminate() )
  163. SetValue( temp );
  164. }
  165. aEvent.Skip();
  166. }
  167. void UNIT_BINDER::onClick( wxMouseEvent& aEvent )
  168. {
  169. wxTextEntry* textEntry = dynamic_cast<wxTextEntry*>( m_valueCtrl );
  170. if( textEntry && ( textEntry->GetValue() == INDETERMINATE_ACTION
  171. || textEntry->GetValue() == INDETERMINATE_STATE ) )
  172. {
  173. // These are tokens, not strings, so do a select all
  174. textEntry->SelectAll();
  175. }
  176. // Needed at least on Windows to avoid hanging
  177. aEvent.Skip();
  178. }
  179. void UNIT_BINDER::onComboBox( wxCommandEvent& aEvent )
  180. {
  181. wxComboBox* combo = dynamic_cast<wxComboBox*>( m_valueCtrl );
  182. wxCHECK( combo, /*void*/ );
  183. const wxString value = combo->GetStringSelection();
  184. const long long int conv = ValueFromString( *m_iuScale, m_units, value, m_dataType );
  185. SetValue( conv );
  186. aEvent.Skip();
  187. }
  188. void UNIT_BINDER::onSetFocus( wxFocusEvent& aEvent )
  189. {
  190. wxTextEntry* textEntry = dynamic_cast<wxTextEntry*>( m_valueCtrl );
  191. if( textEntry )
  192. {
  193. if( m_allowEval )
  194. {
  195. wxString oldStr = m_eval.OriginalText();
  196. if( oldStr.length() && oldStr != textEntry->GetValue() )
  197. {
  198. textEntry->ChangeValue( oldStr );
  199. textEntry->SetSelection( m_selStart, m_selEnd );
  200. }
  201. m_needsEval = true;
  202. }
  203. if( textEntry->GetValue() == INDETERMINATE_ACTION
  204. || textEntry->GetValue() == INDETERMINATE_STATE )
  205. {
  206. // These are tokens, not strings, so do a select all
  207. textEntry->SelectAll();
  208. }
  209. }
  210. aEvent.Skip();
  211. }
  212. void UNIT_BINDER::onKillFocus( wxFocusEvent& aEvent )
  213. {
  214. wxTextEntry* textEntry = dynamic_cast<wxTextEntry*>( m_valueCtrl );
  215. if( m_allowEval && textEntry )
  216. {
  217. wxString value = textEntry->GetValue();
  218. bool success = m_eval.Process( value );
  219. if( success && !value.IsEmpty() )
  220. {
  221. textEntry->GetSelection( &m_selStart, &m_selEnd );
  222. value = m_eval.Result();
  223. if( m_unitsInValue && !value.IsEmpty() )
  224. {
  225. if( !( m_units == EDA_UNITS::DEGREES || m_units == EDA_UNITS::PERCENT ) )
  226. value += wxT( " " );
  227. value += EDA_UNIT_UTILS::GetLabel( m_units, m_dataType );
  228. }
  229. textEntry->ChangeValue( value );
  230. #ifdef __WXGTK__
  231. // Manually copy the selected text to the primary selection clipboard
  232. if( wxTheClipboard->Open() )
  233. {
  234. wxString sel = textEntry->GetStringSelection();
  235. bool clipTarget = wxTheClipboard->IsUsingPrimarySelection();
  236. wxTheClipboard->UsePrimarySelection( true );
  237. wxTheClipboard->SetData( new wxTextDataObject( sel ) );
  238. wxTheClipboard->UsePrimarySelection( clipTarget );
  239. wxTheClipboard->Close();
  240. }
  241. #endif
  242. }
  243. m_needsEval = false;
  244. }
  245. aEvent.Skip();
  246. }
  247. wxString valueDescriptionFromLabel( wxStaticText* aLabel )
  248. {
  249. wxString desc = aLabel->GetLabel();
  250. desc.EndsWith( wxT( ":" ), &desc );
  251. return desc;
  252. }
  253. void UNIT_BINDER::delayedFocusHandler( wxCommandEvent& )
  254. {
  255. if( !m_errorMessage.IsEmpty() )
  256. DisplayErrorMessage( m_valueCtrl->GetParent(), m_errorMessage );
  257. m_errorMessage = wxEmptyString;
  258. m_valueCtrl->SetFocus();
  259. }
  260. bool UNIT_BINDER::Validate( double aMin, double aMax, EDA_UNITS aUnits )
  261. {
  262. wxTextEntry* textEntry = dynamic_cast<wxTextEntry*>( m_valueCtrl );
  263. if( !textEntry
  264. || textEntry->GetValue() == INDETERMINATE_ACTION
  265. || textEntry->GetValue() == INDETERMINATE_STATE )
  266. {
  267. return true;
  268. }
  269. // TODO: Validate() does not currently support m_dataType being anything other than DISTANCE
  270. // Note: aMin and aMax are not always given in internal units
  271. if( GetValue() < FromUserUnit( *m_iuScale, aUnits, aMin ) )
  272. {
  273. double val_min_iu = FromUserUnit( *m_iuScale, aUnits, aMin );
  274. m_errorMessage = wxString::Format( _( "%s must be at least %s." ),
  275. valueDescriptionFromLabel( m_label ),
  276. StringFromValue( *m_iuScale, m_units, val_min_iu, true ) );
  277. textEntry->SelectAll();
  278. // Don't focus directly; we might be inside a KillFocus event handler
  279. wxPostEvent( this, wxCommandEvent( DELAY_FOCUS ) );
  280. return false;
  281. }
  282. if( GetValue() > FromUserUnit( *m_iuScale, aUnits, aMax ) )
  283. {
  284. double val_max_iu = FromUserUnit( *m_iuScale, aUnits, aMax );
  285. m_errorMessage = wxString::Format( _( "%s must be less than %s." ),
  286. valueDescriptionFromLabel( m_label ),
  287. StringFromValue( *m_iuScale, m_units, val_max_iu, true ) );
  288. textEntry->SelectAll();
  289. // Don't focus directly; we might be inside a KillFocus event handler
  290. wxPostEvent( this, wxCommandEvent( DELAY_FOCUS ) );
  291. return false;
  292. }
  293. return true;
  294. }
  295. void UNIT_BINDER::SetValue( long long int aValue )
  296. {
  297. double displayValue = m_originTransforms.ToDisplay( aValue, m_coordType );
  298. wxString textValue = StringFromValue( *m_iuScale, m_units, displayValue, false, m_dataType );
  299. if( displayValue == 0 && m_negativeZero )
  300. SetValue( wxT( "-" ) + textValue );
  301. else
  302. SetValue( textValue );
  303. }
  304. void UNIT_BINDER::SetDoubleValue( double aValue )
  305. {
  306. double displayValue = m_originTransforms.ToDisplay( aValue, m_coordType );
  307. wxString textValue = StringFromValue( *m_iuScale, m_units, setPrecision( displayValue, false ), false,
  308. m_dataType );
  309. if( displayValue == 0 && !std::signbit( displayValue ) && m_negativeZero )
  310. SetValue( wxT( "-" ) + textValue );
  311. else
  312. SetValue( textValue );
  313. }
  314. void UNIT_BINDER::SetAngleValue( const EDA_ANGLE& aValue )
  315. {
  316. SetDoubleValue( aValue.AsDegrees() );
  317. }
  318. void UNIT_BINDER::SetValue( const wxString& aValue )
  319. {
  320. wxTextEntry* textEntry = dynamic_cast<wxTextEntry*>( m_valueCtrl );
  321. wxStaticText* staticText = dynamic_cast<wxStaticText*>( m_valueCtrl );
  322. wxString value = aValue;
  323. if( m_unitsInValue && !value.IsEmpty() )
  324. {
  325. if( !( m_units == EDA_UNITS::DEGREES || m_units == EDA_UNITS::PERCENT ) )
  326. value += wxT( " " );
  327. value += EDA_UNIT_UTILS::GetLabel( m_units, m_dataType );
  328. }
  329. if( textEntry )
  330. textEntry->SetValue( value );
  331. else if( staticText )
  332. staticText->SetLabel( value );
  333. if( m_allowEval )
  334. m_eval.Clear();
  335. if( m_unitLabel )
  336. m_unitLabel->SetLabel( EDA_UNIT_UTILS::GetLabel( m_units, m_dataType ) );
  337. }
  338. wxString UNIT_BINDER::getTextForValue( long long int aValue ) const
  339. {
  340. const double displayValue = m_originTransforms.ToDisplay( aValue, m_coordType );
  341. wxString textValue = StringFromValue( *m_iuScale, m_units, setPrecision( displayValue, false ), false,
  342. m_dataType );
  343. if( displayValue == 0 && m_negativeZero )
  344. textValue = wxT( "-" ) + textValue;
  345. return textValue;
  346. }
  347. wxString UNIT_BINDER::getTextForDoubleValue( double aValue ) const
  348. {
  349. const double displayValue = m_originTransforms.ToDisplay( aValue, m_coordType );
  350. wxString textValue = StringFromValue( *m_iuScale, m_units, setPrecision( displayValue, false ), false,
  351. m_dataType );
  352. if( displayValue == 0 && !std::signbit( displayValue ) && m_negativeZero )
  353. textValue = wxT( "-" ) + textValue;
  354. return textValue;
  355. }
  356. void UNIT_BINDER::ChangeValue( int aValue )
  357. {
  358. ChangeValue( getTextForValue( aValue ) );
  359. }
  360. void UNIT_BINDER::ChangeDoubleValue( double aValue )
  361. {
  362. ChangeValue( getTextForDoubleValue( aValue ) );
  363. }
  364. void UNIT_BINDER::ChangeAngleValue( const EDA_ANGLE& aValue )
  365. {
  366. ChangeDoubleValue( aValue.AsDegrees() );
  367. }
  368. void UNIT_BINDER::ChangeValue( const wxString& aValue )
  369. {
  370. wxTextEntry* textEntry = dynamic_cast<wxTextEntry*>( m_valueCtrl );
  371. wxStaticText* staticText = dynamic_cast<wxStaticText*>( m_valueCtrl );
  372. wxString value = aValue;
  373. if( m_unitsInValue && !value.IsEmpty() )
  374. {
  375. if( !( m_units == EDA_UNITS::DEGREES || m_units == EDA_UNITS::PERCENT ) )
  376. value += wxT( " " );
  377. value += EDA_UNIT_UTILS::GetLabel( m_units, m_dataType );
  378. }
  379. if( textEntry )
  380. textEntry->ChangeValue( value );
  381. else if( staticText )
  382. staticText->SetLabel( value );
  383. if( m_allowEval )
  384. m_eval.Clear();
  385. if( m_unitLabel )
  386. m_unitLabel->SetLabel( EDA_UNIT_UTILS::GetLabel( m_units, m_dataType ) );
  387. }
  388. long long int UNIT_BINDER::GetValue()
  389. {
  390. wxTextEntry* textEntry = dynamic_cast<wxTextEntry*>( m_valueCtrl );
  391. wxStaticText* staticText = dynamic_cast<wxStaticText*>( m_valueCtrl );
  392. wxString value;
  393. if( textEntry )
  394. {
  395. value = textEntry->GetValue();
  396. if( m_needsEval && !value.IsEmpty() && m_eval.Process( value ) )
  397. value = m_eval.Result();
  398. else
  399. value = textEntry->GetValue();
  400. }
  401. else if( staticText )
  402. {
  403. value = staticText->GetLabel();
  404. }
  405. else
  406. {
  407. return 0;
  408. }
  409. long long int displayValue = ValueFromString( *m_iuScale, m_units, value, m_dataType );
  410. return m_originTransforms.FromDisplay( displayValue, m_coordType );
  411. }
  412. double UNIT_BINDER::setPrecision( double aValue, bool aValueUsesUserUnits ) const
  413. {
  414. if( m_precision > 1 )
  415. {
  416. int scale = pow( 10, m_precision );
  417. int64_t tmp = aValue;
  418. if( !aValueUsesUserUnits )
  419. tmp = ToUserUnit( *m_iuScale, m_units, aValue ) * scale;
  420. aValue = static_cast<double>( tmp ) / scale;
  421. if( !aValueUsesUserUnits )
  422. aValue = FromUserUnit( *m_iuScale, m_units, aValue );
  423. }
  424. return aValue;
  425. }
  426. double UNIT_BINDER::GetDoubleValue()
  427. {
  428. wxTextEntry* textEntry = dynamic_cast<wxTextEntry*>( m_valueCtrl );
  429. wxStaticText* staticText = dynamic_cast<wxStaticText*>( m_valueCtrl );
  430. wxString value;
  431. if( textEntry )
  432. {
  433. value = textEntry->GetValue();
  434. if( m_needsEval && !value.IsEmpty() && m_eval.Process( value ) )
  435. value = m_eval.Result();
  436. else
  437. value = textEntry->GetValue();
  438. }
  439. else if( staticText )
  440. {
  441. value = staticText->GetLabel();
  442. }
  443. else
  444. {
  445. return 0.0;
  446. }
  447. double displayValue = DoubleValueFromString( *m_iuScale, m_units, value, m_dataType );
  448. displayValue = setPrecision( displayValue, false );
  449. return m_originTransforms.FromDisplay( displayValue, m_coordType );
  450. }
  451. EDA_ANGLE UNIT_BINDER::GetAngleValue()
  452. {
  453. return EDA_ANGLE( GetDoubleValue(), DEGREES_T );
  454. }
  455. void UNIT_BINDER::SetOptionsList( std::span<const long long int> aOptions )
  456. {
  457. wxComboBox* cb = dynamic_cast<wxComboBox*>( m_valueCtrl );
  458. wxCHECK( cb, /* void */ );
  459. cb->Clear();
  460. for( long long int value : aOptions )
  461. cb->Append( getTextForValue( value ) );
  462. }
  463. void UNIT_BINDER::SetDoubleOptionsList( std::span<const double> aOptions )
  464. {
  465. wxComboBox* cb = dynamic_cast<wxComboBox*>( m_valueCtrl );
  466. wxCHECK( cb, /* void */ );
  467. cb->Clear();
  468. for( double value : aOptions )
  469. cb->Append( getTextForDoubleValue( value ) );
  470. }
  471. bool UNIT_BINDER::IsIndeterminate() const
  472. {
  473. wxTextEntry* te = dynamic_cast<wxTextEntry*>( m_valueCtrl );
  474. if( te )
  475. return te->GetValue() == INDETERMINATE_STATE || te->GetValue() == INDETERMINATE_ACTION;
  476. return false;
  477. }
  478. bool UNIT_BINDER::IsNull() const
  479. {
  480. if( wxTextEntry* te = dynamic_cast<wxTextEntry*>( m_valueCtrl ) )
  481. return te->GetValue().IsEmpty();
  482. return false;
  483. }
  484. void UNIT_BINDER::SetNull()
  485. {
  486. if( wxTextEntry* te = dynamic_cast<wxTextEntry*>( m_valueCtrl ) )
  487. return te->SetValue( wxEmptyString );
  488. }
  489. void UNIT_BINDER::SetLabel( const wxString& aLabel )
  490. {
  491. m_label->SetLabel( aLabel );
  492. }
  493. void UNIT_BINDER::Enable( bool aEnable )
  494. {
  495. if( m_label )
  496. m_label->Enable( aEnable );
  497. m_valueCtrl->Enable( aEnable );
  498. if( m_unitLabel )
  499. m_unitLabel->Enable( aEnable );
  500. }
  501. void UNIT_BINDER::Show( bool aShow, bool aResize )
  502. {
  503. m_label->Show( aShow );
  504. m_valueCtrl->Show( aShow );
  505. if( m_unitLabel )
  506. m_unitLabel->Show( aShow );
  507. if( aResize )
  508. {
  509. if( aShow )
  510. {
  511. m_label->SetSize( -1, -1 );
  512. m_valueCtrl->SetSize( -1, -1 );
  513. if( m_unitLabel )
  514. m_unitLabel->SetSize( -1, -1 );
  515. }
  516. else
  517. {
  518. m_label->SetSize( 0, 0 );
  519. m_valueCtrl->SetSize( 0, 0 );
  520. if( m_unitLabel )
  521. m_unitLabel->SetSize( 0, 0 );
  522. }
  523. }
  524. }
  525. PROPERTY_EDITOR_UNIT_BINDER::PROPERTY_EDITOR_UNIT_BINDER( EDA_DRAW_FRAME* aParent ) :
  526. UNIT_BINDER( aParent, nullptr, nullptr, nullptr, true, false )
  527. {
  528. m_unitsInValue = true;
  529. }
  530. PROPERTY_EDITOR_UNIT_BINDER::~PROPERTY_EDITOR_UNIT_BINDER()
  531. {
  532. }
  533. void PROPERTY_EDITOR_UNIT_BINDER::SetControl( wxWindow* aControl )
  534. {
  535. m_valueCtrl = aControl;
  536. if( m_valueCtrl )
  537. {
  538. m_valueCtrl->Bind( wxEVT_SET_FOCUS, &PROPERTY_EDITOR_UNIT_BINDER::onSetFocus, this );
  539. m_valueCtrl->Bind( wxEVT_KILL_FOCUS, &PROPERTY_EDITOR_UNIT_BINDER::onKillFocus, this );
  540. m_valueCtrl->Bind( wxEVT_LEFT_UP, &PROPERTY_EDITOR_UNIT_BINDER::onClick, this );
  541. m_valueCtrl->Bind( wxEVT_SHOW,
  542. [&]( wxShowEvent& e )
  543. {
  544. if( !e.IsShown() )
  545. SetControl( nullptr );
  546. } );
  547. }
  548. }