From c6046d6da26fbd0bd2ff0b7ce27f3bb0e2f0e698 Mon Sep 17 00:00:00 2001 From: John Beard Date: Tue, 7 Feb 2017 14:40:38 +0800 Subject: [PATCH] Add selection filter dialog to GAL Fixes: lp:1535805 * https://bugs.launchpad.net/kicad/+bug/1535805 --- pcbnew/block.cpp | 2 +- pcbnew/dialogs/dialog_block_options.cpp | 8 +- pcbnew/dialogs/dialog_block_options.h | 1 + pcbnew/tools/pcb_actions.h | 4 + pcbnew/tools/selection_tool.cpp | 154 +++++++++++++++++++++++- pcbnew/tools/selection_tool.h | 7 ++ 6 files changed, 173 insertions(+), 3 deletions(-) diff --git a/pcbnew/block.cpp b/pcbnew/block.cpp index adc74643a8..81d6036375 100644 --- a/pcbnew/block.cpp +++ b/pcbnew/block.cpp @@ -81,7 +81,7 @@ static bool InstallBlockCmdFrame( PCB_BASE_FRAME* parent, const wxString& title wxPoint oldpos = parent->GetCrossHairPosition(); parent->GetCanvas()->SetIgnoreMouseEvents( true ); - DIALOG_BLOCK_OPTIONS * dlg = new DIALOG_BLOCK_OPTIONS( parent, blockOpts, title ); + DIALOG_BLOCK_OPTIONS * dlg = new DIALOG_BLOCK_OPTIONS( parent, blockOpts, true, title ); int cmd = dlg->ShowModal(); dlg->Destroy(); diff --git a/pcbnew/dialogs/dialog_block_options.cpp b/pcbnew/dialogs/dialog_block_options.cpp index 594751d085..d6ce049b33 100644 --- a/pcbnew/dialogs/dialog_block_options.cpp +++ b/pcbnew/dialogs/dialog_block_options.cpp @@ -28,10 +28,16 @@ DIALOG_BLOCK_OPTIONS::DIALOG_BLOCK_OPTIONS( PCB_BASE_FRAME* aParent, - OPTIONS& aOptions, const wxString& aTitle ) : + OPTIONS& aOptions, bool aShowLegacyOptions, + const wxString& aTitle ) : DIALOG_BLOCK_OPTIONS_BASE( aParent, -1, aTitle ), m_options( aOptions ) { + if( !aShowLegacyOptions ) + { + m_DrawBlockItems->Hide(); + } + m_Include_Modules->SetValue( m_options.includeModules ); m_IncludeLockedModules->SetValue( m_options.includeLockedModules ); diff --git a/pcbnew/dialogs/dialog_block_options.h b/pcbnew/dialogs/dialog_block_options.h index 0bc2276c66..bdefe086ab 100644 --- a/pcbnew/dialogs/dialog_block_options.h +++ b/pcbnew/dialogs/dialog_block_options.h @@ -50,6 +50,7 @@ public: }; DIALOG_BLOCK_OPTIONS( PCB_BASE_FRAME* aParent, OPTIONS& aOptions, + bool aShowLegacyOptions, const wxString& aTitle ); ~DIALOG_BLOCK_OPTIONS() diff --git a/pcbnew/tools/pcb_actions.h b/pcbnew/tools/pcb_actions.h index 00c16ef110..1e8985fed4 100644 --- a/pcbnew/tools/pcb_actions.h +++ b/pcbnew/tools/pcb_actions.h @@ -69,6 +69,10 @@ public: /// Selects all components on the same sheet. static TOOL_ACTION selectSameSheet; + + /// Filters the items in the current selection (invokes dialog) + static TOOL_ACTION filterSelection; + // Edit Tool /// Activation of the edit tool static TOOL_ACTION editActivate; diff --git a/pcbnew/tools/selection_tool.cpp b/pcbnew/tools/selection_tool.cpp index 61a544cc9e..bac75cf03d 100644 --- a/pcbnew/tools/selection_tool.cpp +++ b/pcbnew/tools/selection_tool.cpp @@ -38,6 +38,7 @@ using namespace std::placeholders; #include #include #include +#include #include #include @@ -99,6 +100,12 @@ TOOL_ACTION PCB_ACTIONS::find( "pcbnew.InteractiveSelection.Find", TOOL_ACTION PCB_ACTIONS::findMove( "pcbnew.InteractiveSelection.FindMove", AS_GLOBAL, TOOL_ACTION::LegacyHotKey( HK_GET_AND_MOVE_FOOTPRINT ) ); +TOOL_ACTION PCB_ACTIONS::filterSelection( "pcbnew.InteractiveSelection.FilterSelection", + AS_GLOBAL, MD_SHIFT + 'F', + _( "Filter selection" ), _( "Filter the types of items in the selection" ), + nullptr ); + + class SELECT_MENU: public CONTEXT_MENU { @@ -106,6 +113,11 @@ public: SELECT_MENU() { SetTitle( _( "Select..." ) ); + + Add( PCB_ACTIONS::filterSelection ); + + AppendSeparator(); + Add( PCB_ACTIONS::selectConnection ); Add( PCB_ACTIONS::selectCopper ); Add( PCB_ACTIONS::selectNet ); @@ -138,10 +150,21 @@ private: }; +/** + * Private implementation of firewalled private data + */ +class SELECTION_TOOL::PRIV +{ +public: + DIALOG_BLOCK_OPTIONS::OPTIONS m_filterOpts; +}; + + SELECTION_TOOL::SELECTION_TOOL() : PCB_TOOL( "pcbnew.InteractiveSelection" ), m_frame( NULL ), m_additive( false ), m_multiple( false ), - m_locked( true ), m_menu( *this ) + m_locked( true ), m_menu( *this ), + m_priv( std::make_unique() ) { // Do not leave uninitialized members: m_preliminary = false; @@ -522,6 +545,7 @@ void SELECTION_TOOL::SetTransitions() Go( &SELECTION_TOOL::UnselectItem, PCB_ACTIONS::unselectItem.MakeEvent() ); Go( &SELECTION_TOOL::find, PCB_ACTIONS::find.MakeEvent() ); Go( &SELECTION_TOOL::findMove, PCB_ACTIONS::findMove.MakeEvent() ); + Go( &SELECTION_TOOL::filterSelection, PCB_ACTIONS::filterSelection.MakeEvent() ); Go( &SELECTION_TOOL::selectConnection, PCB_ACTIONS::selectConnection.MakeEvent() ); Go( &SELECTION_TOOL::selectCopper, PCB_ACTIONS::selectCopper.MakeEvent() ); Go( &SELECTION_TOOL::selectNet, PCB_ACTIONS::selectNet.MakeEvent() ); @@ -914,6 +938,134 @@ int SELECTION_TOOL::findMove( const TOOL_EVENT& aEvent ) } +/** + * Function itemIsIncludedByFilter() + * + * Determine if an item is included by the filter specified + * + * @return true if the parameter indicate the items should be selected + * by this filter (i..e not filtered out) + */ +static bool itemIsIncludedByFilter( const BOARD_ITEM& aItem, + const BOARD& aBoard, + const LSET& aTechnlLayerMask, + const DIALOG_BLOCK_OPTIONS::OPTIONS& aBlockOpts ) +{ + bool include = true; + const LAYER_ID layer = aItem.GetLayer(); + + // can skip without even checking item type + if( !aBlockOpts.includeItemsOnInvisibleLayers + && !aBoard.IsLayerVisible( layer ) ) + { + include = false; + } + + // if the item needsto be checked agains the options + if( include ) + { + switch( aItem.Type() ) + { + case PCB_MODULE_T: + { + const auto& module = static_cast( aItem ); + + include = aBlockOpts.includeModules; + + if( include && !aBlockOpts.includeLockedModules ) + { + include = !module.IsLocked(); + } + + break; + } + case PCB_TRACE_T: + { + include = aBlockOpts.includeTracks; + break; + } + case PCB_ZONE_AREA_T: + { + include = aBlockOpts.includeZones; + break; + } + case PCB_LINE_T: + case PCB_TARGET_T: + case PCB_DIMENSION_T: + { + include = aTechnlLayerMask[layer]; + break; + } + case PCB_TEXT_T: + { + include = aBlockOpts.includePcbTexts + && aTechnlLayerMask[layer]; + break; + } + default: + { + // no filterering, just select it + break; + } + } + } + + return include; +} + + +/** + * Gets the technical layers that are part of the given selection opts + */ +static LSET getFilteredLayerSet( + const DIALOG_BLOCK_OPTIONS::OPTIONS& blockOpts ) +{ + LSET layerMask( Edge_Cuts ); + + if( blockOpts.includeItemsOnTechLayers ) + layerMask.set(); + + if( !blockOpts.includeBoardOutlineLayer ) + layerMask.set( Edge_Cuts, false ); + + return layerMask; +} + + +int SELECTION_TOOL::filterSelection( const TOOL_EVENT& aEvent ) +{ + auto& opts = m_priv->m_filterOpts; + DIALOG_BLOCK_OPTIONS dlg( m_frame, opts, false, _( "Filter selection" ) ); + + const int cmd = dlg.ShowModal(); + + if( cmd != wxID_OK ) + return 0; + + const auto& board = *getModel(); + const auto layerMask = getFilteredLayerSet( opts ); + + // copy current selection + auto selection = m_selection.GetItems(); + + // clear current selection + clearSelection(); + + // copy selection items from the saved selection + // according to the dialog options + for( auto item : selection ) + { + bool include = itemIsIncludedByFilter( *item, board, layerMask, opts ); + + if( include ) + { + select( item ); + } + } + return 0; +} + + void SELECTION_TOOL::clearSelection() { if( m_selection.Empty() ) diff --git a/pcbnew/tools/selection_tool.h b/pcbnew/tools/selection_tool.h index 1d711d7c58..c0dad23e3e 100644 --- a/pcbnew/tools/selection_tool.h +++ b/pcbnew/tools/selection_tool.h @@ -293,6 +293,9 @@ private: ///> Find an item and start moving. int findMove( const TOOL_EVENT& aEvent ); + ///> Invoke filter dialog and modify current selection + int filterSelection( const TOOL_EVENT& aEvent ); + /** * Function clearSelection() * Clears the current selection. @@ -407,6 +410,10 @@ private: /// Menu model displayed by the tool. TOOL_MENU m_menu; + + /// Private state (opaque pointer/compilation firewall) + class PRIV; + std::unique_ptr m_priv; }; #endif