KiCad PCB EDA Suite
pg_editors.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) 2022 KiCad Developers, see AUTHORS.txt for contributors.
5 *
6 * This program is free software: you can redistribute it and/or modify it
7 * under the terms of the GNU General Public License as published by the
8 * Free Software Foundation, either version 3 of the License, or (at your
9 * option) any later version.
10 *
11 * This program is distributed in the hope that it will be useful, but
12 * WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License along
17 * with this program. If not, see <http://www.gnu.org/licenses/>.
18 */
19
20#include <eda_draw_frame.h>
24#include <widgets/unit_binder.h>
25
26#include <wx/log.h>
27
28const wxString PG_UNIT_EDITOR::EDITOR_NAME = wxS( "KiCadUnitEditor" );
29const wxString PG_CHECKBOX_EDITOR::EDITOR_NAME = wxS( "KiCadCheckboxEditor" );
30
31
33 wxPGTextCtrlEditor(),
34 m_frame( aFrame )
35{
36 m_unitBinder = std::make_unique<PROPERTY_EDITOR_UNIT_BINDER>( m_frame );
37 m_unitBinder->SetUnits( m_frame->GetUserUnits() );
38}
39
40
42{
43}
44
45
47{
48 m_frame = aFrame;
49
50 if( aFrame )
51 {
52 m_unitBinder = std::make_unique<PROPERTY_EDITOR_UNIT_BINDER>( m_frame );
53 m_unitBinder->SetUnits( m_frame->GetUserUnits() );
54 }
55 else
56 {
57 m_unitBinder = nullptr;
58 }
59}
60
61
62wxPGWindowList PG_UNIT_EDITOR::CreateControls( wxPropertyGrid* aPropGrid, wxPGProperty* aProperty,
63 const wxPoint& aPos, const wxSize& aSize ) const
64{
65 wxASSERT( m_unitBinder );
66
67 wxString text = aProperty->GetValueAsString( wxPG_EDITABLE_VALUE );
68 wxWindow* win = aPropGrid->GenerateEditorTextCtrl(aPos, aSize, text, nullptr, 0, aProperty->GetMaxLength() );
69 wxPGWindowList ret( win, nullptr );
70
71 m_unitBinder->SetControl( win );
72 m_unitBinder->RequireEval();
73 m_unitBinder->SetUnits( m_frame->GetUserUnits() );
74
75 if( PGPROPERTY_DISTANCE* prop = dynamic_cast<PGPROPERTY_DISTANCE*>( aProperty ) )
76 m_unitBinder->SetCoordType( prop->CoordType() );
77 else if( dynamic_cast<PGPROPERTY_ANGLE*>( aProperty ) != nullptr )
79
80 UpdateControl( aProperty, win );
81
82 return ret;
83}
84
85
86void PG_UNIT_EDITOR::UpdateControl( wxPGProperty* aProperty, wxWindow* aCtrl ) const
87{
88 wxVariant var = aProperty->GetValue();
89
90 if( var.GetType() == wxPG_VARIANT_TYPE_LONG )
91 {
92 m_unitBinder->ChangeValue( var.GetLong() );
93 }
94 else if( var.GetType() == wxPG_VARIANT_TYPE_DOUBLE )
95 {
96 m_unitBinder->ChangeValue( var.GetDouble() );
97 }
98 else if( var.GetType() == wxT( "EDA_ANGLE" ) )
99 {
100 EDA_ANGLE_VARIANT_DATA* angleData = static_cast<EDA_ANGLE_VARIANT_DATA*>( var.GetData() );
101 m_unitBinder->ChangeAngleValue( angleData->Angle() );
102 }
103 else if( !aProperty->IsValueUnspecified() )
104 {
105 wxFAIL_MSG( wxT( "PG_UNIT_EDITOR should only be used with numeric properties!" ) );
106 }
107}
108
109
110bool PG_UNIT_EDITOR::OnEvent( wxPropertyGrid* aPropGrid, wxPGProperty* aProperty,
111 wxWindow* aCtrl, wxEvent& aEvent ) const
112{
113 if( aEvent.GetEventType() == wxEVT_LEFT_UP )
114 {
115 if( wxTextCtrl* textCtrl = dynamic_cast<wxTextCtrl*>( aCtrl ) )
116 {
117 if( !textCtrl->HasFocus() )
118 {
119 textCtrl->SelectAll();
120 return false;
121 }
122 }
123 }
124
125 return wxPGTextCtrlEditor::OnEvent( aPropGrid, aProperty, aCtrl, aEvent );
126}
127
128
129bool PG_UNIT_EDITOR::GetValueFromControl( wxVariant& aVariant, wxPGProperty* aProperty,
130 wxWindow* aCtrl ) const
131{
132 if( !m_unitBinder )
133 return false;
134
135 wxTextCtrl* textCtrl = dynamic_cast<wxTextCtrl*>( aCtrl );
136 wxCHECK_MSG( textCtrl, false, "PG_UNIT_EDITOR requires a text control!" );
137 wxString textVal = textCtrl->GetValue();
138
139 if( aProperty->UsesAutoUnspecified() && textVal.empty() )
140 {
141 aVariant.MakeNull();
142 return true;
143 }
144 bool changed;
145
146 if( dynamic_cast<PGPROPERTY_ANGLE*>( aProperty ) != nullptr )
147 {
148 EDA_ANGLE angle = m_unitBinder->GetAngleValue();
149
150 if( aVariant.GetType() == wxT( "EDA_ANGLE" ) )
151 {
152 EDA_ANGLE_VARIANT_DATA* ad = static_cast<EDA_ANGLE_VARIANT_DATA*>( aVariant.GetData() );
153 changed = ( aVariant.IsNull() || angle != ad->Angle() );
154
155 if( changed )
156 {
157 ad->SetAngle( angle );
158 m_unitBinder->SetAngleValue( angle );
159 }
160 }
161 else
162 {
163 changed = ( aVariant.IsNull() || angle.AsDegrees() != aVariant.GetDouble() );
164
165 if( changed )
166 {
167 aVariant = angle.AsDegrees();
168 m_unitBinder->SetValue( angle.AsDegrees() );
169 }
170 }
171 }
172 else
173 {
174 long result = m_unitBinder->GetValue();
175 changed = ( aVariant.IsNull() || result != aVariant.GetLong() );
176
177 if( changed )
178 {
179 aVariant = result;
180 m_unitBinder->SetValue( result );
181 }
182 }
183
184 // Changing unspecified always causes event (returning
185 // true here should be enough to trigger it).
186 if( !changed && aVariant.IsNull() )
187 changed = true;
188
189 return changed;
190}
191
192
194 wxPGCheckBoxEditor()
195{
196}
197
198
199wxPGWindowList PG_CHECKBOX_EDITOR::CreateControls( wxPropertyGrid* aGrid, wxPGProperty* aProperty,
200 const wxPoint& aPos, const wxSize& aSize ) const
201{
202 // Override wx behavior and toggle unspecified checkboxes to "true"
203 // CreateControls for a checkbox editor is only triggered when the user activates the checkbox
204 // Set the value to false here; the base class will then trigger an event setting it true.
205 if( aProperty->IsValueUnspecified() )
206 aProperty->SetValueFromInt( 0 );
207
208 return wxPGCheckBoxEditor::CreateControls( aGrid, aProperty, aPos, aSize );
209}
const EDA_ANGLE & Angle()
void SetAngle(const EDA_ANGLE &aAngle)
The base class for create windows for drawing purpose.
‍Customized wxPGProperty class to handle angles
Definition: pg_properties.h:98
‍Customized abstract wxPGProperty class to handle coordinate/size units
Definition: pg_properties.h:37
wxPGWindowList CreateControls(wxPropertyGrid *aGrid, wxPGProperty *aProperty, const wxPoint &aPos, const wxSize &aSize) const override
Definition: pg_editors.cpp:199
static const wxString EDITOR_NAME
Definition: pg_editors.h:71
std::unique_ptr< PROPERTY_EDITOR_UNIT_BINDER > m_unitBinder
Definition: pg_editors.h:64
wxPGWindowList CreateControls(wxPropertyGrid *aPropGrid, wxPGProperty *aProperty, const wxPoint &aPos, const wxSize &aSize) const override
Definition: pg_editors.cpp:62
static const wxString EDITOR_NAME
Definition: pg_editors.h:34
void UpdateControl(wxPGProperty *aProperty, wxWindow *aCtrl) const override
Definition: pg_editors.cpp:86
void UpdateFrame(EDA_DRAW_FRAME *aFrame)
When restarting an editor, the instance of PG_UNIT_EDITOR may be the same but the referenced frame is...
Definition: pg_editors.cpp:46
EDA_DRAW_FRAME * m_frame
Definition: pg_editors.h:62
PG_UNIT_EDITOR(EDA_DRAW_FRAME *aFrame)
Definition: pg_editors.cpp:32
bool GetValueFromControl(wxVariant &aVariant, wxPGProperty *aProperty, wxWindow *aCtrl) const override
Definition: pg_editors.cpp:129
bool OnEvent(wxPropertyGrid *aPropGrid, wxPGProperty *aProperty, wxWindow *aCtrl, wxEvent &aEvent) const override
Definition: pg_editors.cpp:110
virtual ~PG_UNIT_EDITOR()
Definition: pg_editors.cpp:41
EDA_UNITS GetUserUnits() const
static DIRECTION_45::AngleType angle(const VECTOR2I &a, const VECTOR2I &b)