Browse Source

groups: make selection tool work with groups

revert-0c36e162
Mike Williams 6 months ago
parent
commit
05f3c47b4f
  1. 2
      eeschema/sch_group.cpp
  2. 2
      eeschema/tools/sch_group_tool.cpp
  3. 465
      eeschema/tools/sch_selection_tool.cpp
  4. 29
      eeschema/tools/sch_selection_tool.h

2
eeschema/sch_group.cpp

@ -281,7 +281,7 @@ const BOX2I SCH_GROUP::GetBoundingBox() const
bbox.Merge( item->GetBoundingBox() );
}
bbox.Inflate( schIUScale.MilsToIU( 5 ) ); // Give a min size to the bbox
bbox.Inflate( schIUScale.MilsToIU( 10 ) );
return bbox;
}

2
eeschema/tools/sch_group_tool.cpp

@ -72,7 +72,7 @@ int SCH_GROUP_TOOL::PickNewMember( const TOOL_EVENT& aEvent )
if( !isSymbolEditor )
{
while( elem->GetParent() && elem->GetParent()->Type() != SCHEMATIC_T )
while( elem->GetParent() && elem->GetParent()->Type() != SCH_SCREEN_T )
elem = elem->GetParent();
}

465
eeschema/tools/sch_selection_tool.cpp

