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 wxSize minSize = m_valueCtrl->GetMinSize();
91 int minWidth;
92
93 if( m_iuScale->IU_PER_MM <= schIUScale.IU_PER_MM )
94 {
95 // PLEditor and SCH editors don't need as much room
96 minWidth = dc.GetTextExtent( wxT( "XXX.XXXXX" ) ).GetWidth();
97 }
98 else
99 {
100 // Gives enough room to display a value in inches in PCBNew
101 // 3 digits + '.' + 8 digits
102 minWidth = dc.GetTextExtent( wxT( "XXX.XXXXXXXX" ) ).GetWidth();
103 }
104
105 if( minSize.GetWidth() < minWidth )
106 m_valueCtrl->SetMinSize( wxSize( minWidth, minSize.GetHeight() ) );
107
108 // Use ChangeValue() instead of SetValue() so we don't generate events.
109 if( m_negativeZero )
110 textEntry->ChangeValue( wxT( "-0" ) );
111 else
112 textEntry->ChangeValue( wxT( "0" ) );
113 }
114
115 if( m_unitLabel )
117
118 if( m_valueCtrl )
119 {
120 m_valueCtrl->Connect( wxEVT_DESTROY, wxWindowDestroyEventHandler( UNIT_BINDER::onValueCtrlDestroyed ),
121 nullptr, this );
122 m_valueCtrl->Connect( wxEVT_SET_FOCUS, wxFocusEventHandler( UNIT_BINDER::onSetFocus ), nullptr, this );
123 m_valueCtrl->Connect( wxEVT_KILL_FOCUS, wxFocusEventHandler( UNIT_BINDER::onKillFocus ), nullptr, this );
124 m_valueCtrl->Connect( wxEVT_LEFT_UP, wxMouseEventHandler( UNIT_BINDER::onClick ), nullptr, this );
125 m_valueCtrl->Connect( wxEVT_COMBOBOX, wxCommandEventHandler( UNIT_BINDER::onComboBox ), nullptr, this );
126 }
127
128 if( m_bindFocusEvent )
129 Connect( DELAY_FOCUS, wxCommandEventHandler( UNIT_BINDER::delayedFocusHandler ), nullptr, this );
130
131 if( m_eventSource )
132 {
133 m_eventSource->Connect( EDA_EVT_UNITS_CHANGED, wxCommandEventHandler( UNIT_BINDER::onUnitsChanged ),
134 nullptr, this );
135 }
136}
137
138
140{
141 if( m_dialogShim )
142 m_dialogShim->UnregisterUnitBinder( this );
143
144 if( m_valueCtrl )
145 {
146 m_valueCtrl->Disconnect( wxEVT_DESTROY, wxWindowDestroyEventHandler( UNIT_BINDER::onValueCtrlDestroyed ),
147 nullptr, this );
148 m_valueCtrl->Disconnect( wxEVT_SET_FOCUS, wxFocusEventHandler( UNIT_BINDER::onSetFocus ), nullptr, this );
149 m_valueCtrl->Disconnect( wxEVT_KILL_FOCUS, wxFocusEventHandler( UNIT_BINDER::onKillFocus ), nullptr, this );
150 m_valueCtrl->Disconnect( wxEVT_LEFT_UP, wxMouseEventHandler( UNIT_BINDER::onClick ), nullptr, this );
151 m_valueCtrl->Disconnect( wxEVT_COMBOBOX, wxCommandEventHandler( UNIT_BINDER::onComboBox ), nullptr, this );
152 }
153
154 if( m_bindFocusEvent )
155 Disconnect( DELAY_FOCUS, wxCommandEventHandler( UNIT_BINDER::delayedFocusHandler ), nullptr, this );
156
157 if( m_eventSource )
158 {
159 m_eventSource->Disconnect( EDA_EVT_UNITS_CHANGED, wxCommandEventHandler( UNIT_BINDER::onUnitsChanged ),
160 nullptr, this );
161 }
162}
163
164
166{
167 m_units = aUnits;
168
169 m_eval.SetDefaultUnits( m_units );
170 m_eval.LocaleChanged(); // In case locale changed since last run
171
172 if( m_unitLabel )
174}
175
176
177void UNIT_BINDER::SetPrecision( int aLength )
178{
179 m_precision = std::min( aLength, 6 );
180}
181
182
184{
185 m_dataType = aDataType;
186
187 if( m_unitLabel )
189}
190
191
192void UNIT_BINDER::onUnitsChanged( wxCommandEvent& aEvent )
193{
194 EDA_BASE_FRAME* provider = static_cast<EDA_BASE_FRAME*>( aEvent.GetClientData() );
195
196 if( !UnitsInvariant() )
197 {
198 int temp = GetIntValue();
199
200 wxComboBox* const combo = dynamic_cast<wxComboBox*>( m_valueCtrl );
201 std::vector<long long int> comboValues;
202
203 // Read out the current values
204 if( combo )
205 {
206 for( unsigned int i = 0; i < combo->GetCount(); i++ )
207 {
208 const wxString value = combo->GetString( i );
209 long long int conv = ValueFromString( *m_iuScale, m_units, value, m_dataType );
210 comboValues.push_back( conv );
211 }
212 }
213
214 SetUnits( provider->GetUserUnits() );
215 m_iuScale = &provider->GetIuScale();
216
217 // Re-populate the combo box with updated values
218 if( combo )
219 {
220 SetOptionsList( comboValues );
221 }
222
223 if( !IsIndeterminate() )
224 SetValue( temp );
225 }
226
227 aEvent.Skip();
228}
229
230
231void UNIT_BINDER::onClick( wxMouseEvent& aEvent )
232{
233 wxTextEntry* textEntry = dynamic_cast<wxTextEntry*>( m_valueCtrl );
234
235 if( textEntry && ( textEntry->GetValue() == INDETERMINATE_ACTION
236 || textEntry->GetValue() == INDETERMINATE_STATE ) )
237 {
238 // These are tokens, not strings, so do a select all
239 textEntry->SelectAll();
240 }
241
242 // Needed at least on Windows to avoid hanging
243 aEvent.Skip();
244}
245
246
247void UNIT_BINDER::onComboBox( wxCommandEvent& aEvent )
248{
249 wxComboBox* combo = dynamic_cast<wxComboBox*>( m_valueCtrl );
250 wxCHECK( combo, /*void*/ );
251
252 const wxString value = combo->GetStringSelection();
253 const long long int conv = ValueFromString( *m_iuScale, m_units, value, m_dataType );
254
255 CallAfter(
256 [this, conv]
257 {
258 SetValue( conv );
259 } );
260
261 aEvent.Skip();
262}
263
264
265void UNIT_BINDER::onValueCtrlDestroyed( wxWindowDestroyEvent& aEvent )
266{
267 // The bound control is being destroyed before this binder. Drop the dialog registration and
268 // the control reference so neither the binder destructor nor SaveControlState() touches the
269 // freed window.
270 if( aEvent.GetEventObject() == m_valueCtrl )
271 {
272 if( m_dialogShim )
273 {
274 m_dialogShim->UnregisterUnitBinder( this );
275 m_dialogShim = nullptr;
276 }
277
278 m_valueCtrl = nullptr;
279 }
280
281 aEvent.Skip();
282}
283
284
285void UNIT_BINDER::onSetFocus( wxFocusEvent& aEvent )
286{
287 wxTextEntry* textEntry = dynamic_cast<wxTextEntry*>( m_valueCtrl );
288
289 if( textEntry )
290 {
291 if( m_allowEval )
292 {
293 wxString oldStr = m_eval.OriginalText();
294
295 if( oldStr.length() && oldStr != textEntry->GetValue() )
296 {
297 textEntry->ChangeValue( oldStr );
298 textEntry->SetSelection( m_selStart, m_selEnd );
299 }
300
301 m_needsEval = true;
302 }
303
304 if( textEntry->GetValue() == INDETERMINATE_ACTION
305 || textEntry->GetValue() == INDETERMINATE_STATE )
306 {
307 // These are tokens, not strings, so do a select all
308 textEntry->SelectAll();
309 }
310 }
311
312 aEvent.Skip();
313}
314
315
316void UNIT_BINDER::onKillFocus( wxFocusEvent& aEvent )
317{
318 wxTextEntry* textEntry = dynamic_cast<wxTextEntry*>( m_valueCtrl );
319
320 if( m_allowEval && textEntry )
321 {
322 wxString value = textEntry->GetValue();
323 bool success = m_eval.Process( value );
324
325 if( success && !value.IsEmpty() )
326 {
327 textEntry->GetSelection( &m_selStart, &m_selEnd );
328
329 value = m_eval.Result();
330
331 if( m_unitsInValue && !value.IsEmpty() )
332 {
334 value += wxT( " " );
335
337 }
338
339 textEntry->ChangeValue( value );
340
341#ifdef __WXGTK__
342 // Manually copy the selected text to the primary selection clipboard
343 if( wxTheClipboard->Open() )
344 {
345 wxString sel = textEntry->GetStringSelection();
346 bool clipTarget = wxTheClipboard->IsUsingPrimarySelection();
347 wxTheClipboard->UsePrimarySelection( true );
348 wxTheClipboard->SetData( new wxTextDataObject( sel ) );
349 wxTheClipboard->UsePrimarySelection( clipTarget );
350 wxTheClipboard->Close();
351 }
352#endif
353 }
354
355 m_needsEval = false;
356 }
357
358 aEvent.Skip();
359}
360
361
362wxString valueDescriptionFromLabel( wxStaticText* aLabel )
363{
364 wxString desc = aLabel->GetLabel();
365
366 desc.EndsWith( wxT( ":" ), &desc );
367 return desc;
368}
369
370
371void UNIT_BINDER::delayedFocusHandler( wxCommandEvent& )
372{
373 if( !m_errorMessage.IsEmpty() )
375
376 m_errorMessage = wxEmptyString;
377 m_valueCtrl->SetFocus();
378}
379
380
382 EDA_UNITS aBoundUnits, double aBound,
383 EDA_UNITS aDisplayUnits,
384 EDA_DATA_TYPE aDataType )
385{
386 // StringFromValue scales the user value once per dimension (twice for area, thrice for
387 // volume), so invert that same chain to bring the bound into internal units.
388 int conversions = 1;
389
390 switch( aDataType )
391 {
392 case EDA_DATA_TYPE::AREA: conversions = 2; break;
393 case EDA_DATA_TYPE::VOLUME: conversions = 3; break;
394 case EDA_DATA_TYPE::UNITLESS: conversions = 0; break;
395 default: conversions = 1; break;
396 }
397
398 double boundIU = aBound;
399
400 for( int i = 0; i < conversions; ++i )
401 boundIU = FromUserUnit( aIuScale, aBoundUnits, boundIU );
402
403 // GetText has no UNITLESS label, so asking for units text would assert
404 bool addUnitsText = aDataType != EDA_DATA_TYPE::UNITLESS;
405
406 return { boundIU,
407 StringFromValue( aIuScale, aDisplayUnits, boundIU, addUnitsText, aDataType ) };
408}
409
410
411bool UNIT_BINDER::Validate( double aMin, double aMax, EDA_UNITS aUnits )
412{
413 wxTextEntry* textEntry = dynamic_cast<wxTextEntry*>( m_valueCtrl );
414
415 if( !textEntry
416 || textEntry->GetValue() == INDETERMINATE_ACTION
417 || textEntry->GetValue() == INDETERMINATE_STATE )
418 {
419 return true;
420 }
421
422 // Note: aMin and aMax are not always given in internal units
423 RANGE_BOUND minBound = ConvertRangeBound( *m_iuScale, aUnits, aMin, m_units, m_dataType );
424 RANGE_BOUND maxBound = ConvertRangeBound( *m_iuScale, aUnits, aMax, m_units, m_dataType );
425
426 if( GetValue() < minBound.internalUnits )
427 {
428 m_errorMessage = wxString::Format( _( "%s must be at least %s." ),
430 minBound.displayText );
431
432 textEntry->SelectAll();
433
434 // Don't focus directly; we might be inside a KillFocus event handler
435 wxPostEvent( this, wxCommandEvent( DELAY_FOCUS ) );
436
437 return false;
438 }
439
440 if( GetValue() > maxBound.internalUnits )
441 {
442 m_errorMessage = wxString::Format( _( "%s must be less than %s." ),
444 maxBound.displayText );
445
446 textEntry->SelectAll();
447
448 // Don't focus directly; we might be inside a KillFocus event handler
449 wxPostEvent( this, wxCommandEvent( DELAY_FOCUS ) );
450
451 return false;
452 }
453
454 return true;
455}
456
457
458void UNIT_BINDER::SetValue( long long int aValue )
459{
460 double displayValue = m_originTransforms.ToDisplay( aValue, m_coordType );
461 wxString textValue = StringFromValue( *m_iuScale, m_units, displayValue, false, m_dataType );
462
463 if( displayValue == 0 && m_negativeZero )
464 SetValue( wxT( "-" ) + textValue );
465 else
466 SetValue( textValue );
467}
468
469
470void UNIT_BINDER::SetDoubleValue( double aValue )
471{
472 double displayValue = m_originTransforms.ToDisplay( aValue, m_coordType );
473 wxString textValue = StringFromValue( *m_iuScale, m_units, setPrecision( displayValue, false ), false,
474 m_dataType );
475
476 if( displayValue == 0 && !std::signbit( displayValue ) && m_negativeZero )
477 SetValue( wxT( "-" ) + textValue );
478 else
479 SetValue( textValue );
480}
481
482
484{
485 SetDoubleValue( m_originTransforms.ToDisplay( aValue, m_coordType ) );
486}
487
488
489void UNIT_BINDER::SetValue( const wxString& aValue )
490{
491 wxTextEntry* textEntry = dynamic_cast<wxTextEntry*>( m_valueCtrl );
492 wxStaticText* staticText = dynamic_cast<wxStaticText*>( m_valueCtrl );
493
494 wxString value = aValue;
495
496 if( m_unitsInValue && !value.IsEmpty() )
497 {
499 value += wxT( " " );
500
502 }
503
504 if( textEntry )
505 textEntry->SetValue( value );
506 else if( staticText )
507 staticText->SetLabel( value );
508
509 if( m_allowEval )
510 m_eval.Clear();
511
512 if( m_unitLabel )
514
515}
516
517
518wxString UNIT_BINDER::getTextForValue( long long int aValue ) const
519{
520 const double displayValue = m_originTransforms.ToDisplay( aValue, m_coordType );
521 wxString textValue = StringFromValue( *m_iuScale, m_units, setPrecision( displayValue, false ), false,
522 m_dataType );
523
524 if( displayValue == 0 && m_negativeZero )
525 textValue = wxT( "-" ) + textValue;
526
527 return textValue;
528}
529
530
531wxString UNIT_BINDER::getTextForDoubleValue( double aValue ) const
532{
533 const double displayValue = m_originTransforms.ToDisplay( aValue, m_coordType );
534 wxString textValue = StringFromValue( *m_iuScale, m_units, setPrecision( displayValue, false ), false,
535 m_dataType );
536
537 if( displayValue == 0 && !std::signbit( displayValue ) && m_negativeZero )
538 textValue = wxT( "-" ) + textValue;
539
540 return textValue;
541}
542
543
544void UNIT_BINDER::ChangeValue( int aValue )
545{
546 ChangeValue( getTextForValue( aValue ) );
547}
548
549
551{
553}
554
555
557{
558 ChangeDoubleValue( m_originTransforms.ToDisplay( aValue, m_coordType ) );
559}
560
561
562void UNIT_BINDER::ChangeValue( const wxString& aValue )
563{
564 wxTextEntry* textEntry = dynamic_cast<wxTextEntry*>( m_valueCtrl );
565 wxStaticText* staticText = dynamic_cast<wxStaticText*>( m_valueCtrl );
566
567 wxString value = aValue;
568
569 if( m_unitsInValue && !value.IsEmpty() )
570 {
572 value += wxT( " " );
573
575 }
576
577 if( textEntry )
578 textEntry->ChangeValue( value );
579 else if( staticText )
580 staticText->SetLabel( value );
581
582 if( m_allowEval )
583 m_eval.Clear();
584
585 if( m_unitLabel )
587}
588
589
590long long int UNIT_BINDER::GetValue() const
591{
592 wxTextEntry* textEntry = dynamic_cast<wxTextEntry*>( m_valueCtrl );
593 wxStaticText* staticText = dynamic_cast<wxStaticText*>( m_valueCtrl );
594 wxString value;
595
596 if( textEntry )
597 {
598 value = textEntry->GetValue();
599
600 if( m_needsEval && !value.IsEmpty() && m_eval.Process( value ) )
601 value = m_eval.Result();
602 else
603 value = textEntry->GetValue();
604 }
605 else if( staticText )
606 {
607 value = staticText->GetLabel();
608 }
609 else
610 {
611 return 0;
612 }
613
614 long long int displayValue = ValueFromString( *m_iuScale, m_units, value, m_dataType );
615 return m_originTransforms.FromDisplay( displayValue, m_coordType );
616}
617
618
619double UNIT_BINDER::setPrecision( double aValue, bool aValueUsesUserUnits ) const
620{
621 if( m_precision > 1 )
622 {
623 int scale = pow( 10, m_precision );
624 int64_t tmp = aValue;
625
626 if( !aValueUsesUserUnits )
627 tmp = ToUserUnit( *m_iuScale, m_units, aValue ) * scale;
628
629 aValue = static_cast<double>( tmp ) / scale;
630
631 if( !aValueUsesUserUnits )
632 aValue = FromUserUnit( *m_iuScale, m_units, aValue );
633 }
634
635 return aValue;
636}
637
638
640{
641 wxTextEntry* textEntry = dynamic_cast<wxTextEntry*>( m_valueCtrl );
642 wxStaticText* staticText = dynamic_cast<wxStaticText*>( m_valueCtrl );
643 wxString value;
644
645 if( textEntry )
646 {
647 value = textEntry->GetValue();
648
649 if( m_needsEval && !value.IsEmpty() && m_eval.Process( value ) )
650 value = m_eval.Result();
651 else
652 value = textEntry->GetValue();
653 }
654 else if( staticText )
655 {
656 value = staticText->GetLabel();
657 }
658 else
659 {
660 return 0.0;
661 }
662
663 double displayValue = DoubleValueFromString( *m_iuScale, m_units, value, m_dataType );
664 displayValue = setPrecision( displayValue, false );
665
666 return m_originTransforms.FromDisplay( displayValue, m_coordType );
667}
668
669
674
675
676void UNIT_BINDER::SetOptionsList( std::span<const long long int> aOptions )
677{
678 wxComboBox* cb = dynamic_cast<wxComboBox*>( m_valueCtrl );
679 wxCHECK( cb, /* void */ );
680
681 cb->Clear();
682
683 for( long long int value : aOptions )
684 cb->Append( getTextForValue( value ) );
685}
686
687
688void UNIT_BINDER::SetDoubleOptionsList( std::span<const double> aOptions )
689{
690 wxComboBox* cb = dynamic_cast<wxComboBox*>( m_valueCtrl );
691 wxCHECK( cb, /* void */ );
692
693 cb->Clear();
694
695 for( double value : aOptions )
696 cb->Append( getTextForDoubleValue( value ) );
697}
698
699
701{
702 wxTextEntry* te = dynamic_cast<wxTextEntry*>( m_valueCtrl );
703
704 if( te )
705 return te->GetValue() == INDETERMINATE_STATE || te->GetValue() == INDETERMINATE_ACTION;
706
707 return false;
708}
709
710
712{
713 if( wxTextEntry* te = dynamic_cast<wxTextEntry*>( m_valueCtrl ) )
714 return te->GetValue().IsEmpty();
715
716 return false;
717}
718
719
721{
722 if( wxTextEntry* te = dynamic_cast<wxTextEntry*>( m_valueCtrl ) )
723 return te->SetValue( wxEmptyString );
724}
725
726
727void UNIT_BINDER::SetLabel( const wxString& aLabel )
728{
729 m_label->SetLabel( aLabel );
730}
731
732
733void UNIT_BINDER::Enable( bool aEnable )
734{
735 if( m_label )
736 m_label->Enable( aEnable );
737
738 m_valueCtrl->Enable( aEnable );
739
740 if( m_unitLabel )
741 m_unitLabel->Enable( aEnable );
742}
743
744
745void UNIT_BINDER::Show( bool aShow, bool aResize )
746{
747 m_label->Show( aShow );
748 m_valueCtrl->Show( aShow );
749
750 if( m_unitLabel )
751 m_unitLabel->Show( aShow );
752
753 if( aResize )
754 {
755 if( aShow )
756 {
757 m_label->SetSize( -1, -1 );
758 m_valueCtrl->SetSize( -1, -1 );
759
760 if( m_unitLabel )
761 m_unitLabel->SetSize( -1, -1 );
762 }
763 else
764 {
765 m_label->SetSize( 0, 0 );
766 m_valueCtrl->SetSize( 0, 0 );
767
768 if( m_unitLabel )
769 m_unitLabel->SetSize( 0, 0 );
770 }
771 }
772}
773
774
776 UNIT_BINDER( aParent, nullptr, nullptr, nullptr, true, false )
777{
778 m_unitsInValue = true;
779}
780
781
785
787{
788 m_valueCtrl = aControl;
789
790 if( m_valueCtrl )
791 {
792 m_valueCtrl->Bind( wxEVT_SET_FOCUS, &PROPERTY_EDITOR_UNIT_BINDER::onSetFocus, this );
793 m_valueCtrl->Bind( wxEVT_KILL_FOCUS, &PROPERTY_EDITOR_UNIT_BINDER::onKillFocus, this );
794 m_valueCtrl->Bind( wxEVT_LEFT_UP, &PROPERTY_EDITOR_UNIT_BINDER::onClick, this );
795
796 m_valueCtrl->Bind( wxEVT_SHOW,
797 [&]( wxShowEvent& e )
798 {
799 if( !e.IsShown() )
800 SetControl( nullptr );
801 } );
802 }
803}
constexpr EDA_IU_SCALE schIUScale
Definition base_units.h:123
Dialog helper object to sit in the inheritance tree between wxDialog and any class written by wxFormB...
Definition dialog_shim.h:80
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)