Cross-probing/selection for multiple items (PCB -> SCH)
Fixes https://gitlab.com/kicad/code/kicad/issues/10469
This commit is contained in:
parent
8757b3f98a
commit
3a76d42630
|
@ -667,6 +667,7 @@ TOOL_ACTION ACTIONS::reportBug( "common.SuiteControl.reportBug",
|
|||
|
||||
// System-wide selection Events
|
||||
|
||||
const TOOL_EVENT EVENTS::PointSelectedEvent( TC_MESSAGE, TA_ACTION, "common.Interactive.pointSelected" );
|
||||
const TOOL_EVENT EVENTS::SelectedEvent( TC_MESSAGE, TA_ACTION, "common.Interactive.selected" );
|
||||
const TOOL_EVENT EVENTS::UnselectedEvent( TC_MESSAGE, TA_ACTION, "common.Interactive.unselected" );
|
||||
const TOOL_EVENT EVENTS::ClearedEvent( TC_MESSAGE, TA_ACTION, "common.Interactive.cleared" );
|
||||
|
|
|
@ -37,7 +37,10 @@ void SELECTION::Add( EDA_ITEM* aItem )
|
|||
ITER i = std::lower_bound( m_items.begin(), m_items.end(), aItem );
|
||||
|
||||
if( i == m_items.end() || *i > aItem )
|
||||
{
|
||||
m_items.insert( i, aItem );
|
||||
m_lastAddedItem = aItem;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
@ -46,7 +49,12 @@ void SELECTION::Remove( EDA_ITEM* aItem )
|
|||
ITER i = std::lower_bound( m_items.begin(), m_items.end(), aItem );
|
||||
|
||||
if( !( i == m_items.end() || *i > aItem ) )
|
||||
{
|
||||
m_items.erase( i );
|
||||
|
||||
if( aItem == m_lastAddedItem )
|
||||
m_lastAddedItem = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -224,7 +224,8 @@ bool TOOL_EVENT::IsSelectionEvent() const
|
|||
{
|
||||
return Matches( EVENTS::ClearedEvent )
|
||||
|| Matches( EVENTS::UnselectedEvent )
|
||||
|| Matches( EVENTS::SelectedEvent );
|
||||
|| Matches( EVENTS::SelectedEvent )
|
||||
|| Matches( EVENTS::PointSelectedEvent );
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -31,6 +31,7 @@
|
|||
#include <kiface_base.h>
|
||||
#include <kiplatform/app.h>
|
||||
#include <kiway_express.h>
|
||||
#include <string_utils.h>
|
||||
#include <project/project_file.h>
|
||||
#include <macros.h>
|
||||
#include <netlist_reader/netlist_reader.h>
|
||||
|
@ -417,8 +418,8 @@ void CVPCB_MAINFRAME::doCloseWindow()
|
|||
|
||||
m_modified = false;
|
||||
|
||||
// clear highlight symbol in schematic:
|
||||
SendMessageToEESCHEMA( true );
|
||||
// clear symbol selection in schematic:
|
||||
SendComponentSelectionToSch( true );
|
||||
}
|
||||
|
||||
|
||||
|
@ -708,7 +709,7 @@ void CVPCB_MAINFRAME::refreshAfterSymbolSearch( COMPONENT* aSymbol )
|
|||
}
|
||||
}
|
||||
|
||||
SendMessageToEESCHEMA();
|
||||
SendComponentSelectionToSch();
|
||||
DisplayStatus();
|
||||
}
|
||||
|
||||
|
@ -881,22 +882,23 @@ bool CVPCB_MAINFRAME::LoadFootprintFiles()
|
|||
}
|
||||
|
||||
|
||||
void CVPCB_MAINFRAME::SendMessageToEESCHEMA( bool aClearHighligntOnly )
|
||||
void CVPCB_MAINFRAME::SendComponentSelectionToSch( bool aClearSelectionOnly )
|
||||
{
|
||||
if( m_netlist.IsEmpty() )
|
||||
return;
|
||||
|
||||
// clear highlight of previously selected symbols (if any):
|
||||
// Selecting a non existing symbol clears any previously highlighted symbols
|
||||
std::string packet = "$CLEAR: \"HIGHLIGHTED\"";
|
||||
std::string command = "$SELECT: ";
|
||||
|
||||
if( aClearSelectionOnly )
|
||||
{
|
||||
// Sending an empty list means clearing the selection.
|
||||
if( Kiface().IsSingle() )
|
||||
SendCommand( MSG_TO_SCH, packet );
|
||||
SendCommand( MSG_TO_SCH, command );
|
||||
else
|
||||
Kiway().ExpressMail( FRAME_SCH, MAIL_CROSS_PROBE, packet, this );
|
||||
Kiway().ExpressMail( FRAME_SCH, MAIL_SELECTION, command, this );
|
||||
|
||||
if( aClearHighligntOnly )
|
||||
return;
|
||||
}
|
||||
|
||||
int selection = m_symbolsListBox->GetSelection();
|
||||
|
||||
|
@ -906,15 +908,15 @@ void CVPCB_MAINFRAME::SendMessageToEESCHEMA( bool aClearHighligntOnly )
|
|||
if( m_netlist.GetComponent( selection ) == nullptr )
|
||||
return;
|
||||
|
||||
// Now highlight the selected symbol:
|
||||
COMPONENT* symbol = m_netlist.GetComponent( selection );
|
||||
// Now select the corresponding symbol on the schematic:
|
||||
wxString ref = m_netlist.GetComponent( selection )->GetReference();
|
||||
|
||||
packet = std::string( "$PART: \"" ) + TO_UTF8( symbol->GetReference() ) + "\"";
|
||||
command += wxT( "F" ) + EscapeString( ref, CTX_IPC );
|
||||
|
||||
if( Kiface().IsSingle() )
|
||||
SendCommand( MSG_TO_SCH, packet );
|
||||
SendCommand( MSG_TO_SCH, command );
|
||||
else
|
||||
Kiway().ExpressMail( FRAME_SCH, MAIL_CROSS_PROBE, packet, this );
|
||||
Kiway().ExpressMail( FRAME_SCH, MAIL_SELECTION, command, this );
|
||||
}
|
||||
|
||||
|
||||
|
@ -1069,7 +1071,7 @@ void CVPCB_MAINFRAME::SetSelectedComponent( int aIndex, bool aSkipUpdate )
|
|||
{
|
||||
m_symbolsListBox->DeselectAll();
|
||||
m_symbolsListBox->SetSelection( aIndex );
|
||||
SendMessageToEESCHEMA();
|
||||
SendComponentSelectionToSch();
|
||||
}
|
||||
|
||||
m_skipComponentSelect = false;
|
||||
|
|
|
@ -250,10 +250,10 @@ public:
|
|||
* Commands are:
|
||||
* $PART: "reference" put cursor on component anchor
|
||||
*
|
||||
* @param aClearHighligntOnly use true if the message to send is only "clear highlight"
|
||||
* @param aClearSelectionOnly use true if the message to send is only "clear clear selection"
|
||||
* (used when exiting CvPcb)
|
||||
*/
|
||||
void SendMessageToEESCHEMA( bool aClearHighligntOnly = false );
|
||||
void SendComponentSelectionToSch( bool aClearSelectionOnly = false );
|
||||
|
||||
/**
|
||||
* Get the selected component from the component listbox.
|
||||
|
|
|
@ -27,7 +27,9 @@
|
|||
#include <kiway_express.h>
|
||||
#include <eda_dde.h>
|
||||
#include <connection_graph.h>
|
||||
#include <sch_sheet.h>
|
||||
#include <sch_symbol.h>
|
||||
#include <sch_reference_list.h>
|
||||
#include <schematic.h>
|
||||
#include <reporter.h>
|
||||
#include <string_utils.h>
|
||||
|
@ -134,111 +136,13 @@ SCH_ITEM* SCH_EDITOR_CONTROL::FindSymbolAndItem( const wxString* aPath, const wx
|
|||
if( crossProbingSettings.zoom_to_fit )
|
||||
{
|
||||
EDA_RECT bbox = symbol->GetBoundingBox();
|
||||
VECTOR2I bbSize = bbox.Inflate( bbox.GetWidth() * 0.2f ).GetSize();
|
||||
VECTOR2D screenSize = getView()->GetViewport().GetSize();
|
||||
|
||||
// This code tries to come up with a zoom factor that doesn't simply zoom in
|
||||
// to the cross probed symbol, but instead shows a reasonable amount of the
|
||||
// circuit around it to provide context. This reduces or eliminates the need
|
||||
// to manually change the zoom because it's too close.
|
||||
|
||||
// Using the default text height as a constant to compare against, use the
|
||||
// height of the bounding box of visible items for a footprint to figure out
|
||||
// if this is a big symbol (like a processor) or a small symbol (like a resistor).
|
||||
// This ratio is not useful by itself as a scaling factor. It must be "bent" to
|
||||
// provide good scaling at varying symbol sizes. Bigger symbols need less
|
||||
// scaling than small ones.
|
||||
double currTextHeight = Mils2iu( DEFAULT_TEXT_SIZE );
|
||||
|
||||
double compRatio = bbSize.y / currTextHeight; // Ratio of symbol to text height
|
||||
double compRatioBent = 1.0;
|
||||
|
||||
// LUT to scale zoom ratio to provide reasonable schematic context. Must work
|
||||
// with symbols of varying sizes (e.g. 0402 package and 200 pin BGA).
|
||||
// "first" is used as the input and "second" as the output
|
||||
//
|
||||
// "first" = compRatio (symbol height / default text height)
|
||||
// "second" = Amount to scale ratio by
|
||||
std::vector<std::pair<double, double>> lut
|
||||
{
|
||||
{1.25, 16}, // 32
|
||||
{2.5, 12}, //24
|
||||
{5, 8}, // 16
|
||||
{6, 6}, //
|
||||
{10, 4}, //8
|
||||
{20, 2}, //4
|
||||
{40, 1.5}, // 2
|
||||
{100, 1}
|
||||
};
|
||||
|
||||
std::vector<std::pair<double, double>>::iterator it;
|
||||
|
||||
// Large symbol default is last LUT entry (1:1).
|
||||
compRatioBent = lut.back().second;
|
||||
|
||||
// Use LUT to do linear interpolation of "compRatio" within "first", then
|
||||
// use that result to linearly interpolate "second" which gives the scaling
|
||||
// factor needed.
|
||||
if( compRatio >= lut.front().first )
|
||||
{
|
||||
for( it = lut.begin(); it < lut.end() - 1; it++ )
|
||||
{
|
||||
if( it->first <= compRatio && next( it )->first >= compRatio )
|
||||
{
|
||||
|
||||
double diffx = compRatio - it->first;
|
||||
double diffn = next( it )->first - it->first;
|
||||
|
||||
compRatioBent = it->second
|
||||
+ ( next( it )->second - it->second ) * diffx / diffn;
|
||||
break; // We have our interpolated value
|
||||
}
|
||||
}
|
||||
m_toolMgr->GetTool<EE_SELECTION_TOOL>()->ZoomFitCrossProbeBBox( bbox );
|
||||
}
|
||||
|
||||
if( pin )
|
||||
m_frame->FocusOnItem( pin );
|
||||
else
|
||||
{
|
||||
compRatioBent = lut.front().second; // Small symbol default is first entry
|
||||
}
|
||||
|
||||
// This is similar to the original KiCad code that scaled the zoom to make sure
|
||||
// symbols were visible on screen. It's simply a ratio of screen size to
|
||||
// symbol size, and its job is to zoom in to make the component fullscreen.
|
||||
// Earlier in the code the symbol BBox is given a 20% margin to add some
|
||||
// breathing room. We compare the height of this enlarged symbol bbox to the
|
||||
// default text height. If a symbol will end up with the sides clipped, we
|
||||
// adjust later to make sure it fits on screen.
|
||||
screenSize.x = std::max( 10.0, screenSize.x );
|
||||
screenSize.y = std::max( 10.0, screenSize.y );
|
||||
double ratio = std::max( -1.0, fabs( bbSize.y / screenSize.y ) );
|
||||
|
||||
// Original KiCad code for how much to scale the zoom
|
||||
double kicadRatio = std::max( fabs( bbSize.x / screenSize.x ),
|
||||
fabs( bbSize.y / screenSize.y ) );
|
||||
|
||||
// If the width of the part we're probing is bigger than what the screen width
|
||||
// will be after the zoom, then punt and use the KiCad zoom algorithm since it
|
||||
// guarantees the part's width will be encompassed within the screen.
|
||||
if( bbSize.x > screenSize.x * ratio * compRatioBent )
|
||||
{
|
||||
// Use standard KiCad zoom for parts too wide to fit on screen/
|
||||
ratio = kicadRatio;
|
||||
compRatioBent = 1.0; // Reset so we don't modify the "KiCad" ratio
|
||||
wxLogTrace( "CROSS_PROBE_SCALE",
|
||||
"Part TOO WIDE for screen. Using normal KiCad zoom ratio: %1.5f",
|
||||
ratio );
|
||||
}
|
||||
|
||||
// Now that "compRatioBent" holds our final scaling factor we apply it to the
|
||||
// original fullscreen zoom ratio to arrive at the final ratio itself.
|
||||
ratio *= compRatioBent;
|
||||
|
||||
bool alwaysZoom = false; // DEBUG - allows us to minimize zooming or not
|
||||
|
||||
// Try not to zoom on every cross-probe; it gets very noisy
|
||||
if( ( ratio < 0.5 || ratio > 1.0 ) || alwaysZoom )
|
||||
getView()->SetScale( getView()->GetScale() / ratio );
|
||||
}
|
||||
|
||||
m_frame->FocusOnItem( symbol );
|
||||
}
|
||||
}
|
||||
|
@ -273,18 +177,6 @@ SCH_ITEM* SCH_EDITOR_CONTROL::FindSymbolAndItem( const wxString* aPath, const wx
|
|||
|
||||
m_frame->SetStatusText( msg );
|
||||
|
||||
m_probingPcbToSch = true; // recursion guard
|
||||
|
||||
{
|
||||
// Clear any existing highlighting
|
||||
m_toolMgr->RunAction( EE_ACTIONS::clearSelection, true );
|
||||
|
||||
if( foundItem )
|
||||
m_toolMgr->RunAction( EE_ACTIONS::addItemToSel, true, foundItem );
|
||||
}
|
||||
|
||||
m_probingPcbToSch = false;
|
||||
|
||||
m_frame->GetCanvas()->Refresh();
|
||||
|
||||
return foundItem;
|
||||
|
@ -382,7 +274,7 @@ void SCH_EDIT_FRAME::ExecuteRemoteCommand( const char* cmdline )
|
|||
}
|
||||
|
||||
|
||||
void SCH_EDIT_FRAME::SendSelectItems( const std::deque<EDA_ITEM*>& aItems, bool aForce )
|
||||
void SCH_EDIT_FRAME::SendSelectItemsToPcb( const std::deque<EDA_ITEM*>& aItems, bool aForce )
|
||||
{
|
||||
std::set<wxString> parts;
|
||||
|
||||
|
@ -552,6 +444,375 @@ void SCH_EDIT_FRAME::SendCrossProbeClearHighlight()
|
|||
}
|
||||
|
||||
|
||||
bool findSymbolsAndPins(
|
||||
const SCHEMATIC& aSchematic, const SCH_SHEET_PATH& aSheetPath,
|
||||
std::unordered_map<wxString, std::vector<SCH_REFERENCE>>& aSyncSymMap,
|
||||
std::unordered_map<wxString, std::unordered_map<wxString, SCH_PIN*>>& aSyncPinMap,
|
||||
bool aRecursive = false )
|
||||
{
|
||||
if( aRecursive )
|
||||
{
|
||||
// Iterate over children
|
||||
for( const SCH_SHEET_PATH& candidate : aSchematic.GetSheets() )
|
||||
{
|
||||
if( candidate == aSheetPath || !candidate.IsContainedWithin( aSheetPath ) )
|
||||
continue;
|
||||
|
||||
findSymbolsAndPins( aSchematic, candidate, aSyncSymMap, aSyncPinMap, aRecursive );
|
||||
}
|
||||
}
|
||||
|
||||
SCH_REFERENCE_LIST references;
|
||||
|
||||
aSheetPath.GetSymbols( references, false, true );
|
||||
|
||||
for( unsigned ii = 0; ii < references.GetCount(); ii++ )
|
||||
{
|
||||
SCH_REFERENCE& schRef = references[ii];
|
||||
|
||||
if( schRef.IsSplitNeeded() )
|
||||
schRef.Split();
|
||||
|
||||
SCH_SYMBOL* symbol = schRef.GetSymbol();
|
||||
wxString refNum = schRef.GetRefNumber();
|
||||
wxString fullRef = schRef.GetRef() + refNum;
|
||||
|
||||
// Skip power symbols
|
||||
if( fullRef.StartsWith( "#" ) )
|
||||
continue;
|
||||
|
||||
// Unannotated symbols are not supported
|
||||
if( refNum.compare( "?" ) == 0 )
|
||||
continue;
|
||||
|
||||
// Look for whole footprint
|
||||
auto symMatchIt = aSyncSymMap.find( fullRef );
|
||||
|
||||
if( symMatchIt != aSyncSymMap.end() )
|
||||
{
|
||||
symMatchIt->second.emplace_back( schRef );
|
||||
|
||||
// Whole footprint was selected, no need to select pins
|
||||
continue;
|
||||
}
|
||||
|
||||
// Look for pins
|
||||
auto symPinMatchIt = aSyncPinMap.find( fullRef );
|
||||
|
||||
if( symPinMatchIt != aSyncPinMap.end() )
|
||||
{
|
||||
std::unordered_map<wxString, SCH_PIN*>& pinMap = symPinMatchIt->second;
|
||||
std::vector<SCH_PIN*> pinsOnSheet = symbol->GetPins( &aSheetPath );
|
||||
|
||||
for( SCH_PIN* pin : pinsOnSheet )
|
||||
{
|
||||
int pinUnit = pin->GetLibPin()->GetUnit();
|
||||
|
||||
if( pinUnit > 0 && pinUnit != schRef.GetUnit() )
|
||||
continue;
|
||||
|
||||
auto pinIt = pinMap.find( pin->GetNumber() );
|
||||
|
||||
if( pinIt != pinMap.end() )
|
||||
pinIt->second = pin;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
bool sheetContainsOnlyWantedItems(
|
||||
const SCHEMATIC& aSchematic, const SCH_SHEET_PATH& aSheetPath,
|
||||
std::unordered_map<wxString, std::vector<SCH_REFERENCE>>& aSyncSymMap,
|
||||
std::unordered_map<wxString, std::unordered_map<wxString, SCH_PIN*>>& aSyncPinMap,
|
||||
std::unordered_map<SCH_SHEET_PATH, bool>& aCache )
|
||||
{
|
||||
auto cacheIt = aCache.find( aSheetPath );
|
||||
|
||||
if( cacheIt != aCache.end() )
|
||||
return cacheIt->second;
|
||||
|
||||
// Iterate over children
|
||||
for( const SCH_SHEET_PATH& candidate : aSchematic.GetSheets() )
|
||||
{
|
||||
if( candidate == aSheetPath || !candidate.IsContainedWithin( aSheetPath ) )
|
||||
continue;
|
||||
|
||||
bool childRet = sheetContainsOnlyWantedItems( aSchematic, candidate, aSyncSymMap,
|
||||
aSyncPinMap, aCache );
|
||||
|
||||
if( !childRet )
|
||||
{
|
||||
aCache.emplace( aSheetPath, false );
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
SCH_REFERENCE_LIST references;
|
||||
aSheetPath.GetSymbols( references, false, true );
|
||||
|
||||
for( unsigned ii = 0; ii < references.GetCount(); ii++ )
|
||||
{
|
||||
SCH_REFERENCE& schRef = references[ii];
|
||||
|
||||
if( schRef.IsSplitNeeded() )
|
||||
schRef.Split();
|
||||
|
||||
wxString refNum = schRef.GetRefNumber();
|
||||
wxString fullRef = schRef.GetRef() + refNum;
|
||||
|
||||
// Skip power symbols
|
||||
if( fullRef.StartsWith( "#" ) )
|
||||
continue;
|
||||
|
||||
// Unannotated symbols are not supported
|
||||
if( refNum.compare( "?" ) == 0 )
|
||||
continue;
|
||||
|
||||
if( aSyncSymMap.find( fullRef ) == aSyncSymMap.end() )
|
||||
{
|
||||
aCache.emplace( aSheetPath, false );
|
||||
return false; // Some symbol is not wanted.
|
||||
}
|
||||
|
||||
if( aSyncPinMap.find( fullRef ) != aSyncPinMap.end() )
|
||||
{
|
||||
aCache.emplace( aSheetPath, false );
|
||||
return false; // Looking for specific pins, so can't be mapped
|
||||
}
|
||||
}
|
||||
|
||||
aCache.emplace( aSheetPath, true );
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
std::optional<std::tuple<SCH_SHEET_PATH, SCH_ITEM*, std::vector<SCH_ITEM*>>>
|
||||
findItemsFromSyncSelection( const SCHEMATIC& aSchematic, const std::string aSyncStr,
|
||||
bool aFocusOnFirst )
|
||||
{
|
||||
wxArrayString syncArray = wxStringTokenize( aSyncStr, "," );
|
||||
|
||||
std::unordered_map<wxString, std::vector<SCH_REFERENCE>> syncSymMap;
|
||||
std::unordered_map<wxString, std::unordered_map<wxString, SCH_PIN*>> syncPinMap;
|
||||
std::unordered_map<SCH_SHEET_PATH, double> symScores;
|
||||
std::unordered_map<SCH_SHEET_PATH, bool> fullyWantedCache;
|
||||
|
||||
std::optional<wxString> focusSymbol;
|
||||
std::optional<std::pair<wxString, wxString>> focusPin;
|
||||
std::unordered_map<SCH_SHEET_PATH, std::vector<SCH_ITEM*>> focusItemResults;
|
||||
|
||||
const SCH_SHEET_LIST allSheetsList = aSchematic.GetSheets();
|
||||
|
||||
// In orderedSheets, the current sheet comes first.
|
||||
SCH_SHEET_PATHS orderedSheets;
|
||||
orderedSheets.reserve( allSheetsList.size() );
|
||||
orderedSheets.push_back( aSchematic.CurrentSheet() );
|
||||
|
||||
for( const SCH_SHEET_PATH& sheetPath : allSheetsList )
|
||||
{
|
||||
if( sheetPath != aSchematic.CurrentSheet() )
|
||||
orderedSheets.push_back( sheetPath );
|
||||
}
|
||||
|
||||
// Init sync maps from the sync string
|
||||
for( int i = 0; i < syncArray.size(); i++ )
|
||||
{
|
||||
wxString syncEntry = syncArray[i];
|
||||
|
||||
if( syncEntry.empty() )
|
||||
continue;
|
||||
|
||||
wxString syncData = syncEntry.substr( 1 );
|
||||
|
||||
switch( syncEntry.GetChar( 0 ).GetValue() )
|
||||
{
|
||||
case 'F': // Select by footprint: F<Reference>
|
||||
{
|
||||
wxString symRef = UnescapeString( syncData );
|
||||
|
||||
if( aFocusOnFirst && ( i == 0 ) )
|
||||
focusSymbol = symRef;
|
||||
|
||||
syncSymMap[symRef] = std::vector<SCH_REFERENCE>();
|
||||
break;
|
||||
}
|
||||
case 'P': // Select by pad: P<Footprint reference>/<Pad number>
|
||||
{
|
||||
wxString symRef = UnescapeString( syncData.BeforeFirst( '/' ) );
|
||||
wxString padNum = UnescapeString( syncData.AfterFirst( '/' ) );
|
||||
|
||||
if( aFocusOnFirst && ( i == 0 ) )
|
||||
focusPin = std::make_pair( symRef, padNum );
|
||||
|
||||
syncPinMap[symRef][padNum] = nullptr;
|
||||
break;
|
||||
}
|
||||
default: break;
|
||||
}
|
||||
}
|
||||
|
||||
// Lambda definitions
|
||||
auto flattenSyncMaps = [&syncSymMap, &syncPinMap]() -> std::vector<SCH_ITEM*>
|
||||
{
|
||||
std::vector<SCH_ITEM*> allVec;
|
||||
|
||||
for( auto const& pairSym : syncSymMap )
|
||||
{
|
||||
for( const SCH_REFERENCE& ref : pairSym.second )
|
||||
{
|
||||
allVec.push_back( ref.GetSymbol() );
|
||||
}
|
||||
}
|
||||
|
||||
for( auto const& pairSym : syncPinMap )
|
||||
{
|
||||
for( auto const& pairPin : pairSym.second )
|
||||
{
|
||||
if( pairPin.second )
|
||||
allVec.push_back( pairPin.second );
|
||||
}
|
||||
}
|
||||
|
||||
return allVec;
|
||||
};
|
||||
|
||||
auto clearSyncMaps = [&syncSymMap, &syncPinMap]()
|
||||
{
|
||||
for( auto& pairSym : syncSymMap )
|
||||
{
|
||||
pairSym.second.clear();
|
||||
}
|
||||
|
||||
for( auto& pairSym : syncPinMap )
|
||||
{
|
||||
for( auto& pairPin : pairSym.second )
|
||||
{
|
||||
pairPin.second = nullptr;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
auto syncMapsValuesEmpty = [&syncSymMap, &syncPinMap]() -> bool
|
||||
{
|
||||
for( auto const& pairSym : syncSymMap )
|
||||
{
|
||||
if( pairSym.second.size() > 0 )
|
||||
return false;
|
||||
}
|
||||
|
||||
for( auto const& pairSym : syncPinMap )
|
||||
{
|
||||
for( auto const& pairPin : pairSym.second )
|
||||
{
|
||||
if( pairPin.second )
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
};
|
||||
|
||||
auto checkFocusItems = [&]( const SCH_SHEET_PATH& aSheetPath )
|
||||
{
|
||||
if( focusSymbol )
|
||||
{
|
||||
auto findIt = syncSymMap.find( *focusSymbol );
|
||||
if( findIt != syncSymMap.end() )
|
||||
{
|
||||
if( findIt->second.size() > 0 )
|
||||
{
|
||||
focusItemResults[aSheetPath].push_back( findIt->second.front().GetSymbol() );
|
||||
}
|
||||
}
|
||||
}
|
||||
else if( focusPin )
|
||||
{
|
||||
auto findIt = syncPinMap.find( focusPin->first );
|
||||
if( findIt != syncPinMap.end() )
|
||||
{
|
||||
if( findIt->second[focusPin->second] )
|
||||
{
|
||||
focusItemResults[aSheetPath].push_back( findIt->second[focusPin->second] );
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
auto makeRetForSheet = [&]( const SCH_SHEET_PATH& aSheet, SCH_ITEM* aFocusItem )
|
||||
{
|
||||
clearSyncMaps();
|
||||
|
||||
// Fill sync maps
|
||||
findSymbolsAndPins( aSchematic, aSheet, syncSymMap, syncPinMap );
|
||||
std::vector<SCH_ITEM*> itemsVector = flattenSyncMaps();
|
||||
|
||||
// Add fully wanted sheets to vector
|
||||
for( SCH_ITEM* item : aSheet.LastScreen()->Items().OfType( SCH_SHEET_T ) )
|
||||
{
|
||||
KIID_PATH kiidPath = aSheet.Path();
|
||||
kiidPath.push_back( item->m_Uuid );
|
||||
|
||||
std::optional<SCH_SHEET_PATH> subsheetPath =
|
||||
allSheetsList.GetSheetPathByKIIDPath( kiidPath );
|
||||
|
||||
if( !subsheetPath )
|
||||
continue;
|
||||
|
||||
if( sheetContainsOnlyWantedItems( aSchematic, *subsheetPath, syncSymMap, syncPinMap,
|
||||
fullyWantedCache ) )
|
||||
{
|
||||
itemsVector.push_back( item );
|
||||
}
|
||||
}
|
||||
|
||||
return std::make_tuple( aSheet, aFocusItem, itemsVector );
|
||||
};
|
||||
|
||||
if( aFocusOnFirst )
|
||||
{
|
||||
for( const SCH_SHEET_PATH& sheetPath : orderedSheets )
|
||||
{
|
||||
clearSyncMaps();
|
||||
|
||||
findSymbolsAndPins( aSchematic, sheetPath, syncSymMap, syncPinMap );
|
||||
|
||||
checkFocusItems( sheetPath );
|
||||
}
|
||||
|
||||
if( focusItemResults.size() > 0 )
|
||||
{
|
||||
for( const SCH_SHEET_PATH& sheetPath : orderedSheets )
|
||||
{
|
||||
auto vec = focusItemResults[sheetPath];
|
||||
|
||||
if( !vec.empty() )
|
||||
return makeRetForSheet( sheetPath, vec.front() );
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
for( const SCH_SHEET_PATH& sheetPath : orderedSheets )
|
||||
{
|
||||
clearSyncMaps();
|
||||
|
||||
findSymbolsAndPins( aSchematic, sheetPath, syncSymMap, syncPinMap );
|
||||
|
||||
if( !syncMapsValuesEmpty() )
|
||||
{
|
||||
// Something found on sheet
|
||||
return makeRetForSheet( sheetPath, nullptr );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
|
||||
void SCH_EDIT_FRAME::KiwayMailIn( KIWAY_EXPRESS& mail )
|
||||
{
|
||||
std::string& payload = mail.GetPayload();
|
||||
|
@ -562,6 +823,45 @@ void SCH_EDIT_FRAME::KiwayMailIn( KIWAY_EXPRESS& mail )
|
|||
ExecuteRemoteCommand( payload.c_str() );
|
||||
break;
|
||||
|
||||
case MAIL_SELECTION:
|
||||
if( !eeconfig()->m_CrossProbing.on_selection )
|
||||
break;
|
||||
|
||||
KI_FALLTHROUGH;
|
||||
|
||||
case MAIL_SELECTION_FORCE:
|
||||
{
|
||||
// $SELECT: 0,<spec1>,<spec2>,<spec3>
|
||||
// Try to select specified items.
|
||||
|
||||
// $SELECT: 1,<spec1>,<spec2>,<spec3>
|
||||
// Select and focus on <spec1> item, select other specified items that are on the same sheet.
|
||||
|
||||
std::string prefix = "$SELECT: ";
|
||||
|
||||
std::string paramStr = payload.substr( prefix.size() );
|
||||
std::string syncStr = paramStr.substr( 2 );
|
||||
|
||||
bool focusOnFirst = ( paramStr[0] == '1' );
|
||||
|
||||
std::optional<std::tuple<SCH_SHEET_PATH, SCH_ITEM*, std::vector<SCH_ITEM*>>> findRet =
|
||||
findItemsFromSyncSelection( Schematic(), syncStr, focusOnFirst );
|
||||
|
||||
if( findRet )
|
||||
{
|
||||
auto& [sheetPath, focusItem, items] = *findRet;
|
||||
|
||||
m_syncingPcbToSchSelection = true; // recursion guard
|
||||
|
||||
GetToolManager()->GetTool<EE_SELECTION_TOOL>()->SyncSelection( sheetPath, focusItem,
|
||||
items );
|
||||
|
||||
m_syncingPcbToSchSelection = false;
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
case MAIL_SCH_GET_NETLIST:
|
||||
{
|
||||
if( !payload.empty() )
|
||||
|
|
|
@ -120,6 +120,7 @@ SCH_EDIT_FRAME::SCH_EDIT_FRAME( KIWAY* aKiway, wxWindow* aParent ) :
|
|||
|
||||
m_showBorderAndTitleBlock = true; // true to show sheet references
|
||||
m_supportsAutoSave = true;
|
||||
m_syncingPcbToSchSelection = false;
|
||||
m_aboutTitle = _( "KiCad Schematic Editor" );
|
||||
|
||||
m_findReplaceDialog = nullptr;
|
||||
|
@ -1761,11 +1762,14 @@ void SCH_EDIT_FRAME::FocusOnItem( SCH_ITEM* aItem )
|
|||
}
|
||||
|
||||
if( aItem )
|
||||
{
|
||||
if( !aItem->IsBrightened() )
|
||||
{
|
||||
aItem->SetBrightened();
|
||||
|
||||
UpdateItem( aItem );
|
||||
lastBrightenedItemID = aItem->m_Uuid;
|
||||
}
|
||||
|
||||
FocusOnLocation( aItem->GetFocusPosition() );
|
||||
}
|
||||
|
|
|
@ -264,7 +264,7 @@ public:
|
|||
* @param aForce select the element in pcbnew whether or not the user has the select option chosen
|
||||
* This is used for when the eeschema user is using the cross-probe tool
|
||||
*/
|
||||
void SendSelectItems( const std::deque<EDA_ITEM*>& aElements, bool aForce );
|
||||
void SendSelectItemsToPcb( const std::deque<EDA_ITEM*>& aElements, bool aForce );
|
||||
|
||||
/**
|
||||
* Sends a net name to Pcbnew for highlighting
|
||||
|
@ -772,6 +772,8 @@ public:
|
|||
|
||||
void FocusOnItem( SCH_ITEM* aItem );
|
||||
|
||||
bool IsSyncingSelection() { return m_syncingPcbToSchSelection; }
|
||||
|
||||
/**
|
||||
* Update a schematic symbol from a LIB_SYMBOL.
|
||||
*
|
||||
|
@ -923,6 +925,8 @@ private:
|
|||
DIALOG_SCH_FIND* m_findReplaceDialog;
|
||||
|
||||
HIERARCHY_NAVIG_PANEL* m_hierarchy;
|
||||
|
||||
bool m_syncingPcbToSchSelection; // Recursion guard when synchronizing selection from PCB
|
||||
};
|
||||
|
||||
|
||||
|
|
|
@ -866,6 +866,18 @@ void SCH_SHEET_LIST::GetSheetsWithinPath( SCH_SHEET_PATHS& aSheets,
|
|||
}
|
||||
|
||||
|
||||
std::optional<SCH_SHEET_PATH> SCH_SHEET_LIST::GetSheetPathByKIIDPath( const KIID_PATH& aPath ) const
|
||||
{
|
||||
for( const SCH_SHEET_PATH& sheet : *this )
|
||||
{
|
||||
if( sheet.Path() == aPath )
|
||||
return SCH_SHEET_PATH( sheet );
|
||||
}
|
||||
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
|
||||
void SCH_SHEET_LIST::GetMultiUnitSymbols( SCH_MULTI_UNIT_REFERENCE_MAP &aRefList,
|
||||
bool aIncludePowerSymbols ) const
|
||||
{
|
||||
|
|
|
@ -32,8 +32,10 @@
|
|||
#define CLASS_DRAWSHEET_PATH_H
|
||||
|
||||
#include <map>
|
||||
#include <optional>
|
||||
|
||||
#include <kiid.h>
|
||||
#include <wx/string.h>
|
||||
|
||||
/**
|
||||
* A simple container for schematic symbol instance information.
|
||||
|
@ -506,6 +508,15 @@ public:
|
|||
*/
|
||||
void GetSheetsWithinPath( SCH_SHEET_PATHS& aSheets, const SCH_SHEET_PATH& aSheetPath ) const;
|
||||
|
||||
|
||||
/**
|
||||
* Finds a SCH_SHEET_PATH that matches the provided KIID_PATH.
|
||||
*
|
||||
* @param aPath The KIID_PATH to search for.
|
||||
*/
|
||||
std::optional<SCH_SHEET_PATH> GetSheetPathByKIIDPath( const KIID_PATH& aPath ) const;
|
||||
|
||||
|
||||
/**
|
||||
* Add a #SCH_REFERENCE_LIST object to \a aRefList for each same-reference set of
|
||||
* multi-unit parts in the list of sheets. The map key for each element will be the
|
||||
|
|
|
@ -110,6 +110,9 @@ TOOL_ACTION EE_ACTIONS::removeItemsFromSel( "eeschema.InteractiveSelection.Remov
|
|||
TOOL_ACTION EE_ACTIONS::clearSelection( "eeschema.InteractiveSelection.ClearSelection",
|
||||
AS_GLOBAL );
|
||||
|
||||
TOOL_ACTION EE_ACTIONS::syncSelection( "eeschema.InteractiveSelection.SyncSelection",
|
||||
AS_GLOBAL );
|
||||
|
||||
|
||||
// SYMBOL_EDITOR_CONTROL
|
||||
//
|
||||
|
|
|
@ -66,6 +66,9 @@ public:
|
|||
/// Runs a selection menu to select from a list of items
|
||||
static TOOL_ACTION selectionMenu;
|
||||
|
||||
/// Selection synchronization (PCB -> SCH)
|
||||
static TOOL_ACTION syncSelection;
|
||||
|
||||
// Locking
|
||||
static TOOL_ACTION toggleLock;
|
||||
static TOOL_ACTION lock;
|
||||
|
|
|
@ -338,6 +338,7 @@ void EE_INSPECTION_TOOL::setTransitions()
|
|||
Go( &EE_INSPECTION_TOOL::PrevMarker, EE_ACTIONS::prevMarker.MakeEvent() );
|
||||
Go( &EE_INSPECTION_TOOL::NextMarker, EE_ACTIONS::nextMarker.MakeEvent() );
|
||||
// See note 1:
|
||||
Go( &EE_INSPECTION_TOOL::CrossProbe, EVENTS::PointSelectedEvent );
|
||||
Go( &EE_INSPECTION_TOOL::CrossProbe, EVENTS::SelectedEvent );
|
||||
Go( &EE_INSPECTION_TOOL::ExcludeMarker, EE_ACTIONS::excludeMarker.MakeEvent() );
|
||||
|
||||
|
|
|
@ -1477,6 +1477,7 @@ void EE_POINT_EDITOR::rollbackFromUndo()
|
|||
|
||||
void EE_POINT_EDITOR::setTransitions()
|
||||
{
|
||||
Go( &EE_POINT_EDITOR::Main, EVENTS::PointSelectedEvent );
|
||||
Go( &EE_POINT_EDITOR::Main, EVENTS::SelectedEvent );
|
||||
Go( &EE_POINT_EDITOR::Main, ACTIONS::activatePointEditor.MakeEvent() );
|
||||
Go( &EE_POINT_EDITOR::addCorner, EE_ACTIONS::pointEditorAddCorner.MakeEvent() );
|
||||
|
|
|
@ -872,7 +872,7 @@ bool EE_SELECTION_TOOL::selectPoint( EE_COLLECTOR& aCollector, const VECTOR2I& a
|
|||
if( !aAdd && !aSubtract && !aExclusiveOr )
|
||||
ClearSelection();
|
||||
|
||||
bool anyAdded = false;
|
||||
int addedCount = 0;
|
||||
bool anySubtracted = false;
|
||||
|
||||
if( aCollector.GetCount() > 0 )
|
||||
|
@ -908,20 +908,25 @@ bool EE_SELECTION_TOOL::selectPoint( EE_COLLECTOR& aCollector, const VECTOR2I& a
|
|||
{
|
||||
aCollector[i]->SetFlags( flags );
|
||||
select( aCollector[i] );
|
||||
anyAdded = true;
|
||||
addedCount++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if( anyAdded )
|
||||
if( addedCount == 1 )
|
||||
{
|
||||
m_toolMgr->ProcessEvent( EVENTS::SelectedEvent );
|
||||
m_toolMgr->ProcessEvent( EVENTS::PointSelectedEvent );
|
||||
|
||||
if( aItem && aCollector.GetCount() == 1 )
|
||||
*aItem = aCollector[0];
|
||||
|
||||
return true;
|
||||
}
|
||||
else if( addedCount > 1 )
|
||||
{
|
||||
m_toolMgr->ProcessEvent( EVENTS::SelectedEvent );
|
||||
return true;
|
||||
}
|
||||
else if( anySubtracted )
|
||||
{
|
||||
m_toolMgr->ProcessEvent( EVENTS::UnselectedEvent );
|
||||
|
@ -1491,6 +1496,156 @@ int EE_SELECTION_TOOL::ClearSelection( const TOOL_EVENT& aEvent )
|
|||
}
|
||||
|
||||
|
||||
void EE_SELECTION_TOOL::ZoomFitCrossProbeBBox( EDA_RECT bbox )
|
||||
{
|
||||
if( bbox.GetWidth() == 0 )
|
||||
return;
|
||||
|
||||
bbox.Normalize();
|
||||
|
||||
VECTOR2I bbSize = bbox.Inflate( bbox.GetWidth() * 0.2f ).GetSize();
|
||||
VECTOR2D screenSize = getView()->GetViewport().GetSize();
|
||||
|
||||
// This code tries to come up with a zoom factor that doesn't simply zoom in
|
||||
// to the cross probed symbol, but instead shows a reasonable amount of the
|
||||
// circuit around it to provide context. This reduces or eliminates the need
|
||||
// to manually change the zoom because it's too close.
|
||||
|
||||
// Using the default text height as a constant to compare against, use the
|
||||
// height of the bounding box of visible items for a footprint to figure out
|
||||
// if this is a big symbol (like a processor) or a small symbol (like a resistor).
|
||||
// This ratio is not useful by itself as a scaling factor. It must be "bent" to
|
||||
// provide good scaling at varying symbol sizes. Bigger symbols need less
|
||||
// scaling than small ones.
|
||||
double currTextHeight = Mils2iu( DEFAULT_TEXT_SIZE );
|
||||
|
||||
double compRatio = bbSize.y / currTextHeight; // Ratio of symbol to text height
|
||||
double compRatioBent = 1.0;
|
||||
|
||||
// LUT to scale zoom ratio to provide reasonable schematic context. Must work
|
||||
// with symbols of varying sizes (e.g. 0402 package and 200 pin BGA).
|
||||
// "first" is used as the input and "second" as the output
|
||||
//
|
||||
// "first" = compRatio (symbol height / default text height)
|
||||
// "second" = Amount to scale ratio by
|
||||
std::vector<std::pair<double, double>> lut{ { 1.25, 16 }, // 32
|
||||
{ 2.5, 12 }, //24
|
||||
{ 5, 8 }, // 16
|
||||
{ 6, 6 }, //
|
||||
{ 10, 4 }, //8
|
||||
{ 20, 2 }, //4
|
||||
{ 40, 1.5 }, // 2
|
||||
{ 100, 1 } };
|
||||
|
||||
std::vector<std::pair<double, double>>::iterator it;
|
||||
|
||||
// Large symbol default is last LUT entry (1:1).
|
||||
compRatioBent = lut.back().second;
|
||||
|
||||
// Use LUT to do linear interpolation of "compRatio" within "first", then
|
||||
// use that result to linearly interpolate "second" which gives the scaling
|
||||
// factor needed.
|
||||
if( compRatio >= lut.front().first )
|
||||
{
|
||||
for( it = lut.begin(); it < lut.end() - 1; it++ )
|
||||
{
|
||||
if( it->first <= compRatio && next( it )->first >= compRatio )
|
||||
{
|
||||
double diffx = compRatio - it->first;
|
||||
double diffn = next( it )->first - it->first;
|
||||
|
||||
compRatioBent = it->second + ( next( it )->second - it->second ) * diffx / diffn;
|
||||
break; // We have our interpolated value
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
compRatioBent = lut.front().second; // Small symbol default is first entry
|
||||
}
|
||||
|
||||
// This is similar to the original KiCad code that scaled the zoom to make sure
|
||||
// symbols were visible on screen. It's simply a ratio of screen size to
|
||||
// symbol size, and its job is to zoom in to make the component fullscreen.
|
||||
// Earlier in the code the symbol BBox is given a 20% margin to add some
|
||||
// breathing room. We compare the height of this enlarged symbol bbox to the
|
||||
// default text height. If a symbol will end up with the sides clipped, we
|
||||
// adjust later to make sure it fits on screen.
|
||||
screenSize.x = std::max( 10.0, screenSize.x );
|
||||
screenSize.y = std::max( 10.0, screenSize.y );
|
||||
double ratio = std::max( -1.0, fabs( bbSize.y / screenSize.y ) );
|
||||
|
||||
// Original KiCad code for how much to scale the zoom
|
||||
double kicadRatio =
|
||||
std::max( fabs( bbSize.x / screenSize.x ), fabs( bbSize.y / screenSize.y ) );
|
||||
|
||||
// If the width of the part we're probing is bigger than what the screen width
|
||||
// will be after the zoom, then punt and use the KiCad zoom algorithm since it
|
||||
// guarantees the part's width will be encompassed within the screen.
|
||||
if( bbSize.x > screenSize.x * ratio * compRatioBent )
|
||||
{
|
||||
// Use standard KiCad zoom for parts too wide to fit on screen/
|
||||
ratio = kicadRatio;
|
||||
compRatioBent = 1.0; // Reset so we don't modify the "KiCad" ratio
|
||||
wxLogTrace( "CROSS_PROBE_SCALE",
|
||||
"Part TOO WIDE for screen. Using normal KiCad zoom ratio: %1.5f", ratio );
|
||||
}
|
||||
|
||||
// Now that "compRatioBent" holds our final scaling factor we apply it to the
|
||||
// original fullscreen zoom ratio to arrive at the final ratio itself.
|
||||
ratio *= compRatioBent;
|
||||
|
||||
bool alwaysZoom = false; // DEBUG - allows us to minimize zooming or not
|
||||
|
||||
// Try not to zoom on every cross-probe; it gets very noisy
|
||||
if( ( ratio < 0.5 || ratio > 1.0 ) || alwaysZoom )
|
||||
getView()->SetScale( getView()->GetScale() / ratio );
|
||||
}
|
||||
|
||||
|
||||
int EE_SELECTION_TOOL::SyncSelection( std::optional<SCH_SHEET_PATH> targetSheetPath,
|
||||
SCH_ITEM* focusItem, std::vector<SCH_ITEM*> items )
|
||||
{
|
||||
SCH_EDIT_FRAME* editFrame = dynamic_cast<SCH_EDIT_FRAME*>( m_frame );
|
||||
|
||||
if( !editFrame || m_isSymbolEditor || m_isSymbolViewer )
|
||||
return 0;
|
||||
|
||||
if( targetSheetPath && targetSheetPath != editFrame->Schematic().CurrentSheet() )
|
||||
{
|
||||
editFrame->Schematic().SetCurrentSheet( *targetSheetPath );
|
||||
editFrame->DisplayCurrentSheet();
|
||||
}
|
||||
|
||||
ClearSelection( items.size() > 0 ? true /*quiet mode*/ : false );
|
||||
|
||||
// Perform individual selection of each item before processing the event.
|
||||
for( SCH_ITEM* item : items )
|
||||
select( item );
|
||||
|
||||
EDA_RECT bbox = m_selection.GetBoundingBox();
|
||||
|
||||
if( bbox.GetWidth() != 0 && bbox.GetHeight() != 0 )
|
||||
{
|
||||
if( m_frame->eeconfig()->m_CrossProbing.center_on_items )
|
||||
{
|
||||
if( m_frame->eeconfig()->m_CrossProbing.zoom_to_fit )
|
||||
ZoomFitCrossProbeBBox( bbox );
|
||||
|
||||
editFrame->FocusOnItem( focusItem );
|
||||
|
||||
if( !focusItem )
|
||||
editFrame->FocusOnLocation( bbox.Centre() );
|
||||
}
|
||||
}
|
||||
|
||||
if( m_selection.Size() > 0 )
|
||||
m_toolMgr->ProcessEvent( EVENTS::SelectedEvent );
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
void EE_SELECTION_TOOL::RebuildSelection()
|
||||
{
|
||||
m_selection.Clear();
|
||||
|
@ -1604,7 +1759,7 @@ bool EE_SELECTION_TOOL::Selectable( const EDA_ITEM* aItem, const VECTOR2I* aPos,
|
|||
}
|
||||
|
||||
|
||||
void EE_SELECTION_TOOL::ClearSelection()
|
||||
void EE_SELECTION_TOOL::ClearSelection( bool aQuietMode )
|
||||
{
|
||||
if( m_selection.Empty() )
|
||||
return;
|
||||
|
@ -1618,8 +1773,11 @@ void EE_SELECTION_TOOL::ClearSelection()
|
|||
m_selection.ClearReferencePoint();
|
||||
|
||||
// Inform other potentially interested tools
|
||||
if( !aQuietMode )
|
||||
{
|
||||
m_toolMgr->ProcessEvent( EVENTS::ClearedEvent );
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void EE_SELECTION_TOOL::select( EDA_ITEM* aItem )
|
||||
|
|
|
@ -73,6 +73,9 @@ public:
|
|||
|
||||
void OnIdle( wxIdleEvent& aEvent );
|
||||
|
||||
///< Zoom the screen to fit the bounding box for cross probing/selection sync.
|
||||
void ZoomFitCrossProbeBBox( EDA_RECT bbox );
|
||||
|
||||
/**
|
||||
* @return the set of currently selected items.
|
||||
*/
|
||||
|
@ -135,7 +138,7 @@ public:
|
|||
///< Select all visible items in sheet
|
||||
int SelectAll( const TOOL_EVENT& aEvent );
|
||||
|
||||
void ClearSelection();
|
||||
void ClearSelection( bool aQuietMode = false );
|
||||
|
||||
/**
|
||||
* Check conditions for an item to be selected.
|
||||
|
@ -170,6 +173,11 @@ public:
|
|||
bool CollectHits( EE_COLLECTOR& aCollector, const VECTOR2I& aWhere,
|
||||
const std::vector<KICAD_T>& aScanTypes = { SCH_LOCATE_ANY_T } );
|
||||
|
||||
///< Set selection to items passed by parameter.
|
||||
///< Zooms to fit, if enabled.
|
||||
int SyncSelection( std::optional<SCH_SHEET_PATH> targetSheetPath, SCH_ITEM* focusItem,
|
||||
std::vector<SCH_ITEM*> items );
|
||||
|
||||
protected:
|
||||
SELECTION& selection() override { return m_selection; }
|
||||
|
||||
|
|
|
@ -716,14 +716,14 @@ int SCH_EDITOR_CONTROL::ExplicitCrossProbeToPcb( const TOOL_EVENT& aEvent )
|
|||
void SCH_EDITOR_CONTROL::doCrossProbeSchToPcb( const TOOL_EVENT& aEvent, bool aForce )
|
||||
{
|
||||
// Don't get in an infinite loop SCH -> PCB -> SCH -> PCB -> SCH -> ...
|
||||
if( m_probingPcbToSch )
|
||||
if( m_probingPcbToSch || m_frame->IsSyncingSelection() )
|
||||
return;
|
||||
|
||||
EE_SELECTION_TOOL* selTool = m_toolMgr->GetTool<EE_SELECTION_TOOL>();
|
||||
|
||||
EE_SELECTION& selection = aForce ? selTool->RequestSelection() : selTool->GetSelection();
|
||||
|
||||
m_frame->SendSelectItems( selection.GetItems(), aForce );
|
||||
m_frame->SendSelectItemsToPcb( selection.GetItems(), aForce );
|
||||
}
|
||||
|
||||
|
||||
|
@ -2337,6 +2337,7 @@ void SCH_EDITOR_CONTROL::setTransitions()
|
|||
Go( &SCH_EDITOR_CONTROL::UpdateFind, ACTIONS::updateFind.MakeEvent() );
|
||||
Go( &SCH_EDITOR_CONTROL::UpdateFind, EVENTS::SelectedItemsModified );
|
||||
|
||||
Go( &SCH_EDITOR_CONTROL::CrossProbeToPcb, EVENTS::PointSelectedEvent );
|
||||
Go( &SCH_EDITOR_CONTROL::CrossProbeToPcb, EVENTS::SelectedEvent );
|
||||
Go( &SCH_EDITOR_CONTROL::CrossProbeToPcb, EVENTS::UnselectedEvent );
|
||||
Go( &SCH_EDITOR_CONTROL::CrossProbeToPcb, EVENTS::ClearedEvent );
|
||||
|
|
|
@ -149,7 +149,7 @@ public:
|
|||
void AssignFootprints( const std::string& aChangedSetOfReferences );
|
||||
|
||||
/**
|
||||
* Find a symbol in the schematic and an item in this symbol.
|
||||
* Find a symbol in the schematic and an item in this symbol and select it.
|
||||
*
|
||||
* @param aPath The symbol path to find. Pass nullptr to search by aReference.
|
||||
* @param aReference The symbol reference designator to find, or to display in
|
||||
|
@ -222,7 +222,7 @@ private:
|
|||
wxFindReplaceData& aData );
|
||||
|
||||
private:
|
||||
bool m_probingPcbToSch; // Recursion guard when cross-probing to PcbNew
|
||||
bool m_probingPcbToSch; // Recursion guard when cross-probing to schematic editor
|
||||
EDA_ITEM* m_pickerItem; // Current item for picker highlighting.
|
||||
|
||||
// Temporary storage location for Duplicate action
|
||||
|
|
|
@ -37,7 +37,7 @@
|
|||
enum MAIL_T
|
||||
{
|
||||
MAIL_CROSS_PROBE, // PCB<->SCH, CVPCB->SCH cross-probing.
|
||||
MAIL_SELECTION, // SCH->PCB selection synchronization.
|
||||
MAIL_SELECTION, // SCH<->PCB selection synchronization.
|
||||
MAIL_SELECTION_FORCE, // Explicit selection of SCH->PCB selection synchronization.
|
||||
MAIL_ASSIGN_FOOTPRINTS, // CVPCB->SCH footprint stuffing
|
||||
MAIL_SCH_SAVE, // CVPCB->SCH save the schematic
|
||||
|
|
|
@ -198,6 +198,7 @@ public:
|
|||
class EVENTS
|
||||
{
|
||||
public:
|
||||
const static TOOL_EVENT PointSelectedEvent;
|
||||
const static TOOL_EVENT SelectedEvent;
|
||||
const static TOOL_EVENT UnselectedEvent;
|
||||
const static TOOL_EVENT ClearedEvent;
|
||||
|
|
|
@ -42,6 +42,7 @@ public:
|
|||
KIGFX::VIEW_GROUP::VIEW_GROUP()
|
||||
{
|
||||
m_isHover = false;
|
||||
m_lastAddedItem = nullptr;
|
||||
}
|
||||
|
||||
SELECTION( const SELECTION& aOther ) :
|
||||
|
@ -49,12 +50,14 @@ public:
|
|||
{
|
||||
m_items = aOther.m_items;
|
||||
m_isHover = aOther.m_isHover;
|
||||
m_lastAddedItem = aOther.m_lastAddedItem;
|
||||
}
|
||||
|
||||
SELECTION& operator= ( const SELECTION& aOther )
|
||||
{
|
||||
m_items = aOther.m_items;
|
||||
m_isHover = aOther.m_isHover;
|
||||
m_lastAddedItem = aOther.m_lastAddedItem;
|
||||
return *this;
|
||||
}
|
||||
|
||||
|
@ -111,6 +114,11 @@ public:
|
|||
return m_items;
|
||||
}
|
||||
|
||||
EDA_ITEM* GetLastAddedItem() const
|
||||
{
|
||||
return m_lastAddedItem;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a copy of this selection of items sorted by their X then Y position.
|
||||
*
|
||||
|
@ -257,6 +265,7 @@ public:
|
|||
protected:
|
||||
OPT<VECTOR2I> m_referencePoint;
|
||||
std::deque<EDA_ITEM*> m_items;
|
||||
EDA_ITEM* m_lastAddedItem;
|
||||
bool m_isHover;
|
||||
|
||||
// mute hidden overloaded virtual function warnings
|
||||
|
|
|
@ -36,6 +36,7 @@
|
|||
#include <footprint.h>
|
||||
#include <pad.h>
|
||||
#include <pcb_track.h>
|
||||
#include <pcb_group.h>
|
||||
#include <zone.h>
|
||||
#include <collectors.h>
|
||||
#include <eda_dde.h>
|
||||
|
@ -221,11 +222,11 @@ void PCB_EDIT_FRAME::ExecuteRemoteCommand( const char* cmdline )
|
|||
renderSettings->SetHighlight( false );
|
||||
}
|
||||
|
||||
if( crossProbingSettings.center_on_items && bbox.GetWidth() > 0 && bbox.GetHeight() > 0 )
|
||||
if( crossProbingSettings.center_on_items && bbox.GetWidth() != 0 && bbox.GetHeight() != 0 )
|
||||
{
|
||||
if( crossProbingSettings.zoom_to_fit )
|
||||
{
|
||||
GetToolManager()->GetTool<PCB_SELECTION_TOOL>()->zoomFitCrossProbeBBox( bbox );
|
||||
GetToolManager()->GetTool<PCB_SELECTION_TOOL>()->ZoomFitCrossProbeBBox( bbox );
|
||||
}
|
||||
|
||||
FocusOnLocation( (wxPoint) bbox.Centre() );
|
||||
|
@ -293,9 +294,108 @@ std::string FormatProbeItem( BOARD_ITEM* aItem )
|
|||
}
|
||||
|
||||
|
||||
void PCB_EDIT_FRAME::SendMessageToEESCHEMA( BOARD_ITEM* aSyncItem )
|
||||
template <typename ItemContainer>
|
||||
void collectItemsForSyncParts( ItemContainer& aItems, std::set<wxString>& parts )
|
||||
{
|
||||
std::string packet = FormatProbeItem( aSyncItem );
|
||||
for( EDA_ITEM* item : aItems )
|
||||
{
|
||||
switch( item->Type() )
|
||||
{
|
||||
case PCB_GROUP_T:
|
||||
{
|
||||
PCB_GROUP* group = static_cast<PCB_GROUP*>( item );
|
||||
|
||||
collectItemsForSyncParts( group->GetItems(), parts );
|
||||
|
||||
break;
|
||||
}
|
||||
case PCB_FOOTPRINT_T:
|
||||
{
|
||||
FOOTPRINT* footprint = static_cast<FOOTPRINT*>( item );
|
||||
wxString ref = footprint->GetReference();
|
||||
|
||||
parts.emplace( wxT( "F" ) + EscapeString( ref, CTX_IPC ) );
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
case PCB_PAD_T:
|
||||
{
|
||||
PAD* pad = static_cast<PAD*>( item );
|
||||
FOOTPRINT* footprint = static_cast<FOOTPRINT*>( pad->GetParentFootprint() );
|
||||
wxString ref = footprint->GetReference();
|
||||
|
||||
parts.emplace( wxT( "P" ) + EscapeString( ref, CTX_IPC ) + wxT( "/" )
|
||||
+ EscapeString( pad->GetNumber(), CTX_IPC ) );
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
default: break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void PCB_EDIT_FRAME::SendSelectItemsToSch( const std::deque<EDA_ITEM*>& aItems,
|
||||
EDA_ITEM* aFocusItem, bool aForce )
|
||||
{
|
||||
std::string command = "$SELECT: ";
|
||||
|
||||
if( aFocusItem )
|
||||
{
|
||||
std::deque<EDA_ITEM*> focusItems = { aFocusItem };
|
||||
std::set<wxString> focusParts;
|
||||
collectItemsForSyncParts( focusItems, focusParts );
|
||||
|
||||
if( focusParts.size() > 0 )
|
||||
{
|
||||
command += "1,";
|
||||
command += *focusParts.begin();
|
||||
command += ",";
|
||||
}
|
||||
else
|
||||
{
|
||||
command += "0,";
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
command += "0,";
|
||||
}
|
||||
|
||||
std::set<wxString> parts;
|
||||
collectItemsForSyncParts( aItems, parts );
|
||||
|
||||
if( parts.empty() )
|
||||
return;
|
||||
|
||||
for( wxString part : parts )
|
||||
{
|
||||
command += part;
|
||||
command += ",";
|
||||
}
|
||||
|
||||
command.pop_back();
|
||||
|
||||
if( Kiface().IsSingle() )
|
||||
{
|
||||
SendCommand( MSG_TO_PCB, command );
|
||||
}
|
||||
else
|
||||
{
|
||||
// Typically ExpressMail is going to be s-expression packets, but since
|
||||
// we have existing interpreter of the selection packet on the other
|
||||
// side in place, we use that here.
|
||||
Kiway().ExpressMail( FRAME_SCH, aForce ? MAIL_SELECTION_FORCE : MAIL_SELECTION, command,
|
||||
this );
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void PCB_EDIT_FRAME::SendCrossProbeNetName( const wxString& aNetName )
|
||||
{
|
||||
std::string packet = StrPrintf( "$NET: \"%s\"", TO_UTF8( aNetName ) );
|
||||
|
||||
if( !packet.empty() )
|
||||
{
|
||||
|
@ -314,9 +414,9 @@ void PCB_EDIT_FRAME::SendMessageToEESCHEMA( BOARD_ITEM* aSyncItem )
|
|||
}
|
||||
|
||||
|
||||
void PCB_EDIT_FRAME::SendCrossProbeNetName( const wxString& aNetName )
|
||||
void PCB_EDIT_FRAME::SendCrossProbeItem( BOARD_ITEM* aSyncItem )
|
||||
{
|
||||
std::string packet = StrPrintf( "$NET: \"%s\"", TO_UTF8( aNetName ) );
|
||||
std::string packet = FormatProbeItem( aSyncItem );
|
||||
|
||||
if( !packet.empty() )
|
||||
{
|
||||
|
@ -503,7 +603,7 @@ void PCB_EDIT_FRAME::KiwayMailIn( KIWAY_EXPRESS& mail )
|
|||
std::vector<BOARD_ITEM*> items =
|
||||
FindItemsFromSyncSelection( paramStr.substr( modeEnd + 1 ) );
|
||||
|
||||
m_syncingSchToPcbSelection = true; // recursion guard
|
||||
m_probingSchToPcb = true; // recursion guard
|
||||
|
||||
if( selectConnections )
|
||||
{
|
||||
|
@ -516,7 +616,7 @@ void PCB_EDIT_FRAME::KiwayMailIn( KIWAY_EXPRESS& mail )
|
|||
static_cast<void*>( &items ) );
|
||||
}
|
||||
|
||||
m_syncingSchToPcbSelection = false;
|
||||
m_probingSchToPcb = false;
|
||||
}
|
||||
|
||||
break;
|
||||
|
|
|
@ -187,7 +187,7 @@ PCB_EDIT_FRAME::PCB_EDIT_FRAME( KIWAY* aKiway, wxWindow* aParent ) :
|
|||
m_SelLayerBox = nullptr;
|
||||
m_show_layer_manager_tools = true;
|
||||
m_supportsAutoSave = true;
|
||||
m_syncingSchToPcbSelection = false;
|
||||
m_probingSchToPcb = false;
|
||||
|
||||
// We don't know what state board was in when it was last saved, so we have to
|
||||
// assume dirty
|
||||
|
@ -778,6 +778,8 @@ void PCB_EDIT_FRAME::setupUIConditions()
|
|||
ENABLE( SELECTION_CONDITIONS::OnlyTypes( { PCB_TRACE_T, PCB_ARC_T, PCB_VIA_T } ) ) );
|
||||
mgr->SetConditions( PCB_ACTIONS::selectSameSheet,
|
||||
ENABLE( SELECTION_CONDITIONS::OnlyTypes( { PCB_FOOTPRINT_T } ) ) );
|
||||
mgr->SetConditions( PCB_ACTIONS::selectOnSchematic,
|
||||
ENABLE( SELECTION_CONDITIONS::HasTypes( { PCB_PAD_T, PCB_FOOTPRINT_T, PCB_GROUP_T } ) ) );
|
||||
|
||||
|
||||
SELECTION_CONDITION singleZoneCond = SELECTION_CONDITIONS::Count( 1 )
|
||||
|
|
|
@ -637,12 +637,25 @@ public:
|
|||
void OnNetlistChanged( BOARD_NETLIST_UPDATER& aUpdater, bool* aRunDragCommand );
|
||||
|
||||
/**
|
||||
* Send a message to the schematic editor so that it may move its cursor
|
||||
* to a symbol with the same reference as the \a objectToSync.
|
||||
* Send a message to the schematic editor to try to find schematic counterparts
|
||||
* of specified PCB items and select them.
|
||||
*
|
||||
* @param objectToSync The object whose reference is used to synchronize Eeschema.
|
||||
* @param aItems are the items to try to select on schematic.
|
||||
* @param aFocusItem set to item to select and focus on even if selection can't be
|
||||
* represented in Schematic editor fully.
|
||||
* @param aForce select elements in Schematic editor whether or not the user has
|
||||
* the select option chosen.
|
||||
*/
|
||||
void SendMessageToEESCHEMA( BOARD_ITEM* objectToSync );
|
||||
void SendSelectItemsToSch( const std::deque<EDA_ITEM*>& aItems, EDA_ITEM* aFocusItem,
|
||||
bool aForce );
|
||||
|
||||
/**
|
||||
* Send a message to the schematic editor so that it may move its cursor
|
||||
* to an item with the same reference as the \a aSyncItem and highlight it.
|
||||
*
|
||||
* @param aSyncItem The object whose reference is used to highlight in Eeschema.
|
||||
*/
|
||||
void SendCrossProbeItem( BOARD_ITEM* aSyncItem );
|
||||
|
||||
/**
|
||||
* Send a net name to Eeschema for highlighting.
|
||||
|
@ -795,7 +808,7 @@ public:
|
|||
|
||||
bool m_ZoneFillsDirty; // Board has been modified since last zone fill.
|
||||
|
||||
bool m_syncingSchToPcbSelection; // Recursion guard when synchronizing selection from schematic
|
||||
bool m_probingSchToPcb; // Recursion guard when synchronizing selection from schematic
|
||||
|
||||
private:
|
||||
friend struct PCB::IFACE;
|
||||
|
|
|
@ -1403,6 +1403,42 @@ int BOARD_EDITOR_CONTROL::ZoneDuplicate( const TOOL_EVENT& aEvent )
|
|||
}
|
||||
|
||||
|
||||
int BOARD_EDITOR_CONTROL::CrossProbeToSch( const TOOL_EVENT& aEvent )
|
||||
{
|
||||
doCrossProbePcbToSch( aEvent, false );
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
int BOARD_EDITOR_CONTROL::ExplicitCrossProbeToSch( const TOOL_EVENT& aEvent )
|
||||
{
|
||||
doCrossProbePcbToSch( aEvent, true );
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
void BOARD_EDITOR_CONTROL::doCrossProbePcbToSch( const TOOL_EVENT& aEvent, bool aForce )
|
||||
{
|
||||
// Don't get in an infinite loop PCB -> SCH -> PCB -> SCH -> ...
|
||||
if( m_frame->m_probingSchToPcb )
|
||||
return;
|
||||
|
||||
PCB_SELECTION_TOOL* selTool = m_toolMgr->GetTool<PCB_SELECTION_TOOL>();
|
||||
const PCB_SELECTION& selection = selTool->GetSelection();
|
||||
EDA_ITEM* focusItem = nullptr;
|
||||
|
||||
if( aEvent.Matches( EVENTS::PointSelectedEvent ) )
|
||||
focusItem = selection.GetLastAddedItem();
|
||||
|
||||
m_frame->SendSelectItemsToSch( selection.GetItems(), focusItem, aForce );
|
||||
|
||||
// Update 3D viewer highlighting
|
||||
m_frame->Update3DView( false, frame()->GetPcbNewSettings()->m_Display.m_Live3DRefresh );
|
||||
}
|
||||
|
||||
|
||||
int BOARD_EDITOR_CONTROL::EditFpInFpEditor( const TOOL_EVENT& aEvent )
|
||||
{
|
||||
PCB_SELECTION_TOOL* selTool = m_toolMgr->GetTool<PCB_SELECTION_TOOL>();
|
||||
|
@ -1517,6 +1553,13 @@ void BOARD_EDITOR_CONTROL::setTransitions()
|
|||
Go( &BOARD_EDITOR_CONTROL::EditFpInFpEditor, PCB_ACTIONS::editFpInFpEditor.MakeEvent() );
|
||||
Go( &BOARD_EDITOR_CONTROL::EditFpInFpEditor, PCB_ACTIONS::editLibFpInFpEditor.MakeEvent() );
|
||||
|
||||
// Cross-select
|
||||
Go( &BOARD_EDITOR_CONTROL::CrossProbeToSch, EVENTS::PointSelectedEvent );
|
||||
Go( &BOARD_EDITOR_CONTROL::CrossProbeToSch, EVENTS::SelectedEvent );
|
||||
Go( &BOARD_EDITOR_CONTROL::CrossProbeToSch, EVENTS::UnselectedEvent );
|
||||
Go( &BOARD_EDITOR_CONTROL::CrossProbeToSch, EVENTS::ClearedEvent );
|
||||
Go( &BOARD_EDITOR_CONTROL::ExplicitCrossProbeToSch, PCB_ACTIONS::selectOnSchematic.MakeEvent() );
|
||||
|
||||
// Other
|
||||
Go( &BOARD_EDITOR_CONTROL::ToggleLockSelected, PCB_ACTIONS::toggleLock.MakeEvent() );
|
||||
Go( &BOARD_EDITOR_CONTROL::LockSelected, PCB_ACTIONS::lock.MakeEvent() );
|
||||
|
|
|
@ -93,6 +93,12 @@ public:
|
|||
|
||||
int EditFpInFpEditor( const TOOL_EVENT& aEvent );
|
||||
|
||||
///< Notify Eeschema about selected items.
|
||||
int CrossProbeToSch( const TOOL_EVENT& aEvent );
|
||||
|
||||
///< Equivalent to the above, but initiated by the user.
|
||||
int ExplicitCrossProbeToSch( const TOOL_EVENT& aEvent );
|
||||
|
||||
/**
|
||||
* Display a dialog to select a footprint to be added and allows the user to set its position.
|
||||
*/
|
||||
|
@ -128,6 +134,8 @@ private:
|
|||
///< Set up handlers for various events.
|
||||
void setTransitions() override;
|
||||
|
||||
void doCrossProbePcbToSch( const TOOL_EVENT& aEvent, bool aForce );
|
||||
|
||||
private:
|
||||
PCB_EDIT_FRAME* m_frame;
|
||||
bool m_inPlaceFootprint; // Re-entrancy guard for tool.
|
||||
|
|
|
@ -45,7 +45,6 @@ BOARD_INSPECTION_TOOL::BOARD_INSPECTION_TOOL() :
|
|||
PCB_TOOL_BASE( "pcbnew.InspectionTool" ),
|
||||
m_frame( nullptr )
|
||||
{
|
||||
m_probingSchToPcb = false;
|
||||
m_dynamicData = nullptr;
|
||||
}
|
||||
|
||||
|
@ -1245,39 +1244,18 @@ int BOARD_INSPECTION_TOOL::InspectConstraints( const TOOL_EVENT& aEvent )
|
|||
}
|
||||
|
||||
|
||||
int BOARD_INSPECTION_TOOL::CrossProbePcbToSch( const TOOL_EVENT& aEvent )
|
||||
{
|
||||
// Don't get in an infinite loop PCB -> SCH -> PCB -> SCH -> ...
|
||||
if( m_probingSchToPcb || m_frame->m_syncingSchToPcbSelection )
|
||||
return 0;
|
||||
|
||||
PCB_SELECTION_TOOL* selTool = m_toolMgr->GetTool<PCB_SELECTION_TOOL>();
|
||||
const PCB_SELECTION& selection = selTool->GetSelection();
|
||||
|
||||
if( selection.Size() == 1 )
|
||||
m_frame->SendMessageToEESCHEMA( static_cast<BOARD_ITEM*>( selection.Front() ) );
|
||||
else
|
||||
m_frame->SendMessageToEESCHEMA( nullptr );
|
||||
|
||||
// Update 3D viewer highlighting
|
||||
m_frame->Update3DView( false, frame()->GetPcbNewSettings()->m_Display.m_Live3DRefresh );
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
int BOARD_INSPECTION_TOOL::HighlightItem( const TOOL_EVENT& aEvent )
|
||||
{
|
||||
BOARD_ITEM* item = aEvent.Parameter<BOARD_ITEM*>();
|
||||
|
||||
m_probingSchToPcb = true; // recursion guard
|
||||
m_frame->m_probingSchToPcb = true; // recursion guard
|
||||
{
|
||||
m_toolMgr->RunAction( PCB_ACTIONS::selectionClear, true );
|
||||
|
||||
if( item )
|
||||
m_toolMgr->RunAction( PCB_ACTIONS::selectItem, true, (void*) item );
|
||||
}
|
||||
m_probingSchToPcb = false;
|
||||
m_frame->m_probingSchToPcb = false;
|
||||
|
||||
bool request3DviewRedraw = frame()->GetPcbNewSettings()->m_Display.m_Live3DRefresh;
|
||||
|
||||
|
@ -1363,7 +1341,7 @@ int BOARD_INSPECTION_TOOL::HighlightItem( const TOOL_EVENT& aEvent )
|
|||
filter.lockedItems = saved;
|
||||
|
||||
// Clear the previous highlight
|
||||
m_frame->SendMessageToEESCHEMA( nullptr );
|
||||
//m_frame->SendMessageToEESCHEMA( nullptr );
|
||||
|
||||
bool highContrast = settings->GetHighContrast();
|
||||
PCB_LAYER_ID contrastLayer = settings->GetPrimaryHighContrastLayer();
|
||||
|
@ -1388,7 +1366,7 @@ int BOARD_INSPECTION_TOOL::HighlightItem( const TOOL_EVENT& aEvent )
|
|||
BOARD_CONNECTED_ITEM* targetItem = static_cast<BOARD_CONNECTED_ITEM*>( collector[0] );
|
||||
|
||||
if( targetItem->Type() == PCB_PAD_T )
|
||||
m_frame->SendMessageToEESCHEMA( targetItem );
|
||||
m_frame->SendCrossProbeItem( targetItem );
|
||||
|
||||
net = targetItem->GetNetCode();
|
||||
}
|
||||
|
@ -1829,10 +1807,6 @@ void BOARD_INSPECTION_TOOL::doHideNet( int aNetCode, bool aHide )
|
|||
|
||||
void BOARD_INSPECTION_TOOL::setTransitions()
|
||||
{
|
||||
Go( &BOARD_INSPECTION_TOOL::CrossProbePcbToSch, EVENTS::SelectedEvent );
|
||||
Go( &BOARD_INSPECTION_TOOL::CrossProbePcbToSch, EVENTS::UnselectedEvent );
|
||||
Go( &BOARD_INSPECTION_TOOL::CrossProbePcbToSch, EVENTS::ClearedEvent );
|
||||
|
||||
Go( &BOARD_INSPECTION_TOOL::LocalRatsnestTool,
|
||||
PCB_ACTIONS::localRatsnestTool.MakeEvent() );
|
||||
Go( &BOARD_INSPECTION_TOOL::HideDynamicRatsnest,
|
||||
|
|
|
@ -57,9 +57,6 @@ public:
|
|||
*/
|
||||
int ShowStatisticsDialog( const TOOL_EVENT& aEvent );
|
||||
|
||||
///< Notify Eeschema about the selected item.
|
||||
int CrossProbePcbToSch( const TOOL_EVENT& aEvent );
|
||||
|
||||
///< Highlight net belonging to the item under the cursor.
|
||||
int HighlightNet( const TOOL_EVENT& aEvent );
|
||||
|
||||
|
@ -143,7 +140,6 @@ private:
|
|||
private:
|
||||
PCB_EDIT_FRAME* m_frame; // Pointer to the currently used edit frame.
|
||||
|
||||
bool m_probingSchToPcb; // Recursion guard when cross-probing to Eeschema
|
||||
std::set<int> m_currentlyHighlighted; // Active net being highlighted, or -1 when off
|
||||
std::set<int> m_lastHighlighted; // For toggling between last two highlighted nets
|
||||
|
||||
|
|
|
@ -300,6 +300,7 @@ void DRC_TOOL::setTransitions()
|
|||
Go( &DRC_TOOL::PrevMarker, ACTIONS::prevMarker.MakeEvent() );
|
||||
Go( &DRC_TOOL::NextMarker, ACTIONS::nextMarker.MakeEvent() );
|
||||
Go( &DRC_TOOL::ExcludeMarker, ACTIONS::excludeMarker.MakeEvent() );
|
||||
Go( &DRC_TOOL::CrossProbe, EVENTS::PointSelectedEvent );
|
||||
Go( &DRC_TOOL::CrossProbe, EVENTS::SelectedEvent );
|
||||
}
|
||||
|
||||
|
|
|
@ -1291,6 +1291,12 @@ TOOL_ACTION PCB_ACTIONS::selectSameSheet( "pcbnew.InteractiveSelection.SelectSam
|
|||
_( "Selects all footprints and tracks in the same schematic sheet" ),
|
||||
BITMAPS::select_same_sheet );
|
||||
|
||||
TOOL_ACTION PCB_ACTIONS::selectOnSchematic( "pcbnew.InteractiveSelection.SelectOnSchematic",
|
||||
AS_GLOBAL, 0, "",
|
||||
_( "Select on Schematic" ),
|
||||
_( "Selects corresponding items in Schematic editor" ),
|
||||
BITMAPS::select_same_sheet );
|
||||
|
||||
TOOL_ACTION PCB_ACTIONS::filterSelection( "pcbnew.InteractiveSelection.FilterSelection",
|
||||
AS_GLOBAL, 0, "",
|
||||
_( "Filter Selected Items..." ), _( "Remove items from the selection by type" ),
|
||||
|
|
|
@ -91,6 +91,9 @@ public:
|
|||
/// Select all components on the same sheet as the selected footprint.
|
||||
static TOOL_ACTION selectSameSheet;
|
||||
|
||||
/// Select symbols/pins on schematic corresponding to selected footprints/pads.
|
||||
static TOOL_ACTION selectOnSchematic;
|
||||
|
||||
/// Filter the items in the current selection (invokes dialog)
|
||||
static TOOL_ACTION filterSelection;
|
||||
|
||||
|
|
|
@ -1464,6 +1464,7 @@ void PCB_CONTROL::setTransitions()
|
|||
Go( &PCB_CONTROL::Paste, ACTIONS::paste.MakeEvent() );
|
||||
Go( &PCB_CONTROL::Paste, ACTIONS::pasteSpecial.MakeEvent() );
|
||||
|
||||
Go( &PCB_CONTROL::UpdateMessagePanel, EVENTS::PointSelectedEvent );
|
||||
Go( &PCB_CONTROL::UpdateMessagePanel, EVENTS::SelectedEvent );
|
||||
Go( &PCB_CONTROL::UpdateMessagePanel, EVENTS::UnselectedEvent );
|
||||
Go( &PCB_CONTROL::UpdateMessagePanel, EVENTS::ClearedEvent );
|
||||
|
|
|
@ -2425,6 +2425,7 @@ void PCB_POINT_EDITOR::setTransitions()
|
|||
Go( &PCB_POINT_EDITOR::addCorner, PCB_ACTIONS::pointEditorAddCorner.MakeEvent() );
|
||||
Go( &PCB_POINT_EDITOR::removeCorner, PCB_ACTIONS::pointEditorRemoveCorner.MakeEvent() );
|
||||
Go( &PCB_POINT_EDITOR::modifiedSelection, EVENTS::SelectedItemsModified );
|
||||
Go( &PCB_POINT_EDITOR::OnSelectionChange, EVENTS::PointSelectedEvent );
|
||||
Go( &PCB_POINT_EDITOR::OnSelectionChange, EVENTS::SelectedEvent );
|
||||
Go( &PCB_POINT_EDITOR::OnSelectionChange, EVENTS::UnselectedEvent );
|
||||
Go( &PCB_POINT_EDITOR::changeEditMethod, ACTIONS::changeEditMethod.MakeEvent() );
|
||||
|
|
|
@ -86,6 +86,7 @@ public:
|
|||
// This could be enabled if we have better logic for picking the target net with the mouse
|
||||
// Add( PCB_ACTIONS::deselectNet );
|
||||
Add( PCB_ACTIONS::selectSameSheet );
|
||||
Add( PCB_ACTIONS::selectOnSchematic );
|
||||
}
|
||||
|
||||
private:
|
||||
|
@ -740,7 +741,7 @@ bool PCB_SELECTION_TOOL::selectPoint( const VECTOR2I& aWhere, bool aOnDrag,
|
|||
}
|
||||
}
|
||||
|
||||
bool anyAdded = false;
|
||||
int addedCount = 0;
|
||||
bool anySubtracted = false;
|
||||
|
||||
if( !m_additive && !m_subtractive && !m_exclusive_or )
|
||||
|
@ -764,12 +765,17 @@ bool PCB_SELECTION_TOOL::selectPoint( const VECTOR2I& aWhere, bool aOnDrag,
|
|||
else
|
||||
{
|
||||
select( collector[i] );
|
||||
anyAdded = true;
|
||||
addedCount++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if( anyAdded )
|
||||
if( addedCount == 1 )
|
||||
{
|
||||
m_toolMgr->ProcessEvent( EVENTS::PointSelectedEvent );
|
||||
return true;
|
||||
}
|
||||
else if( addedCount > 1 )
|
||||
{
|
||||
m_toolMgr->ProcessEvent( EVENTS::SelectedEvent );
|
||||
return true;
|
||||
|
@ -1536,12 +1542,12 @@ void PCB_SELECTION_TOOL::doSyncSelection( const std::vector<BOARD_ITEM*>& aItems
|
|||
|
||||
EDA_RECT bbox = m_selection.GetBoundingBox();
|
||||
|
||||
if( bbox.GetWidth() > 0 && bbox.GetHeight() > 0 )
|
||||
if( bbox.GetWidth() != 0 && bbox.GetHeight() != 0 )
|
||||
{
|
||||
if( m_frame->GetPcbNewSettings()->m_CrossProbing.center_on_items )
|
||||
{
|
||||
if( m_frame->GetPcbNewSettings()->m_CrossProbing.zoom_to_fit )
|
||||
zoomFitCrossProbeBBox( bbox );
|
||||
ZoomFitCrossProbeBBox( bbox );
|
||||
|
||||
m_frame->FocusOnLocation( bbox.Centre() );
|
||||
}
|
||||
|
@ -1630,14 +1636,16 @@ void PCB_SELECTION_TOOL::zoomFitSelection()
|
|||
}
|
||||
|
||||
|
||||
void PCB_SELECTION_TOOL::zoomFitCrossProbeBBox( EDA_RECT bbox )
|
||||
void PCB_SELECTION_TOOL::ZoomFitCrossProbeBBox( EDA_RECT bbox )
|
||||
{
|
||||
// Should recalculate the view to zoom in on the bbox.
|
||||
auto view = getView();
|
||||
|
||||
if( bbox.GetWidth() == 0 && bbox.GetHeight() != 0 )
|
||||
if( bbox.GetWidth() == 0 )
|
||||
return;
|
||||
|
||||
bbox.Normalize();
|
||||
|
||||
//#define DEFAULT_PCBNEW_CODE // Un-comment for normal full zoom KiCad algorithm
|
||||
#ifdef DEFAULT_PCBNEW_CODE
|
||||
auto bbSize = bbox.Inflate( bbox.GetWidth() * 0.2f ).GetSize();
|
||||
|
|
|
@ -160,7 +160,7 @@ public:
|
|||
void zoomFitSelection();
|
||||
|
||||
///< Zoom the screen to fit the bounding box for cross probing/selection sync.
|
||||
void zoomFitCrossProbeBBox( EDA_RECT bbox );
|
||||
void ZoomFitCrossProbeBBox( EDA_RECT bbox );
|
||||
|
||||
/**
|
||||
* Enter the group at the head of the current selection.
|
||||
|
|
Loading…
Reference in New Issue