@ -41,6 +41,7 @@
#include <sch_edit_frame.h>
#include <sch_line.h>
#include <sch_bus_entry.h>
#include <sch_group.h>
#include <sch_marker.h>
#include <sch_no_connect.h>
#include <sch_sheet_pin.h>
@ -155,6 +156,7 @@ SCH_SELECTION_TOOL::SCH_SELECTION_TOOL() :
SELECTION_TOOL( "common.InteractiveSelection" ),
m_frame( nullptr ),
m_nonModifiedCursor( KICURSOR::ARROW ),
m_enteredGroup( nullptr ),
m_isSymbolEditor( false ),
m_isSymbolViewer( false ),
m_unit( 0 ),
@ -169,6 +171,7 @@ SCH_SELECTION_TOOL::SCH_SELECTION_TOOL() :
SCH_SELECTION_TOOL::~SCH_SELECTION_TOOL()
{
getView()->Remove( &m_selection );
getView()->Remove( &m_enteredGroupOverlay );
}
@ -272,6 +275,15 @@ bool SCH_SELECTION_TOOL::Init()
static_cast<SYMBOL_EDIT_FRAME*>( m_frame )->GetCurSymbol();
};
auto groupEnterCondition =
SELECTION_CONDITIONS::Count( 1 ) && SELECTION_CONDITIONS::HasType( SCH_GROUP_T );
auto inGroupCondition =
[this] ( const SELECTION& )
{
return m_enteredGroup != nullptr;
};
auto symbolDisplayNameIsEditable =
[&]( const SELECTION& sel )
{
@ -290,6 +302,8 @@ bool SCH_SELECTION_TOOL::Init()
auto& menu = m_menu->GetMenu();
// clang-format off
menu.AddItem( ACTIONS::groupEnter, groupEnterCondition, 1 );
menu.AddItem( ACTIONS::groupLeave, inGroupCondition, 1 );
menu.AddItem( SCH_ACTIONS::clearHighlight, haveHighlight && SCH_CONDITIONS::Idle, 1 );
menu.AddSeparator( haveHighlight && SCH_CONDITIONS::Idle, 1 );
@ -345,6 +359,9 @@ void SCH_SELECTION_TOOL::Reset( RESET_REASON aReason )
if( aReason != TOOL_BASE::REDRAW )
{
if( m_enteredGroup )
ExitGroup();
// Remove pointers to the selected items from containers without changing their
// properties (as they are already deleted while a new sheet is loaded)
m_selection.Clear();
@ -375,6 +392,9 @@ void SCH_SELECTION_TOOL::Reset( RESET_REASON aReason )
// Reinsert the VIEW_GROUP, in case it was removed from the VIEW
getView()->Remove( &m_selection );
getView()->Add( &m_selection );
getView()->Remove( &m_enteredGroupOverlay );
getView()->Add( &m_enteredGroupOverlay );
}
int SCH_SELECTION_TOOL::Main( const TOOL_EVENT& aEvent )
@ -611,6 +631,8 @@ int SCH_SELECTION_TOOL::Main( const TOOL_EVENT& aEvent )
if( item && item->Type() == SCH_SHEET_T )
m_toolMgr->PostAction( SCH_ACTIONS::enterSheet );
else if( m_selection.GetSize() == 1 && m_selection[0]->Type() == SCH_GROUP_T )
EnterGroup();
else
m_toolMgr->PostAction( SCH_ACTIONS::properties );
}
@ -992,10 +1014,17 @@ int SCH_SELECTION_TOOL::Main( const TOOL_EVENT& aEvent )
}
else if( evt->FirstResponder() == this && evt->GetCommandId() == (int) WXK_ESCAPE )
{
SCH_EDITOR_CONTROL* editor = m_toolMgr->GetTool<SCH_EDITOR_CONTROL>();
if( m_enteredGroup )
{
ExitGroup();
}
else
{
SCH_EDITOR_CONTROL* editor = m_toolMgr->GetTool<SCH_EDITOR_CONTROL>();
if( editor && m_frame->eeconfig()->m_Input.esc_clears_net_highlight )
editor->ClearHighlight( *evt );
if( editor && m_frame->eeconfig()->m_Input.esc_clears_net_highlight )
editor->ClearHighlight( *evt );
}
}
}
else if( evt->Action() == TA_UNDO_REDO_PRE )
@ -1113,6 +1142,57 @@ int SCH_SELECTION_TOOL::Main( const TOOL_EVENT& aEvent )
}
void SCH_SELECTION_TOOL::EnterGroup()
{
wxCHECK_RET( m_selection.GetSize() == 1 && m_selection[0]->Type() == SCH_GROUP_T,
wxT( "EnterGroup called when selection is not a single group" ) );
SCH_GROUP* aGroup = static_cast<SCH_GROUP*>( m_selection[0] );
if( m_enteredGroup != nullptr )
ExitGroup();
ClearSelection();
m_enteredGroup = aGroup;
m_enteredGroup->SetFlags( ENTERED );
m_enteredGroup->RunOnChildren(
[&]( SCH_ITEM* item )
{
if( item->Type() == SCH_LINE_T )
item->SetFlags( STARTPOINT | ENDPOINT );
select( item );
},
RECURSE_MODE::NO_RECURSE );
m_toolMgr->ProcessEvent( EVENTS::SelectedEvent );
getView()->Hide( m_enteredGroup, true );
m_enteredGroupOverlay.Add( m_enteredGroup );
getView()->Update( &m_enteredGroupOverlay );
}
void SCH_SELECTION_TOOL::ExitGroup( bool aSelectGroup )
{
// Only continue if there is a group entered
if( m_enteredGroup == nullptr )
return;
m_enteredGroup->ClearFlags( ENTERED );
getView()->Hide( m_enteredGroup, false );
ClearSelection();
if( aSelectGroup )
{
select( m_enteredGroup );
m_toolMgr->ProcessEvent( EVENTS::SelectedEvent );
}
m_enteredGroupOverlay.Clear();
m_enteredGroup = nullptr;
getView()->Update( &m_enteredGroupOverlay );
}
OPT_TOOL_EVENT SCH_SELECTION_TOOL::autostartEvent( TOOL_EVENT* aEvent, EE_GRID_HELPER& aGrid,
SCH_ITEM* aItem )
{
@ -1327,6 +1407,8 @@ void SCH_SELECTION_TOOL::narrowSelection( SCH_COLLECTOR& collector, const VECTOR
}
}
filterCollectorForHierarchy( collector, false );
// Apply some ugly heuristics to avoid disambiguation menus whenever possible
if( collector.GetCount() > 1 && !m_skip_heuristics )
GuessSelectionCandidates( collector, aWhere );
@ -1363,6 +1445,27 @@ bool SCH_SELECTION_TOOL::selectPoint( SCH_COLLECTOR& aCollector, const VECTOR2I&
if( !aAdd && !aSubtract && !aExclusiveOr )
ClearSelection();
// It is possible for slop in the selection model to cause us to be outside the group,
// but also selecting an item within the group, so only exit if the selection doesn't
// have an item belonging to the group
if( m_enteredGroup && !m_enteredGroup->GetBoundingBox().Contains( aWhere ) )
{
bool foundEnteredGroup = false;
for( EDA_ITEM* item : aCollector )
{
if( item->GetParentGroup() == m_enteredGroup )
{
foundEnteredGroup = true;
break;
}
}
if( !foundEnteredGroup )
ExitGroup();
}
filterCollectorForHierarchy( aCollector, true );
int addedCount = 0;
bool anySubtracted = false;
@ -1457,46 +1560,53 @@ bool SCH_SELECTION_TOOL::SelectPoint( const VECTOR2I& aWhere,
int SCH_SELECTION_TOOL::SelectAll( const TOOL_EVENT& aEvent )
{
SCH_COLLECTOR collection;
m_multiple = true; // Multiple selection mode is active
KIGFX::VIEW* view = getView();
// hold all visible items
std::vector<KIGFX::VIEW::LAYER_ITEM_PAIR> selectedItems;
std::vector<KIGFX::VIEW::LAYER_ITEM_PAIR> sheetPins;
std::vector<EDA_ITEM*> sheetPins;
// Filter the view items based on the selection box
BOX2I selectionBox;
selectionBox.SetMaximum();
view->Query( selectionBox, selectedItems ); // Get the list of selected items
view->Query( selectionBox,
[&]( KIGFX::VIEW_ITEM* viewItem ) -> bool
{
SCH_ITEM* item = static_cast<SCH_ITEM*>( viewItem );
if( !item )
return true;
collection.Append( item );
return true;
} );
filterCollectorForHierarchy( collection, true );
// Sheet pins aren't in the view; add them by hand
for( KIGFX::VIEW::LAYER_ITEM_PAIR& pair : selectedItems )
for( EDA_ITEM* item : collection )
{
SCH_SHEET* sheet = dynamic_cast<SCH_SHEET*>( pair.first );
SCH_SHEET* sheet = dynamic_cast<SCH_SHEET*>( item );
if( sheet )
{
int layer = pair.second;
for( SCH_SHEET_PIN* pin : sheet->GetPins() )
sheetPins.emplace_back( KIGFX::VIEW::LAYER_ITEM_PAIR( pin, layer ) );
sheetPins.emplace_back( pin );
}
}
selectedItems.insert( selectedItems.end(), sheetPins.begin(), sheetPins.end() );
for( EDA_ITEM* pin : sheetPins )
collection.Append( pin );
for( const std::pair<KIGFX::VIEW_ITEM*, int>& item_pair : selectedItems )
for( EDA_ITEM* item : collection )
{
if( EDA_ITEM* item = dynamic_cast<EDA_ITEM*>( item_pair.first ) )
if( Selectable( item ) && itemPassesFilter( item ) )
{
if( Selectable( item ) && itemPassesFilter( item ) )
{
if( item->Type() == SCH_LINE_T )
item->SetFlags( STARTPOINT | ENDPOINT );
if( item->Type() == SCH_LINE_T )
item->SetFlags( STARTPOINT | ENDPOINT );
select( item );
}
select( item );
}
}
@ -1807,6 +1917,24 @@ SCH_SELECTION& SCH_SELECTION_TOOL::RequestSelection( const std::vector<KICAD_T>&
}
void SCH_SELECTION_TOOL::filterCollectedItems( SCH_COLLECTOR& aCollector, bool aMultiSelect )
{
if( aCollector.GetCount() == 0 )
return;
std::set<EDA_ITEM*> rejected;
for( EDA_ITEM* item : aCollector )
{
if( !itemPassesFilter( item ) )
rejected.insert( item );
}
for( EDA_ITEM* item : rejected )
aCollector.Remove( item );
}
bool SCH_SELECTION_TOOL::itemPassesFilter( EDA_ITEM* aItem )
{
if( !aItem )
@ -1983,49 +2111,78 @@ bool SCH_SELECTION_TOOL::selectMultiple()
view->SetVisible( &area, false );
// Fetch items from the RTree that are in our area of interest
std::vector<KIGFX::VIEW::LAYER_ITEM_PAIR> nearbyViewItems;
view->Query( area.ViewBBox(), nearbyViewItems );
std::vector<KIGFX::VIEW::LAYER_ITEM_PAIR> candidates;
BOX2I selectionBox = area.ViewBBox();
view->Query( selectionBox, candidates );
// Construct a BOX2I to determine BOARD_ITEM selection
BOX2I selectionRect( area.GetOrigin(), VECTOR2I( width, height ) );
selectionRect.Normalize();
// Build lists of nearby items and their children
std::unordered_set<EDA_ITEM*> nearbyItems;
std::vector<EDA_ITEM*> nearbyChildren;
std::vector<EDA_ITEM*> flaggedItems;
SCH_COLLECTOR collector;
SCH_COLLECTOR pinsCollector;
std::set<EDA_ITEM*> group_items;
for( KIGFX::VIEW::LAYER_ITEM_PAIR& pair : nearbyViewItems )
for( EDA_ITEM* item : m_frame->GetScreen()->Items().OfType( SCH_GROUP_T ) )
{
if( EDA_ITEM* item = dynamic_cast<EDA_ITEM*>( pair.first ) )
SCH_GROUP* group = static_cast<SCH_GROUP*>( item );
// The currently entered group does not get limited
if( m_enteredGroup == group )
continue;
std::unordered_set<EDA_ITEM*>& newset = group->GetItems();
// If we are not greedy and have selected the whole group, add just one item
// to allow it to be promoted to the group later
if( !isGreedy && selectionRect.Contains( group->GetBoundingBox() ) && newset.size() )
{
if( nearbyItems.insert( item ).second )
for( EDA_ITEM* group_item : newset )
{
item->ClearFlags( CANDIDATE );
if( SCH_ITEM* sch_item = dynamic_cast<SCH_ITEM*>( item ) )
{
sch_item->RunOnChildren(
[&]( SCH_ITEM* aChild )
{
// Filter pins by unit
if( SCH_PIN* pin = dynamic_cast<SCH_PIN*>( aChild ) )
{
int unit = pin->GetLibPin()->GetUnit();
if( unit && unit != pin->GetParentSymbol()->GetUnit() )
return;
}
nearbyChildren.push_back( aChild );
},
RECURSE_MODE::NO_RECURSE );
}
if( Selectable( static_cast<SCH_ITEM*>( group_item ) ) )
collector.Append( *newset.begin() );
}
}
for( EDA_ITEM* group_item : newset )
group_items.emplace( group_item );
}
for( KIGFX::VIEW::LAYER_ITEM_PAIR& candidate : candidates )
{
SCH_ITEM* item = static_cast<SCH_ITEM*>( candidate.first );
// If the item is a line, add it even if it doesn't pass the hit test using the greedy
// flag as we handle partially selecting line ends later
if( item && Selectable( item )
&& ( item->HitTest( selectionRect, !isGreedy ) || item->Type() == SCH_LINE_T )
&& ( isGreedy || !group_items.count( item ) ) )
{
if( item->Type() == SCH_PIN_T && !m_isSymbolEditor )
pinsCollector.Append( item );
else
collector.Append( item );
}
}
std::vector<EDA_ITEM*> sortedNearbyItems( nearbyItems.begin(), nearbyItems.end() );
// Apply the stateful filter
filterCollectedItems( collector, true );
filterCollectorForHierarchy( collector, true );
// If we selected nothing but pins, allow them to be selected
if( collector.GetCount() == 0 )
{
collector = pinsCollector;
filterCollectedItems( collector, true );
filterCollectorForHierarchy( collector, true );
}
// Sort the filtered selection by rows and columns to have a nice default
// for tools that can use it.
std::sort( sortedNearbyItems.begin(), sortedNearbyItems.end(),
std::sort( collector.begin(), collector.end(),
[]( EDA_ITEM* a, EDA_ITEM* b )
{
VECTOR2I aPos = a->GetPosition();
@ -2037,9 +2194,6 @@ bool SCH_SELECTION_TOOL::selectMultiple()
return aPos.y < bPos.y;
} );
BOX2I selectionRect( area.GetOrigin(), VECTOR2I( width, height ) );
selectionRect.Normalize();
bool anyAdded = false;
bool anySubtracted = false;
@ -2072,61 +2226,44 @@ bool SCH_SELECTION_TOOL::selectMultiple()
}
};
for( EDA_ITEM* item : sortedNearbyItems )
std::vector<EDA_ITEM*> flaggedItems;
for( EDA_ITEM* item : collector )
{
bool selected = false;
EDA_ITEM_FLAGS flags = 0;
EDA_ITEM_FLAGS flags = 0;
item->SetFlags( CANDIDATE );
flaggedItems.push_back( item );
if( m_frame->GetRenderSettings()->m_ShowPinsElectricalType )
item->SetFlags( SHOW_ELEC_TYPE );
if( Selectable( item ) && itemPassesFilter( item ) )
if( item->Type() == SCH_LINE_T )
{
if( item->Type() == SCH_LINE_T )
{
SCH_LINE* line = static_cast<SCH_LINE*>( item );
if( ( isGreedy && line->HitTest( selectionRect, false ) )
|| ( selectionRect.Contains( line->GetEndPoint() )
&& selectionRect.Contains( line->GetStartPoint() ) ) )
{
selected = true;
flags |= STARTPOINT | ENDPOINT;
}
else if( !isGreedy )
{
if( selectionRect.Contains( line->GetStartPoint() )
&& line->IsStartDangling() )
{
selected = true;
flags |= STARTPOINT;
}
SCH_LINE* line = static_cast<SCH_LINE*>( item );
if( selectionRect.Contains( line->GetEndPoint() )
&& line->IsEndDangling() )
{
selected = true;
flags |= ENDPOINT;
}
}
if( ( isGreedy && line->HitTest( selectionRect, false ) )
|| ( selectionRect.Contains( line->GetEndPoint() )
&& selectionRect.Contains( line->GetStartPoint() ) ) )
{
flags |= STARTPOINT | ENDPOINT;
}
else
else if( !isGreedy )
{
selected = item->HitTest( selectionRect, !isGreedy );
if( selectionRect.Contains( line->GetStartPoint() ) && line->IsStartDangling() )
flags |= STARTPOINT;
if( selectionRect.Contains( line->GetEndPoint() ) && line->IsEndDangling() )
flags |= ENDPOINT;
}
}
if( selected )
{
item->SetFlags( CANDIDATE );
flaggedItems.push_back( item );
selectItem( item, flags );
}
selectItem( item, flags );
item->ClearFlags( SHOW_ELEC_TYPE );
}
for( EDA_ITEM* item : nearbyChildren )
for( EDA_ITEM* item : pinsCollector )
{
if( m_frame->GetRenderSettings()->m_ShowPinsElectricalType )
item->SetFlags( SHOW_ELEC_TYPE );
@ -2180,6 +2317,78 @@ bool SCH_SELECTION_TOOL::selectMultiple()
return cancelled;
}
void SCH_SELECTION_TOOL::filterCollectorForHierarchy( SCH_COLLECTOR& aCollector,
bool aMultiselect ) const
{
std::unordered_set<EDA_ITEM*> toAdd;
// Set CANDIDATE on all parents which are included in the GENERAL_COLLECTOR. This
// algorithm is O(3n), whereas checking for the parent inclusion could potentially be O(n^2).
for( int j = 0; j < aCollector.GetCount(); j++ )
{
if( aCollector[j]->GetParent() )
aCollector[j]->GetParent()->ClearFlags( CANDIDATE );
if( aCollector[j]->GetParentSymbol() )
aCollector[j]->GetParentSymbol()->ClearFlags( CANDIDATE );
}
if( aMultiselect )
{
for( int j = 0; j < aCollector.GetCount(); j++ )
aCollector[j]->SetFlags( CANDIDATE );
}
for( int j = 0; j < aCollector.GetCount(); )
{
SCH_ITEM* item = aCollector[j];
SYMBOL* sym = item->GetParentSymbol();
SCH_ITEM* start = item;
if( !m_isSymbolEditor && sym )
start = sym;
// If a group is entered, disallow selections of objects outside the group.
if( m_enteredGroup && !SCH_GROUP::WithinScope( item, m_enteredGroup, m_isSymbolEditor ) )
{
aCollector.Remove( item );
continue;
}
// If any element is a member of a group, replace those elements with the top containing
// group.
if( EDA_GROUP* top = SCH_GROUP::TopLevelGroup( start, m_enteredGroup, m_isSymbolEditor ) )
{
if( top->AsEdaItem() != item )
{
toAdd.insert( top->AsEdaItem() );
top->AsEdaItem()->SetFlags( CANDIDATE );
aCollector.Remove( item );
continue;
}
}
// Symbols are a bit easier as they can't be nested.
if( sym && ( sym->GetFlags() & CANDIDATE ) )
{
// Remove children of selected items
aCollector.Remove( item );
continue;
}
++j;
}
for( EDA_ITEM* item : toAdd )
{
if( !aCollector.HasItem( item ) )
aCollector.Append( item );
}
}
void SCH_SELECTION_TOOL::InitializeSelectionState( SCH_TABLE* aTable )
{
for( SCH_TABLECELL* cell : aTable->GetCells() )
@ -2633,6 +2842,8 @@ void SCH_SELECTION_TOOL::RebuildSelection()
{
m_selection.Clear();
bool enteredGroupFound = false;
if( m_isSymbolEditor )
{
LIB_SYMBOL* start = static_cast<SYMBOL_EDIT_FRAME*>( m_frame )->GetCurSymbol();
@ -2641,6 +2852,19 @@ void SCH_SELECTION_TOOL::RebuildSelection()
{
if( item.IsSelected() )
select( &item );
if( item.Type() == SCH_GROUP_T )
{
if( &item == m_enteredGroup )
{
item.SetFlags( ENTERED );
enteredGroupFound = true;
}
else
{
item.ClearFlags( ENTERED );
}
}
}
}
else
@ -2662,11 +2886,30 @@ void SCH_SELECTION_TOOL::RebuildSelection()
},
RECURSE_MODE::NO_RECURSE );
}
if( item->Type() == SCH_GROUP_T )
{
if( item == m_enteredGroup )
{
item->SetFlags( ENTERED );
enteredGroupFound = true;
}
else
{
item->ClearFlags( ENTERED );
}
}
}
}
updateReferencePoint();
if( !enteredGroupFound )
{
m_enteredGroupOverlay.Clear();
m_enteredGroup = nullptr;
}
// Inform other potentially interested tools
m_toolMgr->ProcessEvent( EVENTS::SelectedEvent );
}
@ -2800,6 +3043,11 @@ void SCH_SELECTION_TOOL::ClearSelection( bool aQuietMode )
void SCH_SELECTION_TOOL::select( EDA_ITEM* aItem )
{
if( m_enteredGroup && !SCH_GROUP::WithinScope( static_cast<SCH_ITEM*>( aItem ), m_enteredGroup, m_isSymbolEditor ) )
{
ExitGroup();
}
highlight( aItem, SELECTED, &m_selection );
}
@ -2824,20 +3072,25 @@ void SCH_SELECTION_TOOL::highlight( EDA_ITEM* aItem, int aMode, SELECTION* aGrou
// represented in the LIB_SYMBOL and will inherit the settings of the parent symbol.)
if( SCH_ITEM* sch_item = dynamic_cast<SCH_ITEM*>( aItem ) )
{
sch_item->RunOnChildren(
[&]( SCH_ITEM* aChild )
{
if( aMode == SELECTED )
{
aChild->SetSelected();
getView()->Hide( aChild, true );
}
else if( aMode == BRIGHTENED )
// We don't want to select group children if the group itself is selected,
// we can only select them when the group is entered
if( sch_item->Type() != SCH_GROUP_T )
{
sch_item->RunOnChildren(
[&]( SCH_ITEM* aChild )
{
aChild->SetBrightened();
}
},
RECURSE_MODE::NO_RECURSE );
if( aMode == SELECTED )
{
aChild->SetSelected();
getView()->Hide( aChild, true );
}
else if( aMode == BRIGHTENED )
{
aChild->SetBrightened();
}
},
RECURSE_MODE::NO_RECURSE );
}
}
if( aGroup && aMode != BRIGHTENED )

