KiCad PCB EDA Suite
Loading...
Searching...
No Matches
rule_editor_dialog_base.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
22#include <widgets/wx_infobar.h>
23#include <widgets/wx_panel.h>
24#include <widgets/ui_common.h>
25
26#include <wx/button.h>
27#include <wx/grid.h>
28#include <wx/sizer.h>
29#include <wx/treectrl.h>
30#include <wx/listctrl.h>
31#include <wx/stc/stc.h>
32#include <wx/menu.h>
33#include <wx/log.h>
34#include <wx/wx.h>
35#include <wx/dnd.h>
36#include <wx/dcclient.h> // Include for wxClientDC if needed
37#include <wx/dcbuffer.h> // Include for double-buffered drawing
38#include <wx/bitmap.h>
39
40#include <confirm.h>
41#include <paths.h>
42#include <bitmaps.h>
43#include <launch_ext.h>
44#include <algorithm>
47
48
49static wxSearchCtrl* CreateTextFilterBox( wxWindow* aParent, const wxString& aDescriptiveText )
50{
51 wxSearchCtrl* search_widget = new wxSearchCtrl( aParent, wxID_ANY );
52
53 search_widget->ShowSearchButton( false );
54 search_widget->ShowCancelButton( true );
55
56 search_widget->SetDescriptiveText( aDescriptiveText );
57
58#ifdef __WXGTK__
59 // wxSearchCtrl vertical height is not calculated correctly on some GTK setups
60 // See https://gitlab.com/kicad/code/kicad/-/issues/9019
61 search_widget->SetMinSize( wxSize( -1, aParent->GetTextExtent( wxT( "qb" ) ).y + 10 ) );
62#endif
63
64 return search_widget;
65}
66
67
68RULE_EDITOR_DIALOG_BASE::RULE_EDITOR_DIALOG_BASE( wxWindow* aParent, const wxString& aTitle,
69 const wxSize& aInitialSize ) :
70 DIALOG_SHIM( aParent, wxID_ANY, aTitle, wxDefaultPosition, aInitialSize,
71 wxDEFAULT_DIALOG_STYLE | wxRESIZE_BORDER ),
72 m_isDragging( false ),
73 m_enableMoveUp( false ),
74 m_enableMoveDown( false ),
75 m_enableAddRule( false ),
76 m_enableDuplicateRule( false ),
77 m_enableDeleteRule( false ),
78 m_modified( false ),
81 m_title( aTitle ),
82 m_selectedData( nullptr ),
83 m_previousId( nullptr ),
84 m_draggedItem( nullptr )
85{
86 wxBoxSizer* mainSizer = new wxBoxSizer( wxVERTICAL );
87 SetSizer( mainSizer );
88
89 wxBoxSizer* infoBarSizer = new wxBoxSizer( wxHORIZONTAL );
90
91 m_infoBar = new WX_INFOBAR( this );
92 infoBarSizer->Add( m_infoBar, 0, wxEXPAND, 0 );
93
94 // Add the tree panel to the content sizer
95 m_splitter = new wxSplitterWindow( this, wxID_ANY, wxDefaultPosition, wxDefaultSize,
96 wxBORDER_NONE | wxSP_LIVE_UPDATE | wxSP_3DSASH );
97 m_splitter->SetMinimumPaneSize( 50 ); // Set a minimum pane size
98
99 // Create the tree control panel
100 WX_PANEL* treeCtrlPanel = new WX_PANEL( m_splitter, wxID_ANY, wxDefaultPosition, wxDefaultSize,
101 wxBORDER_NONE | wxTAB_TRAVERSAL );
102 treeCtrlPanel->SetBorders( false, false, false, true );
103 wxBoxSizer* treeCtrlSizer = new wxBoxSizer( wxVERTICAL );
104 treeCtrlPanel->SetSizer( treeCtrlSizer );
105
106 // Add a search text box above the tree control
107 m_filterSearch = CreateTextFilterBox( treeCtrlPanel, _( "Type filter text" ) );
108 treeCtrlSizer->Add( m_filterSearch, 0, wxEXPAND, 5 );
109
110 // Create the tree control and set its font
111 m_ruleTreeCtrl = new wxTreeCtrl( treeCtrlPanel, wxID_ANY, wxDefaultPosition, wxDefaultSize,
112 wxTR_DEFAULT_STYLE | wxTR_HIDE_ROOT | wxTR_HAS_BUTTONS | wxBORDER_NONE );
113 m_ruleTreeCtrl->SetFont( KIUI::GetControlFont( this ) );
114
115 // Add the tree control to its sizer
116 treeCtrlSizer->Add( m_ruleTreeCtrl, 1, wxEXPAND | wxBOTTOM, 3 );
117
118 // Create a sizer for the action buttons
119 wxBoxSizer* actionButtonsSizer = new wxBoxSizer( wxHORIZONTAL );
120
121 // Create the action buttons
122 m_addRuleButton = new STD_BITMAP_BUTTON( treeCtrlPanel, wxID_ANY, wxNullBitmap, wxDefaultPosition,
123 wxDefaultSize, wxBU_AUTODRAW );
124 m_copyRuleButton = new STD_BITMAP_BUTTON( treeCtrlPanel, wxID_ANY, wxNullBitmap, wxDefaultPosition,
125 wxDefaultSize, wxBU_AUTODRAW );
126 m_moveTreeItemUpButton = new STD_BITMAP_BUTTON( treeCtrlPanel, wxID_ANY, wxNullBitmap, wxDefaultPosition,
127 wxDefaultSize, wxBU_AUTODRAW );
128 m_moveTreeItemDownButton = new STD_BITMAP_BUTTON( treeCtrlPanel, wxID_ANY, wxNullBitmap, wxDefaultPosition,
129 wxDefaultSize, wxBU_AUTODRAW );
130 m_deleteRuleButton = new STD_BITMAP_BUTTON( treeCtrlPanel, wxID_ANY, wxNullBitmap, wxDefaultPosition,
131 wxDefaultSize, wxBU_AUTODRAW );
132
133 actionButtonsSizer->Add( m_addRuleButton, 0, wxLEFT, 5 );
134 actionButtonsSizer->Add( m_copyRuleButton, 0, wxLEFT, 5 );
135 actionButtonsSizer->Add( m_moveTreeItemUpButton, 0, wxLEFT, 5 );
136 actionButtonsSizer->Add( m_moveTreeItemDownButton, 0, wxLEFT, 5 );
137
138 // Add a spacer between the "Move" buttons and the "Delete" button
139 actionButtonsSizer->AddSpacer( 20 ); // Spacer between the Move and Delete buttons
140
141 // Add the "Delete" button at the end
142 actionButtonsSizer->Add( m_deleteRuleButton, 0, wxRIGHT, 5 );
143
144 // Add the action buttons sizer to the tree control sizer
145 treeCtrlSizer->Add( actionButtonsSizer, 0, wxBOTTOM | wxEXPAND, 5 );
146
147 treeCtrlPanel->Layout();
148
154
155 // Create a scrolled window for the dynamic content panel
156 m_scrolledContentWin = new wxScrolledWindow( m_splitter, wxID_ANY, wxDefaultPosition, wxDefaultSize,
157 wxVSCROLL | wxBORDER_NONE );
158 m_scrolledContentWin->SetScrollRate( 0, 10 );
159 m_scrolledContentWin->SetBackgroundColour( wxSystemSettings::GetColour( wxSYS_COLOUR_FRAMEBK ) );
160 m_contentPanel = nullptr;
161
162 // Add the tree control panel to the splitter.
163 // Calculate the minimum tree panel width based on the tree control's best size.
164 treeCtrlPanel->Layout();
165 int minTreeWidth = treeCtrlPanel->GetBestSize().GetWidth();
166
167 // Ensure a reasonable minimum width for the tree panel
168 if( minTreeWidth < 240 )
169 minTreeWidth = 240;
170
171 m_defaultSashPosition = minTreeWidth;
172
173 m_splitter->SplitVertically( treeCtrlPanel, m_scrolledContentWin, m_defaultSashPosition );
174
175 // Set gravity to 0 so the tree panel maintains its size and the content panel resizes
176 m_splitter->SetSashGravity( 0.0 );
177
178 wxBoxSizer* m_sizerButtons = new wxBoxSizer( wxHORIZONTAL );
179
180 wxStdDialogButtonSizer* m_sdbSizer = new wxStdDialogButtonSizer();
181 m_cancelRuleButton = new wxButton( this, wxID_CANCEL );
182 m_cancelRuleButton->SetLabelText( _( "Close" ) );
183 m_sdbSizer->AddButton( m_cancelRuleButton );
184 m_saveRuleButton = new wxButton( this, wxID_OK );
185 m_saveRuleButton->SetLabelText( _( "Save" ) );
186 m_sdbSizer->AddButton( m_saveRuleButton );
187 m_sdbSizer->Realize();
188
189 m_sizerButtons->Add( m_sdbSizer, 1, wxEXPAND, 5 );
190
191
192 // Add the info bar sizer to the main sizer
193 mainSizer->Add( infoBarSizer, 0, wxEXPAND, 0 );
194 mainSizer->Add( m_splitter, 1, wxEXPAND | wxBOTTOM, 5 );
195 mainSizer->Add( m_sizerButtons, 0, wxALL | wxEXPAND, 5 );
196
197 if( aInitialSize != wxDefaultSize )
198 SetSize( aInitialSize );
199
200 Layout();
201
202 // Bind the context menu event
203 m_filterSearch->Bind( wxEVT_COMMAND_TEXT_UPDATED, &RULE_EDITOR_DIALOG_BASE::onFilterSearch, this );
204 m_ruleTreeCtrl->Bind( wxEVT_TREE_ITEM_RIGHT_CLICK, &RULE_EDITOR_DIALOG_BASE::onRuleTreeItemRightClick, this );
205 m_ruleTreeCtrl->Bind( wxEVT_TREE_SEL_CHANGED, &RULE_EDITOR_DIALOG_BASE::onRuleTreeItemSelectionChanged, this );
206 m_ruleTreeCtrl->Bind( wxEVT_TREE_ITEM_ACTIVATED, &RULE_EDITOR_DIALOG_BASE::onRuleTreeItemActivated, this );
210
216 m_saveRuleButton->Bind( wxEVT_BUTTON, &RULE_EDITOR_DIALOG_BASE::OnSave, this );
217 m_cancelRuleButton->Bind( wxEVT_BUTTON, &RULE_EDITOR_DIALOG_BASE::OnCancel, this );
218
219 // Initially disable Save button until modifications are made
220 m_saveRuleButton->Enable( false );
221
222 this->Bind( wxEVT_SIZE, &RULE_EDITOR_DIALOG_BASE::onResize, this );
223
224 this->Bind( wxEVT_CLOSE_WINDOW, &RULE_EDITOR_DIALOG_BASE::onClose, this );
225
226 m_scrolledContentWin->Bind( wxEVT_SIZE,
227 [this]( wxSizeEvent& evt )
228 {
230 evt.Skip();
231 } );
232}
233
234
236{
238
239 // finishDialogSettings() calls GetSizer()->SetSizeHints() which inflates the dialog
240 // to the full unconstrained best size of the scrolled content area. Reset to the
241 // caller's initial size and a reasonable minimum so Show() doesn't inherit the
242 // inflated values.
243 SetMinSize( wxSize( 400, 500 ) );
244 SetSize( m_initialSize );
245
246 wxLogTrace( "debug_dlg_size", "finishInitialization: size=%dx%d minSize=%dx%d bestSize=%dx%d",
247 GetSize().x, GetSize().y, GetMinSize().x, GetMinSize().y, GetBestSize().x,
248 GetBestSize().y );
249}
250
251
253{
254 bool ret = DIALOG_SHIM::Show( show );
255
256 if( show )
257 {
258 // DIALOG_SHIM::Show() sets SetMinSize(GetBestSize()) which includes the unconstrained
259 // height of the scrolled content area. Cap the minimum to a usable value so the user
260 // can resize the dialog smaller.
261 wxSize minSize = GetMinSize();
262
263 if( minSize.GetHeight() > 500 )
264 SetMinSize( wxSize( minSize.GetWidth(), 500 ) );
265
266 wxLogTrace( "debug_dlg_size", "Show: size=%dx%d minSize=%dx%d",
267 GetSize().x, GetSize().y, GetMinSize().x, GetMinSize().y );
268 }
269
270 return ret;
271}
272
273
275{
276 m_filterSearch->Unbind( wxEVT_COMMAND_TEXT_UPDATED, &RULE_EDITOR_DIALOG_BASE::onFilterSearch, this );
277 m_ruleTreeCtrl->Unbind( wxEVT_TREE_ITEM_RIGHT_CLICK, &RULE_EDITOR_DIALOG_BASE::onRuleTreeItemRightClick, this );
278 m_ruleTreeCtrl->Unbind( wxEVT_TREE_SEL_CHANGED, &RULE_EDITOR_DIALOG_BASE::onRuleTreeItemSelectionChanged, this );
279 m_ruleTreeCtrl->Unbind( wxEVT_TREE_ITEM_ACTIVATED, &RULE_EDITOR_DIALOG_BASE::onRuleTreeItemActivated, this );
280 m_ruleTreeCtrl->Unbind( wxEVT_LEFT_DOWN, &RULE_EDITOR_DIALOG_BASE::onRuleTreeItemLeftDown, this );
282 m_ruleTreeCtrl->Unbind( wxEVT_LEFT_UP, &RULE_EDITOR_DIALOG_BASE::onRuleTreeItemLeftUp, this );
283
289 m_saveRuleButton->Unbind( wxEVT_BUTTON, &RULE_EDITOR_DIALOG_BASE::OnSave, this );
290 m_cancelRuleButton->Unbind( wxEVT_BUTTON, &RULE_EDITOR_DIALOG_BASE::OnCancel, this );
291
292 this->Unbind( wxEVT_SIZE, &RULE_EDITOR_DIALOG_BASE::onResize, this );
293 this->Unbind( wxEVT_CLOSE_WINDOW, &RULE_EDITOR_DIALOG_BASE::onClose, this );
294
295 m_selectedData = nullptr;
296 m_previousId = nullptr;
297}
298
299
301{
303
304 // Call TransferDataToWindow() only once:
305 // this is enough on wxWidgets 3.1
306 if( !DIALOG_SHIM::TransferDataToWindow() )
307 return false;
308
309 return true;
310}
311
312
314{
315 bool ret = true;
316
317 // Call TransferDataFromWindow() only once:
318 // this is enough on wxWidgets 3.1
319 if( !DIALOG_SHIM::TransferDataFromWindow() )
320 ret = false;
321
322 return ret;
323}
324
325
327{
328 if( aEvt.GetKeyCode() == 'S' && aEvt.ControlDown() && !aEvt.ShiftDown() && !aEvt.AltDown() )
329 {
330 wxCommandEvent evt;
331 OnSave( evt );
332 return;
333 }
334
336}
337
338
340{
341 while( aParent )
342 {
343 if( RULE_EDITOR_DIALOG_BASE* currentDialog = dynamic_cast<RULE_EDITOR_DIALOG_BASE*>( aParent ) )
344 return currentDialog;
345
346 aParent = aParent->GetParent();
347 }
348
349 return nullptr;
350}
351
352
353void RULE_EDITOR_DIALOG_BASE::InitRuleTreeItems( const std::vector<RULE_TREE_NODE>& aNodes )
354{
355 if( aNodes.empty() )
356 return;
357
358 m_defaultTreeItems = aNodes;
359
360 m_ruleTreeCtrl->Freeze();
362
363 wxTreeItemId rootId = m_ruleTreeCtrl->AddRoot( aNodes[0].m_nodeName );
364
365 RULE_TREE_ITEM_DATA* itemData = new RULE_TREE_ITEM_DATA( aNodes[0].m_nodeId, nullptr, rootId );
366 m_ruleTreeCtrl->SetItemData( rootId, itemData );
367
368 std::vector<RULE_TREE_NODE> childNodes;
369 getRuleTreeChildNodes( aNodes, aNodes[0].m_nodeId, childNodes );
370
371 for( const auto& child : childNodes )
372 {
373 populateRuleTreeCtrl( aNodes, child, rootId );
374 }
375
376 m_treeHistoryData.clear();
377 saveRuleTreeState( m_ruleTreeCtrl->GetRootItem(), m_defaultTreeItems[0].m_nodeId );
378
379 m_ruleTreeCtrl->CollapseAll();
380
382 m_ruleTreeCtrl->Thaw();
383
384 m_ruleTreeCtrl->SelectItem( m_ruleTreeCtrl->GetFirstVisibleItem() );
385}
386
387
388void RULE_EDITOR_DIALOG_BASE::SetContentPanel( wxPanel* aContentPanel )
389{
390 m_scrolledContentWin->Freeze();
391
392 if( m_contentPanel )
393 {
395 m_contentPanel->Destroy();
396 m_contentPanel = nullptr;
397 }
398
399 m_contentPanel = aContentPanel;
400 m_scrolledContentWin->SetBackgroundColour( m_contentPanel->GetBackgroundColour() );
401
403
404 Layout();
405 m_scrolledContentWin->Thaw();
406
407 CallAfter(
408 [this]()
409 {
411 } );
412}
413
414
416{
418 return;
419
420 m_contentPanel->Layout();
421
422 wxSize clientSize = m_scrolledContentWin->GetClientSize();
423 wxSize bestSize = m_contentPanel->GetBestSize();
424 int width = clientSize.GetWidth();
425 int height = std::max( clientSize.GetHeight(), bestSize.GetHeight() );
426
427 m_contentPanel->SetSize( width, height );
428 m_scrolledContentWin->SetVirtualSize( width, height );
429 m_scrolledContentWin->Refresh();
430}
431
432
434 wxTreeItemId aParent )
435{
436 wxTreeItemId currentTreeItemId = appendRuleTreeItem( aNode, aParent );
437
438 auto it = m_treeHistoryData.find( aNode.m_nodeData->GetParentId() );
439
440 if( it != m_treeHistoryData.end() )
441 {
442 std::vector<int>& existingChildren = std::get<1>( it->second );
443 existingChildren.push_back( aNode.m_nodeId );
444
445 m_treeHistoryData[aNode.m_nodeId] = { aNode.m_nodeName, {}, currentTreeItemId };
446 }
447
449 m_ruleTreeCtrl->SelectItem( currentTreeItemId );
450}
451
452
453void RULE_EDITOR_DIALOG_BASE::UpdateRuleTreeItemText( wxTreeItemId aItemId, wxString aItemText )
454{
455 m_ruleTreeCtrl->SetItemText( aItemId, aItemText );
456}
457
458
460{
461 m_ruleTreeCtrl->Enable( aEnable );
462 m_filterSearch->Enable( aEnable );
463
465
467 {
468 if( !aEnable )
469 {
470 m_cancelRuleButton->SetLabelText( _( "Cancel" ) );
471 }
472 else if( m_modified )
473 {
474 m_cancelRuleButton->SetLabelText( _( "Discard" ) );
475 }
476 else
477 {
478 m_cancelRuleButton->SetLabelText( _( "Close" ) );
479 }
480 }
481}
482
483
485{
486 m_modified = true;
487
488 if( m_saveRuleButton )
489 m_saveRuleButton->Enable( true );
490
491 if( m_cancelRuleButton && m_ruleTreeCtrl->IsEnabled() )
492 m_cancelRuleButton->SetLabelText( _( "Discard" ) );
493
494 if( m_selectedData )
495 {
496 wxTreeItemId itemId = m_selectedData->GetTreeItemId();
497 if( itemId.IsOk() )
498 {
499 wxString currentText = m_ruleTreeCtrl->GetItemText( itemId );
500
501 if( !currentText.EndsWith( wxS( " *" ) ) )
502 {
503 m_ruleTreeCtrl->SetItemText( itemId, currentText + wxS( " *" ) );
504 }
505 }
506 }
507}
508
509
511{
512 m_modified = false;
513
514 if( m_saveRuleButton )
515 m_saveRuleButton->Enable( false );
516
517 if( m_cancelRuleButton && m_ruleTreeCtrl->IsEnabled() )
518 m_cancelRuleButton->SetLabelText( _( "Close" ) );
519}
520
521
522void RULE_EDITOR_DIALOG_BASE::DeleteRuleTreeItem( wxTreeItemId aItemId, const int& aNodeId )
523{
524 if( m_selectedData && m_selectedData->GetNodeId() == aNodeId )
525 m_selectedData = nullptr;
526
527 m_ruleTreeCtrl->Delete( aItemId );
528 m_treeHistoryData.erase( aNodeId );
529}
530
531
532void RULE_EDITOR_DIALOG_BASE::populateRuleTreeCtrl( const std::vector<RULE_TREE_NODE>& aNodes,
533 const RULE_TREE_NODE& aNode, wxTreeItemId aParent )
534{
535 wxTreeItemId currentId = appendRuleTreeItem( aNode, aParent );
536
537 std::vector<RULE_TREE_NODE> childNodes;
538 getRuleTreeChildNodes( aNodes, aNode.m_nodeId, childNodes );
539
540 for( const auto& child : childNodes )
541 {
542 populateRuleTreeCtrl( aNodes, child, currentId );
543 }
544
545 m_ruleTreeCtrl->Expand( currentId );
546}
547
548
550{
551 wxTreeItemId item = aEvent.GetItem();
552
553 if( !item.IsOk() )
554 return;
555
556 m_ruleTreeCtrl->SelectItem( item );
557
558 RULE_TREE_ITEM_DATA* ruleTreeItemData = dynamic_cast<RULE_TREE_ITEM_DATA*>( m_ruleTreeCtrl->GetItemData( item ) );
559
560 if( !ruleTreeItemData )
561 return;
562
563 updateRuleTreeActionButtonsState( ruleTreeItemData );
564
565 wxMenu menu;
566
567 if( m_enableAddRule )
568 KIUI::AddMenuItem( &menu, ID_NEWRULE, _( "New Rule" ), KiBitmap( BITMAPS::small_plus ) );
569
570 if( m_enableAddRule )
571 KIUI::AddMenuItem( &menu, ID_COPYRULE, _( "Copy Rule" ), KiBitmap( BITMAPS::copy ) );
572
574 KIUI::AddMenuItem( &menu, ID_DELETERULE, _( "Delete Rule" ), KiBitmap( BITMAPS::small_trash ) );
575
577 KIUI::AddMenuItem( &menu, ID_MOVEUP, _( "Move Up" ), KiBitmap( BITMAPS::small_up ) );
578
580 KIUI::AddMenuItem( &menu, ID_MOVEDOWN, _( "Move Down" ), KiBitmap( BITMAPS::small_down ) );
581
582 menu.Bind( wxEVT_COMMAND_MENU_SELECTED,
583 [&]( wxCommandEvent& aCmd )
584 {
585 switch( aCmd.GetId() )
586 {
587 case ID_NEWRULE: onNewRuleOptionClick( aCmd ); break;
588
589 case ID_COPYRULE: onDuplicateRuleOptionClick( aCmd ); break;
590
591 case ID_DELETERULE: onDeleteRuleOptionClick( aCmd ); break;
592
593 case ID_MOVEUP: onMoveUpRuleOptionClick( aCmd ); break;
594
595 case ID_MOVEDOWN: onMoveDownRuleOptionClick( aCmd ); break;
596 default: aCmd.Skip();
597 }
598 } );
599
600 PopupMenu( &menu );
601}
602
603
605{
607 return;
608
609 wxTreeItemId selectedItem = aEvent.GetItem();
610
611 RULE_TREE_ITEM_DATA* selectedItemData =
612 dynamic_cast<RULE_TREE_ITEM_DATA*>( m_ruleTreeCtrl->GetItemData( selectedItem ) );
613
614 if( !selectedItemData )
615 return;
616
617 if( m_selectedData )
618 {
619 if( m_selectedData->GetNodeId() == selectedItemData->GetNodeId() )
620 {
621 m_selectedData = selectedItemData;
622 updateRuleTreeActionButtonsState( selectedItemData );
623 return;
624 }
625
626 m_previousId = m_selectedData->GetTreeItemId();
627 }
628
629 m_selectedData = selectedItemData;
630
632
633 updateRuleTreeActionButtonsState( selectedItemData );
634}
635
637{
638 RULE_TREE_ITEM_DATA* itemData =
639 dynamic_cast<RULE_TREE_ITEM_DATA*>( m_ruleTreeCtrl->GetItemData( aEvent.GetItem() ) );
640
641 if( itemData &&
643 {
644 DuplicateRule( itemData );
645 }
646 else if( itemData &&
648 {
649 AddNewRule( itemData );
650 }
651}
652
653
655{
657}
658
659
664
665
667{
668 RemoveRule( m_selectedData->GetNodeId() );
669}
670
671
673{
674 if( !m_enableMoveUp )
675 return;
676
677 wxTreeItemId selectedItem = m_ruleTreeCtrl->GetSelection();
678
679 if( !selectedItem.IsOk() )
680 return;
681
682 wxTreeItemId parent = m_ruleTreeCtrl->GetItemParent( selectedItem );
683
684 if( !parent.IsOk() )
685 return;
686
687 wxTreeItemIdValue cookie;
688 wxTreeItemId current = m_ruleTreeCtrl->GetFirstChild( parent, cookie );
689 wxTreeItemId previous;
690 wxTreeItemId beforePrevious;
691
692 while( current.IsOk() && current != selectedItem )
693 {
694 beforePrevious = previous;
695 previous = current;
696 current = m_ruleTreeCtrl->GetNextChild( parent, cookie );
697 }
698
699 if( !previous.IsOk() )
700 {
701 return;
702 }
703
704 wxTreeItemId insertPosition = beforePrevious.IsOk() ? beforePrevious : wxTreeItemId();
705
706 wxTreeItemId newItem = m_ruleTreeCtrl->InsertItem( parent, insertPosition,
707 m_ruleTreeCtrl->GetItemText( selectedItem ) );
708
709 moveRuleTreeItemChildrensTooOnDrag( selectedItem, newItem );
710
711 wxTreeItemData* itemData = m_ruleTreeCtrl->GetItemData( selectedItem );
712
713 if( itemData )
714 {
715 RULE_TREE_ITEM_DATA* ruleTreeItemData = dynamic_cast<RULE_TREE_ITEM_DATA*>( itemData );
716 ruleTreeItemData->SetTreeItemId( newItem );
717
718 m_ruleTreeCtrl->SetItemData( newItem, itemData );
719 m_ruleTreeCtrl->SetItemData( selectedItem, nullptr ); // Detach data from the old item
720
721 saveRuleTreeState( newItem, ruleTreeItemData->GetNodeId() );
722
723 m_ruleTreeCtrl->SelectItem( newItem );
724
725 m_ruleTreeCtrl->Expand( newItem );
726 m_ruleTreeCtrl->ExpandAllChildren( newItem );
727 }
728
729 m_ruleTreeCtrl->DeleteChildren( selectedItem );
730 m_ruleTreeCtrl->Delete( selectedItem );
731}
732
733
735{
736 if( !m_enableMoveDown )
737 return;
738
739 wxTreeItemId selectedItem = m_ruleTreeCtrl->GetSelection();
740
741 if( !selectedItem.IsOk() )
742 return;
743
744 wxTreeItemId parent = m_ruleTreeCtrl->GetItemParent( selectedItem );
745 wxTreeItemIdValue cookie;
746 wxTreeItemId current = m_ruleTreeCtrl->GetFirstChild( parent, cookie );
747
748 while( current.IsOk() && current != selectedItem )
749 {
750 current = m_ruleTreeCtrl->GetNextChild( parent, cookie );
751 }
752
753 wxTreeItemId next = m_ruleTreeCtrl->GetNextChild( parent, cookie );
754
755 if( !next.IsOk() )
756 {
757 return;
758 }
759
760 wxString itemText = m_ruleTreeCtrl->GetItemText( selectedItem );
761 wxTreeItemData* itemData = m_ruleTreeCtrl->GetItemData( selectedItem );
762
763 wxTreeItemId newItem = m_ruleTreeCtrl->InsertItem( parent, next, itemText );
764
765 moveRuleTreeItemChildrensTooOnDrag( selectedItem, newItem );
766
767 if( itemData )
768 {
769 RULE_TREE_ITEM_DATA* ruleTreeItemData = dynamic_cast<RULE_TREE_ITEM_DATA*>( itemData );
770 ruleTreeItemData->SetTreeItemId( newItem );
771
772 m_ruleTreeCtrl->SetItemData( newItem, itemData );
773 m_ruleTreeCtrl->SetItemData( selectedItem, nullptr ); // Detach data
774
775 saveRuleTreeState( newItem, ruleTreeItemData->GetNodeId() );
776
777 m_ruleTreeCtrl->SelectItem( newItem );
778
779 m_ruleTreeCtrl->Expand( newItem );
780 }
781
782 m_ruleTreeCtrl->DeleteChildren( selectedItem );
783 m_ruleTreeCtrl->Delete( selectedItem );
784}
785
786
788{
789 wxPoint pt = aEvent.GetPosition();
790 int flags;
791 wxTreeItemId item = m_ruleTreeCtrl->HitTest( pt, flags );
792
793 // Check if click is on the expand/collapse button
794 if( flags & wxTREE_HITTEST_ONITEMBUTTON )
795 {
796 // Prevent wxEVT_LEFT_DOWN from propagating further
797 aEvent.Skip();
798 return;
799 }
800
801 if( item.IsOk() )
802 {
803 m_draggedItem = item;
804 m_isDragging = false;
805 }
806
807 aEvent.Skip();
808}
809
810
812{
813 if( aEvent.Dragging() && m_draggedItem.IsOk() )
814 {
815 m_isDragging = true;
816
817 // Clear previous highlight
818 if( m_dropTargetItem.IsOk() )
819 {
820 m_ruleTreeCtrl->SetItemBackgroundColour( m_dropTargetItem, wxNullColour );
821 m_dropTargetItem = wxTreeItemId();
822 }
823
824 // Highlight item under cursor
825 int flags;
826 wxTreeItemId hitItem = m_ruleTreeCtrl->HitTest( aEvent.GetPosition(), flags );
827
828 if( hitItem.IsOk() && hitItem != m_draggedItem )
829 {
830 wxTreeItemId hitParent = m_ruleTreeCtrl->GetItemParent( hitItem );
831 wxTreeItemId dragParent = m_ruleTreeCtrl->GetItemParent( m_draggedItem );
832
833 if( hitParent == dragParent )
834 {
835 m_ruleTreeCtrl->SetItemBackgroundColour( hitItem,
836 wxSystemSettings::GetColour( wxSYS_COLOUR_HIGHLIGHT ) );
837 m_dropTargetItem = hitItem;
838 }
839 }
840 }
841
842 aEvent.Skip();
843}
844
846{
847 if( m_draggedItem.IsOk() && m_isDragging )
848 {
849 m_isDragging = false;
850
851 if( m_dropTargetItem.IsOk() )
852 {
853 m_ruleTreeCtrl->SetItemBackgroundColour( m_dropTargetItem, wxNullColour );
854 m_dropTargetItem = wxTreeItemId();
855 }
856
857 wxPoint pos = aEvent.GetPosition();
858 int flags;
859 wxTreeItemId targetItem = m_ruleTreeCtrl->HitTest( pos, flags );
860
861 if( !targetItem.IsOk() )
862 return;
863
864 wxTreeItemId draggedParent = m_ruleTreeCtrl->GetItemParent( m_draggedItem );
865 wxTreeItemId targetParent = m_ruleTreeCtrl->GetItemParent( targetItem );
866
867 if( draggedParent != targetParent )
868 return;
869
870 if( draggedParent == targetParent )
871 {
872 wxTreeItemId newItem;
873 wxTreeItemIdValue cookie;
874
875 if( flags & wxTREE_HITTEST_ONITEMLABEL
876 && targetItem == m_ruleTreeCtrl->GetFirstChild( targetParent, cookie ) )
877 {
878 // Prepend item as the first child of target parent
879 newItem = m_ruleTreeCtrl->PrependItem( targetParent,
880 m_ruleTreeCtrl->GetItemText( m_draggedItem ) );
881 }
882 else
883 {
884 wxTreeItemId current = m_ruleTreeCtrl->GetFirstChild( targetParent, cookie );
885 wxTreeItemId previous;
886
887 // Traverse through siblings to find the position of the target item
888 while( current.IsOk() && current != targetItem )
889 {
890 previous = current;
891 current = m_ruleTreeCtrl->GetNextChild( targetParent, cookie );
892 }
893
894 if( !previous.IsOk() )
895 {
896 // If no previous item, insert as the first child
897 newItem = m_ruleTreeCtrl->PrependItem( targetParent,
898 m_ruleTreeCtrl->GetItemText( m_draggedItem ) );
899 }
900 else
901 {
902 wxTreeItemId nextSibling = m_ruleTreeCtrl->GetNextChild( targetParent, cookie );
903
904 if( nextSibling.IsOk() )
905 {
906 // If there is a next sibling, insert after the previous item
907 newItem = m_ruleTreeCtrl->InsertItem( targetParent, previous,
908 m_ruleTreeCtrl->GetItemText( m_draggedItem ) );
909 }
910 else
911 {
912 // If no next sibling, append the item as the last child
913 newItem = m_ruleTreeCtrl->AppendItem( targetParent,
914 m_ruleTreeCtrl->GetItemText( m_draggedItem ) );
915 }
916 }
917 }
918
920
921 wxTreeItemData* itemData = m_ruleTreeCtrl->GetItemData( m_draggedItem );
922
923 if( itemData )
924 {
925 RULE_TREE_ITEM_DATA* ruleTreeItemData =
926 dynamic_cast<RULE_TREE_ITEM_DATA*>( itemData );
927 ruleTreeItemData->SetTreeItemId( newItem );
928
929 m_ruleTreeCtrl->SetItemData( newItem, ruleTreeItemData );
930 m_ruleTreeCtrl->SetItemData( m_draggedItem, nullptr );
931
932 saveRuleTreeState( newItem, ruleTreeItemData->GetNodeId() );
933
934 m_ruleTreeCtrl->SelectItem( newItem );
935
936 m_ruleTreeCtrl->Expand( newItem );
937 }
938
939 m_ruleTreeCtrl->DeleteChildren( m_draggedItem );
940 m_ruleTreeCtrl->Delete( m_draggedItem );
941 }
942
943 m_draggedItem = nullptr;
944 }
945
946 aEvent.Skip();
947}
948
949
950void RULE_EDITOR_DIALOG_BASE::onFilterSearch( wxCommandEvent& aEvent )
951{
952 const auto searchStr = aEvent.GetString().Lower();
953
954 m_ruleTreeCtrl->Freeze();
956
957 m_ruleTreeCtrl->DeleteAllItems();
958
959 restoreRuleTree( nullptr, m_defaultTreeItems[0].m_nodeId );
960
961 wxTreeItemId root = m_ruleTreeCtrl->GetRootItem();
962
963 if( root.IsOk() )
964 {
965 filterRuleTree( root, searchStr );
966 }
967
969 m_ruleTreeCtrl->Thaw();
970}
971
972
973bool RULE_EDITOR_DIALOG_BASE::filterRuleTree( const wxTreeItemId& aItem, const wxString& aFilter )
974{
975 bool matches = m_ruleTreeCtrl->GetItemText( aItem ).Lower().Contains( aFilter );
976
977 wxTreeItemIdValue cookie;
978 wxTreeItemId child = m_ruleTreeCtrl->GetFirstChild( aItem, cookie );
979 bool hasVisibleChildren = false;
980
981 std::vector<wxTreeItemId> itemsToDelete;
982
983 while( child.IsOk() )
984 {
985 if( filterRuleTree( child, aFilter ) )
986 {
987 hasVisibleChildren = true;
988 }
989 else
990 {
991 itemsToDelete.push_back( child );
992 }
993
994 child = m_ruleTreeCtrl->GetNextChild( aItem, cookie );
995 }
996
997 for( const auto& id : itemsToDelete )
998 {
999 m_ruleTreeCtrl->Delete( id );
1000 }
1001
1002 return matches || hasVisibleChildren;
1003}
1004
1005
1006void RULE_EDITOR_DIALOG_BASE::saveRuleTreeState( const wxTreeItemId& aItem, const int& aNodeId )
1007{
1008 wxString itemText = m_ruleTreeCtrl->GetItemText( aItem );
1009 std::vector<int> children;
1010
1011 wxTreeItemIdValue cookie;
1012 wxTreeItemId child = m_ruleTreeCtrl->GetFirstChild( aItem, cookie );
1013
1014 while( child.IsOk() )
1015 {
1016 RULE_TREE_ITEM_DATA* childItemData =
1017 dynamic_cast<RULE_TREE_ITEM_DATA*>( m_ruleTreeCtrl->GetItemData( child ) );
1018 int childId = childItemData->GetNodeId();
1019
1020 children.push_back( childId );
1021
1022 saveRuleTreeState( child, childId );
1023
1024 child = m_ruleTreeCtrl->GetNextChild( aItem, cookie );
1025 }
1026
1027 m_treeHistoryData[aNodeId] = { itemText, children, aItem };
1028}
1029
1030
1031void RULE_EDITOR_DIALOG_BASE::restoreRuleTree( const wxTreeItemId& aParent, const int& aNodeId )
1032{
1033 auto it = m_treeHistoryData.find( aNodeId );
1034
1035 if( it == m_treeHistoryData.end() )
1036 return;
1037
1038 const auto& [itemText, children, itemId] = it->second;
1039
1040 wxTreeItemId newItem;
1041
1042 if( aParent )
1043 newItem = m_ruleTreeCtrl->AppendItem( aParent, itemText );
1044 else
1045 newItem = m_ruleTreeCtrl->AddRoot( itemText );
1046
1047 if( newItem )
1048 {
1049 wxTreeItemId& treeItemId = std::get<2>( it->second );
1050 treeItemId = newItem;
1051 }
1052
1053 RULE_TREE_ITEM_DATA* itemData = new RULE_TREE_ITEM_DATA( aNodeId, aParent, newItem );
1054 m_ruleTreeCtrl->SetItemData( newItem, itemData );
1055
1056 for( const auto& childId : children )
1057 {
1058 restoreRuleTree( newItem, childId );
1059 }
1060
1061 // Don't expand the root item because it is hidden
1062 if( aParent )
1063 m_ruleTreeCtrl->Expand( newItem );
1064}
1065
1066
1067wxTreeItemId RULE_EDITOR_DIALOG_BASE::appendRuleTreeItem( const RULE_TREE_NODE& aNode, wxTreeItemId aParent )
1068{
1069 wxString displayName = aNode.m_nodeName;
1070
1071 if( aNode.m_nodeData && aNode.m_nodeData->IsNew() )
1072 displayName += wxS( " *" );
1073
1074 wxTreeItemId currentTreeItemId = m_ruleTreeCtrl->AppendItem( aParent, displayName );
1075
1076 RULE_TREE_ITEM_DATA* itemData = new RULE_TREE_ITEM_DATA( aNode.m_nodeId, aParent, currentTreeItemId );
1077 m_ruleTreeCtrl->SetItemData( currentTreeItemId, itemData );
1078
1079 m_ruleTreeCtrl->Expand( currentTreeItemId );
1080
1081 return currentTreeItemId;
1082}
1083
1084
1085void RULE_EDITOR_DIALOG_BASE::getRuleTreeChildNodes( const std::vector<RULE_TREE_NODE>& aNodes,
1086 int aParentId,
1087 std::vector<RULE_TREE_NODE>& aResult )
1088{
1089 std::vector<RULE_TREE_NODE> filteredNodes;
1090
1091 std::copy_if( aNodes.begin(), aNodes.end(), std::back_inserter( filteredNodes ),
1092 [&aParentId]( const RULE_TREE_NODE& node )
1093 {
1094 return node.m_nodeData->GetParentId() == aParentId;
1095 } );
1096
1097 if( filteredNodes.size() > 0 )
1098 {
1099 aResult.insert( aResult.end(), filteredNodes.begin(), filteredNodes.end() );
1100 }
1101}
1102
1104 wxTreeItemId aDest )
1105{
1106 wxTreeItemIdValue cookie;
1107 wxTreeItemId child = m_ruleTreeCtrl->GetFirstChild( aSrc, cookie );
1108
1109 while( child.IsOk() )
1110 {
1111 wxTreeItemId newChild = m_ruleTreeCtrl->AppendItem( aDest, m_ruleTreeCtrl->GetItemText( child ) );
1112
1113 RULE_TREE_ITEM_DATA* ruleTreeItemData =
1114 dynamic_cast<RULE_TREE_ITEM_DATA*>( m_ruleTreeCtrl->GetItemData( child ) );
1115 ruleTreeItemData->SetParentTreeItemId( aDest );
1116 ruleTreeItemData->SetTreeItemId( newChild );
1117
1118 m_ruleTreeCtrl->SetItemData( newChild, ruleTreeItemData );
1119 m_ruleTreeCtrl->SetItemData( child, nullptr );
1120
1121 moveRuleTreeItemChildrensTooOnDrag( child, newChild );
1122
1123 child = m_ruleTreeCtrl->GetNextChild( aSrc, cookie );
1124 }
1125}
1126
1127
1129{
1130 wxTreeItemId selectedItem = m_ruleTreeCtrl->GetSelection();
1131
1132 m_enableMoveUp = false;
1133 m_enableMoveDown = false;
1134
1135 if( !selectedItem.IsOk() )
1136 return;
1137
1138 if( selectedItem == m_ruleTreeCtrl->GetRootItem() )
1139 return;
1140
1141 RULE_TREE_ITEM_DATA* itemData =
1142 dynamic_cast<RULE_TREE_ITEM_DATA*>( m_ruleTreeCtrl->GetItemData( selectedItem ) );
1143
1144 if( !itemData ||
1147 {
1148 return;
1149 }
1150
1151 wxTreeItemId parent = m_ruleTreeCtrl->GetItemParent( selectedItem );
1152 wxTreeItemIdValue cookie;
1153 wxTreeItemId firstChild = m_ruleTreeCtrl->GetFirstChild( parent, cookie );
1154 wxTreeItemId lastChild = firstChild;
1155
1156 while( lastChild.IsOk() )
1157 {
1158 wxTreeItemId next = m_ruleTreeCtrl->GetNextChild( parent, cookie );
1159
1160 if( !next.IsOk() )
1161 break;
1162
1163 lastChild = next;
1164 }
1165
1166 m_enableMoveUp = ( selectedItem != firstChild );
1167 m_enableMoveDown = ( selectedItem != lastChild );
1168}
1169
1170
1172{
1173 wxTreeItemId selectedItem = m_ruleTreeCtrl->GetSelection();
1174
1175 if( !selectedItem.IsOk() || !m_ruleTreeCtrl->IsEnabled() )
1176 {
1177 m_addRuleButton->Enable( false );
1178 m_copyRuleButton->Enable( false );
1179 m_moveTreeItemUpButton->Enable( false );
1180 m_moveTreeItemDownButton->Enable( false );
1181 m_deleteRuleButton->Enable( false );
1182
1183 return;
1184 }
1185
1186 m_enableAddRule = false;
1187 m_enableDuplicateRule = false;
1188 m_enableDeleteRule = false;
1189
1191 m_enableAddRule = true;
1192
1194 m_enableDuplicateRule = true;
1195
1197 m_enableDeleteRule = true;
1198
1200
1206}
1207
1208
1209void RULE_EDITOR_DIALOG_BASE::onResize( wxSizeEvent& event )
1210{
1211 Layout();
1212
1213 event.Skip();
1214}
1215
1216
1217void RULE_EDITOR_DIALOG_BASE::onClose( wxCloseEvent& aEvt )
1218{
1219 wxPostEvent( this, wxCommandEvent( wxEVT_COMMAND_BUTTON_CLICKED, wxID_CANCEL ) );
1220}
wxBitmap KiBitmap(BITMAPS aBitmap, int aHeightTag)
Construct a wxBitmap from an image identifier Returns the image from the active theme if the image ha...
Definition bitmap.cpp:104
wxBitmapBundle KiBitmapBundle(BITMAPS aBitmap, int aMinHeight)
Definition bitmap.cpp:110
bool Show(bool show) override
void resetUndoRedoForNewContent(wxWindowList &aChildren)
Reset undo/redo tracking after dynamically replacing child panels.
void unregisterUnitBinders(wxWindow *aWindow)
Remove UNIT_BINDER registrations for a window and all its descendants.
void finishDialogSettings()
In all dialogs, we must call the same functions to fix minimal dlg size, the default position and per...
DIALOG_SHIM(wxWindow *aParent, wxWindowID id, const wxString &title, const wxPoint &pos=wxDefaultPosition, const wxSize &size=wxDefaultSize, long style=wxDEFAULT_FRAME_STYLE|wxRESIZE_BORDER, const wxString &name=wxDialogNameStr)
wxSize m_initialSize
virtual void OnCharHook(wxKeyEvent &aEvt)
bool IsNew()
Check if the rule is marked as new.
int GetParentId()
Get the parent ID of the rule.
void populateRuleTreeCtrl(const std::vector< RULE_TREE_NODE > &aRuleTreeNodes, const RULE_TREE_NODE &aRuleTreeNode, wxTreeItemId aParentTreeItemId)
Populates the rule tree with nodes and their children.
void onRuleTreeItemSelectionChanged(wxTreeEvent &aEvent)
Updates action buttons based on the selected tree item.
STD_BITMAP_BUTTON * m_moveTreeItemUpButton
void moveRuleTreeItemChildrensTooOnDrag(wxTreeItemId aSrcTreeItemId, wxTreeItemId aDestTreeItemId)
Recursively moves all child nodes of a source item to a destination during drag.
void DeleteRuleTreeItem(wxTreeItemId aItemId, const int &aNodeId)
Deletes a tree item and removes its corresponding node from history.
void onRuleTreeItemMouseMotion(wxMouseEvent &aEvent)
Handles drag motion to move the item along with the cursor.
void UpdateRuleTreeItemText(wxTreeItemId aItemId, wxString aItemText)
Updates the text of a specified rule tree item.
STD_BITMAP_BUTTON * m_deleteRuleButton
void onNewRuleOptionClick(wxCommandEvent &aEvent)
Creates a new rule when the "New Rule" option is clicked.
void onRuleTreeItemLeftDown(wxMouseEvent &aEvent)
Initiates drag operation for a tree item on mouse down.
void onMoveUpRuleOptionClick(wxCommandEvent &aEvent)
Moves a rule item up in the tree when "Move Up" is clicked.
virtual void RuleTreeItemSelectionChanged(RULE_TREE_ITEM_DATA *aCurrentRuleTreeItemData)=0
Pure virtual method to handle tree item selection changes.
void onClose(wxCloseEvent &aEvt)
bool Show(bool show) override
void SetModified()
Marks the dialog as modified, indicating unsaved changes.
void RefreshContentScrollArea()
Recalculates the scrolled content area's virtual size based on the current content panel's best size,...
void onMoveDownRuleOptionClick(wxCommandEvent &aEvent)
Moves a rule item down in the tree when "Move Down" is clicked.
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 saveRuleTreeState(const wxTreeItemId &aItem, const int &aNodeId=0)
Saves the state of a tree item to history.
static RULE_EDITOR_DIALOG_BASE * GetDialog(wxWindow *aWindow)
Static method to retrieve the rule editor dialog instance associated with a given window.
void onRuleTreeItemLeftUp(wxMouseEvent &aEvent)
Completes the drag operation on mouse release.
void onRuleTreeItemActivated(wxTreeEvent &aEvent)
Handles double-click activation of a tree item.
void SetContentPanel(wxPanel *aContentPanel)
Replaces the current content panel with a new one based on the selected constraint type.
virtual void OnSave(wxCommandEvent &aEvent)=0
void OnCharHook(wxKeyEvent &aEvt) override
std::vector< RULE_TREE_NODE > m_defaultTreeItems
virtual void AddNewRule(RULE_TREE_ITEM_DATA *aRuleTreeItemData)=0
Pure virtual method to add a new rule to the tree.
STD_BITMAP_BUTTON * m_moveTreeItemDownButton
void onDuplicateRuleOptionClick(wxCommandEvent &aEvent)
Duplicates the selected rule when "Duplicate Rule" is clicked.
wxScrolledWindow * m_scrolledContentWin
void ClearModified()
Clears the modified flag, typically after saving.
RULE_TREE_ITEM_DATA * m_selectedData
void restoreRuleTree(const wxTreeItemId &aParent, const int &aNodeId)
Restores a tree item from history and appends it under a parent.
RULE_EDITOR_DIALOG_BASE(wxWindow *aParent, const wxString &aTitle, const wxSize &aInitialSize=wxDefaultSize)
virtual void RemoveRule(int aNodeId)=0
Pure virtual method to remove a rule from the tree.
wxTreeItemId appendRuleTreeItem(const RULE_TREE_NODE &aRuleTreeNode, wxTreeItemId aParentTreeItemId)
Appends a new rule item to the tree.
std::unordered_map< int, std::tuple< wxString, std::vector< int >, wxTreeItemId > > m_treeHistoryData
void onResize(wxSizeEvent &event)
STD_BITMAP_BUTTON * m_addRuleButton
STD_BITMAP_BUTTON * m_copyRuleButton
void onDeleteRuleOptionClick(wxCommandEvent &aEvent)
Deletes the selected rule when "Delete Rule" is clicked.
virtual void DuplicateRule(RULE_TREE_ITEM_DATA *aRuleTreeItemData)=0
Pure virtual method to duplicate an existing rule in the tree.
void onRuleTreeItemRightClick(wxTreeEvent &aEvent)
Handles right-click on a rule tree item to create a context menu.
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.
void onFilterSearch(wxCommandEvent &aEvent)
Applies filter to the rule tree based on the search string.
virtual bool isEnabled(RULE_TREE_ITEM_DATA *aRuleTreeItemData, RULE_EDITOR_TREE_CONTEXT_OPT aOption)=0
Pure virtual method to verify if a context menu option for a rule tree item should be enabled.
void updateRuleTreeItemMoveOptionState()
Updates the state of move options (up/down) for the selected item.
virtual void OnCancel(wxCommandEvent &aEvent)=0
void updateRuleTreeActionButtonsState(RULE_TREE_ITEM_DATA *aRuleTreeItemData)
Updates the action buttons based on the current selection.
void SetControlsEnabled(bool aEnable)
Enables or disables controls within the rule editor dialog.
bool filterRuleTree(const wxTreeItemId &aItem, const wxString &aFilter)
Recursively filters tree items to show only those matching the filter.
A class representing additional data associated with a wxTree item.
void SetTreeItemId(wxTreeItemId aTreeItemId)
void SetParentTreeItemId(wxTreeItemId aParentTreeItemId)
A bitmap button widget that behaves like a standard dialog button except with an icon.
A modified version of the wxInfoBar class that allows us to:
Definition wx_infobar.h:77
void SetBorders(bool aLeft, bool aRight, bool aTop, bool aBottom)
Definition wx_panel.h:39
This file is part of the common library.
const int minSize
Push and Shove router track width and via size dialog.
#define _(s)
KICOMMON_API wxFont GetControlFont(wxWindow *aWindow)
KICOMMON_API wxMenuItem * AddMenuItem(wxMenu *aMenu, int aId, const wxString &aText, const wxBitmapBundle &aImage, wxItemKind aType=wxITEM_NORMAL)
Create and insert a menu item with an icon into aMenu.
static wxSearchCtrl * CreateTextFilterBox(wxWindow *aParent, const wxString &aDescriptiveText)
Helper function to add a filter box to a panel, with some sensible defaults for that purpose.
CITER next(CITER it)
Definition ptree.cpp:124
static wxSearchCtrl * CreateTextFilterBox(wxWindow *aParent, const wxString &aDescriptiveText)
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
Functions to provide common constants and other functions to assist in making a consistent UI.