KiCad PCB EDA Suite
Loading...
Searching...
No Matches
unit_binder.cpp
Go to the documentation of this file.
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 <[email protected]>
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, see <https://www.gnu.org/licenses/>.
20 */
21
22#include <wx/clipbrd.h>
23#include <wx/combobox.h>
24#include <wx/stattext.h>
25#include <wx/textentry.h>
26#include <eda_units.h>
27#include <eda_draw_frame.h>
28#include <confirm.h>
29#include <dialog_shim.h>
30
31#include "widgets/unit_binder.h"
32#include "wx/dcclient.h"
33
34using namespace EDA_UNIT_UTILS::UI;
35
36
37wxDEFINE_EVENT( DELAY_FOCUS, wxCommandEvent );
38
39
40UNIT_BINDER::UNIT_BINDER( EDA_DRAW_FRAME* aParent, wxStaticText* aLabel, wxWindow* aValueCtrl,
41 wxStaticText* aUnitLabel, bool allowEval, bool aBindFrameEvents ) :
42 UNIT_BINDER( aParent, aParent, aLabel, aValueCtrl, aUnitLabel, allowEval, aBindFrameEvents )
43{
44}
45
46UNIT_BINDER::UNIT_BINDER( UNITS_PROVIDER* aUnitsProvider, wxWindow* aEventSource,
47 wxStaticText* aLabel, wxWindow* aValueCtrl, wxStaticText* aUnitLabel,
48 bool aAllowEval, bool aBindFocusEvent ) :
49 m_bindFocusEvent( aBindFocusEvent ),
50 m_label( aLabel ),
51 m_valueCtrl( aValueCtrl ),
52 m_eventSource( aEventSource ),
53 m_unitLabel( aUnitLabel ),
54 m_iuScale( &aUnitsProvider->GetIuScale() ),
55 m_units( aUnitsProvider->GetUserUnits() ),
56 m_negativeZero( false ),
58 m_precision( 0 ),
59 m_eval( aUnitsProvider->GetUserUnits() ),
60 m_allowEval( aAllowEval && ( !m_valueCtrl || dynamic_cast<wxTextEntry*>( m_valueCtrl ) ) ),
61 m_needsEval( false ),
62 m_selStart( 0 ),
63 m_selEnd( 0 ),
64 m_unitsInValue( false ),
65 m_originTransforms( aUnitsProvider->GetOriginTransforms() ),
66 m_coordType( ORIGIN_TRANSFORMS::NOT_A_COORD ),
67 m_dialogShim( nullptr )
68{
69 if( m_valueCtrl )
70 {
71 // Register the UNIT_BINDER for control state save/restore
72 wxWindow* parent = m_valueCtrl->GetParent();
73
74 while( parent && !dynamic_cast<DIALOG_SHIM*>( parent ) )
75 parent = parent->GetParent();
76
77 if( parent )
78 {
79 m_dialogShim = static_cast<DIALOG_SHIM*>( parent );
80 m_dialogShim->RegisterUnitBinder( this, m_valueCtrl );
81 }
82 }
83
84 wxTextEntry* textEntry = dynamic_cast<wxTextEntry*>( m_valueCtrl );
85
86 if( textEntry )
87 {
88 wxClientDC dc( m_valueCtrl );
89
90 // Gives enough room to display a value in inches in textEntry
91 // 3 digits + '.' + 10 digits
92 wxSize minSize = m_valueCtrl->GetMinSize();
93 int minWidth = dc.GetTextExtent( wxT( "XXX.XXXXXXXXXX" ) ).GetWidth();
94
95 if( minSize.GetWidth() < minWidth )
96 m_valueCtrl->SetMinSize( wxSize( minWidth, minSize.GetHeight() ) );
97
98 // Use ChangeValue() instead of SetValue() so we don't generate events.
99 if( m_negativeZero )
100 textEntry->ChangeValue( wxT( "-0" ) );
101 else
102 textEntry->ChangeValue( wxT( "0" ) );
103 }
104
105 if( m_unitLabel )
107
108 if( m_valueCtrl )
109 {
110 m_valueCtrl->Connect( wxEVT_DESTROY, wxWindowDestroyEventHandler( UNIT_BINDER::onValueCtrlDestroyed ),
111 nullptr, this );
112 m_valueCtrl->Connect( wxEVT_SET_FOCUS, wxFocusEventHandler( UNIT_BINDER::onSetFocus ), nullptr, this );
113 m_valueCtrl->Connect( wxEVT_KILL_FOCUS, wxFocusEventHandler( UNIT_BINDER::onKillFocus ), nullptr, this );
114 m_valueCtrl->Connect( wxEVT_LEFT_UP, wxMouseEventHandler( UNIT_BINDER::onClick ), nullptr, this );
115 m_valueCtrl->Connect( wxEVT_COMBOBOX, wxCommandEventHandler( UNIT_BINDER::onComboBox ), nullptr, this );
116 }
117
118 if( m_bindFocusEvent )
119 Connect( DELAY_FOCUS, wxCommandEventHandler( UNIT_BINDER::delayedFocusHandler ), nullptr, this );
120
121 if( m_eventSource )
122 {
123 m_eventSource->Connect( EDA_EVT_UNITS_CHANGED, wxCommandEventHandler( UNIT_BINDER::onUnitsChanged ),
124 nullptr, this );
125 }
126}
127
128
130{
131 if( m_dialogShim )
132 m_dialogShim->UnregisterUnitBinder( this );
133
134 if( m_valueCtrl )
135 {
136 m_valueCtrl->Disconnect( wxEVT_DESTROY, wxWindowDestroyEventHandler( UNIT_BINDER::onValueCtrlDestroyed ),
137 nullptr, this );
138 m_valueCtrl->Disconnect( wxEVT_SET_FOCUS, wxFocusEventHandler( UNIT_BINDER::onSetFocus ), nullptr, this );
139 m_valueCtrl->Disconnect( wxEVT_KILL_FOCUS, wxFocusEventHandler( UNIT_BINDER::onKillFocus ), nullptr, this );
140 m_valueCtrl->Disconnect( wxEVT_LEFT_UP, wxMouseEventHandler( UNIT_BINDER::onClick ), nullptr, this );
141 m_valueCtrl->Disconnect( wxEVT_COMBOBOX, wxCommandEventHandler( UNIT_BINDER::onComboBox ), nullptr, this );
142 }
143
144 if( m_bindFocusEvent )
145 Disconnect( DELAY_FOCUS, wxCommandEventHandler( UNIT_BINDER::delayedFocusHandler ), nullptr, this );
146
147 if( m_eventSource )
148 {
149 m_eventSource->Disconnect( EDA_EVT_UNITS_CHANGED, wxCommandEventHandler( UNIT_BINDER::onUnitsChanged ),
150 nullptr, this );
151 }
152}
153
154
156{
157 m_units = aUnits;
158
159 m_eval.SetDefaultUnits( m_units );
160 m_eval.LocaleChanged(); // In case locale changed since last run
161
162 if( m_unitLabel )
164}
165
166
167void UNIT_BINDER::SetPrecision( int aLength )
168{
169 m_precision = std::min( aLength, 6 );
170}
171
172
174{
175 m_dataType = aDataType;
176
177 if( m_unitLabel )
179}
180
181
182void UNIT_BINDER::onUnitsChanged( wxCommandEvent& aEvent )
183{
184 EDA_BASE_FRAME* provider = static_cast<EDA_BASE_FRAME*>( aEvent.GetClientData() );
185
186 if( !UnitsInvariant() )
187 {
188 int temp = GetIntValue();
189
190 wxComboBox* const combo = dynamic_cast<wxComboBox*>( m_valueCtrl );
191 std::vector<long long int> comboValues;
192
193 // Read out the current values
194 if( combo )
195 {
196 for( unsigned int i = 0; i < combo->GetCount(); i++ )
197 {
198 const wxString value = combo->GetString( i );
199 long long int conv = ValueFromString( *m_iuScale, m_units, value, m_dataType );
200 comboValues.push_back( conv );
201 }
202 }
203
204 SetUnits( provider->GetUserUnits() );
205 m_iuScale = &provider->GetIuScale();
206
207 // Re-populate the combo box with updated values
208 if( combo )
209 {
210 SetOptionsList( comboValues );
211 }
212
213 if( !IsIndeterminate() )
214 SetValue( temp );
215 }
216
217 aEvent.Skip();
218}
219
220
221void UNIT_BINDER::onClick( wxMouseEvent& aEvent )
222{
223 wxTextEntry* textEntry = dynamic_cast<wxTextEntry*>( m_valueCtrl );
224
225 if( textEntry && ( textEntry->GetValue() == INDETERMINATE_ACTION
226 || textEntry->GetValue() == INDETERMINATE_STATE ) )
227 {
228 // These are tokens, not strings, so do a select all
229 textEntry->SelectAll();
230 }
231
232 // Needed at least on Windows to avoid hanging
233 aEvent.Skip();
234}
235
236
237void UNIT_BINDER::onComboBox( wxCommandEvent& aEvent )
238{
239 wxComboBox* combo = dynamic_cast<wxComboBox*>( m_valueCtrl );
240 wxCHECK( combo, /*void*/ );
241
242 const wxString value = combo->GetStringSelection();
243 const long long int conv = ValueFromString( *m_iuScale, m_units, value, m_dataType );
244
245 CallAfter(
246 [this, conv]
247 {
248 SetValue( conv );
249 } );
250
251 aEvent.Skip();
252}
253
254
255void UNIT_BINDER::onValueCtrlDestroyed( wxWindowDestroyEvent& aEvent )
256{
257 // The bound control is being destroyed before this binder. Drop the dialog registration and
258 // the control reference so neither the binder destructor nor SaveControlState() touches the
259 // freed window.
260 if( aEvent.GetEventObject() == m_valueCtrl )
261 {
262 if( m_dialogShim )
263 {
264 m_dialogShim->UnregisterUnitBinder( this );
265 m_dialogShim = nullptr;
266 }
267
268 m_valueCtrl = nullptr;
269 }
270
271 aEvent.Skip();
272}
273
274
275void UNIT_BINDER::onSetFocus( wxFocusEvent& aEvent )
276{
277 wxTextEntry* textEntry = dynamic_cast<wxTextEntry*>( m_valueCtrl );
278
279 if( textEntry )
280 {
281 if( m_allowEval )
282 {
283 wxString oldStr = m_eval.OriginalText();
284
285 if( oldStr.length() && oldStr != textEntry->GetValue() )
286 {
287 textEntry->ChangeValue( oldStr );
288 textEntry->SetSelection( m_selStart, m_selEnd );
289 }
290
291 m_needsEval = true;
292 }
293
294 if( textEntry->GetValue() == INDETERMINATE_ACTION
295 || textEntry->GetValue() == INDETERMINATE_STATE )
296 {
297 // These are tokens, not strings, so do a select all
298 textEntry->SelectAll();
299 }
300 }
301
302 aEvent.Skip();
303}
304
305
306void UNIT_BINDER::onKillFocus( wxFocusEvent& aEvent )
307{
308 wxTextEntry* textEntry = dynamic_cast<wxTextEntry*>( m_valueCtrl );
309
310 if( m_allowEval && textEntry )
311 {
312 wxString value = textEntry->GetValue();
313 bool success = m_eval.Process( value );
314
315 if( success && !value.IsEmpty() )
316 {
317 textEntry->GetSelection( &m_selStart, &m_selEnd );
318
319 value = m_eval.Result();
320
321 if( m_unitsInValue && !value.IsEmpty() )
322 {
324 value += wxT( " " );
325
327 }
328
329 textEntry->ChangeValue( value );
330
331#ifdef __WXGTK__
332 // Manually copy the selected text to the primary selection clipboard
333 if( wxTheClipboard->Open() )
334 {
335 wxString sel = textEntry->GetStringSelection();
336 bool clipTarget = wxTheClipboard->IsUsingPrimarySelection();
337 wxTheClipboard->UsePrimarySelection( true );
338 wxTheClipboard->SetData( new wxTextDataObject( sel ) );
339 wxTheClipboard->UsePrimarySelection( clipTarget );
340 wxTheClipboard->Close();
341 }
342#endif
343 }
344
345 m_needsEval = false;
346 }
347
348 aEvent.Skip();
349}
350
351
352wxString valueDescriptionFromLabel( wxStaticText* aLabel )
353{
354 wxString desc = aLabel->GetLabel();
355
356 desc.EndsWith( wxT( ":" ), &desc );
357 return desc;
358}
359
360
361void UNIT_BINDER::delayedFocusHandler( wxCommandEvent& )
362{
363 if( !m_errorMessage.IsEmpty() )
365
366 m_errorMessage = wxEmptyString;
367 m_valueCtrl->SetFocus();
368}
369
370
372 EDA_UNITS aBoundUnits, double aBound,
373 EDA_UNITS aDisplayUnits,
374 EDA_DATA_TYPE aDataType )
375{
376 // StringFromValue scales the user value once per dimension (twice for area, thrice for
377 // volume), so invert that same chain to bring the bound into internal units.
378 int conversions = 1;
379
380 switch( aDataType )
381 {
382 case EDA_DATA_TYPE::AREA: conversions = 2; break;
383 case EDA_DATA_TYPE::VOLUME: conversions = 3; break;
384 case EDA_DATA_TYPE::UNITLESS: conversions = 0; break;
385 default: conversions = 1; break;
386 }
387
388 double boundIU = aBound;
389
390 for( int i = 0; i < conversions; ++i )
391 boundIU = FromUserUnit( aIuScale, aBoundUnits, boundIU );
392
393 // GetText has no UNITLESS label, so asking for units text would assert
394 bool addUnitsText = aDataType != EDA_DATA_TYPE::UNITLESS;
395
396 return { boundIU,
397 StringFromValue( aIuScale, aDisplayUnits, boundIU, addUnitsText, aDataType ) };
398}
399
400
401bool UNIT_BINDER::Validate( double aMin, double aMax, EDA_UNITS aUnits )
402{
403 wxTextEntry* textEntry = dynamic_cast<wxTextEntry*>( m_valueCtrl );
404
405 if( !textEntry
406 || textEntry->GetValue() == INDETERMINATE_ACTION
407 || textEntry->GetValue() == INDETERMINATE_STATE )
408 {
409 return true;
410 }
411
412 // Note: aMin and aMax are not always given in internal units
413 RANGE_BOUND minBound = ConvertRangeBound( *m_iuScale, aUnits, aMin, m_units, m_dataType );
414 RANGE_BOUND maxBound = ConvertRangeBound( *m_iuScale, aUnits, aMax, m_units, m_dataType );
415
416 if( GetValue() < minBound.internalUnits )
417 {
418 m_errorMessage = wxString::Format( _( "%s must be at least %s." ),
420 minBound.displayText );
421
422 textEntry->SelectAll();
423
424 // Don't focus directly; we might be inside a KillFocus event handler
425 wxPostEvent( this, wxCommandEvent( DELAY_FOCUS ) );
426
427 return false;
428 }
429
430 if( GetValue() > maxBound.internalUnits )
431 {
432 m_errorMessage = wxString::Format( _( "%s must be less than %s." ),
434 maxBound.displayText );
435
436 textEntry->SelectAll();
437
438 // Don't focus directly; we might be inside a KillFocus event handler
439 wxPostEvent( this, wxCommandEvent( DELAY_FOCUS ) );
440
441 return false;
442 }
443
444 return true;
445}
446
447
448void UNIT_BINDER::SetValue( long long int aValue )
449{
450 double displayValue = m_originTransforms.ToDisplay( aValue, m_coordType );
451 wxString textValue = StringFromValue( *m_iuScale, m_units, displayValue, false, m_dataType );
452
453 if( displayValue == 0 && m_negativeZero )
454 SetValue( wxT( "-" ) + textValue );
455 else
456 SetValue( textValue );
457}
458
459
460void UNIT_BINDER::SetDoubleValue( double aValue )
461{
462 double displayValue = m_originTransforms.ToDisplay( aValue, m_coordType );
463 wxString textValue = StringFromValue( *m_iuScale, m_units, setPrecision( displayValue, false ), false,
464 m_dataType );
465
466 if( displayValue == 0 && !std::signbit( displayValue ) && m_negativeZero )
467 SetValue( wxT( "-" ) + textValue );
468 else
469 SetValue( textValue );
470}
471
472
474{
475 SetDoubleValue( m_originTransforms.ToDisplay( aValue, m_coordType ) );
476}
477
478
479void UNIT_BINDER::SetValue( const wxString& aValue )
480{
481 wxTextEntry* textEntry = dynamic_cast<wxTextEntry*>( m_valueCtrl );
482 wxStaticText* staticText = dynamic_cast<wxStaticText*>( m_valueCtrl );
483
484 wxString value = aValue;
485
486 if( m_unitsInValue && !value.IsEmpty() )
487 {
489 value += wxT( " " );
490
492 }
493
494 if( textEntry )
495 textEntry->SetValue( value );
496 else if( staticText )
497 staticText->SetLabel( value );
498
499 if( m_allowEval )
500 m_eval.Clear();
501
502 if( m_unitLabel )
504
505}
506
507
508wxString UNIT_BINDER::getTextForValue( long long int aValue ) const
509{
510 const double displayValue = m_originTransforms.ToDisplay( aValue, m_coordType );
511 wxString textValue = StringFromValue( *m_iuScale, m_units, setPrecision( displayValue, false ), false,
512 m_dataType );
513
514 if( displayValue == 0 && m_negativeZero )
515 textValue = wxT( "-" ) + textValue;
516
517 return textValue;
518}
519
520
521wxString UNIT_BINDER::getTextForDoubleValue( double aValue ) const
522{
523 const double displayValue = m_originTransforms.ToDisplay( aValue, m_coordType );
524 wxString textValue = StringFromValue( *m_iuScale, m_units, setPrecision( displayValue, false ), false,
525 m_dataType );
526
527 if( displayValue == 0 && !std::signbit( displayValue ) && m_negativeZero )
528 textValue = wxT( "-" ) + textValue;
529
530 return textValue;
531}
532
533
534void UNIT_BINDER::ChangeValue( int aValue )
535{
536 ChangeValue( getTextForValue( aValue ) );
537}
538
539
541{
543}
544
545
547{
548 ChangeDoubleValue( m_originTransforms.ToDisplay( aValue, m_coordType ) );
549}
550
551
552void UNIT_BINDER::ChangeValue( const wxString& aValue )
553{
554 wxTextEntry* textEntry = dynamic_cast<wxTextEntry*>( m_valueCtrl );
555 wxStaticText* staticText = dynamic_cast<wxStaticText*>( m_valueCtrl );
556
557 wxString value = aValue;
558
559 if( m_unitsInValue && !value.IsEmpty() )
560 {
562 value += wxT( " " );
563
565 }
566
567 if( textEntry )
568 textEntry->ChangeValue( value );
569 else if( staticText )
570 staticText->SetLabel( value );
571
572 if( m_allowEval )
573 m_eval.Clear();
574
575 if( m_unitLabel )
577}
578
579
580long long int UNIT_BINDER::GetValue() const
581{
582 wxTextEntry* textEntry = dynamic_cast<wxTextEntry*>( m_valueCtrl );
583 wxStaticText* staticText = dynamic_cast<wxStaticText*>( m_valueCtrl );
584 wxString value;
585
586 if( textEntry )
587 {
588 value = textEntry->GetValue();
589
590 if( m_needsEval && !value.IsEmpty() && m_eval.Process( value ) )
591 value = m_eval.Result();
592 else
593 value = textEntry->GetValue();
594 }
595 else if( staticText )
596 {
597 value = staticText->GetLabel();
598 }
599 else
600 {
601 return 0;
602 }
603
604 long long int displayValue = ValueFromString( *m_iuScale, m_units, value, m_dataType );
605 return m_originTransforms.FromDisplay( displayValue, m_coordType );
606}
607
608
609double UNIT_BINDER::setPrecision( double aValue, bool aValueUsesUserUnits ) const
610{
611 if( m_precision > 1 )
612 {
613 int scale = pow( 10, m_precision );
614 int64_t tmp = aValue;
615
616 if( !aValueUsesUserUnits )
617 tmp = ToUserUnit( *m_iuScale, m_units, aValue ) * scale;
618
619 aValue = static_cast<double>( tmp ) / scale;
620
621 if( !aValueUsesUserUnits )
622 aValue = FromUserUnit( *m_iuScale, m_units, aValue );
623 }
624
625 return aValue;
626}
627
628
630{
631 wxTextEntry* textEntry = dynamic_cast<wxTextEntry*>( m_valueCtrl );
632 wxStaticText* staticText = dynamic_cast<wxStaticText*>( m_valueCtrl );
633 wxString value;
634
635 if( textEntry )
636 {
637 value = textEntry->GetValue();
638
639 if( m_needsEval && !value.IsEmpty() && m_eval.Process( value ) )
640 value = m_eval.Result();
641 else
642 value = textEntry->GetValue();
643 }
644 else if( staticText )
645 {
646 value = staticText->GetLabel();
647 }
648 else
649 {
650 return 0.0;
651 }
652
653 double displayValue = DoubleValueFromString( *m_iuScale, m_units, value, m_dataType );
654 displayValue = setPrecision( displayValue, false );
655
656 return m_originTransforms.FromDisplay( displayValue, m_coordType );
657}
658
659
664
665
666void UNIT_BINDER::SetOptionsList( std::span<const long long int> aOptions )
667{
668 wxComboBox* cb = dynamic_cast<wxComboBox*>( m_valueCtrl );
669 wxCHECK( cb, /* void */ );
670
671 cb->Clear();
672
673 for( long long int value : aOptions )
674 cb->Append( getTextForValue( value ) );
675}
676
677
678void UNIT_BINDER::SetDoubleOptionsList( std::span<const double> aOptions )
679{
680 wxComboBox* cb = dynamic_cast<wxComboBox*>( m_valueCtrl );
681 wxCHECK( cb, /* void */ );
682
683 cb->Clear();
684
685 for( double value : aOptions )
686 cb->Append( getTextForDoubleValue( value ) );
687}
688
689
691{
692 wxTextEntry* te = dynamic_cast<wxTextEntry*>( m_valueCtrl );
693
694 if( te )
695 return te->GetValue() == INDETERMINATE_STATE || te->GetValue() == INDETERMINATE_ACTION;
696
697 return false;
698}
699
700
702{
703 if( wxTextEntry* te = dynamic_cast<wxTextEntry*>( m_valueCtrl ) )
704 return te->GetValue().IsEmpty();
705
706 return false;
707}
708
709
711{
712 if( wxTextEntry* te = dynamic_cast<wxTextEntry*>( m_valueCtrl ) )
713 return te->SetValue( wxEmptyString );
714}
715
716
717void UNIT_BINDER::SetLabel( const wxString& aLabel )
718{
719 m_label->SetLabel( aLabel );
720}
721
722
723void UNIT_BINDER::Enable( bool aEnable )
724{
725 if( m_label )
726 m_label->Enable( aEnable );
727
728 m_valueCtrl->Enable( aEnable );
729
730 if( m_unitLabel )
731 m_unitLabel->Enable( aEnable );
732}
733
734
735void UNIT_BINDER::Show( bool aShow, bool aResize )
736{
737 m_label->Show( aShow );
738 m_valueCtrl->Show( aShow );
739
740 if( m_unitLabel )
741 m_unitLabel->Show( aShow );
742
743 if( aResize )
744 {
745 if( aShow )
746 {
747 m_label->SetSize( -1, -1 );
748 m_valueCtrl->SetSize( -1, -1 );
749
750 if( m_unitLabel )
751 m_unitLabel->SetSize( -1, -1 );
752 }
753 else
754 {
755 m_label->SetSize( 0, 0 );
756 m_valueCtrl->SetSize( 0, 0 );
757
758 if( m_unitLabel )
759 m_unitLabel->SetSize( 0, 0 );
760 }
761 }
762}
763
764
766 UNIT_BINDER( aParent, nullptr, nullptr, nullptr, true, false )
767{
768 m_unitsInValue = true;
769}
770
771
775
777{
778 m_valueCtrl = aControl;
779
780 if( m_valueCtrl )
781 {
782 m_valueCtrl->Bind( wxEVT_SET_FOCUS, &PROPERTY_EDITOR_UNIT_BINDER::onSetFocus, this );
783 m_valueCtrl->Bind( wxEVT_KILL_FOCUS, &PROPERTY_EDITOR_UNIT_BINDER::onKillFocus, this );
784 m_valueCtrl->Bind( wxEVT_LEFT_UP, &PROPERTY_EDITOR_UNIT_BINDER::onClick, this );
785
786 m_valueCtrl->Bind( wxEVT_SHOW,
787 [&]( wxShowEvent& e )
788 {
789 if( !e.IsShown() )
790 SetControl( nullptr );
791 } );
792 }
793}
Dialog helper object to sit in the inheritance tree between wxDialog and any class written by wxFormB...
Definition dialog_shim.h:65
The base frame for deriving all KiCad main window classes.
The base class for create windows for drawing purpose.
A class to perform either relative or absolute display origin transforms for a single axis of a point...
void SetControl(wxWindow *aControl)
PROPERTY_EDITOR_UNIT_BINDER(EDA_DRAW_FRAME *aParent)
const EDA_IU_SCALE & GetIuScale() const
EDA_UNITS GetUserUnits() const
double setPrecision(double aValue, bool aValueUsesUserUnits) const
When m_precision > 0 truncate the value aValue to show only m_precision digits in mantissa.
ORIGIN_TRANSFORMS::COORD_TYPES_T m_coordType
Type of coordinate for display origin transforms.
wxString getTextForValue(long long int aValue) const
virtual void ChangeDoubleValue(double aValue)
Set new value (in Internal Units) for the text field, taking care of units conversion WITHOUT trigger...
void onKillFocus(wxFocusEvent &aEvent)
void Enable(bool aEnable)
Enable/disable the label, widget and units label.
void onClick(wxMouseEvent &aEvent)
DIALOG_SHIM * m_dialogShim
The dialog this binder registered itself with, or nullptr if it isn't owned by a dialog.
virtual void SetPrecision(int aLength)
Normally not needed, but can be used to set the precision when using internal units that are floats (...
virtual void SetUnits(EDA_UNITS aUnits)
Normally not needed (as the UNIT_BINDER inherits from the parent frame), but can be used to set to DE...
virtual double GetDoubleValue() const
Return the current value in Internal Units.
wxString getTextForDoubleValue(double aValue) const
const EDA_IU_SCALE * m_iuScale
Currently used units.
wxString m_errorMessage
virtual EDA_ANGLE GetAngleValue()
bool m_negativeZero
Indicates "-0" should be displayed for 0.
virtual long long int GetValue() const
Return the current value in Internal Units.
int m_precision
0 to 6.
static RANGE_BOUND ConvertRangeBound(const EDA_IU_SCALE &aIuScale, EDA_UNITS aBoundUnits, double aBound, EDA_UNITS aDisplayUnits, EDA_DATA_TYPE aDataType)
Convert a range bound and format its display string honoring aDataType.
wxStaticText * m_unitLabel
Can be nullptr.
bool m_unitsInValue
Units label should be included in value text.
wxWindow * m_valueCtrl
wxWindow * m_eventSource
void onSetFocus(wxFocusEvent &aEvent)
void onComboBox(wxCommandEvent &aEvent)
UNIT_BINDER(EDA_DRAW_FRAME *aParent, wxStaticText *aLabel, wxWindow *aValueCtrl, wxStaticText *aUnitLabel, bool aAllowEval=true, bool aBindFocusEvent=true)
wxStaticText * m_label
The bound widgets.
ORIGIN_TRANSFORMS & m_originTransforms
A reference to an ORIGIN_TRANSFORMS object.
bool m_bindFocusEvent
long m_selStart
Selection start and end of the original text.
virtual void SetDoubleOptionsList(std::span< const double > aOptions)
void onValueCtrlDestroyed(wxWindowDestroyEvent &aEvent)
EDA_UNITS m_units
virtual void SetOptionsList(std::span< const long long int > aOptions)
Set the list of options for a combobox control.
bool IsIndeterminate() const
Return true if the control holds the indeterminate value (for instance, if it represents a multiple s...
void SetDataType(EDA_DATA_TYPE aDataType)
Used to override the datatype of the displayed property (default is DISTANCE)
int GetIntValue() const
void delayedFocusHandler(wxCommandEvent &aEvent)
EDA_DATA_TYPE m_dataType
virtual void SetAngleValue(const EDA_ANGLE &aValue)
void SetLabel(const wxString &aLabel)
virtual void ChangeAngleValue(const EDA_ANGLE &aValue)
virtual void SetDoubleValue(double aValue)
Set new value (in Internal Units) for the text field, taking care of units conversion.
virtual ~UNIT_BINDER() override
bool UnitsInvariant() const
Definition unit_binder.h:70
virtual bool Validate(double aMin, double aMax, EDA_UNITS aUnits=EDA_UNITS::UNSCALED)
Validate the control against the given range, informing the user of any errors found.
virtual void ChangeValue(int aValue)
Set new value (in Internal Units) for the text field, taking care of units conversion WITHOUT trigger...
virtual void SetValue(long long int aValue)
Set new value (in Internal Units) for the text field, taking care of units conversion.
void Show(bool aShow, bool aResize=false)
Show/hide the label, widget and units label.
NUMERIC_EVALUATOR m_eval
bool IsNull() const
Return true if the control holds no value (ie: empty string, not 0).
void onUnitsChanged(wxCommandEvent &aEvent)
void DisplayErrorMessage(wxWindow *aParent, const wxString &aText, const wxString &aExtraInfo)
Display an error message with aMessage.
Definition confirm.cpp:217
This file is part of the common library.
const int minSize
Push and Shove router track width and via size dialog.
#define _(s)
@ DEGREES_T
Definition eda_angle.h:31
EDA_DATA_TYPE
The type of unit.
Definition eda_units.h:34
EDA_UNITS
Definition eda_units.h:44
KICOMMON_API double FromUserUnit(const EDA_IU_SCALE &aIuScale, EDA_UNITS aUnit, double aValue)
Return in internal units the value aValue given in a real unit such as "in", "mm",...
KICOMMON_API long long int ValueFromString(const EDA_IU_SCALE &aIuScale, EDA_UNITS aUnits, const wxString &aTextValue, EDA_DATA_TYPE aType=EDA_DATA_TYPE::DISTANCE)
Convert aTextValue in aUnits to internal units used by the application.
KICOMMON_API wxString StringFromValue(const EDA_IU_SCALE &aIuScale, EDA_UNITS aUnits, double aValue, bool aAddUnitsText=false, EDA_DATA_TYPE aType=EDA_DATA_TYPE::DISTANCE)
Return the string from aValue according to aUnits (inch, mm ...) for display.
KICOMMON_API double DoubleValueFromString(const EDA_IU_SCALE &aIuScale, EDA_UNITS aUnits, const wxString &aTextValue, EDA_DATA_TYPE aType=EDA_DATA_TYPE::DISTANCE)
Convert aTextValue to a double.
KICOMMON_API double ToUserUnit(const EDA_IU_SCALE &aIuScale, EDA_UNITS aUnit, double aValue)
Convert aValue in internal units to the appropriate user units defined by aUnit.
KICOMMON_API wxString GetLabel(EDA_UNITS aUnits, EDA_DATA_TYPE aType=EDA_DATA_TYPE::DISTANCE)
Get the units string for a given units type.
const int scale
A range bound converted to internal units together with its user-facing display string.
#define INDETERMINATE_ACTION
Definition ui_common.h:47
#define INDETERMINATE_STATE
Used for holding indeterminate values, such as with multiple selections holding different values or c...
Definition ui_common.h:46
wxDEFINE_EVENT(DELAY_FOCUS, wxCommandEvent)
wxString valueDescriptionFromLabel(wxStaticText *aLabel)