29
eeschema/tools/sch_selection_tool.h

@ -35,6 +35,7 @@
#include <gal/cursors.h>
class SCH_BASE_FRAME;
class SCH_GROUP;
class SCH_ITEM;
class SCH_TABLE;
class EE_GRID_HELPER;
@ -83,6 +84,23 @@ public:
///< Zoom the screen to fit the bounding box for cross probing/selection sync.
void ZoomFitCrossProbeBBox( const BOX2I& aBBox );
/**
* Enter the group at the head of the current selection.
*/
void EnterGroup() override;
/**
* Leave the currently-entered group.
*
* @param aSelectGroup [optional] Select the group after leaving.
*/
void ExitGroup( bool aSelectGroup = false ) override;
/**
* @return the currently-entered group.
*/
SCH_GROUP* GetEnteredGroup() { return m_enteredGroup; }
/**
* @return the set of currently selected items.
*/
@ -315,6 +333,13 @@ private:
*/
bool itemPassesFilter( EDA_ITEM* aItem );
/**
* In general we don't want to select both a parent and any of it's children. This includes
* both symbols and their items, and groups and their members.
*/
void filterCollectorForHierarchy( SCH_COLLECTOR& aCollector, bool aMultiselect ) const;
void filterCollectedItems( SCH_COLLECTOR& aCollector, bool aMultiSelect );
///< Set up handlers for various events.
void setTransitions() override;
@ -329,6 +354,10 @@ private:
int m_unit; // Fixed unit filter (for symbol editor)
int m_bodyStyle; // Fixed DeMorgan filter (for symbol editor)
SCH_GROUP* m_enteredGroup; // If non-null, selections are limited to
// members of this group
KIGFX::VIEW_GROUP m_enteredGroupOverlay; // Overlay for the entered group's frame.
SCH_SELECTION_FILTER_OPTIONS m_filter;
SCH_TABLECELL* m_previous_first_cell; // First selected cell for shift+click selection range

Loading…
Cancel
Save