KiCad PCB EDA Suite
Loading...
Searching...
No Matches
drc_re_condition_row_panel.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) 2024 KiCad Developers, see AUTHORS.txt for contributors.
5 *
6 * This program is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU General Public License
8 * as published by the Free Software Foundation; either version 2
9 * of the License, or (at your option) any later version.
10 *
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License
17 * along with this program; if not, you may find one here:
18 * http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
19 * or you may search the http://www.gnu.org website for the version 2 license,
20 * or you may write to the Free Software Foundation, Inc.,
21 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
22 */
23
25
26#include <board.h>
30#include <bitmaps.h>
31
32#include <wx/sizer.h>
33#include <wx/choice.h>
34#include <wx/bmpbuttn.h>
35#include <wx/stc/stc.h>
36#include <wx/regex.h>
37#include <wx/log.h>
38
39static constexpr const wxChar* TRACE_COND = wxT( "KI_TRACE_DRC_RULE_EDITOR" );
40
41
43 bool aShowObjectSelector ) :
44 wxPanel( aParent ),
45 m_showObjectSelector( aShowObjectSelector )
46{
47 wxLogTrace( TRACE_COND, wxS( "[DRC_RE_CONDITION_ROW_PANEL] ctor START" ) );
48
49 // Outer horizontal sizer: content on left, delete button on right
50 m_mainSizer = new wxBoxSizer( wxHORIZONTAL );
51
52 // Content sizer holds row of dropdowns and custom query text below
53 m_contentSizer = new wxBoxSizer( wxVERTICAL );
54 m_rowSizer = new wxBoxSizer( wxHORIZONTAL );
55
56 // Object selector (A/B) - only shown for two-object constraints
57 wxArrayString objectChoices;
58 objectChoices.Add( _( "Object A" ) );
59 objectChoices.Add( _( "Object B" ) );
60
61 m_objectChoice = new wxChoice( this, wxID_ANY, wxDefaultPosition, wxDefaultSize, objectChoices );
62 m_objectChoice->SetSelection( 0 );
63 m_rowSizer->Add( m_objectChoice, 0, wxALL | wxALIGN_CENTER_VERTICAL, 2 );
64
65 if( !aShowObjectSelector )
66 m_objectChoice->Hide();
67
68 // Condition type dropdown
69 wxArrayString conditionChoices;
70 conditionChoices.Add( _( "Any" ) );
71 conditionChoices.Add( _( "Net" ) );
72 conditionChoices.Add( _( "Netclass" ) );
73 conditionChoices.Add( _( "Within Area" ) );
74 conditionChoices.Add( _( "Custom Query" ) );
75
76 m_conditionChoice = new wxChoice( this, wxID_ANY, wxDefaultPosition, wxDefaultSize, conditionChoices );
77 m_conditionChoice->SetSelection( 0 );
78 m_rowSizer->Add( m_conditionChoice, 0, wxALL | wxALIGN_CENTER_VERTICAL, 2 );
79
80 // Net selector
81 m_netSelector = new NET_SELECTOR( this, wxID_ANY );
82 m_netSelector->SetNetInfo( &aBoard->GetNetInfo() );
83 m_rowSizer->Add( m_netSelector, 1, wxALL | wxEXPAND, 2 );
84 m_netSelector->Hide();
85
86 // Netclass selector
87 m_netclassSelector = new NETCLASS_SELECTOR( this, wxID_ANY );
88 m_netclassSelector->SetBoard( aBoard );
89 m_rowSizer->Add( m_netclassSelector, 1, wxALL | wxEXPAND, 2 );
90 m_netclassSelector->Hide();
91
92 // Area selector
93 m_areaSelector = new AREA_SELECTOR( this, wxID_ANY );
94 m_areaSelector->SetBoard( aBoard );
95 m_rowSizer->Add( m_areaSelector, 1, wxALL | wxEXPAND, 2 );
96 m_areaSelector->Hide();
97
98 m_contentSizer->Add( m_rowSizer, 0, wxEXPAND, 0 );
99
100 // Custom query text control - shown only when Custom Query is selected
101 m_customQueryCtrl = new wxStyledTextCtrl( this, wxID_ANY, wxDefaultPosition, wxSize( -1, 60 ) );
102 m_customQueryCtrl->SetUseTabs( true );
103 m_customQueryCtrl->SetTabWidth( 4 );
104 m_customQueryCtrl->SetIndent( 4 );
105 m_customQueryCtrl->SetTabIndents( true );
106 m_customQueryCtrl->SetBackSpaceUnIndents( true );
107 m_customQueryCtrl->SetViewEOL( false );
108 m_customQueryCtrl->SetViewWhiteSpace( false );
109 m_customQueryCtrl->SetIndentationGuides( true );
110 m_customQueryCtrl->SetReadOnly( false );
111 m_customQueryCtrl->SetUseHorizontalScrollBar( false );
112 m_customQueryCtrl->SetMaxSize( wxSize( -1, 60 ) );
113 m_contentSizer->Add( m_customQueryCtrl, 0, wxEXPAND | wxLEFT | wxRIGHT | wxBOTTOM, 5 );
114 m_customQueryCtrl->Hide();
115
116 m_mainSizer->Add( m_contentSizer, 1, wxEXPAND, 0 );
117
118 // Delete button on right side, aligned to top
119 m_deleteBtn = new wxBitmapButton( this, wxID_ANY, KiBitmapBundle( BITMAPS::trash ) );
120 m_deleteBtn->SetToolTip( _( "Remove this condition" ) );
121 m_mainSizer->Add( m_deleteBtn, 0, wxALL | wxALIGN_TOP, 2 );
122
123 wxLogTrace( TRACE_COND, wxS( "[DRC_RE_CONDITION_ROW_PANEL] setting sizer" ) );
124 SetSizer( m_mainSizer );
125
126 // Bind events
129 m_deleteBtn->Bind( wxEVT_BUTTON, &DRC_RE_CONDITION_ROW_PANEL::onDeleteClicked, this );
130 wxLogTrace( TRACE_COND, wxS( "[DRC_RE_CONDITION_ROW_PANEL] ctor END" ) );
131}
132
133
135{
136 m_objectChoice->SetSelection( static_cast<int>( aTarget ) );
137}
138
139
144
145
147{
148 m_conditionChoice->SetSelection( static_cast<int>( aType ) );
150}
151
152
157
158
159void DRC_RE_CONDITION_ROW_PANEL::SetValue( const wxString& aValue )
160{
161 switch( GetConditionType() )
162 {
164 m_netSelector->SetSelectedNet( aValue );
165 break;
166
168 m_netclassSelector->SetSelectedNetclass( aValue );
169 break;
170
172 m_areaSelector->SetSelectedArea( aValue );
173 break;
174
176 m_customQueryCtrl->SetValue( aValue );
177 break;
178
179 default:
180 break;
181 }
182}
183
184
186{
187 switch( GetConditionType() )
188 {
190 return m_netSelector->GetSelectedNetname();
191
193 return m_netclassSelector->GetSelectedNetclass();
194
196 return m_areaSelector->GetSelectedArea();
197
199 return m_customQueryCtrl->GetText();
200
201 default:
202 return wxString();
203 }
204}
205
206
208{
209 wxLogTrace( TRACE_COND, wxS( "[ParseExpression] expr='%s'" ), aExpr );
210
211 if( aExpr.IsEmpty() )
212 {
213 wxLogTrace( TRACE_COND, wxS( "[ParseExpression] empty -> ANY" ) );
215 return true;
216 }
217
218 wxString expr = aExpr;
219
220 // Check for object prefix (A. or B.)
221 if( expr.StartsWith( "A." ) )
222 {
224 expr = expr.Mid( 2 );
225 }
226 else if( expr.StartsWith( "B." ) )
227 {
229 expr = expr.Mid( 2 );
230 }
231
232 // Try to match known patterns
233 wxRegEx netRe( wxT( "^NetName\\s*==\\s*'([^']*)'" ) );
234 wxRegEx netclassRe1( wxT( "^hasNetclass\\('([^']*)'\\)" ) );
235 wxRegEx netclassRe2( wxT( "^NetClass\\s*==\\s*'([^']*)'" ) );
236 wxRegEx areaRe( wxT( "^(?:enclosedByArea|intersectsArea)\\('([^']*)'\\)" ) );
237
238 if( netRe.Matches( expr ) )
239 {
240 wxLogTrace( TRACE_COND, wxS( "[ParseExpression] matched NET pattern" ) );
242 m_netSelector->SetSelectedNet( netRe.GetMatch( expr, 1 ) );
243 return true;
244 }
245 else if( netclassRe1.Matches( expr ) )
246 {
247 wxLogTrace( TRACE_COND, wxS( "[ParseExpression] matched NETCLASS (hasNetclass) pattern" ) );
249 m_netclassSelector->SetSelectedNetclass( netclassRe1.GetMatch( expr, 1 ) );
250 return true;
251 }
252 else if( netclassRe2.Matches( expr ) )
253 {
254 wxLogTrace( TRACE_COND, wxS( "[ParseExpression] matched NETCLASS (NetClass==) pattern" ) );
256 m_netclassSelector->SetSelectedNetclass( netclassRe2.GetMatch( expr, 1 ) );
257 return true;
258 }
259 else if( areaRe.Matches( expr ) )
260 {
261 wxLogTrace( TRACE_COND, wxS( "[ParseExpression] matched WITHIN_AREA pattern" ) );
263 m_areaSelector->SetSelectedArea( areaRe.GetMatch( expr, 1 ) );
264 return true;
265 }
266
267 // Fallback to custom query
268 wxLogTrace( TRACE_COND, wxS( "[ParseExpression] no match -> CUSTOM" ) );
270 m_customQueryCtrl->SetValue( aExpr );
271
272 return true;
273}
274
275
277{
278 wxString prefix = m_showObjectSelector
279 ? ( GetObjectTarget() == OBJECT_TARGET::OBJECT_A ? "A" : "B" )
280 : "A";
281
282 switch( GetConditionType() )
283 {
285 {
286 wxString net = m_netSelector->GetSelectedNetname();
287
288 if( net.IsEmpty() )
289 return wxEmptyString;
290
291 return prefix + wxString::Format( ".NetName == '%s'", net );
292 }
293
295 {
296 wxString netclass = m_netclassSelector->GetSelectedNetclass();
297
298 if( netclass.IsEmpty() )
299 return wxEmptyString;
300
301 return prefix + wxString::Format( ".hasNetclass('%s')", netclass );
302 }
303
305 {
306 wxString area = m_areaSelector->GetSelectedArea();
307
308 if( area.IsEmpty() )
309 return wxEmptyString;
310
311 return prefix + wxString::Format( ".intersectsArea('%s')", area );
312 }
313
315 return m_customQueryCtrl->GetText();
316
317 default:
318 return wxEmptyString;
319 }
320}
321
322
324{
325 m_deleteBtn->Show( aShow );
326 Layout();
327}
328
329
334
335
336void DRC_RE_CONDITION_ROW_PANEL::onObjectChoice( wxCommandEvent& aEvent )
337{
338 if( m_changeCallback )
340}
341
342
344{
346
347 if( m_changeCallback )
349}
350
351
353{
354 if( m_deleteCallback )
356}
357
358
360{
361 m_netSelector->Hide();
362 m_netclassSelector->Hide();
363 m_areaSelector->Hide();
364 m_customQueryCtrl->Hide();
365
366 switch( GetConditionType() )
367 {
369 m_netSelector->Show();
370 break;
371
373 m_netclassSelector->Show();
374 break;
375
377 m_areaSelector->Show();
378 break;
379
381 m_customQueryCtrl->Show();
382 break;
383
384 default:
385 break;
386 }
387
388 Layout();
389
390 // Notify parent to update layout since our size may have changed
391 if( wxWindow* parent = GetParent() )
392 parent->Layout();
393}
wxBitmapBundle KiBitmapBundle(BITMAPS aBitmap, int aMinHeight)
Definition bitmap.cpp:110
Information pertinent to a Pcbnew printed circuit board.
Definition board.h:322
const NETINFO_LIST & GetNetInfo() const
Definition board.h:996
void SetValue(const wxString &aValue)
DRC_RE_CONDITION_ROW_PANEL(wxWindow *aParent, BOARD *aBoard, bool aShowObjectSelector)
wxString BuildExpression() const
Build a condition expression from the row's current state.
void SetConditionType(CONDITION_TYPE aType)
bool ParseExpression(const wxString &aExpr)
Parse a condition expression and set the row's state.
void onConditionChoice(wxCommandEvent &aEvent)
void onObjectChoice(wxCommandEvent &aEvent)
void onDeleteClicked(wxCommandEvent &aEvent)
void SetObjectTarget(OBJECT_TARGET aTarget)
static constexpr const wxChar * TRACE_COND
#define _(s)