KiCad PCB EDA Suite
Loading...
Searching...
No Matches
dialog_drc_rule_editor.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 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
23
24#include <confirm.h>
25#include <pcb_edit_frame.h>
26#include <kiface_base.h>
27
42#include "drc_re_rule_loader.h"
43#include "drc_re_rule_saver.h"
44#include <drc/drc_engine.h>
46#include <tool/tool_manager.h>
47#include <tool/actions.h>
48#include <wx/ffile.h>
49#include <memory>
50
51
52const RULE_TREE_NODE* FindNodeById( const std::vector<RULE_TREE_NODE>& aNodes, int aTargetId )
53{
54 auto it = std::find_if( aNodes.begin(), aNodes.end(),
55 [aTargetId]( const RULE_TREE_NODE& node )
56 {
57 return node.m_nodeId == aTargetId;
58 } );
59
60 if( it != aNodes.end() )
61 {
62 return &( *it );
63 }
64
65 return nullptr;
66}
67
68
70 RULE_EDITOR_DIALOG_BASE( aParent, _( "Design Rule Editor" ), wxSize( 980, 680 ) ),
72 m_reporter( nullptr ),
73 m_nodeId( 0 )
74{
75 m_frame = aEditorFrame;
76 m_currentBoard = m_frame->GetBoard();
77 m_ruleEditorPanel = nullptr;
78
79 m_ruleTreeCtrl->DeleteAllItems();
80
82
84
86
87 if( Prj().IsReadOnly() )
88 {
89 m_infoBar->ShowMessage( _( "Project is missing or read-only. Settings will not be "
90 "editable." ),
91 wxICON_WARNING );
92 }
93
94 m_severities = 0;
95
96 m_markersProvider = std::make_shared<DRC_ITEMS_PROVIDER>( m_currentBoard, MARKER_BASE::MARKER_DRC,
98
100 new wxDataViewCtrl( this, wxID_ANY, wxDefaultPosition, wxDefaultSize, wxDV_ROW_LINES | wxDV_SINGLE );
101
103 m_markerDataView->AssociateModel( m_markersTreeModel );
105
106 m_markerDataView->Hide();
107}
108
109
113
114
116{
118
119 // Ensure minimum size is our intended small value after base sizing logic
120 Layout();
121 SetMinSize( wxSize( 400, 300 ) );
122
123 // If SetSizeHints inflated the height (e.g., to full display height), reset to the ctor's
124 // intended initial size so that any saved geometry can apply without being trumped by the
125 // current oversized height (Show() uses max(current, saved)).
126 SetSize( wxSize( 980, 680 ) );
127
128 return ok;
129}
130
131
133{
135 return false;
136
138
139 return true;
140}
141
142
144{
145 std::vector<RULE_TREE_NODE> result;
146
147 int lastParentId;
148 int electricalItemId;
149 int manufacturabilityItemId;
150 int highSpeedDesignId;
151 int footprintItemId;
152
153 result.push_back( buildRuleTreeNodeData( "Design Rules", DRC_RULE_EDITOR_ITEM_TYPE::ROOT ) );
154 lastParentId = m_nodeId;
155
156 result.push_back( buildRuleTreeNodeData( "Electrical", DRC_RULE_EDITOR_ITEM_TYPE::CATEGORY, lastParentId ) );
157 electricalItemId = m_nodeId;
158
159 result.push_back( buildRuleTreeNodeData( "Manufacturability", DRC_RULE_EDITOR_ITEM_TYPE::CATEGORY, lastParentId ) );
160 manufacturabilityItemId = m_nodeId;
161
162 result.push_back( buildRuleTreeNodeData( "Highspeed design", DRC_RULE_EDITOR_ITEM_TYPE::CATEGORY, lastParentId ) );
163 highSpeedDesignId = m_nodeId;
164
165 result.push_back( buildRuleTreeNodeData( "Footprints", DRC_RULE_EDITOR_ITEM_TYPE::CATEGORY, lastParentId ) );
166 footprintItemId = m_nodeId;
167
168 std::vector<RULE_TREE_NODE> subItemNodes = buildElectricalRuleTreeNodes( electricalItemId );
169 result.insert( result.end(), subItemNodes.begin(), subItemNodes.end() );
170
171 subItemNodes = buildManufacturabilityRuleTreeNodes( manufacturabilityItemId );
172 result.insert( result.end(), subItemNodes.begin(), subItemNodes.end() );
173
174 subItemNodes = buildHighspeedDesignRuleTreeNodes( highSpeedDesignId );
175 result.insert( result.end(), subItemNodes.begin(), subItemNodes.end() );
176
177 subItemNodes = buildFootprintsRuleTreeNodes( footprintItemId );
178 result.insert( result.end(), subItemNodes.begin(), subItemNodes.end() );
179
180 // Custom rules category
181 result.push_back( buildRuleTreeNodeData( "Custom", DRC_RULE_EDITOR_ITEM_TYPE::CATEGORY, lastParentId ) );
182 int customItemId = m_nodeId;
183 result.push_back(
185
186 return result;
187}
188
190{
191 wxFileName rulesFile( m_frame->GetDesignRulesPath() );
192
193 if( !rulesFile.FileExists() )
194 return;
195
196 DRC_RULE_LOADER loader;
197 std::vector<DRC_RE_LOADED_PANEL_ENTRY> entries = loader.LoadFile( rulesFile.GetFullPath() );
198
199 wxLogTrace( wxS( "KI_TRACE_DRC_RULE_EDITOR" ),
200 wxS( "[LoadExistingRules] Loaded %zu entries from %s" ),
201 entries.size(), rulesFile.GetFullPath() );
202
203 // Debug: Log all constraint nodes available for parent lookup
204 wxLogTrace( wxS( "KI_TRACE_DRC_RULE_EDITOR" ),
205 wxS( "[LoadExistingRules] Available constraint nodes in m_ruleTreeNodeDatas:" ) );
206
207 for( const RULE_TREE_NODE& node : m_ruleTreeNodeDatas )
208 {
209 if( node.m_nodeType == CONSTRAINT )
210 {
211 wxLogTrace( wxS( "KI_TRACE_DRC_RULE_EDITOR" ),
212 wxS( "[LoadExistingRules] Node '%s': nodeId=%d, m_nodeTypeMap=%d" ),
213 wxString( node.m_nodeName ), node.m_nodeId,
214 node.m_nodeTypeMap ? static_cast<int>( *node.m_nodeTypeMap ) : -1 );
215 }
216 }
217
218 // Helper to find tree item by node ID
219 std::function<wxTreeItemId( wxTreeItemId, int )> findItem =
220 [&]( wxTreeItemId aItem, int aTargetId ) -> wxTreeItemId
221 {
222 RULE_TREE_ITEM_DATA* data =
223 dynamic_cast<RULE_TREE_ITEM_DATA*>( m_ruleTreeCtrl->GetItemData( aItem ) );
224
225 if( data && data->GetNodeId() == aTargetId )
226 return aItem;
227
228 wxTreeItemIdValue cookie;
229 wxTreeItemId child = m_ruleTreeCtrl->GetFirstChild( aItem, cookie );
230
231 while( child.IsOk() )
232 {
233 wxTreeItemId res = findItem( child, aTargetId );
234
235 if( res.IsOk() )
236 return res;
237
238 child = m_ruleTreeCtrl->GetNextChild( aItem, cookie );
239 }
240
241 return wxTreeItemId();
242 };
243
244 for( DRC_RE_LOADED_PANEL_ENTRY& entry : entries )
245 {
246 DRC_RULE_EDITOR_CONSTRAINT_NAME type = entry.panelType;
247
248 wxLogTrace( wxS( "KI_TRACE_DRC_RULE_EDITOR" ),
249 wxS( "[LoadExistingRules] Processing entry: rule='%s', panelType=%d" ),
250 entry.ruleName, static_cast<int>( type ) );
251
252 // Find parent node by constraint type
253 int parentId = -1;
254
255 for( const RULE_TREE_NODE& node : m_ruleTreeNodeDatas )
256 {
257 if( node.m_nodeType == CONSTRAINT && node.m_nodeTypeMap && *node.m_nodeTypeMap == type )
258 {
259 parentId = node.m_nodeId;
260 break;
261 }
262 }
263
264 if( parentId == -1 )
265 {
266 wxLogTrace( wxS( "KI_TRACE_DRC_RULE_EDITOR" ),
267 wxS( "[LoadExistingRules] No parent found for panelType=%d, skipping" ),
268 static_cast<int>( type ) );
269 continue;
270 }
271
272 wxTreeItemId parentItem = findItem( m_ruleTreeCtrl->GetRootItem(), parentId );
273
274 if( !parentItem.IsOk() )
275 {
276 wxLogTrace( wxS( "KI_TRACE_DRC_RULE_EDITOR" ),
277 wxS( "[LoadExistingRules] Tree item not found for parentId=%d, skipping" ),
278 parentId );
279 continue;
280 }
281
282 wxLogTrace( wxS( "KI_TRACE_DRC_RULE_EDITOR" ),
283 wxS( "[LoadExistingRules] Found parent node: parentId=%d" ), parentId );
284
285 RULE_TREE_NODE node =
286 buildRuleTreeNodeData( entry.ruleName.ToStdString(), RULE, parentId, type );
287
288 // Transfer loaded entry data to the constraint data
289 auto ruleData = std::dynamic_pointer_cast<DRC_RE_BASE_CONSTRAINT_DATA>( entry.constraintData );
290
291 if( ruleData )
292 {
293 ruleData->SetId( node.m_nodeData->GetId() );
294 ruleData->SetParentId( parentId );
295 ruleData->SetOriginalRuleText( entry.originalRuleText );
296 ruleData->SetWasEdited( entry.wasEdited );
297 node.m_nodeData = ruleData;
298 }
299
300 m_ruleTreeNodeDatas.push_back( node );
301 AppendNewRuleTreeItem( node, parentItem );
302
303 wxLogTrace( wxS( "KI_TRACE_DRC_RULE_EDITOR" ),
304 wxS( "[LoadExistingRules] Appended rule '%s' to tree under parentId=%d" ),
305 entry.ruleName, parentId );
306 }
307}
308
309
311{
312 wxTreeItemId treeItemId;
313 RULE_TREE_NODE* nodeDetail = getRuleTreeNodeInfo( aRuleTreeItemData->GetNodeId() );
314
315 if( nodeDetail->m_nodeType == CONSTRAINT )
316 {
317 treeItemId = aRuleTreeItemData->GetTreeItemId();
318 }
319 else
320 {
321 treeItemId = aRuleTreeItemData->GetParentTreeItemId();
322 }
323
324 AppendNewRuleTreeItem( buildRuleTreeNode( aRuleTreeItemData ), treeItemId );
325}
326
327
329{
330 RULE_TREE_NODE* sourceTreeNode = getRuleTreeNodeInfo( aRuleTreeItemData->GetNodeId() );
331 RULE_TREE_NODE targetTreeNode = buildRuleTreeNode( aRuleTreeItemData );
332
333 auto sourceDataPtr = dynamic_pointer_cast<RULE_EDITOR_DATA_BASE>( sourceTreeNode->m_nodeData );
334
335 if( sourceDataPtr )
336 {
337 targetTreeNode.m_nodeData->CopyFrom( *sourceDataPtr );
338 }
339
340 wxTreeItemId treeItemId = aRuleTreeItemData->GetParentTreeItemId();
341 AppendNewRuleTreeItem( targetTreeNode, treeItemId );
342}
343
344
346{
347 RULE_TREE_NODE* nodeDetail = getRuleTreeNodeInfo( aCurrentRuleTreeItemData->GetNodeId() );
348
349 if( nodeDetail->m_nodeType == ROOT || nodeDetail->m_nodeType == CATEGORY || nodeDetail->m_nodeType == CONSTRAINT )
350 {
351 std::vector<RULE_TREE_NODE*> ruleNodes;
352 collectChildRuleNodes( nodeDetail->m_nodeId, ruleNodes );
353
354 std::vector<DRC_RULE_ROW> rows;
355 rows.reserve( ruleNodes.size() );
356
357 for( RULE_TREE_NODE* ruleNode : ruleNodes )
358 {
359 RULE_TREE_NODE* parentNode = getRuleTreeNodeInfo( ruleNode->m_nodeData->GetParentId() );
360 wxString type = parentNode ? parentNode->m_nodeName : wxString{};
361 rows.push_back( { type, ruleNode->m_nodeData->GetRuleName(), ruleNode->m_nodeData->GetComment() } );
362 }
363
366 m_ruleEditorPanel = nullptr;
367 }
368 else if( nodeDetail->m_nodeType == RULE )
369 {
370 RULE_TREE_ITEM_DATA* parentItemData = dynamic_cast<RULE_TREE_ITEM_DATA*>(
371 m_ruleTreeCtrl->GetItemData( aCurrentRuleTreeItemData->GetParentTreeItemId() ) );
372 RULE_TREE_NODE* paretNodeDetail = getRuleTreeNodeInfo( parentItemData->GetNodeId() );
373 wxString constraintName = paretNodeDetail->m_nodeName;
374
376 m_splitter, m_frame->GetBoard(),
377 static_cast<DRC_RULE_EDITOR_CONSTRAINT_NAME>( nodeDetail->m_nodeTypeMap.value_or( -1 ) ),
378 &constraintName, dynamic_pointer_cast<DRC_RE_BASE_CONSTRAINT_DATA>( nodeDetail->m_nodeData ) );
379
381
382 m_ruleEditorPanel->TransferDataToWindow();
383
384 m_ruleEditorPanel->SetSaveCallback(
385 [this]( int aNodeId )
386 {
387 this->saveRule( aNodeId );
388 } );
389
390 m_ruleEditorPanel->SetRemoveCallback(
391 [this]( int aNodeId )
392 {
393 this->RemoveRule( aNodeId );
394 } );
395
396 m_ruleEditorPanel->SetCloseCallback(
397 [this]( int aNodeId )
398 {
399 this->closeRuleEntryView( aNodeId );
400 } );
401
402 m_ruleEditorPanel->SetRuleNameValidationCallback(
403 [this]( int aNodeId, wxString aRuleName )
404 {
405 return this->validateRuleName( aNodeId, aRuleName );
406 } );
407
408 m_ruleEditorPanel->SetShowMatchesCallBack(
409 [this]( int aNodeId ) -> int
410 {
411 return this->highlightMatchingItems( aNodeId );
412 } );
413
414 m_groupHeaderPanel = nullptr;
415 }
416}
417
418
419void DIALOG_DRC_RULE_EDITOR::OnSave( wxCommandEvent& aEvent )
420{
422 m_ruleEditorPanel->Save( aEvent );
423}
424
425
426void DIALOG_DRC_RULE_EDITOR::OnCancel( wxCommandEvent& aEvent )
427{
429 {
430 auto data = m_ruleEditorPanel->GetConstraintData();
431 bool isNew = data && data->IsNew();
432
433 m_ruleEditorPanel->Cancel( aEvent );
434
435 if( isNew )
436 return;
437 }
438
439 aEvent.Skip();
440}
441
442
444{
445 RULE_TREE_NODE* nodeDetail = getRuleTreeNodeInfo( aRuleTreeItemData->GetNodeId() );
446
448 {
449 m_ruleEditorPanel->TransferDataFromWindow();
450
451 nodeDetail->m_nodeName = nodeDetail->m_nodeData->GetRuleName();
452 nodeDetail->m_nodeData->SetIsNew( false );
453
454 // Mark as edited so the rule gets regenerated instead of using original text
455 auto constraintData =
456 std::dynamic_pointer_cast<DRC_RE_BASE_CONSTRAINT_DATA>( nodeDetail->m_nodeData );
457
458 if( constraintData )
459 constraintData->SetWasEdited( true );
460
461 UpdateRuleTreeItemText( aRuleTreeItemData->GetTreeItemId(), nodeDetail->m_nodeName );
462 }
463}
464
465
484
485
487{
488 RULE_TREE_ITEM_DATA* itemData = dynamic_cast<RULE_TREE_ITEM_DATA*>(
489 m_ruleTreeCtrl->GetItemData( GetCurrentlySelectedRuleTreeItemData()->GetTreeItemId() ) );
490 RULE_TREE_NODE* nodeDetail = getRuleTreeNodeInfo( itemData->GetNodeId() );
491
492 if( !nodeDetail->m_nodeData->IsNew() )
493 {
494 if( OKOrCancelDialog( this, _( "Confirmation" ), "", _( "Are you sure you want to delete?" ), _( "Delete" ) )
495 != wxID_OK )
496 {
497 return;
498 }
499 }
500
501 if( itemData )
502 {
503 int nodeId = itemData->GetNodeId();
504
505 DeleteRuleTreeItem( GetCurrentlySelectedRuleTreeItemData()->GetTreeItemId(), nodeId );
506 deleteTreeNodeData( nodeId );
507 }
508
509 SetControlsEnabled( true );
510}
511
512
513std::vector<RULE_TREE_NODE> DIALOG_DRC_RULE_EDITOR::buildElectricalRuleTreeNodes( int& aParentId )
514{
515 std::vector<RULE_TREE_NODE> result;
516 int lastParentId;
517
518 result.push_back( buildRuleTreeNodeData( "Clearance", DRC_RULE_EDITOR_ITEM_TYPE::CATEGORY, aParentId ) );
519 lastParentId = m_nodeId;
520
521 result.push_back( buildRuleTreeNodeData( "Basic clearance", DRC_RULE_EDITOR_ITEM_TYPE::CONSTRAINT, lastParentId,
522 BASIC_CLEARANCE ) );
523 result.push_back( buildRuleTreeNodeData( "Board outline clearance", DRC_RULE_EDITOR_ITEM_TYPE::CONSTRAINT,
524 lastParentId, BOARD_OUTLINE_CLEARANCE ) );
525 result.push_back( buildRuleTreeNodeData( "Minimum clearance", DRC_RULE_EDITOR_ITEM_TYPE::CONSTRAINT, lastParentId,
527 result.push_back( buildRuleTreeNodeData( "Minimum item clearance", DRC_RULE_EDITOR_ITEM_TYPE::CONSTRAINT,
528 lastParentId, MINIMUM_ITEM_CLEARANCE ) );
529 result.push_back( buildRuleTreeNodeData( "Copper to edge clearance", DRC_RULE_EDITOR_ITEM_TYPE::CONSTRAINT,
530 lastParentId, COPPER_TO_EDGE_CLEARANCE ) );
531 result.push_back( buildRuleTreeNodeData( "Courtyard Clearance", DRC_RULE_EDITOR_ITEM_TYPE::CONSTRAINT, lastParentId,
533 result.push_back( buildRuleTreeNodeData( "Physical Clearance", DRC_RULE_EDITOR_ITEM_TYPE::CONSTRAINT, lastParentId,
535 result.push_back( buildRuleTreeNodeData( "Creepage distance", DRC_RULE_EDITOR_ITEM_TYPE::CONSTRAINT, lastParentId,
537
538 result.push_back( buildRuleTreeNodeData( "Connection Width", DRC_RULE_EDITOR_ITEM_TYPE::CATEGORY, aParentId ) );
539 lastParentId = m_nodeId;
540
541 result.push_back( buildRuleTreeNodeData( "Minimum connection width", DRC_RULE_EDITOR_ITEM_TYPE::CONSTRAINT,
542 lastParentId, MINIMUM_CONNECTION_WIDTH ) );
543 result.push_back( buildRuleTreeNodeData( "Minimum track width", DRC_RULE_EDITOR_ITEM_TYPE::CONSTRAINT, lastParentId,
545
546 result.push_back( buildRuleTreeNodeData( "Hole Clearance", DRC_RULE_EDITOR_ITEM_TYPE::CATEGORY, aParentId ) );
547 lastParentId = m_nodeId;
548
549 result.push_back( buildRuleTreeNodeData( "Copper to hole clearance", DRC_RULE_EDITOR_ITEM_TYPE::CONSTRAINT,
550 lastParentId, COPPER_TO_HOLE_CLEARANCE ) );
551 result.push_back( buildRuleTreeNodeData( "Hole to hole clearance", DRC_RULE_EDITOR_ITEM_TYPE::CONSTRAINT,
552 lastParentId, HOLE_TO_HOLE_CLEARANCE ) );
553
554 result.push_back( buildRuleTreeNodeData( "Spoke Count", DRC_RULE_EDITOR_ITEM_TYPE::CATEGORY, aParentId ) );
555 lastParentId = m_nodeId;
556
557 result.push_back( buildRuleTreeNodeData( "Minimum thermal relief spoke count",
560
561 return result;
562}
563
564
565std::vector<RULE_TREE_NODE> DIALOG_DRC_RULE_EDITOR::buildManufacturabilityRuleTreeNodes( int& aParentId )
566{
567 std::vector<RULE_TREE_NODE> result;
568 int lastParentId;
569
570 result.push_back( buildRuleTreeNodeData( "Annular Width", DRC_RULE_EDITOR_ITEM_TYPE::CATEGORY, aParentId ) );
571 lastParentId = m_nodeId;
572
573 result.push_back( buildRuleTreeNodeData( "Minimum annular width", DRC_RULE_EDITOR_ITEM_TYPE::CONSTRAINT,
574 lastParentId, MINIMUM_ANNULAR_WIDTH ) );
575 result.push_back( buildRuleTreeNodeData( "Hole", DRC_RULE_EDITOR_ITEM_TYPE::CATEGORY, aParentId ) );
576 lastParentId = m_nodeId;
577 result.push_back( buildRuleTreeNodeData( "Minimum through hole", DRC_RULE_EDITOR_ITEM_TYPE::CONSTRAINT,
578 lastParentId, MINIMUM_THROUGH_HOLE ) );
579 result.push_back( buildRuleTreeNodeData( "Hole to hole distance", DRC_RULE_EDITOR_ITEM_TYPE::CONSTRAINT,
580 lastParentId, HOLE_TO_HOLE_DISTANCE ) );
581 result.push_back( buildRuleTreeNodeData( "Minimum uvia hole", DRC_RULE_EDITOR_ITEM_TYPE::CONSTRAINT, lastParentId,
583 result.push_back( buildRuleTreeNodeData( "Minimum uvia diameter", DRC_RULE_EDITOR_ITEM_TYPE::CONSTRAINT,
584 lastParentId, MINIMUM_UVIA_DIAMETER ) );
585 result.push_back(
587
588 result.push_back( buildRuleTreeNodeData( "Text Geometry", DRC_RULE_EDITOR_ITEM_TYPE::CATEGORY, aParentId ) );
589 lastParentId = m_nodeId;
590
591 result.push_back( buildRuleTreeNodeData( "Minimum text height and thickness", DRC_RULE_EDITOR_ITEM_TYPE::CONSTRAINT,
592 lastParentId, MINIMUM_TEXT_HEIGHT_AND_THICKNESS ) );
593
594 result.push_back( buildRuleTreeNodeData( "Silkscreen Clearance", DRC_RULE_EDITOR_ITEM_TYPE::CATEGORY, aParentId ) );
595 lastParentId = m_nodeId;
596
597 result.push_back( buildRuleTreeNodeData( "Silk to silk clearance", DRC_RULE_EDITOR_ITEM_TYPE::CONSTRAINT,
598 lastParentId, SILK_TO_SILK_CLEARANCE ) );
599 result.push_back( buildRuleTreeNodeData( "Silk to soldermask clearance", DRC_RULE_EDITOR_ITEM_TYPE::CONSTRAINT,
600 lastParentId, SILK_TO_SOLDERMASK_CLEARANCE ) );
601
602 result.push_back( buildRuleTreeNodeData( "Soldermask", DRC_RULE_EDITOR_ITEM_TYPE::CATEGORY, aParentId ) );
603 lastParentId = m_nodeId;
604
605 result.push_back( buildRuleTreeNodeData( "Minimum soldermask silver", DRC_RULE_EDITOR_ITEM_TYPE::CONSTRAINT,
606 lastParentId, MINIMUM_SOLDERMASK_SILVER ) );
607 result.push_back( buildRuleTreeNodeData( "Soldermask expansion", DRC_RULE_EDITOR_ITEM_TYPE::CONSTRAINT,
608 lastParentId, SOLDERMASK_EXPANSION ) );
609
610 result.push_back( buildRuleTreeNodeData( "Solderpaste", DRC_RULE_EDITOR_ITEM_TYPE::CATEGORY, aParentId ) );
611 lastParentId = m_nodeId;
612
613 result.push_back( buildRuleTreeNodeData( "Solderpaste expansion", DRC_RULE_EDITOR_ITEM_TYPE::CONSTRAINT,
614 lastParentId, SOLDERPASTE_EXPANSION ) );
615
616 result.push_back( buildRuleTreeNodeData( "Deviation", DRC_RULE_EDITOR_ITEM_TYPE::CATEGORY, aParentId ) );
617 lastParentId = m_nodeId;
618
619 result.push_back( buildRuleTreeNodeData( "Maximum allowed deviation", DRC_RULE_EDITOR_ITEM_TYPE::CONSTRAINT,
620 lastParentId, MAXIMUM_ALLOWED_DEVIATION ) );
621
622 result.push_back( buildRuleTreeNodeData( "Annular Ring", DRC_RULE_EDITOR_ITEM_TYPE::CATEGORY, aParentId ) );
623 lastParentId = m_nodeId;
624
625 result.push_back( buildRuleTreeNodeData( "Minimum annular ring", DRC_RULE_EDITOR_ITEM_TYPE::CONSTRAINT,
626 lastParentId, MINIMUM_ANGULAR_RING ) );
627
628 return result;
629}
630
631
632std::vector<RULE_TREE_NODE> DIALOG_DRC_RULE_EDITOR::buildHighspeedDesignRuleTreeNodes( int& aParentId )
633{
634 std::vector<RULE_TREE_NODE> result;
635 int lastParentId;
636
637 result.push_back( buildRuleTreeNodeData( "Diff Pair (width, gap, uncoupled length)",
639 lastParentId = m_nodeId;
640
641 result.push_back( buildRuleTreeNodeData( "Routing diff pair", DRC_RULE_EDITOR_ITEM_TYPE::CONSTRAINT, lastParentId,
643 result.push_back( buildRuleTreeNodeData( "Routing width", DRC_RULE_EDITOR_ITEM_TYPE::CONSTRAINT, lastParentId,
644 ROUTING_WIDTH ) );
645 result.push_back( buildRuleTreeNodeData( "Maximum via count", DRC_RULE_EDITOR_ITEM_TYPE::CONSTRAINT, lastParentId,
647
648 result.push_back( buildRuleTreeNodeData( "Skew", DRC_RULE_EDITOR_ITEM_TYPE::CATEGORY, aParentId ) );
649 lastParentId = m_nodeId;
650
651 result.push_back( buildRuleTreeNodeData( "Length Matching", DRC_RULE_EDITOR_ITEM_TYPE::CATEGORY, aParentId ) );
652 lastParentId = m_nodeId;
653
654 result.push_back( buildRuleTreeNodeData( "Matched length diff pair", DRC_RULE_EDITOR_ITEM_TYPE::CONSTRAINT,
655 lastParentId, MATCHED_LENGTH_DIFF_PAIR ) );
656 result.push_back( buildRuleTreeNodeData( "Absolute length", DRC_RULE_EDITOR_ITEM_TYPE::CONSTRAINT, lastParentId,
657 ABSOLUTE_LENGTH ) );
658
659 return result;
660}
661
662
663std::vector<RULE_TREE_NODE> DIALOG_DRC_RULE_EDITOR::buildFootprintsRuleTreeNodes( int& aParentId )
664{
665 std::vector<RULE_TREE_NODE> result;
666 int lastParentId;
667
668 result.push_back( buildRuleTreeNodeData( "Allowed Layers", DRC_RULE_EDITOR_ITEM_TYPE::CATEGORY, aParentId ) );
669 lastParentId = m_nodeId;
670
671 result.push_back( buildRuleTreeNodeData( "Permitted layers", DRC_RULE_EDITOR_ITEM_TYPE::CONSTRAINT, lastParentId,
673
674 result.push_back( buildRuleTreeNodeData( "Orientation", DRC_RULE_EDITOR_ITEM_TYPE::CATEGORY, aParentId ) );
675 lastParentId = m_nodeId;
676
677 result.push_back( buildRuleTreeNodeData( "Allowed orientation", DRC_RULE_EDITOR_ITEM_TYPE::CONSTRAINT, lastParentId,
679
680 result.push_back( buildRuleTreeNodeData( "Via Placement", DRC_RULE_EDITOR_ITEM_TYPE::CATEGORY, aParentId ) );
681 lastParentId = m_nodeId;
682
683 result.push_back( buildRuleTreeNodeData( "Vias under SMD", DRC_RULE_EDITOR_ITEM_TYPE::CONSTRAINT, lastParentId,
684 VIAS_UNDER_SMD ) );
685
686 return result;
687}
688
689
697bool nodeExists( const RULE_TREE_NODE& aRuleTreeNode, const wxString& aTargetName )
698{
699 if( aRuleTreeNode.m_nodeName == aTargetName )
700 {
701 return true;
702 }
703
704 for( const auto& child : aRuleTreeNode.m_childNodes )
705 {
706 if( nodeExists( child, aTargetName ) )
707 {
708 return true;
709 }
710 }
711
712 return false;
713}
714
715
723bool nodeExists( const std::vector<RULE_TREE_NODE>& aRuleTreeNodes, const wxString& aTargetName )
724{
725 for( const auto& node : aRuleTreeNodes )
726 {
727 if( nodeExists( node, aTargetName ) )
728 {
729 return true;
730 }
731 }
732
733 return false;
734}
735
736
738{
739 // Factory function type for creating constraint data objects
740 using ConstraintDataFactory =
741 std::function<std::shared_ptr<DRC_RE_BASE_CONSTRAINT_DATA>( const DRC_RE_BASE_CONSTRAINT_DATA& )>;
742
743 // Factory map for constraint data creation
744 static const std::unordered_map<DRC_RULE_EDITOR_CONSTRAINT_NAME, ConstraintDataFactory> s_constraintFactories = {
746 []( const DRC_RE_BASE_CONSTRAINT_DATA& data )
747 {
748 return std::make_shared<DRC_RE_VIA_STYLE_CONSTRAINT_DATA>( data );
749 } },
751 []( const DRC_RE_BASE_CONSTRAINT_DATA& data )
752 {
753 return std::make_shared<DRC_RE_MINIMUM_TEXT_HEIGHT_THICKNESS_CONSTRAINT_DATA>( data );
754 } },
756 []( const DRC_RE_BASE_CONSTRAINT_DATA& data )
757 {
758 return std::make_shared<DRC_RE_ROUTING_DIFF_PAIR_CONSTRAINT_DATA>( data );
759 } },
761 []( const DRC_RE_BASE_CONSTRAINT_DATA& data )
762 {
763 return std::make_shared<DRC_RE_ROUTING_WIDTH_CONSTRAINT_DATA>( data );
764 } },
766 []( const DRC_RE_BASE_CONSTRAINT_DATA& data )
767 {
768 return std::make_shared<DRC_RE_PERMITTED_LAYERS_CONSTRAINT_DATA>( data );
769 } },
771 []( const DRC_RE_BASE_CONSTRAINT_DATA& data )
772 {
773 return std::make_shared<DRC_RE_ALLOWED_ORIENTATION_CONSTRAINT_DATA>( data );
774 } },
776 []( const DRC_RE_BASE_CONSTRAINT_DATA& data )
777 {
778 return std::make_shared<DRC_RE_CUSTOM_RULE_CONSTRAINT_DATA>( data );
779 } }
780 };
781
782 RULE_TREE_ITEM_DATA* treeItemData;
783 RULE_TREE_NODE* nodeDetail = getRuleTreeNodeInfo( aRuleTreeItemData->GetNodeId() );
784
785 if( nodeDetail->m_nodeType == CONSTRAINT )
786 {
787 treeItemData = aRuleTreeItemData;
788 }
789 else
790 {
791 treeItemData = dynamic_cast<RULE_TREE_ITEM_DATA*>(
792 m_ruleTreeCtrl->GetItemData( aRuleTreeItemData->GetParentTreeItemId() ) );
793 nodeDetail = getRuleTreeNodeInfo( treeItemData->GetNodeId() );
794 }
795
796 m_nodeId++;
797
798 wxString nodeName = nodeDetail->m_nodeName + " 1";
799
800 int loop = 2;
801 bool check = false;
802
803 do
804 {
805 check = false;
806
807 if( nodeExists( m_ruleTreeNodeDatas, nodeName ) )
808 {
809 nodeName = nodeDetail->m_nodeName + wxString::Format( " %d", loop );
810 loop++;
811 check = true;
812 }
813 } while( check );
814
816 nodeName.ToStdString(), RULE, nodeDetail->m_nodeId,
817 static_cast<DRC_RULE_EDITOR_CONSTRAINT_NAME>( nodeDetail->m_nodeTypeMap.value_or( 0 ) ), {}, m_nodeId );
818
819 auto nodeType = static_cast<DRC_RULE_EDITOR_CONSTRAINT_NAME>( newRuleNode.m_nodeTypeMap.value_or( -1 ) );
820
821 DRC_RE_BASE_CONSTRAINT_DATA clearanceData( m_nodeId, nodeDetail->m_nodeData->GetId(), newRuleNode.m_nodeName );
822
823 if( s_constraintFactories.find( nodeType ) != s_constraintFactories.end() )
824 {
825 newRuleNode.m_nodeData = s_constraintFactories.at( nodeType )( clearanceData );
826 }
827 else if( DRC_RULE_EDITOR_UTILS::IsNumericInputType( nodeType ) )
828 {
829 newRuleNode.m_nodeData = std::make_shared<DRC_RE_NUMERIC_INPUT_CONSTRAINT_DATA>( clearanceData );
830 }
831 else if( DRC_RULE_EDITOR_UTILS::IsBoolInputType( nodeType ) )
832 {
833 newRuleNode.m_nodeData = std::make_shared<DRC_RE_BOOL_INPUT_CONSTRAINT_DATA>( clearanceData );
834 }
835 else
836 {
837 wxLogWarning( "No factory found for constraint type: %d", nodeType );
838 newRuleNode.m_nodeData = std::make_shared<DRC_RE_BASE_CONSTRAINT_DATA>( clearanceData );
839 }
840
841 std::static_pointer_cast<DRC_RE_BASE_CONSTRAINT_DATA>( newRuleNode.m_nodeData )
842 ->SetConstraintCode( DRC_RULE_EDITOR_UTILS::ConstraintToKicadDrc( nodeType ) );
843 newRuleNode.m_nodeData->SetIsNew( true );
844
845 m_ruleTreeNodeDatas.push_back( newRuleNode );
846
847 return newRuleNode;
848}
849
850
852{
853 auto it = std::find_if( m_ruleTreeNodeDatas.begin(), m_ruleTreeNodeDatas.end(),
854 [aNodeId]( const RULE_TREE_NODE& node )
855 {
856 return node.m_nodeId == aNodeId;
857 } );
858
859 if( it != m_ruleTreeNodeDatas.end() )
860 {
861 return &( *it ); // Return pointer to the found node
862 }
863 else
864 return nullptr;
865}
866
867
869{
870 if( !m_ruleEditorPanel->GetIsValidationSucceeded() )
871 {
872 std::string validationMessage = m_ruleEditorPanel->GetValidationMessage();
873
874 DisplayErrorMessage( this, validationMessage );
875 }
876 else
877 {
878 RULE_TREE_ITEM_DATA* itemData = dynamic_cast<RULE_TREE_ITEM_DATA*>(
879 m_ruleTreeCtrl->GetItemData( GetCurrentlySelectedRuleTreeItemData()->GetTreeItemId() ) );
880
881 if( itemData )
882 {
883 UpdateRuleTypeTreeItemData( itemData );
884 }
885
887
888 SetControlsEnabled( true );
889 }
890}
891
892
894{
895 SetControlsEnabled( true );
896}
897
898
900{
901 (void) aNodeId;
902
903 if( !m_ruleEditorPanel )
904 return -1;
905
906 // Ensure we use the latest text from the condition editor
907 m_ruleEditorPanel->TransferDataFromWindow();
908 wxString condition = m_ruleEditorPanel->GetConstraintData()->GetRuleCondition();
909
910 wxLogTrace( wxS( "KI_TRACE_DRC_RULE_EDITOR" ),
911 wxS( "[ShowMatches] nodeId=%d, condition='%s'" ), aNodeId, condition );
912
913 // Empty condition matches nothing
914 if( condition.IsEmpty() )
915 {
916 m_frame->FocusOnItems( {} );
917 Raise();
918 return 0;
919 }
920
921 // Pre-compile condition to detect syntax errors
922 DRC_RULE_CONDITION testCondition( condition );
923
924 if( !testCondition.Compile( nullptr ) )
925 {
926 wxLogTrace( wxS( "KI_TRACE_DRC_RULE_EDITOR" ), wxS( "[ShowMatches] compile failed" ) );
927 return -1;
928 }
929
930 m_drcTool = m_frame->GetToolManager()->GetTool<DRC_TOOL>();
931
932 std::vector<BOARD_ITEM*> allMatches =
933 m_drcTool->GetDRCEngine()->GetItemsMatchingCondition( condition, ASSERTION_CONSTRAINT, m_reporter );
934
935 // Filter out items without visible geometry
936 std::vector<BOARD_ITEM*> matches;
937
938 for( BOARD_ITEM* item : allMatches )
939 {
940 switch( item->Type() )
941 {
942 case PCB_NETINFO_T:
943 case PCB_GENERATOR_T:
944 case PCB_GROUP_T:
945 continue;
946
947 default:
948 matches.push_back( item );
949 break;
950 }
951 }
952
953 int matchCount = static_cast<int>( matches.size() );
954
955 wxLogTrace( wxS( "KI_TRACE_DRC_RULE_EDITOR" ), wxS( "[ShowMatches] matched_count=%d (filtered from %zu)" ),
956 matchCount, allMatches.size() );
957
958 // Clear any existing selection and select matched items
959 m_frame->GetToolManager()->RunAction( ACTIONS::selectionClear );
960
961 if( matches.size() > 0 )
962 {
963 std::vector<EDA_ITEM*> selectItems;
964
965 for( BOARD_ITEM* item : matches )
966 selectItems.push_back( item );
967
968 m_frame->GetToolManager()->RunAction( ACTIONS::selectItems, &selectItems );
969 m_frame->GetToolManager()->RunAction( ACTIONS::zoomFitSelection );
970 }
971
972 // Also brighten items to provide additional visual feedback
973 m_frame->FocusOnItems( matches );
974 Raise();
975
976 return matchCount;
977}
978
979
980bool DIALOG_DRC_RULE_EDITOR::validateRuleName( int aNodeId, wxString aRuleName )
981{
982 auto it = std::find_if( m_ruleTreeNodeDatas.begin(), m_ruleTreeNodeDatas.end(),
983 [aNodeId, aRuleName]( const RULE_TREE_NODE& node )
984 {
985 return node.m_nodeName == aRuleName && node.m_nodeId != aNodeId
986 && node.m_nodeType == RULE;
987 } );
988
989 if( it != m_ruleTreeNodeDatas.end() )
990 {
991 return false;
992 }
993
994 return true;
995}
996
997
999{
1000 size_t initial_size = m_ruleTreeNodeDatas.size();
1001
1002 m_ruleTreeNodeDatas.erase( std::remove_if( m_ruleTreeNodeDatas.begin(), m_ruleTreeNodeDatas.end(),
1003 [aNodeId]( const RULE_TREE_NODE& node )
1004 {
1005 return node.m_nodeId == aNodeId;
1006 } ),
1007 m_ruleTreeNodeDatas.end() );
1008
1009 if( m_ruleTreeNodeDatas.size() < initial_size )
1010 return true;
1011 else
1012 return false;
1013}
1014
1015
1016void DIALOG_DRC_RULE_EDITOR::collectChildRuleNodes( int aParentId, std::vector<RULE_TREE_NODE*>& aResult )
1017{
1018 std::vector<RULE_TREE_NODE> children;
1019 getRuleTreeChildNodes( m_ruleTreeNodeDatas, aParentId, children );
1020
1021 for( const auto& child : children )
1022 {
1023 RULE_TREE_NODE* childNode = getRuleTreeNodeInfo( child.m_nodeId );
1024
1025 if( childNode->m_nodeType == RULE )
1026 aResult.push_back( childNode );
1027
1028 collectChildRuleNodes( childNode->m_nodeId, aResult );
1029 }
1030}
1031
1032
1034 const std::string& aName, const DRC_RULE_EDITOR_ITEM_TYPE& aNodeType, const std::optional<int>& aParentId,
1035 const std::optional<DRC_RULE_EDITOR_CONSTRAINT_NAME>& aConstraintType,
1036 const std::vector<RULE_TREE_NODE>& aChildNodes, const std::optional<int>& id )
1037{
1038 unsigned int newId;
1039
1040 if( id )
1041 {
1042 newId = *id; // Use provided ID
1043 }
1044 else
1045 {
1046 newId = 1;
1047
1048 if( m_nodeId )
1049 newId = m_nodeId + 1;
1050 }
1051
1052 m_nodeId = newId;
1053
1054 RULE_EDITOR_DATA_BASE baseData;
1055 baseData.SetId( newId );
1056
1057 if( aParentId )
1058 {
1059 baseData.SetParentId( *aParentId );
1060 }
1061
1062 return { .m_nodeId = m_nodeId,
1063 .m_nodeName = aName,
1064 .m_nodeType = aNodeType,
1065 .m_nodeLevel = -1,
1066 .m_nodeTypeMap = aConstraintType,
1067 .m_childNodes = aChildNodes,
1068 .m_nodeData = std::make_shared<RULE_EDITOR_DATA_BASE>( baseData ) };
1069}
1070
1071
1072RULE_TREE_NODE DIALOG_DRC_RULE_EDITOR::buildRuleNodeFromKicadDrc( const wxString& aName, const wxString& aCode,
1073 const std::optional<int>& aParentId )
1074{
1076 RULE_TREE_NODE node =
1077 buildRuleTreeNodeData( aName.ToStdString(), DRC_RULE_EDITOR_ITEM_TYPE::CONSTRAINT, aParentId, typeOpt );
1078
1079 auto baseData = std::dynamic_pointer_cast<DRC_RE_BASE_CONSTRAINT_DATA>( node.m_nodeData );
1080 DRC_RULE_EDITOR_UTILS::ConstraintFromKicadDrc( aCode, baseData.get() );
1081 node.m_nodeData = baseData;
1082 return node;
1083}
1084
1085
1087{
1088 return !m_cancelled;
1089}
1090
1091
1092void DIALOG_DRC_RULE_EDITOR::AdvancePhase( const wxString& aMessage )
1093{
1095 SetCurrentProgress( 0.0 );
1096}
1097
1098
1103
1105{
1106 std::vector<DRC_RE_LOADED_PANEL_ENTRY> entries;
1107
1108 for( const RULE_TREE_NODE& node : m_ruleTreeNodeDatas )
1109 {
1110 if( node.m_nodeType != RULE )
1111 continue;
1112
1113 auto data = std::dynamic_pointer_cast<DRC_RE_BASE_CONSTRAINT_DATA>( node.m_nodeData );
1114
1115 if( !data )
1116 continue;
1117
1119
1120 if( node.m_nodeTypeMap )
1121 entry.panelType = static_cast<DRC_RULE_EDITOR_CONSTRAINT_NAME>( *node.m_nodeTypeMap );
1122 else
1123 entry.panelType = CUSTOM_RULE;
1124
1125 entry.constraintData = data;
1126 entry.ruleName = data->GetRuleName();
1127 entry.condition = data->GetRuleCondition();
1128 entry.originalRuleText = data->GetOriginalRuleText();
1129 entry.wasEdited = data->WasEdited();
1130
1131 entries.push_back( entry );
1132 }
1133
1134 DRC_RULE_SAVER saver;
1135 saver.SaveFile( m_frame->GetDesignRulesPath(), entries, m_currentBoard );
1136}
static TOOL_ACTION zoomFitSelection
Definition actions.h:144
static TOOL_ACTION selectionClear
Clear the current selection.
Definition actions.h:224
static TOOL_ACTION selectItems
Select a list of items (specified as the event parameter)
Definition actions.h:232
A base class for any item which can be embedded within the BOARD container class, and therefore insta...
Definition board_item.h:83
std::vector< RULE_TREE_NODE > m_ruleTreeNodeDatas
PANEL_DRC_GROUP_HEADER * m_groupHeaderPanel
std::vector< RULE_TREE_NODE > buildElectricalRuleTreeNodes(int &aParentId)
std::vector< RULE_TREE_NODE > buildHighspeedDesignRuleTreeNodes(int &aParentId)
void UpdateRuleTypeTreeItemData(RULE_TREE_ITEM_DATA *aCurrentRuleTreeItemData) override
Updates the rule tree item data by transferring data from the rule editor panel and updating the item...
void collectChildRuleNodes(int aParentId, std::vector< RULE_TREE_NODE * > &aResult)
Collects all child rule nodes for a given parent node ID.
int highlightMatchingItems(int aNodeId)
Highlights board items matching the current rule condition.
void saveRule(int aNodeId)
Saves the rule after validating the rule editor panel.
void AddNewRule(RULE_TREE_ITEM_DATA *aRuleTreeItemData) override
Adds a new rule to the rule tree, either as a child or under the parent, based on the node type (CONS...
void RuleTreeItemSelectionChanged(RULE_TREE_ITEM_DATA *aCurrentRuleTreeItemData) override
Handles rule tree item selection changes, updating the content panel with appropriate editor or heade...
RULE_TREE_NODE buildRuleTreeNodeData(const std::string &aName, const DRC_RULE_EDITOR_ITEM_TYPE &aNodeType, const std::optional< int > &aParentId=std::nullopt, const std::optional< DRC_RULE_EDITOR_CONSTRAINT_NAME > &aConstraintType=std::nullopt, const std::vector< RULE_TREE_NODE > &aChildNodes={}, const std::optional< int > &aId=std::nullopt)
Creates a new rule tree node with the specified parameters, generating a new ID if not provided.
RULE_TREE_NODE buildRuleNodeFromKicadDrc(const wxString &aName, const wxString &aCode, const std::optional< int > &aParentId=std::nullopt)
Build a rule tree node from a constraint keyword loaded from a .kicad_drc file.
std::vector< RULE_TREE_NODE > GetDefaultRuleTreeItems() override
Pure virtual method to get the default rule tree items.
std::shared_ptr< RC_ITEMS_PROVIDER > m_markersProvider
std::vector< RULE_TREE_NODE > buildManufacturabilityRuleTreeNodes(int &aParentId)
void RemoveRule(int aNodeId) override
Removes a rule from the rule tree after confirmation, deleting the item and associated data.
void OnCancel(wxCommandEvent &aEvent) override
std::vector< RULE_TREE_NODE > buildFootprintsRuleTreeNodes(int &aParentId)
RULE_TREE_NODE * getRuleTreeNodeInfo(const int &aNodeId)
Retrieves the rule tree node for a given ID.
PANEL_DRC_RULE_EDITOR * m_ruleEditorPanel
RULE_TREE_NODE buildRuleTreeNode(RULE_TREE_ITEM_DATA *aRuleTreeItemData)
Creates a new rule tree node with a unique name and assigns the appropriate constraint data.
bool deleteTreeNodeData(const int &aNodeId)
Deletes a rule tree node by its ID.
bool isEnabled(RULE_TREE_ITEM_DATA *aRuleTreeItemData, RULE_EDITOR_TREE_CONTEXT_OPT aOption) override
Verifies if a context menu option should be enabled based on the rule tree item type.
void closeRuleEntryView(int aNodeId)
Closes the rule entry view and re-enables controls.
void OnSave(wxCommandEvent &aEvent) override
void DuplicateRule(RULE_TREE_ITEM_DATA *aRuleTreeItemData) override
Duplicates a rule from the source tree node and appends it as a new item under the same parent.
bool validateRuleName(int aNodeId, wxString aRuleName)
Validates if the rule name is unique for the given node ID.
bool Compile(REPORTER *aReporter, int aSourceLine=0, int aSourceOffset=0)
static bool IsNumericInputType(const DRC_RULE_EDITOR_CONSTRAINT_NAME &aConstraintType)
static wxString ConstraintToKicadDrc(DRC_RULE_EDITOR_CONSTRAINT_NAME aType)
Convert a constraint type into the keyword used in a .kicad_drc file.
static bool ConstraintFromKicadDrc(const wxString &aCode, DRC_RE_BASE_CONSTRAINT_DATA *aData)
Populate a constraint data object using a keyword from a .kicad_drc file.
static std::optional< DRC_RULE_EDITOR_CONSTRAINT_NAME > GetConstraintTypeFromCode(const wxString &aCode)
Resolve a constraint keyword from a rules file into the corresponding rule tree enumeration value.
static bool IsBoolInputType(const DRC_RULE_EDITOR_CONSTRAINT_NAME &aConstraintType)
Loads DRC rules from .kicad_dru files and converts them to panel entries.
std::vector< DRC_RE_LOADED_PANEL_ENTRY > LoadFile(const wxString &aPath)
Load all rules from a .kicad_dru file.
Saves DRC panel entries back to .kicad_dru files.
bool SaveFile(const wxString &aPath, const std::vector< DRC_RE_LOADED_PANEL_ENTRY > &aEntries, const BOARD *aBoard=nullptr)
Save all panel entries to a file.
PROJECT & Prj() const
Return a reference to the PROJECT associated with this KIWAY.
@ MARKER_DRAWING_SHEET
Definition marker_base.h:56
The main frame for Pcbnew.
virtual void AdvancePhase() override
Use the next available virtual zone of the dialog progress bar.
virtual void SetCurrentProgress(double aProgress) override
Set the progress value to aProgress (0..1).
virtual void AdvancePhase()=0
Use the next available virtual zone of the dialog progress bar.
Concrete class representing the base data structure for a rule editor.
bool IsNew()
Check if the rule is marked as new.
int GetId()
Get the unique ID of the rule.
void SetIsNew(bool aIsNew)
Mark the rule as new or not.
void SetId(int aId)
Set the unique ID of the rule.
void SetParentId(int aParentId)
Set the parent ID of the rule.
void CopyFrom(const ICopyable &aSource) override
Implementation of the polymorphic CopyFrom method.
wxString GetRuleName()
Get the name of the rule.
void DeleteRuleTreeItem(wxTreeItemId aItemId, const int &aNodeId)
Deletes a tree item and removes its corresponding node from history.
void UpdateRuleTreeItemText(wxTreeItemId aItemId, wxString aItemText)
Updates the text of a specified rule tree item.
void AppendNewRuleTreeItem(const RULE_TREE_NODE &aRuleTreeNode, wxTreeItemId aParentTreeItemId)
Adds a new rule tree item under the specified parent and updates the tree history.
void InitRuleTreeItems(const std::vector< RULE_TREE_NODE > &aRuleTreeNodes)
Initializes the rule tree by adding nodes, setting up the structure, and saving its state.
void SetContentPanel(wxPanel *aContentPanel)
Replaces the current content panel with a new one based on the selected constraint type.
RULE_EDITOR_DIALOG_BASE(wxWindow *aParent, const wxString &aTitle, const wxSize &aInitialSize=wxDefaultSize)
void getRuleTreeChildNodes(const std::vector< RULE_TREE_NODE > &aNodes, int aParentId, std::vector< RULE_TREE_NODE > &aResult)
Retrieves child nodes of a given parent node.
RULE_TREE_ITEM_DATA * GetCurrentlySelectedRuleTreeItemData()
Retrieves the currently selected rule tree item data.
void SetControlsEnabled(bool aEnable)
Enables or disables controls within the rule editor dialog.
A class representing additional data associated with a wxTree item.
wxTreeItemId GetTreeItemId() const
wxTreeItemId GetParentTreeItemId() const
int OKOrCancelDialog(wxWindow *aParent, const wxString &aWarning, const wxString &aMessage, const wxString &aDetailedMessage, const wxString &aOKLabel, const wxString &aCancelLabel, bool *aApplyToAll)
Display a warning dialog with aMessage and returns the user response.
Definition confirm.cpp:150
void DisplayErrorMessage(wxWindow *aParent, const wxString &aText, const wxString &aExtraInfo)
Display an error message with aMessage.
Definition confirm.cpp:202
This file is part of the common library.
bool nodeExists(const RULE_TREE_NODE &aRuleTreeNode, const wxString &aTargetName)
Checks if a node with the given name exists in the rule tree or its child nodes.
const RULE_TREE_NODE * FindNodeById(const std::vector< RULE_TREE_NODE > &aNodes, int aTargetId)
SIM_MODEL::PARAM::CATEGORY CATEGORY
@ ASSERTION_CONSTRAINT
Definition drc_rule.h:79
DRC_RULE_EDITOR_CONSTRAINT_NAME
@ MINIMUM_SOLDERMASK_SILVER
@ ALLOWED_ORIENTATION
@ MINIMUM_ITEM_CLEARANCE
@ SILK_TO_SILK_CLEARANCE
@ MINIMUM_TRACK_WIDTH
@ ROUTING_DIFF_PAIR
@ HOLE_TO_HOLE_CLEARANCE
@ SOLDERPASTE_EXPANSION
@ SILK_TO_SOLDERMASK_CLEARANCE
@ MINIMUM_ANGULAR_RING
@ MINIMUM_UVIA_HOLE
@ BOARD_OUTLINE_CLEARANCE
@ COURTYARD_CLEARANCE
@ MINIMUM_CONNECTION_WIDTH
@ SOLDERMASK_EXPANSION
@ MAXIMUM_VIA_COUNT
@ MINIMUM_ANNULAR_WIDTH
@ PHYSICAL_CLEARANCE
@ MINIMUM_THROUGH_HOLE
@ CREEPAGE_DISTANCE
@ ABSOLUTE_LENGTH
@ MINIMUM_CLEARANCE
@ MINIMUM_THERMAL_RELIEF_SPOKE_COUNT
@ BASIC_CLEARANCE
@ PERMITTED_LAYERS
@ MINIMUM_TEXT_HEIGHT_AND_THICKNESS
@ COPPER_TO_HOLE_CLEARANCE
@ MAXIMUM_ALLOWED_DEVIATION
@ MINIMUM_UVIA_DIAMETER
@ HOLE_TO_HOLE_DISTANCE
@ MATCHED_LENGTH_DIFF_PAIR
@ COPPER_TO_EDGE_CLEARANCE
DRC_RULE_EDITOR_ITEM_TYPE
#define _(s)
RULE_EDITOR_TREE_CONTEXT_OPT
Enumeration representing the available context menu options for the rule editor tree.
Represents a rule loaded from a .kicad_dru file and mapped to a panel.
wxString ruleName
wxString originalRuleText
wxString condition
bool wasEdited
std::shared_ptr< DRC_RE_BASE_CONSTRAINT_DATA > constraintData
DRC_RULE_EDITOR_CONSTRAINT_NAME panelType
Structure representing a node in a rule tree, collection of this used for building the rule tree.
std::shared_ptr< RULE_EDITOR_DATA_BASE > m_nodeData
std::optional< int > m_nodeTypeMap
std::vector< RULE_TREE_NODE > m_childNodes
VECTOR3I res
wxString result
Test unit parsing edge cases and error handling.
@ PCB_GENERATOR_T
class PCB_GENERATOR, generator on a layer
Definition typeinfo.h:91
@ PCB_GROUP_T
class PCB_GROUP, a set of BOARD_ITEMs
Definition typeinfo.h:111
@ PCB_NETINFO_T
class NETINFO_ITEM, a description of a net
Definition typeinfo.h:110