Cross-probing/selection for multiple items (SCH->PCB)
This commit is contained in:
parent
51adf1ace4
commit
bc1ff6756f
|
@ -2,7 +2,7 @@
|
|||
* This program source code file is part of KiCad, a free EDA CAD application.
|
||||
*
|
||||
* Copyright (C) 2020 Jon Evans <jon@craftyjon.com>
|
||||
* Copyright (C) 2020 KiCad Developers, see AUTHORS.txt for contributors.
|
||||
* Copyright (C) 2020-2022 KiCad Developers, see AUTHORS.txt for contributors.
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License as published by the
|
||||
|
@ -129,6 +129,9 @@ APP_SETTINGS_BASE::APP_SETTINGS_BASE( const std::string& aFilename, int aSchemaV
|
|||
|
||||
addParamsForWindow( &m_Window, "window" );
|
||||
|
||||
m_params.emplace_back( new PARAM<bool>( "cross_probing.on_selection",
|
||||
&m_CrossProbing.on_selection, true ) );
|
||||
|
||||
m_params.emplace_back( new PARAM<bool>( "cross_probing.center_on_items",
|
||||
&m_CrossProbing.center_on_items, true ) );
|
||||
|
||||
|
|
|
@ -174,6 +174,17 @@ wxString EscapeString( const wxString& aSource, ESCAPE_CONTEXT aContext )
|
|||
else
|
||||
converted += c;
|
||||
}
|
||||
else if( aContext == CTX_IPC )
|
||||
{
|
||||
if( c == '/' )
|
||||
converted += "{slash}";
|
||||
else if( c == ',' )
|
||||
converted += "{comma}";
|
||||
else if( c == '\"' )
|
||||
converted += "{dblquote}";
|
||||
else
|
||||
converted += c;
|
||||
}
|
||||
else if( aContext == CTX_QUOTED_STR )
|
||||
{
|
||||
if( c == '\"' )
|
||||
|
@ -276,6 +287,7 @@ wxString UnescapeString( const wxString& aSource )
|
|||
else if( token == wxS( "backslash" ) ) newbuf.append( wxS( "\\" ) );
|
||||
else if( token == wxS( "slash" ) ) newbuf.append( wxS( "/" ) );
|
||||
else if( token == wxS( "bar" ) ) newbuf.append( wxS( "|" ) );
|
||||
else if( token == wxS( "comma" ) ) newbuf.append( wxS( "," ) );
|
||||
else if( token == wxS( "colon" ) ) newbuf.append( wxS( ":" ) );
|
||||
else if( token == wxS( "space" ) ) newbuf.append( wxS( " " ) );
|
||||
else if( token == wxS( "dollar" ) ) newbuf.append( wxS( "$" ) );
|
||||
|
|
|
@ -62,6 +62,12 @@ SELECTION_CONDITION SELECTION_CONDITIONS::HasType( KICAD_T aType )
|
|||
}
|
||||
|
||||
|
||||
SELECTION_CONDITION SELECTION_CONDITIONS::HasTypes( const KICAD_T aTypes[] )
|
||||
{
|
||||
return std::bind( &SELECTION_CONDITIONS::hasTypesFunc, _1, aTypes );
|
||||
}
|
||||
|
||||
|
||||
SELECTION_CONDITION SELECTION_CONDITIONS::OnlyType( KICAD_T aType )
|
||||
{
|
||||
return std::bind( &SELECTION_CONDITIONS::onlyTypeFunc, _1, aType );
|
||||
|
@ -94,7 +100,10 @@ SELECTION_CONDITION SELECTION_CONDITIONS::LessThan( int aNumber )
|
|||
|
||||
bool SELECTION_CONDITIONS::hasTypeFunc( const SELECTION& aSelection, KICAD_T aType )
|
||||
{
|
||||
for( const auto& item : aSelection )
|
||||
if( aSelection.Empty() )
|
||||
return false;
|
||||
|
||||
for( const EDA_ITEM* item : aSelection )
|
||||
{
|
||||
if( item->Type() == aType )
|
||||
return true;
|
||||
|
@ -104,6 +113,21 @@ bool SELECTION_CONDITIONS::hasTypeFunc( const SELECTION& aSelection, KICAD_T aTy
|
|||
}
|
||||
|
||||
|
||||
bool SELECTION_CONDITIONS::hasTypesFunc( const SELECTION& aSelection, const KICAD_T aTypes[] )
|
||||
{
|
||||
if( aSelection.Empty() )
|
||||
return false;
|
||||
|
||||
for( const EDA_ITEM* item : aSelection )
|
||||
{
|
||||
if( item->IsType( aTypes ) )
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
bool SELECTION_CONDITIONS::onlyTypeFunc( const SELECTION& aSelection, KICAD_T aType )
|
||||
{
|
||||
if( aSelection.Empty() )
|
||||
|
@ -111,7 +135,7 @@ bool SELECTION_CONDITIONS::onlyTypeFunc( const SELECTION& aSelection, KICAD_T aT
|
|||
|
||||
KICAD_T types[] = { aType, EOT };
|
||||
|
||||
for( const auto& item : aSelection )
|
||||
for( const EDA_ITEM* item : aSelection )
|
||||
{
|
||||
if( !item->IsType( types ) )
|
||||
return false;
|
||||
|
@ -126,7 +150,7 @@ bool SELECTION_CONDITIONS::onlyTypesFunc( const SELECTION& aSelection, const KIC
|
|||
if( aSelection.Empty() )
|
||||
return false;
|
||||
|
||||
for( const auto& item : aSelection )
|
||||
for( const EDA_ITEM* item : aSelection )
|
||||
{
|
||||
if( !item->IsType( aTypes ) )
|
||||
return false;
|
||||
|
|
|
@ -3,7 +3,7 @@
|
|||
*
|
||||
* Copyright (C) 2019 Jean-Pierre Charras, jp.charras at wanadoo.fr
|
||||
* Copyright (C) 2011 Wayne Stambaugh <stambaughw@gmail.com>
|
||||
* Copyright (C) 2004-2021 KiCad Developers, see AUTHORS.txt for contributors.
|
||||
* Copyright (C) 2004-2022 KiCad Developers, see AUTHORS.txt for contributors.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
|
@ -473,6 +473,116 @@ void SCH_EDIT_FRAME::SendMessageToPCBNEW( EDA_ITEM* aObjectToSync, SCH_SYMBOL* a
|
|||
}
|
||||
|
||||
|
||||
std::string FormatProbeItems( bool aSelectConnections, const std::deque<EDA_ITEM*>& aItems )
|
||||
{
|
||||
std::string command = "";
|
||||
std::set<wxString> parts;
|
||||
|
||||
for( EDA_ITEM* item : aItems )
|
||||
{
|
||||
switch( item->Type() )
|
||||
{
|
||||
case SCH_SYMBOL_T:
|
||||
{
|
||||
SCH_SYMBOL* symbol = (SCH_SYMBOL*) item;
|
||||
|
||||
wxString ref = symbol->GetField( REFERENCE_FIELD )->GetText();
|
||||
|
||||
parts.insert( "F" + EscapeString( ref, CTX_IPC ) );
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
case SCH_SHEET_T:
|
||||
{
|
||||
// For cross probing, we need the full path of the sheet, because
|
||||
// in complex hierarchies the sheet uuid of not unique
|
||||
SCH_SHEET* sheet = (SCH_SHEET*) item;
|
||||
wxString full_path;
|
||||
|
||||
SCH_SHEET* parent = sheet;
|
||||
|
||||
while( ( parent = dynamic_cast<SCH_SHEET*>( parent->GetParent() ) ) )
|
||||
{
|
||||
if( parent->GetParent() && parent->GetParent()->Type() == SCH_SHEET_T )
|
||||
{
|
||||
// The root sheet has no parent sheet and path is just "/"
|
||||
|
||||
full_path.Prepend( parent->m_Uuid.AsString() );
|
||||
full_path.Prepend( "/" );
|
||||
}
|
||||
}
|
||||
|
||||
full_path += "/" + sheet->m_Uuid.AsString();
|
||||
|
||||
parts.insert( "S" + full_path );
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
case SCH_PIN_T:
|
||||
{
|
||||
SCH_PIN* pin = (SCH_PIN*) item;
|
||||
SCH_SYMBOL* symbol = pin->GetParentSymbol();
|
||||
|
||||
wxString ref = symbol->GetField( REFERENCE_FIELD )->GetText();
|
||||
|
||||
parts.insert( "P" + EscapeString( ref, CTX_IPC ) + "/"
|
||||
+ EscapeString( pin->GetShownNumber(), CTX_IPC ) );
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
default: break;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
if( !parts.empty() )
|
||||
{
|
||||
command = "$SELECT: ";
|
||||
|
||||
if( aSelectConnections )
|
||||
command += "1";
|
||||
else
|
||||
command += "0";
|
||||
|
||||
command += ",";
|
||||
|
||||
for( wxString part : parts )
|
||||
{
|
||||
command += part;
|
||||
command += ",";
|
||||
}
|
||||
|
||||
command.pop_back();
|
||||
}
|
||||
|
||||
return command;
|
||||
}
|
||||
|
||||
|
||||
void SCH_EDIT_FRAME::SendSelectItems( bool aSelectConnections, const std::deque<EDA_ITEM*>& aItems )
|
||||
{
|
||||
std::string packet = FormatProbeItems( aSelectConnections, aItems );
|
||||
|
||||
if( !packet.empty() )
|
||||
{
|
||||
if( Kiface().IsSingle() )
|
||||
{
|
||||
SendCommand( MSG_TO_PCB, packet );
|
||||
}
|
||||
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_PCB_EDITOR, MAIL_SELECTION, packet, this );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void SCH_EDIT_FRAME::SendCrossProbeNetName( const wxString& aNetName )
|
||||
{
|
||||
// The command is a keyword followed by a quoted string.
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
* This program source code file is part of KiCad, a free EDA CAD application.
|
||||
*
|
||||
* Copyright (C) 2009 Wayne Stambaugh <stambaughw@gmail.com>
|
||||
* Copyright (C) 1992-2021 KiCad Developers, see AUTHORS.txt for contributors.
|
||||
* Copyright (C) 1992-2022 KiCad Developers, see AUTHORS.txt for contributors.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
|
@ -66,6 +66,7 @@ void PANEL_EESCHEMA_DISPLAY_OPTIONS::loadEEschemaSettings( EESCHEMA_SETTINGS* cf
|
|||
m_selWidthCtrl->SetValue( cfg->m_Selection.selection_thickness );
|
||||
m_highlightWidthCtrl->SetValue( cfg->m_Selection.highlight_thickness );
|
||||
|
||||
m_checkCrossProbeOnSelection->SetValue( cfg->m_CrossProbing.on_selection );
|
||||
m_checkCrossProbeCenter->SetValue( cfg->m_CrossProbing.center_on_items );
|
||||
m_checkCrossProbeZoom->SetValue( cfg->m_CrossProbing.zoom_to_fit );
|
||||
m_checkCrossProbeAutoHighlight->SetValue( cfg->m_CrossProbing.auto_highlight );
|
||||
|
@ -106,9 +107,10 @@ bool PANEL_EESCHEMA_DISPLAY_OPTIONS::TransferDataFromWindow()
|
|||
cfg->m_Selection.selection_thickness = KiROUND( m_selWidthCtrl->GetValue() );
|
||||
cfg->m_Selection.highlight_thickness = KiROUND( m_highlightWidthCtrl->GetValue() );
|
||||
|
||||
cfg->m_CrossProbing.on_selection = m_checkCrossProbeOnSelection->GetValue();
|
||||
cfg->m_CrossProbing.center_on_items = m_checkCrossProbeCenter->GetValue();
|
||||
cfg->m_CrossProbing.zoom_to_fit = m_checkCrossProbeZoom->GetValue();
|
||||
cfg->m_CrossProbing.auto_highlight = m_checkCrossProbeAutoHighlight->GetValue();
|
||||
cfg->m_CrossProbing.zoom_to_fit = m_checkCrossProbeZoom->GetValue();
|
||||
cfg->m_CrossProbing.auto_highlight = m_checkCrossProbeAutoHighlight->GetValue();
|
||||
|
||||
m_galOptsPanel->TransferDataFromWindow();
|
||||
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
///////////////////////////////////////////////////////////////////////////
|
||||
// C++ code generated with wxFormBuilder (version Oct 26 2018)
|
||||
// C++ code generated with wxFormBuilder (version 3.10.1-0-g8feb16b3)
|
||||
// http://www.wxformbuilder.org/
|
||||
//
|
||||
// PLEASE DO *NOT* EDIT THIS FILE!
|
||||
|
@ -112,6 +112,10 @@ PANEL_EESCHEMA_DISPLAY_OPTIONS_BASE::PANEL_EESCHEMA_DISPLAY_OPTIONS_BASE( wxWind
|
|||
wxStaticBoxSizer* sbSizer31;
|
||||
sbSizer31 = new wxStaticBoxSizer( new wxStaticBox( this, wxID_ANY, _("Cross-probing") ), wxVERTICAL );
|
||||
|
||||
m_checkCrossProbeOnSelection = new wxCheckBox( sbSizer31->GetStaticBox(), wxID_ANY, _("Cross-probe on selection"), wxDefaultPosition, wxDefaultSize, 0 );
|
||||
m_checkCrossProbeOnSelection->SetValue(true);
|
||||
sbSizer31->Add( m_checkCrossProbeOnSelection, 0, wxALL, 5 );
|
||||
|
||||
m_checkCrossProbeCenter = new wxCheckBox( sbSizer31->GetStaticBox(), wxID_ANY, _("Center view on cross-probed items"), wxDefaultPosition, wxDefaultSize, 0 );
|
||||
m_checkCrossProbeCenter->SetValue(true);
|
||||
sbSizer31->Add( m_checkCrossProbeCenter, 0, wxBOTTOM|wxRIGHT|wxLEFT, 5 );
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
<?xml version="1.0" encoding="UTF-8" standalone="yes" ?>
|
||||
<wxFormBuilder_Project>
|
||||
<FileVersion major="1" minor="15" />
|
||||
<FileVersion major="1" minor="16" />
|
||||
<object class="Project" expanded="1">
|
||||
<property name="class_decoration"></property>
|
||||
<property name="code_generation">C++</property>
|
||||
|
@ -14,6 +14,7 @@
|
|||
<property name="file">panel_eeschema_display_options_base</property>
|
||||
<property name="first_id">1000</property>
|
||||
<property name="help_provider">none</property>
|
||||
<property name="image_path_wrapper_function_name"></property>
|
||||
<property name="indent_with_spaces"></property>
|
||||
<property name="internationalize">1</property>
|
||||
<property name="name">PanelEeschemaDisplayOptions</property>
|
||||
|
@ -25,6 +26,7 @@
|
|||
<property name="skip_php_events">1</property>
|
||||
<property name="skip_python_events">1</property>
|
||||
<property name="ui_table">UI</property>
|
||||
<property name="use_array_enum">0</property>
|
||||
<property name="use_enum">1</property>
|
||||
<property name="use_microsoft_bom">0</property>
|
||||
<object class="Panel" expanded="1">
|
||||
|
@ -46,6 +48,7 @@
|
|||
<property name="size">-1,-1</property>
|
||||
<property name="subclass">RESETTABLE_PANEL; widgets/resettable_panel.h; Not forward_declare</property>
|
||||
<property name="tooltip"></property>
|
||||
<property name="two_step_creation">0</property>
|
||||
<property name="window_extra_style"></property>
|
||||
<property name="window_name"></property>
|
||||
<property name="window_style">wxTAB_TRAVERSAL</property>
|
||||
|
@ -1169,6 +1172,70 @@
|
|||
<property name="orient">wxVERTICAL</property>
|
||||
<property name="parent">1</property>
|
||||
<property name="permission">none</property>
|
||||
<object class="sizeritem" expanded="1">
|
||||
<property name="border">5</property>
|
||||
<property name="flag">wxALL</property>
|
||||
<property name="proportion">0</property>
|
||||
<object class="wxCheckBox" expanded="1">
|
||||
<property name="BottomDockable">1</property>
|
||||
<property name="LeftDockable">1</property>
|
||||
<property name="RightDockable">1</property>
|
||||
<property name="TopDockable">1</property>
|
||||
<property name="aui_layer"></property>
|
||||
<property name="aui_name"></property>
|
||||
<property name="aui_position"></property>
|
||||
<property name="aui_row"></property>
|
||||
<property name="best_size"></property>
|
||||
<property name="bg"></property>
|
||||
<property name="caption"></property>
|
||||
<property name="caption_visible">1</property>
|
||||
<property name="center_pane">0</property>
|
||||
<property name="checked">1</property>
|
||||
<property name="close_button">1</property>
|
||||
<property name="context_help"></property>
|
||||
<property name="context_menu">1</property>
|
||||
<property name="default_pane">0</property>
|
||||
<property name="dock">Dock</property>
|
||||
<property name="dock_fixed">0</property>
|
||||
<property name="docking">Left</property>
|
||||
<property name="enabled">1</property>
|
||||
<property name="fg"></property>
|
||||
<property name="floatable">1</property>
|
||||
<property name="font"></property>
|
||||
<property name="gripper">0</property>
|
||||
<property name="hidden">0</property>
|
||||
<property name="id">wxID_ANY</property>
|
||||
<property name="label">Cross-probe on selection</property>
|
||||
<property name="max_size"></property>
|
||||
<property name="maximize_button">0</property>
|
||||
<property name="maximum_size"></property>
|
||||
<property name="min_size"></property>
|
||||
<property name="minimize_button">0</property>
|
||||
<property name="minimum_size"></property>
|
||||
<property name="moveable">1</property>
|
||||
<property name="name">m_checkCrossProbeOnSelection</property>
|
||||
<property name="pane_border">1</property>
|
||||
<property name="pane_position"></property>
|
||||
<property name="pane_size"></property>
|
||||
<property name="permission">protected</property>
|
||||
<property name="pin_button">1</property>
|
||||
<property name="pos"></property>
|
||||
<property name="resize">Resizable</property>
|
||||
<property name="show">1</property>
|
||||
<property name="size"></property>
|
||||
<property name="style"></property>
|
||||
<property name="subclass">; ; forward_declare</property>
|
||||
<property name="toolbar_pane">0</property>
|
||||
<property name="tooltip"></property>
|
||||
<property name="validator_data_type"></property>
|
||||
<property name="validator_style">wxFILTER_NONE</property>
|
||||
<property name="validator_type">wxDefaultValidator</property>
|
||||
<property name="validator_variable"></property>
|
||||
<property name="window_extra_style"></property>
|
||||
<property name="window_name"></property>
|
||||
<property name="window_style"></property>
|
||||
</object>
|
||||
</object>
|
||||
<object class="sizeritem" expanded="1">
|
||||
<property name="border">5</property>
|
||||
<property name="flag">wxBOTTOM|wxRIGHT|wxLEFT</property>
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
///////////////////////////////////////////////////////////////////////////
|
||||
// C++ code generated with wxFormBuilder (version Oct 26 2018)
|
||||
// C++ code generated with wxFormBuilder (version 3.10.1-0-g8feb16b3)
|
||||
// http://www.wxformbuilder.org/
|
||||
//
|
||||
// PLEASE DO *NOT* EDIT THIS FILE!
|
||||
|
@ -54,6 +54,7 @@ class PANEL_EESCHEMA_DISPLAY_OPTIONS_BASE : public RESETTABLE_PANEL
|
|||
wxStaticText* m_highlightColorNote;
|
||||
wxStaticText* m_highlightWidthLabel;
|
||||
wxSpinCtrlDouble* m_highlightWidthCtrl;
|
||||
wxCheckBox* m_checkCrossProbeOnSelection;
|
||||
wxCheckBox* m_checkCrossProbeCenter;
|
||||
wxCheckBox* m_checkCrossProbeZoom;
|
||||
wxCheckBox* m_checkCrossProbeAutoHighlight;
|
||||
|
@ -61,6 +62,7 @@ class PANEL_EESCHEMA_DISPLAY_OPTIONS_BASE : public RESETTABLE_PANEL
|
|||
public:
|
||||
|
||||
PANEL_EESCHEMA_DISPLAY_OPTIONS_BASE( wxWindow* parent, wxWindowID id = wxID_ANY, const wxPoint& pos = wxDefaultPosition, const wxSize& size = wxSize( -1,-1 ), long style = wxTAB_TRAVERSAL, const wxString& name = wxEmptyString );
|
||||
|
||||
~PANEL_EESCHEMA_DISPLAY_OPTIONS_BASE();
|
||||
|
||||
};
|
||||
|
|
|
@ -307,6 +307,14 @@ public:
|
|||
*/
|
||||
void SendMessageToPCBNEW( EDA_ITEM* aObjectToSync, SCH_SYMBOL* aPart );
|
||||
|
||||
/**
|
||||
* Sends items to Pcbnew for selection
|
||||
*
|
||||
* @param aSelectConnections - set to select connected tracks/vias too
|
||||
* @param aElements are the items to select
|
||||
*/
|
||||
void SendSelectItems( bool aSelectConnections, const std::deque<EDA_ITEM*>& aElements );
|
||||
|
||||
/**
|
||||
* Sends a net name to Pcbnew for highlighting
|
||||
*
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
* This program source code file is part of KiCad, a free EDA CAD application.
|
||||
*
|
||||
* Copyright (C) 2019 CERN
|
||||
* Copyright (C) 2019-2020 KiCad Developers, see AUTHORS.txt for contributors.
|
||||
* Copyright (C) 2019-2022 KiCad Developers, see AUTHORS.txt for contributors.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
|
@ -641,9 +641,10 @@ TOOL_ACTION EE_ACTIONS::generateBOM( "eeschema.EditorControl.generateBOM",
|
|||
_( "Generate BOM..." ), _( "Generate a bill of materials for the current schematic" ),
|
||||
BITMAPS::post_bom );
|
||||
|
||||
TOOL_ACTION EE_ACTIONS::explicitCrossProbe( "eeschema.EditorControl.explicitCrossProbe",
|
||||
TOOL_ACTION EE_ACTIONS::selectOnPCB( "eeschema.EditorControl.selectOnPCB",
|
||||
AS_GLOBAL, 0, "",
|
||||
_( "Highlight on PCB" ), _( "Highlight corresponding items in PCB editor" ),
|
||||
_( "Select on PCB" ),
|
||||
_( "Select corresponding items in PCB editor" ),
|
||||
BITMAPS::select_same_sheet );
|
||||
|
||||
TOOL_ACTION EE_ACTIONS::toggleHiddenPins( "eeschema.EditorControl.showHiddenPins",
|
||||
|
|
|
@ -201,7 +201,7 @@ public:
|
|||
static TOOL_ACTION toggleERCExclusions;
|
||||
static TOOL_ACTION toggleSyncedPinsMode;
|
||||
static TOOL_ACTION restartMove;
|
||||
static TOOL_ACTION explicitCrossProbe;
|
||||
static TOOL_ACTION selectOnPCB;
|
||||
static TOOL_ACTION pushPinLength;
|
||||
static TOOL_ACTION pushPinNameSize;
|
||||
static TOOL_ACTION pushPinNumSize;
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
* This program source code file is part of KiCad, a free EDA CAD application.
|
||||
*
|
||||
* Copyright (C) 2019 CERN
|
||||
* Copyright (C) 2019-2021 KiCad Developers, see AUTHORS.txt for contributors.
|
||||
* Copyright (C) 2019-2022 KiCad Developers, see AUTHORS.txt for contributors.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
|
@ -171,11 +171,14 @@ bool EE_SELECTION_TOOL::Init()
|
|||
SCH_PIN_T,
|
||||
EOT };
|
||||
|
||||
static KICAD_T crossProbingTypes[] = { SCH_SYMBOL_T, SCH_PIN_T, SCH_SHEET_T, EOT };
|
||||
|
||||
auto wireSelection = E_C::MoreThan( 0 ) && E_C::OnlyType( SCH_ITEM_LOCATE_WIRE_T );
|
||||
auto busSelection = E_C::MoreThan( 0 ) && E_C::OnlyType( SCH_ITEM_LOCATE_BUS_T );
|
||||
auto wireOrBusSelection = E_C::MoreThan( 0 ) && E_C::OnlyTypes( wireOrBusTypes );
|
||||
auto connectedSelection = E_C::MoreThan( 0 ) && E_C::OnlyTypes( connectedTypes );
|
||||
auto sheetSelection = E_C::Count( 1 ) && E_C::OnlyType( SCH_SHEET_T );
|
||||
auto sheetSelection = E_C::Count( 1 ) && E_C::OnlyType( SCH_SHEET_T );
|
||||
auto crossProbingSelection = E_C::MoreThan( 0 ) && E_C::HasTypes( crossProbingTypes );
|
||||
|
||||
auto schEditSheetPageNumberCondition =
|
||||
[&] ( const SELECTION& aSel )
|
||||
|
@ -211,7 +214,7 @@ bool EE_SELECTION_TOOL::Init()
|
|||
auto& menu = m_menu.GetMenu();
|
||||
|
||||
menu.AddItem( EE_ACTIONS::enterSheet, sheetSelection && EE_CONDITIONS::Idle, 1 );
|
||||
menu.AddItem( EE_ACTIONS::explicitCrossProbe, sheetSelection && EE_CONDITIONS::Idle, 1 );
|
||||
menu.AddItem( EE_ACTIONS::selectOnPCB, crossProbingSelection && EE_CONDITIONS::Idle, 1 );
|
||||
menu.AddItem( EE_ACTIONS::leaveSheet, belowRootSheetCondition, 1 );
|
||||
|
||||
menu.AddSeparator( 100 );
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
* This program source code file is part of KiCad, a free EDA CAD application.
|
||||
*
|
||||
* Copyright (C) 2019 CERN
|
||||
* Copyright (C) 1992-2021 KiCad Developers, see AUTHORS.txt for contributors.
|
||||
* Copyright (C) 1992-2022 KiCad Developers, see AUTHORS.txt for contributors.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
|
@ -672,63 +672,14 @@ void SCH_EDITOR_CONTROL::doCrossProbeSchToPcb( const TOOL_EVENT& aEvent, bool aF
|
|||
if( m_probingPcbToSch )
|
||||
return;
|
||||
|
||||
EE_SELECTION_TOOL* selTool = m_toolMgr->GetTool<EE_SELECTION_TOOL>();
|
||||
SCH_ITEM* item = nullptr;
|
||||
SCH_SYMBOL* symbol = nullptr;
|
||||
|
||||
if( aForce )
|
||||
{
|
||||
EE_SELECTION& selection = selTool->RequestSelection();
|
||||
|
||||
if( selection.GetSize() >= 1 )
|
||||
item = (SCH_ITEM*) selection.Front();
|
||||
}
|
||||
else
|
||||
{
|
||||
EE_SELECTION& selection = selTool->GetSelection();
|
||||
|
||||
if( selection.GetSize() >= 1 )
|
||||
item = (SCH_ITEM*) selection.Front();
|
||||
}
|
||||
|
||||
if( !item )
|
||||
{
|
||||
if( aForce )
|
||||
m_frame->SendMessageToPCBNEW( nullptr, nullptr );
|
||||
|
||||
if( !aForce && !m_frame->eeconfig()->m_CrossProbing.on_selection )
|
||||
return;
|
||||
}
|
||||
|
||||
EE_SELECTION_TOOL* selTool = m_toolMgr->GetTool<EE_SELECTION_TOOL>();
|
||||
|
||||
switch( item->Type() )
|
||||
{
|
||||
case SCH_FIELD_T:
|
||||
case LIB_FIELD_T:
|
||||
if( item->GetParent() && item->GetParent()->Type() == SCH_SYMBOL_T )
|
||||
{
|
||||
symbol = (SCH_SYMBOL*) item->GetParent();
|
||||
m_frame->SendMessageToPCBNEW( item, symbol );
|
||||
}
|
||||
break;
|
||||
EE_SELECTION& selection = aForce ? selTool->RequestSelection() : selTool->GetSelection();
|
||||
|
||||
case SCH_SYMBOL_T:
|
||||
symbol = (SCH_SYMBOL*) item;
|
||||
m_frame->SendMessageToPCBNEW( item, symbol );
|
||||
break;
|
||||
|
||||
case SCH_PIN_T:
|
||||
symbol = (SCH_SYMBOL*) item->GetParent();
|
||||
m_frame->SendMessageToPCBNEW( static_cast<SCH_PIN*>( item ), symbol );
|
||||
break;
|
||||
|
||||
case SCH_SHEET_T:
|
||||
if( aForce )
|
||||
m_frame->SendMessageToPCBNEW( item, nullptr );
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
m_frame->SendSelectItems( false, selection.GetItems() );
|
||||
}
|
||||
|
||||
|
||||
|
@ -2318,7 +2269,7 @@ void SCH_EDITOR_CONTROL::setTransitions()
|
|||
Go( &SCH_EDITOR_CONTROL::CrossProbeToPcb, EVENTS::SelectedEvent );
|
||||
Go( &SCH_EDITOR_CONTROL::CrossProbeToPcb, EVENTS::UnselectedEvent );
|
||||
Go( &SCH_EDITOR_CONTROL::CrossProbeToPcb, EVENTS::ClearedEvent );
|
||||
Go( &SCH_EDITOR_CONTROL::ExplicitCrossProbeToPcb, EE_ACTIONS::explicitCrossProbe.MakeEvent() );
|
||||
Go( &SCH_EDITOR_CONTROL::ExplicitCrossProbeToPcb, EE_ACTIONS::selectOnPCB.MakeEvent() );
|
||||
|
||||
#ifdef KICAD_SPICE
|
||||
Go( &SCH_EDITOR_CONTROL::SimProbe, EE_ACTIONS::simProbe.MakeEvent() );
|
||||
|
|
|
@ -84,8 +84,7 @@ public:
|
|||
///< Notifies pcbnew about the selected item.
|
||||
int CrossProbeToPcb( const TOOL_EVENT& aEvent );
|
||||
|
||||
///< Equivalent to the above, but initiated by the user. We also do SCH_SHEETs on this
|
||||
///< one (they're too slow on big projects for the auto version above).
|
||||
///< Equivalent to the above, but initiated by the user.
|
||||
int ExplicitCrossProbeToPcb( const TOOL_EVENT& aEvent );
|
||||
|
||||
#ifdef KICAD_SPICE
|
||||
|
@ -151,7 +150,7 @@ public:
|
|||
* Find a symbol in the schematic and an item in this symbol.
|
||||
*
|
||||
* @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
|
||||
* @param aReference The symbol reference designator to find, or to display in
|
||||
* status bar if aPath is specified
|
||||
* @param aSearchHierarchy If false, search the current sheet only. Otherwise,
|
||||
* the entire hierarchy
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
* This program source code file is part of KiCad, a free EDA CAD application.
|
||||
*
|
||||
* Copyright (C) 2014 CERN
|
||||
* Copyright (C) 1992-2021 KiCad Developers, see AUTHORS.TXT for contributors.
|
||||
* Copyright (C) 1992-2022 KiCad Developers, see AUTHORS.TXT for contributors.
|
||||
* @author Maciej Suminski <maciej.suminski@cern.ch>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
|
@ -37,6 +37,7 @@
|
|||
enum MAIL_T
|
||||
{
|
||||
MAIL_CROSS_PROBE, // PCB<->SCH, CVPCB->SCH cross-probing.
|
||||
MAIL_SELECTION, // SCH->PCB selection synchronization.
|
||||
MAIL_ASSIGN_FOOTPRINTS, // CVPCB->SCH footprint stuffing
|
||||
MAIL_SCH_SAVE, // CVPCB->SCH save the schematic
|
||||
MAIL_EESCHEMA_NETLIST, // SCH->CVPCB netlist immediately after launching CVPCB
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
* This program source code file is part of KiCad, a free EDA CAD application.
|
||||
*
|
||||
* Copyright (C) 2020 Jon Evans <jon@craftyjon.com>
|
||||
* Copyright (C) 2020 KiCad Developers, see AUTHORS.txt for contributors.
|
||||
* Copyright (C) 2020-2022 KiCad Developers, see AUTHORS.txt for contributors.
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License as published by the
|
||||
|
@ -29,6 +29,7 @@
|
|||
*/
|
||||
struct CROSS_PROBING_SETTINGS
|
||||
{
|
||||
bool on_selection; ///< Synchronize the selection for multiple items too
|
||||
bool center_on_items; ///< Automatically pan to cross-probed items
|
||||
bool zoom_to_fit; ///< Zoom to fit items (ignored if center_on_items is off)
|
||||
bool auto_highlight; ///< Automatically turn on highlight mode in the target frame
|
||||
|
|
|
@ -53,6 +53,7 @@ enum ESCAPE_CONTEXT
|
|||
{
|
||||
CTX_NETNAME,
|
||||
CTX_LIBID,
|
||||
CTX_IPC,
|
||||
CTX_QUOTED_STR,
|
||||
CTX_LINE,
|
||||
CTX_FILENAME,
|
||||
|
|
|
@ -131,6 +131,16 @@ public:
|
|||
*/
|
||||
static SELECTION_CONDITION HasType( KICAD_T aType );
|
||||
|
||||
/**
|
||||
* Create a functor that tests if among the selected items there is at least one of a
|
||||
* given types.
|
||||
*
|
||||
* @param aTypes is an array containing types that are searched. It has to be ended with
|
||||
* #KICAD_T::EOT as end marker.
|
||||
* @return Functor testing for presence of items of a given types.
|
||||
*/
|
||||
static SELECTION_CONDITION HasTypes( const KICAD_T aTypes[] );
|
||||
|
||||
/**
|
||||
* Create a functor that tests if the selected items are *only* of given type.
|
||||
*
|
||||
|
@ -179,6 +189,9 @@ private:
|
|||
///< Helper function used by HasType()
|
||||
static bool hasTypeFunc( const SELECTION& aSelection, KICAD_T aType );
|
||||
|
||||
///< Helper function used by HasTypes()
|
||||
static bool hasTypesFunc( const SELECTION& aSelection, const KICAD_T aTypes[] );
|
||||
|
||||
///< Helper function used by OnlyType()
|
||||
static bool onlyTypeFunc( const SELECTION& aSelection, KICAD_T aType );
|
||||
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
/*
|
||||
* This program source code file is part of KiCad, a free EDA CAD application.
|
||||
*
|
||||
* Copyright (C) 2019-2021 KiCad Developers, see AUTHORS.txt for contributors.
|
||||
* Copyright (C) 2019-2022 KiCad Developers, see AUTHORS.txt for contributors.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
|
@ -41,6 +41,7 @@
|
|||
#include <eda_dde.h>
|
||||
#include <kiface_base.h>
|
||||
#include <kiway_express.h>
|
||||
#include <string_utils.h>
|
||||
#include <netlist_reader/pcb_netlist.h>
|
||||
#include <netlist_reader/board_netlist_updater.h>
|
||||
#include <painter.h>
|
||||
|
@ -277,133 +278,7 @@ void PCB_EDIT_FRAME::ExecuteRemoteCommand( const char* cmdline )
|
|||
{
|
||||
if( crossProbingSettings.zoom_to_fit )
|
||||
{
|
||||
//#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();
|
||||
auto screenSize = view->ToWorld( GetCanvas()->GetClientSize(), false );
|
||||
|
||||
// The "fabs" on x ensures the right answer when the view is flipped
|
||||
screenSize.x = std::max( 10.0, fabs( screenSize.x ) );
|
||||
screenSize.y = std::max( 10.0, screenSize.y );
|
||||
double ratio = std::max( fabs( bbSize.x / screenSize.x ),
|
||||
fabs( bbSize.y / screenSize.y ) );
|
||||
|
||||
// Try not to zoom on every cross-probe; it gets very noisy
|
||||
if( crossProbingSettings.zoom_to_fit && ( ratio < 0.5 || ratio > 1.0 ) )
|
||||
view->SetScale( view->GetScale() / ratio );
|
||||
#endif // DEFAULT_PCBNEW_CODE
|
||||
|
||||
#ifndef DEFAULT_PCBNEW_CODE // Do the scaled zoom
|
||||
auto bbSize = bbox.Inflate( bbox.GetWidth() * 0.2f ).GetSize();
|
||||
auto screenSize = view->ToWorld( GetCanvas()->GetClientSize(), false );
|
||||
|
||||
// This code tries to come up with a zoom factor that doesn't simply zoom in
|
||||
// to the cross probed component, 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 footprint (like a processor) or a small footprint (like a resistor).
|
||||
// This ratio is not useful by itself as a scaling factor. It must be "bent" to
|
||||
// provide good scaling at varying component sizes. Bigger components need less
|
||||
// scaling than small ones.
|
||||
double currTextHeight = Millimeter2iu( DEFAULT_TEXT_SIZE );
|
||||
|
||||
double compRatio = bbSize.y / currTextHeight; // Ratio of component to text height
|
||||
|
||||
// This will end up as the scaling factor we apply to "ratio".
|
||||
double compRatioBent = 1.0;
|
||||
|
||||
// This is similar to the original KiCad code that scaled the zoom to make sure
|
||||
// components were visible on screen. It's simply a ratio of screen size to
|
||||
// component size, and its job is to zoom in to make the component fullscreen.
|
||||
// Earlier in the code the component BBox is given a 20% margin to add some
|
||||
// breathing room. We compare the height of this enlarged component bbox to the
|
||||
// default text height. If a component will end up with the sides clipped, we
|
||||
// adjust later to make sure it fits on screen.
|
||||
//
|
||||
// The "fabs" on x ensures the right answer when the view is flipped
|
||||
screenSize.x = std::max( 10.0, fabs( 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 ) );
|
||||
|
||||
// LUT to scale zoom ratio to provide reasonable schematic context. Must work
|
||||
// with footprints of varying sizes (e.g. 0402 package and 200 pin BGA).
|
||||
// "first" is used as the input and "second" as the output
|
||||
//
|
||||
// "first" = compRatio (footprint height / default text height)
|
||||
// "second" = Amount to scale ratio by
|
||||
std::vector<std::pair<double, double>> lut{
|
||||
{ 1, 8 },
|
||||
{ 1.5, 5 },
|
||||
{ 3, 3 },
|
||||
{ 4.5, 2.5 },
|
||||
{ 8, 2.0 },
|
||||
{ 12, 1.7 },
|
||||
{ 16, 1.5 },
|
||||
{ 24, 1.3 },
|
||||
{ 32, 1.0 },
|
||||
};
|
||||
|
||||
|
||||
std::vector<std::pair<double, double>>::iterator it;
|
||||
|
||||
compRatioBent = lut.back().second; // Large component default
|
||||
|
||||
if( compRatio >= lut.front().first )
|
||||
{
|
||||
// Use LUT to do linear interpolation of "compRatio" within "first", then
|
||||
// use that result to linearly interpolate "second" which gives the scaling
|
||||
// factor needed.
|
||||
|
||||
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 component default
|
||||
}
|
||||
|
||||
// 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. This will apply to parts that
|
||||
// are much wider than they are tall.
|
||||
|
||||
if( bbSize.x > screenSize.x * ratio * compRatioBent )
|
||||
{
|
||||
// Use standard KiCad zoom algorithm for parts too wide to fit 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 )
|
||||
view->SetScale( view->GetScale() / ratio );
|
||||
#endif // ifndef DEFAULT_PCBNEW_CODE
|
||||
GetToolManager()->GetTool<PCB_SELECTION_TOOL>()->zoomFitCrossProbeBBox( bbox );
|
||||
}
|
||||
|
||||
FocusOnLocation( (wxPoint) bbox.Centre() );
|
||||
|
@ -510,6 +385,77 @@ void PCB_EDIT_FRAME::SendCrossProbeNetName( const wxString& aNetName )
|
|||
}
|
||||
|
||||
|
||||
std::vector<BOARD_ITEM*> PCB_EDIT_FRAME::FindItemsFromSyncSelection( std::string syncStr )
|
||||
{
|
||||
wxArrayString syncArray = wxStringTokenize( syncStr, "," );
|
||||
|
||||
std::vector<BOARD_ITEM*> items;
|
||||
|
||||
for( FOOTPRINT* footprint : GetBoard()->Footprints() )
|
||||
{
|
||||
if( footprint == nullptr )
|
||||
continue;
|
||||
|
||||
wxString fpSheetPath = footprint->GetPath().AsString().BeforeLast( '/' );
|
||||
wxString fpUUID = footprint->m_Uuid.AsString();
|
||||
|
||||
if( fpSheetPath.IsEmpty() )
|
||||
fpSheetPath += '/';
|
||||
|
||||
if( fpUUID.empty() )
|
||||
continue;
|
||||
|
||||
wxString fpRefEscaped = EscapeString( footprint->GetReference(), CTX_IPC );
|
||||
|
||||
for( wxString syncEntry : syncArray )
|
||||
{
|
||||
if( syncEntry.empty() )
|
||||
continue;
|
||||
|
||||
wxString syncData = syncEntry.substr( 1 );
|
||||
|
||||
switch( syncEntry.GetChar( 0 ).GetValue() )
|
||||
{
|
||||
case 'S': // Select sheet with subsheets: S<Sheet path>
|
||||
if( fpSheetPath.StartsWith( syncData ) )
|
||||
{
|
||||
items.push_back( footprint );
|
||||
}
|
||||
break;
|
||||
case 'F': // Select footprint: F<Reference>
|
||||
if( syncData == fpRefEscaped )
|
||||
{
|
||||
items.push_back( footprint );
|
||||
}
|
||||
break;
|
||||
case 'P': // Select pad: P<Footprint reference>/<Pad number>
|
||||
{
|
||||
if( syncData.StartsWith( fpRefEscaped ) )
|
||||
{
|
||||
wxString selectPadNumberEscaped =
|
||||
syncData.substr( fpRefEscaped.size() + 1 ); // Skips the slash
|
||||
|
||||
wxString selectPadNumber = UnescapeString( selectPadNumberEscaped );
|
||||
|
||||
for( PAD* pad : footprint->Pads() )
|
||||
{
|
||||
if( selectPadNumber == pad->GetNumber() )
|
||||
{
|
||||
items.push_back( pad );
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
default: break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return items;
|
||||
}
|
||||
|
||||
|
||||
void PCB_EDIT_FRAME::KiwayMailIn( KIWAY_EXPRESS& mail )
|
||||
{
|
||||
std::string& payload = mail.GetPayload();
|
||||
|
@ -575,6 +521,50 @@ void PCB_EDIT_FRAME::KiwayMailIn( KIWAY_EXPRESS& mail )
|
|||
ExecuteRemoteCommand( payload.c_str() );
|
||||
break;
|
||||
|
||||
case MAIL_SELECTION:
|
||||
{
|
||||
// $SELECT: <mode 0 - only footprints, 1 - with connections>,<spec1>,<spec2>,<spec3>
|
||||
std::string prefix = "$SELECT: ";
|
||||
|
||||
if( !payload.compare( 0, prefix.size(), prefix ) )
|
||||
{
|
||||
std::string del = ",";
|
||||
std::string paramStr = payload.substr( prefix.size() );
|
||||
int modeEnd = paramStr.find( del );
|
||||
bool selectConnections = false;
|
||||
|
||||
try
|
||||
{
|
||||
if( std::stoi( paramStr.substr( 0, modeEnd ) ) == 1 )
|
||||
selectConnections = true;
|
||||
}
|
||||
catch( std::invalid_argument& )
|
||||
{
|
||||
wxFAIL;
|
||||
}
|
||||
|
||||
std::vector<BOARD_ITEM*> items =
|
||||
FindItemsFromSyncSelection( paramStr.substr( modeEnd + 1 ) );
|
||||
|
||||
m_syncingSchToPcbSelection = true; // recursion guard
|
||||
|
||||
if( selectConnections )
|
||||
{
|
||||
GetToolManager()->RunAction( PCB_ACTIONS::syncSelectionWithNets, true,
|
||||
static_cast<void*>( &items ) );
|
||||
}
|
||||
else
|
||||
{
|
||||
GetToolManager()->RunAction( PCB_ACTIONS::syncSelection, true,
|
||||
static_cast<void*>( &items ) );
|
||||
}
|
||||
|
||||
m_syncingSchToPcbSelection = false;
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
case MAIL_PCB_UPDATE:
|
||||
m_toolManager->RunAction( ACTIONS::updatePcbFromSchematic, true );
|
||||
break;
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
* This program source code file is part of KiCad, a free EDA CAD application.
|
||||
*
|
||||
* Copyright (C) 2015 Jean-Pierre Charras, jean-pierre.charras at wanadoo.fr
|
||||
* Copyright (C) 1992-2021 KiCad Developers, see AUTHORS.txt for contributors.
|
||||
* Copyright (C) 1992-2022 KiCad Developers, see AUTHORS.txt for contributors.
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License as published by the
|
||||
|
@ -57,6 +57,7 @@ void PANEL_DISPLAY_OPTIONS::loadPCBSettings( PCBNEW_SETTINGS* aCfg )
|
|||
m_OptDisplayPadNoConn->SetValue( aCfg->m_Display.m_DisplayPadNoConnects );
|
||||
m_ShowNetNamesOption->SetSelection( aCfg->m_Display.m_DisplayNetNamesMode );
|
||||
m_live3Drefresh->SetValue( aCfg->m_Display.m_Live3DRefresh );
|
||||
m_checkCrossProbeOnSelection->SetValue( aCfg->m_CrossProbing.on_selection );
|
||||
m_checkCrossProbeCenter->SetValue( aCfg->m_CrossProbing.center_on_items );
|
||||
m_checkCrossProbeZoom->SetValue( aCfg->m_CrossProbing.zoom_to_fit );
|
||||
m_checkCrossProbeAutoHighlight->SetValue( aCfg->m_CrossProbing.auto_highlight );
|
||||
|
@ -99,7 +100,7 @@ bool PANEL_DISPLAY_OPTIONS::TransferDataFromWindow()
|
|||
cfg->m_Display.m_DisplayPadNoConnects = m_OptDisplayPadNoConn->GetValue();
|
||||
cfg->m_Display.m_DisplayNetNamesMode = m_ShowNetNamesOption->GetSelection();
|
||||
cfg->m_Display.m_Live3DRefresh = m_live3Drefresh->GetValue();
|
||||
cfg->m_CrossProbing.center_on_items = m_checkCrossProbeCenter->GetValue();
|
||||
cfg->m_CrossProbing.on_selection = m_checkCrossProbeOnSelection->GetValue();
|
||||
cfg->m_CrossProbing.zoom_to_fit = m_checkCrossProbeZoom->GetValue();
|
||||
cfg->m_CrossProbing.auto_highlight = m_checkCrossProbeAutoHighlight->GetValue();
|
||||
}
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
///////////////////////////////////////////////////////////////////////////
|
||||
// C++ code generated with wxFormBuilder (version Oct 26 2018)
|
||||
// C++ code generated with wxFormBuilder (version 3.10.1-0-g8feb16b3)
|
||||
// http://www.wxformbuilder.org/
|
||||
//
|
||||
// PLEASE DO *NOT* EDIT THIS FILE!
|
||||
|
@ -73,6 +73,10 @@ PANEL_DISPLAY_OPTIONS_BASE::PANEL_DISPLAY_OPTIONS_BASE( wxWindow* parent, wxWind
|
|||
wxStaticBoxSizer* sbSizer3;
|
||||
sbSizer3 = new wxStaticBoxSizer( new wxStaticBox( pcbPage, wxID_ANY, _("Cross-probing") ), wxVERTICAL );
|
||||
|
||||
m_checkCrossProbeOnSelection = new wxCheckBox( sbSizer3->GetStaticBox(), wxID_ANY, _("Cross-probe on selection"), wxDefaultPosition, wxDefaultSize, 0 );
|
||||
m_checkCrossProbeOnSelection->SetValue(true);
|
||||
sbSizer3->Add( m_checkCrossProbeOnSelection, 0, wxALL, 5 );
|
||||
|
||||
m_checkCrossProbeCenter = new wxCheckBox( sbSizer3->GetStaticBox(), wxID_ANY, _("Scroll cross-probed items into view"), wxDefaultPosition, wxDefaultSize, 0 );
|
||||
m_checkCrossProbeCenter->SetValue(true);
|
||||
sbSizer3->Add( m_checkCrossProbeCenter, 0, wxBOTTOM|wxRIGHT|wxLEFT, 5 );
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
<?xml version="1.0" encoding="UTF-8" standalone="yes" ?>
|
||||
<wxFormBuilder_Project>
|
||||
<FileVersion major="1" minor="15" />
|
||||
<FileVersion major="1" minor="16" />
|
||||
<object class="Project" expanded="1">
|
||||
<property name="class_decoration"></property>
|
||||
<property name="code_generation">C++</property>
|
||||
|
@ -14,6 +14,7 @@
|
|||
<property name="file">panel_display_options_base</property>
|
||||
<property name="first_id">1000</property>
|
||||
<property name="help_provider">none</property>
|
||||
<property name="image_path_wrapper_function_name"></property>
|
||||
<property name="indent_with_spaces"></property>
|
||||
<property name="internationalize">1</property>
|
||||
<property name="name">PanelDisplayOptions</property>
|
||||
|
@ -25,6 +26,7 @@
|
|||
<property name="skip_php_events">1</property>
|
||||
<property name="skip_python_events">1</property>
|
||||
<property name="ui_table">UI</property>
|
||||
<property name="use_array_enum">0</property>
|
||||
<property name="use_enum">1</property>
|
||||
<property name="use_microsoft_bom">0</property>
|
||||
<object class="Panel" expanded="1">
|
||||
|
@ -46,6 +48,7 @@
|
|||
<property name="size">-1,-1</property>
|
||||
<property name="subclass">RESETTABLE_PANEL; widgets/resettable_panel.h; Not forward_declare</property>
|
||||
<property name="tooltip"></property>
|
||||
<property name="two_step_creation">0</property>
|
||||
<property name="window_extra_style"></property>
|
||||
<property name="window_name"></property>
|
||||
<property name="window_style">wxTAB_TRAVERSAL</property>
|
||||
|
@ -608,6 +611,70 @@
|
|||
<property name="orient">wxVERTICAL</property>
|
||||
<property name="parent">1</property>
|
||||
<property name="permission">none</property>
|
||||
<object class="sizeritem" expanded="1">
|
||||
<property name="border">5</property>
|
||||
<property name="flag">wxALL</property>
|
||||
<property name="proportion">0</property>
|
||||
<object class="wxCheckBox" expanded="1">
|
||||
<property name="BottomDockable">1</property>
|
||||
<property name="LeftDockable">1</property>
|
||||
<property name="RightDockable">1</property>
|
||||
<property name="TopDockable">1</property>
|
||||
<property name="aui_layer"></property>
|
||||
<property name="aui_name"></property>
|
||||
<property name="aui_position"></property>
|
||||
<property name="aui_row"></property>
|
||||
<property name="best_size"></property>
|
||||
<property name="bg"></property>
|
||||
<property name="caption"></property>
|
||||
<property name="caption_visible">1</property>
|
||||
<property name="center_pane">0</property>
|
||||
<property name="checked">1</property>
|
||||
<property name="close_button">1</property>
|
||||
<property name="context_help"></property>
|
||||
<property name="context_menu">1</property>
|
||||
<property name="default_pane">0</property>
|
||||
<property name="dock">Dock</property>
|
||||
<property name="dock_fixed">0</property>
|
||||
<property name="docking">Left</property>
|
||||
<property name="enabled">1</property>
|
||||
<property name="fg"></property>
|
||||
<property name="floatable">1</property>
|
||||
<property name="font"></property>
|
||||
<property name="gripper">0</property>
|
||||
<property name="hidden">0</property>
|
||||
<property name="id">wxID_ANY</property>
|
||||
<property name="label">Cross-probe on selection</property>
|
||||
<property name="max_size"></property>
|
||||
<property name="maximize_button">0</property>
|
||||
<property name="maximum_size"></property>
|
||||
<property name="min_size"></property>
|
||||
<property name="minimize_button">0</property>
|
||||
<property name="minimum_size"></property>
|
||||
<property name="moveable">1</property>
|
||||
<property name="name">m_checkCrossProbeOnSelection</property>
|
||||
<property name="pane_border">1</property>
|
||||
<property name="pane_position"></property>
|
||||
<property name="pane_size"></property>
|
||||
<property name="permission">protected</property>
|
||||
<property name="pin_button">1</property>
|
||||
<property name="pos"></property>
|
||||
<property name="resize">Resizable</property>
|
||||
<property name="show">1</property>
|
||||
<property name="size"></property>
|
||||
<property name="style"></property>
|
||||
<property name="subclass">; ; forward_declare</property>
|
||||
<property name="toolbar_pane">0</property>
|
||||
<property name="tooltip"></property>
|
||||
<property name="validator_data_type"></property>
|
||||
<property name="validator_style">wxFILTER_NONE</property>
|
||||
<property name="validator_type">wxDefaultValidator</property>
|
||||
<property name="validator_variable"></property>
|
||||
<property name="window_extra_style"></property>
|
||||
<property name="window_name"></property>
|
||||
<property name="window_style"></property>
|
||||
</object>
|
||||
</object>
|
||||
<object class="sizeritem" expanded="1">
|
||||
<property name="border">5</property>
|
||||
<property name="flag">wxBOTTOM|wxRIGHT|wxLEFT</property>
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
///////////////////////////////////////////////////////////////////////////
|
||||
// C++ code generated with wxFormBuilder (version Oct 26 2018)
|
||||
// C++ code generated with wxFormBuilder (version 3.10.1-0-g8feb16b3)
|
||||
// http://www.wxformbuilder.org/
|
||||
//
|
||||
// PLEASE DO *NOT* EDIT THIS FILE!
|
||||
|
@ -45,6 +45,7 @@ class PANEL_DISPLAY_OPTIONS_BASE : public RESETTABLE_PANEL
|
|||
wxCheckBox* m_OptDisplayPadNoConn;
|
||||
wxRadioBox* m_OptDisplayTracksClearance;
|
||||
wxCheckBox* m_OptDisplayPadClearence;
|
||||
wxCheckBox* m_checkCrossProbeOnSelection;
|
||||
wxCheckBox* m_checkCrossProbeCenter;
|
||||
wxCheckBox* m_checkCrossProbeZoom;
|
||||
wxCheckBox* m_checkCrossProbeAutoHighlight;
|
||||
|
@ -53,6 +54,7 @@ class PANEL_DISPLAY_OPTIONS_BASE : public RESETTABLE_PANEL
|
|||
public:
|
||||
|
||||
PANEL_DISPLAY_OPTIONS_BASE( wxWindow* parent, wxWindowID id = wxID_ANY, const wxPoint& pos = wxDefaultPosition, const wxSize& size = wxSize( -1,-1 ), long style = wxTAB_TRAVERSAL, const wxString& name = wxEmptyString );
|
||||
|
||||
~PANEL_DISPLAY_OPTIONS_BASE();
|
||||
|
||||
};
|
||||
|
|
|
@ -4,7 +4,7 @@
|
|||
* Copyright (C) 2018 Jean-Pierre Charras, jp.charras at wanadoo.fr
|
||||
* Copyright (C) 2013 SoftPLC Corporation, Dick Hollenbeck <dick@softplc.com>
|
||||
* Copyright (C) 2013 Wayne Stambaugh <stambaughw@gmail.com>
|
||||
* Copyright (C) 2013-2021 KiCad Developers, see AUTHORS.txt for contributors.
|
||||
* Copyright (C) 2013-2022 KiCad Developers, see AUTHORS.txt for contributors.
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License as published by the
|
||||
|
@ -175,10 +175,10 @@ END_EVENT_TABLE()
|
|||
|
||||
|
||||
PCB_EDIT_FRAME::PCB_EDIT_FRAME( KIWAY* aKiway, wxWindow* aParent ) :
|
||||
PCB_BASE_EDIT_FRAME( aKiway, aParent, FRAME_PCB_EDITOR, _( "PCB Editor" ), wxDefaultPosition,
|
||||
wxDefaultSize, KICAD_DEFAULT_DRAWFRAME_STYLE, PCB_EDIT_FRAME_NAME ),
|
||||
m_exportNetlistAction( nullptr ),
|
||||
m_findDialog( nullptr )
|
||||
PCB_BASE_EDIT_FRAME( aKiway, aParent, FRAME_PCB_EDITOR, _( "PCB Editor" ),
|
||||
wxDefaultPosition, wxDefaultSize, KICAD_DEFAULT_DRAWFRAME_STYLE,
|
||||
PCB_EDIT_FRAME_NAME ),
|
||||
m_exportNetlistAction( nullptr ), m_findDialog( nullptr )
|
||||
{
|
||||
m_maximizeByDefault = true;
|
||||
m_showBorderAndTitleBlock = true; // true to display sheet references
|
||||
|
@ -187,6 +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;
|
||||
|
||||
// We don't know what state board was in when it was last saved, so we have to
|
||||
// assume dirty
|
||||
|
|
|
@ -121,6 +121,11 @@ public:
|
|||
|
||||
void KiwayMailIn( KIWAY_EXPRESS& aEvent ) override;
|
||||
|
||||
/**
|
||||
* Used to find items by selection synchronization spec string.
|
||||
*/
|
||||
std::vector<BOARD_ITEM*> FindItemsFromSyncSelection( std::string syncStr );
|
||||
|
||||
/**
|
||||
* Show the Find dialog.
|
||||
*/
|
||||
|
@ -782,6 +787,8 @@ public:
|
|||
|
||||
bool m_ZoneFillsDirty; // Board has been modified since last zone fill.
|
||||
|
||||
bool m_syncingSchToPcbSelection; // Recursion guard when synchronizing selection from schematic
|
||||
|
||||
private:
|
||||
friend struct PCB::IFACE;
|
||||
friend class APPEARANCE_CONTROLS;
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
/*
|
||||
* This program source code file is part of KiCad, a free EDA CAD application.
|
||||
*
|
||||
* Copyright (C) 2019-2021 KiCad Developers, see AUTHORS.txt for contributors.
|
||||
* Copyright (C) 2019-2022 KiCad Developers, see AUTHORS.txt for contributors.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
|
@ -866,7 +866,10 @@ 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 )
|
||||
if( m_probingSchToPcb || m_frame->m_syncingSchToPcbSelection )
|
||||
return 0;
|
||||
|
||||
if( !frame()->Settings().m_CrossProbing.on_selection )
|
||||
return 0;
|
||||
|
||||
PCB_SELECTION_TOOL* selTool = m_toolMgr->GetTool<PCB_SELECTION_TOOL>();
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
* This program source code file is part of KiCad, a free EDA CAD application.
|
||||
*
|
||||
* Copyright (C) 2013-2016 CERN
|
||||
* Copyright (C) 2016-2021 KiCad Developers, see AUTHORS.txt for contributors.
|
||||
* Copyright (C) 2016-2022 KiCad Developers, see AUTHORS.txt for contributors.
|
||||
* @author Maciej Suminski <maciej.suminski@cern.ch>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
|
@ -1240,6 +1240,12 @@ TOOL_ACTION PCB_ACTIONS::selectConnection( "pcbnew.InteractiveSelection.SelectCo
|
|||
_( "Selects a connection or expands an existing selection to junctions, pads, or entire connections" ),
|
||||
BITMAPS::add_tracks );
|
||||
|
||||
TOOL_ACTION PCB_ACTIONS::syncSelection( "pcbnew.InteractiveSelection.SyncSelection",
|
||||
AS_GLOBAL );
|
||||
|
||||
TOOL_ACTION PCB_ACTIONS::syncSelectionWithNets( "pcbnew.InteractiveSelection.SyncSelectionWithNets",
|
||||
AS_GLOBAL );
|
||||
|
||||
TOOL_ACTION PCB_ACTIONS::selectNet( "pcbnew.InteractiveSelection.SelectNet",
|
||||
AS_GLOBAL, 0, "",
|
||||
_( "Select All Tracks in Net" ),
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
* This program source code file is part of KiCad, a free EDA CAD application.
|
||||
*
|
||||
* Copyright (C) 2013-2016 CERN
|
||||
* Copyright (C) 2016-2021 KiCad Developers, see AUTHORS.txt for contributors.
|
||||
* Copyright (C) 2016-2022 KiCad Developers, see AUTHORS.txt for contributors.
|
||||
*
|
||||
* @author Maciej Suminski <maciej.suminski@cern.ch>
|
||||
*
|
||||
|
@ -66,6 +66,12 @@ public:
|
|||
static TOOL_ACTION selectItems;
|
||||
static TOOL_ACTION unselectItems;
|
||||
|
||||
/// Sets selection to specified items, zooms to fit, if enabled
|
||||
static TOOL_ACTION syncSelection;
|
||||
|
||||
/// Sets selection to specified items with connected nets, zooms to fit, if enabled
|
||||
static TOOL_ACTION syncSelectionWithNets;
|
||||
|
||||
/// Run a selection menu to select from a list of items
|
||||
static TOOL_ACTION selectionMenu;
|
||||
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
* This program source code file is part of KiCad, a free EDA CAD application.
|
||||
*
|
||||
* Copyright (C) 2013-2017 CERN
|
||||
* Copyright (C) 2018-2021 KiCad Developers, see AUTHORS.txt for contributors.
|
||||
* Copyright (C) 2018-2022 KiCad Developers, see AUTHORS.txt for contributors.
|
||||
* @author Tomasz Wlostowski <tomasz.wlostowski@cern.ch>
|
||||
* @author Maciej Suminski <maciej.suminski@cern.ch>
|
||||
*
|
||||
|
@ -25,6 +25,7 @@
|
|||
*/
|
||||
|
||||
#include <limits>
|
||||
#include <cmath>
|
||||
#include <functional>
|
||||
using namespace std::placeholders;
|
||||
#include <core/kicad_algo.h>
|
||||
|
@ -62,6 +63,7 @@ using namespace std::placeholders;
|
|||
#include <wx/event.h>
|
||||
#include <wx/timer.h>
|
||||
#include <wx/log.h>
|
||||
#include <profile.h>
|
||||
|
||||
|
||||
class SELECT_MENU : public ACTION_MENU
|
||||
|
@ -1100,34 +1102,49 @@ int PCB_SELECTION_TOOL::expandConnection( const TOOL_EVENT& aEvent )
|
|||
|
||||
for( const EDA_ITEM* item : m_selection.GetItems() )
|
||||
{
|
||||
if( dynamic_cast<const BOARD_CONNECTED_ITEM*>( item ) )
|
||||
if( item->Type() == PCB_FOOTPRINT_T || BOARD_CONNECTED_ITEM::ClassOf( item ) )
|
||||
initialCount++;
|
||||
}
|
||||
|
||||
if( initialCount == 0 )
|
||||
selectCursor( true, connectedItemFilter );
|
||||
|
||||
m_frame->SetStatusText( _( "Select/Expand Connection..." ) );
|
||||
|
||||
for( STOP_CONDITION stopCondition : { STOP_AT_JUNCTION, STOP_AT_PAD, STOP_NEVER } )
|
||||
{
|
||||
// copy the selection, since we're going to iterate and modify
|
||||
std::deque<EDA_ITEM*> selectedItems = m_selection.GetItems();
|
||||
|
||||
for( EDA_ITEM* item : selectedItems )
|
||||
item->ClearTempFlags();
|
||||
|
||||
std::vector<BOARD_CONNECTED_ITEM*> startItems;
|
||||
|
||||
for( EDA_ITEM* item : selectedItems )
|
||||
{
|
||||
PCB_TRACK* trackItem = dynamic_cast<PCB_TRACK*>( item );
|
||||
if( item->Type() == PCB_FOOTPRINT_T )
|
||||
{
|
||||
FOOTPRINT* footprint = static_cast<FOOTPRINT*>( item );
|
||||
|
||||
// Track items marked SKIP_STRUCT have already been visited
|
||||
if( trackItem && !( trackItem->GetFlags() & SKIP_STRUCT ) )
|
||||
selectConnectedTracks( *trackItem, stopCondition );
|
||||
for( PAD* pad : footprint->Pads() )
|
||||
{
|
||||
startItems.push_back( pad );
|
||||
}
|
||||
}
|
||||
else if( BOARD_CONNECTED_ITEM::ClassOf( item ) )
|
||||
{
|
||||
startItems.push_back( static_cast<BOARD_CONNECTED_ITEM*>( item ) );
|
||||
}
|
||||
}
|
||||
|
||||
selectAllConnectedTracks( startItems, stopCondition );
|
||||
|
||||
if( m_selection.GetItems().size() > initialCount )
|
||||
break;
|
||||
}
|
||||
|
||||
m_frame->SetStatusText( wxEmptyString );
|
||||
|
||||
// Inform other potentially interested tools
|
||||
if( m_selection.Size() > 0 )
|
||||
m_toolMgr->ProcessEvent( EVENTS::SelectedEvent );
|
||||
|
@ -1136,165 +1153,220 @@ int PCB_SELECTION_TOOL::expandConnection( const TOOL_EVENT& aEvent )
|
|||
}
|
||||
|
||||
|
||||
void PCB_SELECTION_TOOL::selectConnectedTracks( BOARD_CONNECTED_ITEM& aStartItem,
|
||||
STOP_CONDITION aStopCondition )
|
||||
void PCB_SELECTION_TOOL::selectAllConnectedTracks(
|
||||
const std::vector<BOARD_CONNECTED_ITEM*>& aStartItems, STOP_CONDITION aStopCondition )
|
||||
{
|
||||
constexpr KICAD_T types[] = { PCB_TRACE_T, PCB_ARC_T, PCB_VIA_T, PCB_PAD_T, EOT };
|
||||
constexpr PCB_LAYER_ID ALL_LAYERS = UNDEFINED_LAYER;
|
||||
constexpr KICAD_T types[] = { PCB_TRACE_T, PCB_ARC_T, PCB_VIA_T, PCB_PAD_T, EOT };
|
||||
const LSET allCuMask = LSET::AllCuMask();
|
||||
|
||||
PROF_TIMER refreshTimer;
|
||||
double refreshIntervalMs = 500; // Refresh display with this interval to indicate progress
|
||||
int lastSelectionSize = m_selection.GetSize();
|
||||
|
||||
auto connectivity = board()->GetConnectivity();
|
||||
auto connectedItems = connectivity->GetConnectedItems( &aStartItem, types, true );
|
||||
|
||||
std::map<VECTOR2I, std::vector<PCB_TRACK*>> trackMap;
|
||||
std::map<VECTOR2I, PCB_VIA*> viaMap;
|
||||
std::map<VECTOR2I, PAD*> padMap;
|
||||
std::set<PAD*> startPadSet;
|
||||
std::vector<BOARD_CONNECTED_ITEM*> cleanupItems;
|
||||
std::vector<std::pair<VECTOR2I, LSET>> activePts;
|
||||
|
||||
// Build maps of connected items
|
||||
for( BOARD_CONNECTED_ITEM* item : connectedItems )
|
||||
for( BOARD_CONNECTED_ITEM* startItem : aStartItems )
|
||||
{
|
||||
switch( item->Type() )
|
||||
// Track starting pads
|
||||
if( startItem->Type() == PCB_PAD_T )
|
||||
startPadSet.insert( static_cast<PAD*>( startItem ) );
|
||||
}
|
||||
|
||||
for( BOARD_CONNECTED_ITEM* startItem : aStartItems )
|
||||
{
|
||||
if( startItem->HasFlag( SKIP_STRUCT ) ) // Skip already visited items
|
||||
continue;
|
||||
|
||||
std::vector<BOARD_CONNECTED_ITEM*> connectedItems =
|
||||
connectivity->GetConnectedItems( startItem, types, true );
|
||||
|
||||
// Build maps of connected items
|
||||
for( BOARD_CONNECTED_ITEM* item : connectedItems )
|
||||
{
|
||||
switch( item->Type() )
|
||||
{
|
||||
case PCB_ARC_T:
|
||||
case PCB_TRACE_T:
|
||||
{
|
||||
PCB_TRACK* track = static_cast<PCB_TRACK*>( item );
|
||||
trackMap[track->GetStart()].push_back( track );
|
||||
trackMap[track->GetEnd()].push_back( track );
|
||||
break;
|
||||
}
|
||||
|
||||
case PCB_VIA_T:
|
||||
{
|
||||
PCB_VIA* via = static_cast<PCB_VIA*>( item );
|
||||
viaMap[via->GetStart()] = via;
|
||||
break;
|
||||
}
|
||||
|
||||
case PCB_PAD_T:
|
||||
{
|
||||
PAD* pad = static_cast<PAD*>( item );
|
||||
padMap[pad->GetPosition()] = pad;
|
||||
break;
|
||||
}
|
||||
|
||||
default: break;
|
||||
}
|
||||
}
|
||||
|
||||
// Set up the initial active points
|
||||
switch( startItem->Type() )
|
||||
{
|
||||
case PCB_ARC_T:
|
||||
case PCB_TRACE_T:
|
||||
{
|
||||
PCB_TRACK* track = static_cast<PCB_TRACK*>( item );
|
||||
trackMap[ track->GetStart() ].push_back( track );
|
||||
trackMap[ track->GetEnd() ].push_back( track );
|
||||
PCB_TRACK* track = static_cast<PCB_TRACK*>( startItem );
|
||||
|
||||
activePts.push_back( { track->GetStart(), track->GetLayerSet() } );
|
||||
activePts.push_back( { track->GetEnd(), track->GetLayerSet() } );
|
||||
break;
|
||||
}
|
||||
|
||||
case PCB_VIA_T:
|
||||
{
|
||||
PCB_VIA* via = static_cast<PCB_VIA*>( item );
|
||||
viaMap[ via->GetStart() ] = via;
|
||||
activePts.push_back( { startItem->GetPosition(), startItem->GetLayerSet() } );
|
||||
break;
|
||||
}
|
||||
|
||||
case PCB_PAD_T:
|
||||
{
|
||||
PAD* pad = static_cast<PAD*>( item );
|
||||
padMap[ pad->GetPosition() ] = pad;
|
||||
activePts.push_back( { startItem->GetPosition(), startItem->GetLayerSet() } );
|
||||
break;
|
||||
|
||||
default: break;
|
||||
}
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
bool expand = true;
|
||||
int failSafe = 0;
|
||||
|
||||
item->ClearFlags( TEMP_SELECTED );
|
||||
}
|
||||
|
||||
std::vector<std::pair<VECTOR2I, PCB_LAYER_ID>> activePts;
|
||||
|
||||
// Set up the initial active points
|
||||
switch( aStartItem.Type() )
|
||||
{
|
||||
case PCB_ARC_T:
|
||||
case PCB_TRACE_T:
|
||||
{
|
||||
PCB_TRACK* track = static_cast<PCB_TRACK*>( &aStartItem );
|
||||
|
||||
activePts.push_back( { track->GetStart(), track->GetLayer() } );
|
||||
activePts.push_back( { track->GetEnd(), track->GetLayer() } );
|
||||
}
|
||||
break;
|
||||
|
||||
case PCB_VIA_T:
|
||||
activePts.push_back( { aStartItem.GetPosition(), ALL_LAYERS } );
|
||||
break;
|
||||
|
||||
case PCB_PAD_T:
|
||||
activePts.push_back( { aStartItem.GetPosition(), ALL_LAYERS } );
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
bool expand = true;
|
||||
int failSafe = 0;
|
||||
|
||||
// Iterative push from all active points
|
||||
while( expand && failSafe++ < 100000 )
|
||||
{
|
||||
expand = false;
|
||||
|
||||
for( int i = activePts.size() - 1; i >= 0; --i )
|
||||
// Iterative push from all active points
|
||||
while( expand && failSafe++ < 100000 )
|
||||
{
|
||||
VECTOR2I pt = activePts[i].first;
|
||||
PCB_LAYER_ID layer = activePts[i].second;
|
||||
size_t pt_count = 0;
|
||||
expand = false;
|
||||
|
||||
for( PCB_TRACK* track : trackMap[pt] )
|
||||
for( int i = activePts.size() - 1; i >= 0; --i )
|
||||
{
|
||||
if( layer == ALL_LAYERS || layer == track->GetLayer() )
|
||||
pt_count++;
|
||||
}
|
||||
VECTOR2I pt = activePts[i].first;
|
||||
LSET layerSetCu = activePts[i].second & allCuMask;
|
||||
|
||||
if( aStopCondition == STOP_AT_JUNCTION )
|
||||
{
|
||||
if( pt_count > 2
|
||||
|| ( viaMap.count( pt ) && layer != ALL_LAYERS )
|
||||
|| ( padMap.count( pt ) && layer != ALL_LAYERS ) )
|
||||
auto viaIt = viaMap.find( pt );
|
||||
auto padIt = padMap.find( pt );
|
||||
|
||||
bool gotVia = ( viaIt != viaMap.end() )
|
||||
&& ( layerSetCu & ( viaIt->second->GetLayerSet() ) ).any();
|
||||
|
||||
bool gotPad = ( padIt != padMap.end() )
|
||||
&& ( layerSetCu & ( padIt->second->GetLayerSet() ) ).any();
|
||||
|
||||
bool gotNonStartPad =
|
||||
gotPad && ( startPadSet.find( padIt->second ) == startPadSet.end() );
|
||||
|
||||
if( aStopCondition == STOP_AT_JUNCTION )
|
||||
{
|
||||
activePts.erase( activePts.begin() + i );
|
||||
continue;
|
||||
size_t pt_count = 0;
|
||||
|
||||
for( PCB_TRACK* track : trackMap[pt] )
|
||||
{
|
||||
if( layerSetCu.Contains( track->GetLayer() ) )
|
||||
pt_count++;
|
||||
}
|
||||
|
||||
if( pt_count > 2 || gotVia || gotNonStartPad )
|
||||
{
|
||||
activePts.erase( activePts.begin() + i );
|
||||
continue;
|
||||
}
|
||||
}
|
||||
}
|
||||
else if( aStopCondition == STOP_AT_PAD )
|
||||
{
|
||||
if( padMap.count( pt ) )
|
||||
else if( aStopCondition == STOP_AT_PAD )
|
||||
{
|
||||
activePts.erase( activePts.begin() + i );
|
||||
continue;
|
||||
if( gotNonStartPad )
|
||||
{
|
||||
activePts.erase( activePts.begin() + i );
|
||||
continue;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if( padMap.count( pt ) )
|
||||
{
|
||||
PAD* pad = padMap[ pt ];
|
||||
|
||||
if( !( pad->GetFlags() & TEMP_SELECTED ) )
|
||||
if( gotPad )
|
||||
{
|
||||
pad->SetFlags( TEMP_SELECTED );
|
||||
activePts.push_back( { pad->GetPosition(), ALL_LAYERS } );
|
||||
expand = true;
|
||||
PAD* pad = padIt->second;
|
||||
|
||||
if( !pad->HasFlag( SKIP_STRUCT ) )
|
||||
{
|
||||
pad->SetFlags( SKIP_STRUCT );
|
||||
cleanupItems.push_back( pad );
|
||||
|
||||
activePts.push_back( { pad->GetPosition(), pad->GetLayerSet() } );
|
||||
expand = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for( PCB_TRACK* track : trackMap[ pt ] )
|
||||
{
|
||||
if( layer != ALL_LAYERS && track->GetLayer() != layer )
|
||||
continue;
|
||||
|
||||
if( !track->IsSelected() )
|
||||
for( PCB_TRACK* track : trackMap[pt] )
|
||||
{
|
||||
select( track );
|
||||
if( !layerSetCu.Contains( track->GetLayer() ) )
|
||||
continue;
|
||||
|
||||
if( track->GetStart() == pt )
|
||||
activePts.push_back( { track->GetEnd(), track->GetLayer() } );
|
||||
else
|
||||
activePts.push_back( { track->GetStart(), track->GetLayer() } );
|
||||
if( !track->IsSelected() )
|
||||
select( track );
|
||||
|
||||
expand = true;
|
||||
if( !track->HasFlag( SKIP_STRUCT ) )
|
||||
{
|
||||
track->SetFlags( SKIP_STRUCT );
|
||||
cleanupItems.push_back( track );
|
||||
|
||||
if( track->GetStart() == pt )
|
||||
activePts.push_back( { track->GetEnd(), track->GetLayerSet() } );
|
||||
else
|
||||
activePts.push_back( { track->GetStart(), track->GetLayerSet() } );
|
||||
|
||||
expand = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if( viaMap.count( pt ) )
|
||||
{
|
||||
PCB_VIA* via = viaMap[ pt ];
|
||||
|
||||
if( !via->IsSelected() )
|
||||
if( viaMap.count( pt ) )
|
||||
{
|
||||
select( via );
|
||||
activePts.push_back( { via->GetPosition(), ALL_LAYERS } );
|
||||
expand = true;
|
||||
PCB_VIA* via = viaMap[pt];
|
||||
|
||||
if( !via->IsSelected() )
|
||||
select( via );
|
||||
|
||||
if( !via->HasFlag( SKIP_STRUCT ) )
|
||||
{
|
||||
via->SetFlags( SKIP_STRUCT );
|
||||
cleanupItems.push_back( via );
|
||||
|
||||
activePts.push_back( { via->GetPosition(), via->GetLayerSet() } );
|
||||
expand = true;
|
||||
}
|
||||
}
|
||||
|
||||
activePts.erase( activePts.begin() + i );
|
||||
}
|
||||
|
||||
activePts.erase( activePts.begin() + i );
|
||||
// Refresh display for the feel of progress
|
||||
if( refreshTimer.msecs() >= refreshIntervalMs )
|
||||
{
|
||||
if( m_selection.Size() != lastSelectionSize )
|
||||
{
|
||||
m_frame->GetCanvas()->ForceRefresh();
|
||||
lastSelectionSize = m_selection.Size();
|
||||
}
|
||||
|
||||
refreshTimer.Start();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for( BOARD_CONNECTED_ITEM* item : cleanupItems )
|
||||
{
|
||||
item->ClearFlags( SKIP_STRUCT );
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
@ -1348,7 +1420,7 @@ int PCB_SELECTION_TOOL::selectNet( const TOOL_EVENT& aEvent )
|
|||
|
||||
void PCB_SELECTION_TOOL::selectAllItemsOnSheet( wxString& aSheetPath )
|
||||
{
|
||||
std::list<FOOTPRINT*> footprintList;
|
||||
std::vector<BOARD_ITEM*> footprints;
|
||||
|
||||
// store all footprints that are on that sheet path
|
||||
for( FOOTPRINT* footprint : board()->Footprints() )
|
||||
|
@ -1356,52 +1428,88 @@ void PCB_SELECTION_TOOL::selectAllItemsOnSheet( wxString& aSheetPath )
|
|||
if( footprint == nullptr )
|
||||
continue;
|
||||
|
||||
wxString footprint_path = footprint->GetPath().AsString().BeforeLast('/');
|
||||
wxString footprint_path = footprint->GetPath().AsString().BeforeLast( '/' );
|
||||
|
||||
if( aSheetPath.IsEmpty() )
|
||||
aSheetPath += '/';
|
||||
|
||||
if( footprint_path == aSheetPath )
|
||||
footprintList.push_back( footprint );
|
||||
footprints.push_back( footprint );
|
||||
}
|
||||
|
||||
// Generate a list of all pads, and of all nets they belong to.
|
||||
std::list<int> netcodeList;
|
||||
std::list<PAD*> padList;
|
||||
|
||||
for( FOOTPRINT* footprint : footprintList )
|
||||
for( BOARD_ITEM* i : footprints )
|
||||
{
|
||||
for( PAD* pad : footprint->Pads() )
|
||||
if( i != nullptr )
|
||||
select( i );
|
||||
}
|
||||
|
||||
selectConnections( footprints );
|
||||
}
|
||||
|
||||
|
||||
void PCB_SELECTION_TOOL::selectConnections( const std::vector<BOARD_ITEM*>& aItems )
|
||||
{
|
||||
// Generate a list of all pads, and of all nets they belong to.
|
||||
std::list<int> netcodeList;
|
||||
std::vector<BOARD_CONNECTED_ITEM*> padList;
|
||||
|
||||
for( BOARD_ITEM* item : aItems )
|
||||
{
|
||||
switch( item->Type() )
|
||||
{
|
||||
case PCB_FOOTPRINT_T:
|
||||
{
|
||||
for( PAD* pad : static_cast<FOOTPRINT*>( item )->Pads() )
|
||||
{
|
||||
if( pad->IsConnected() )
|
||||
{
|
||||
netcodeList.push_back( pad->GetNetCode() );
|
||||
padList.push_back( pad );
|
||||
}
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
case PCB_PAD_T:
|
||||
{
|
||||
PAD* pad = static_cast<PAD*>( item );
|
||||
|
||||
if( pad->IsConnected() )
|
||||
{
|
||||
netcodeList.push_back( pad->GetNetCode() );
|
||||
padList.push_back( pad );
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
default: break;
|
||||
}
|
||||
}
|
||||
|
||||
// Sort for binary search
|
||||
std::sort( padList.begin(), padList.end() );
|
||||
|
||||
// remove all duplicates
|
||||
netcodeList.sort();
|
||||
netcodeList.unique();
|
||||
|
||||
for( PAD* pad : padList )
|
||||
selectConnectedTracks( *pad, STOP_NEVER );
|
||||
selectAllConnectedTracks( padList, STOP_AT_PAD );
|
||||
|
||||
// now we need to find all footprints that are connected to each of these nets then we need
|
||||
// to determine if these footprints are in the list of footprints belonging to this sheet
|
||||
std::list<int> removeCodeList;
|
||||
// to determine if these footprints are in the list of footprints
|
||||
std::vector<int> removeCodeList;
|
||||
constexpr KICAD_T padType[] = { PCB_PAD_T, EOT };
|
||||
|
||||
for( int netCode : netcodeList )
|
||||
{
|
||||
for( BOARD_CONNECTED_ITEM* mitem : board()->GetConnectivity()->GetNetItems( netCode,
|
||||
padType ) )
|
||||
for( BOARD_CONNECTED_ITEM* mitem :
|
||||
board()->GetConnectivity()->GetNetItems( netCode, padType ) )
|
||||
{
|
||||
if( mitem->Type() == PCB_PAD_T && !alg::contains( footprintList, mitem->GetParent() ) )
|
||||
if( mitem->Type() == PCB_PAD_T
|
||||
&& !std::binary_search( padList.begin(), padList.end(), mitem ) )
|
||||
{
|
||||
// if we cannot find the footprint of the pad in the footprintList then we can
|
||||
// assume that that footprint is not located in the same schematic, therefore
|
||||
// if we cannot find the pad in the padList then we can
|
||||
// assume that that pad should not be used, therefore
|
||||
// invalidate this netcode.
|
||||
removeCodeList.push_back( netCode );
|
||||
break;
|
||||
|
@ -1409,31 +1517,21 @@ void PCB_SELECTION_TOOL::selectAllItemsOnSheet( wxString& aSheetPath )
|
|||
}
|
||||
}
|
||||
|
||||
// remove all duplicates
|
||||
removeCodeList.sort();
|
||||
removeCodeList.unique();
|
||||
|
||||
for( int removeCode : removeCodeList )
|
||||
{
|
||||
netcodeList.remove( removeCode );
|
||||
}
|
||||
|
||||
std::list<BOARD_CONNECTED_ITEM*> localConnectionList;
|
||||
constexpr KICAD_T trackViaType[] = { PCB_TRACE_T, PCB_ARC_T, PCB_VIA_T, EOT };
|
||||
std::vector<BOARD_CONNECTED_ITEM*> localConnectionList;
|
||||
constexpr KICAD_T trackViaType[] = { PCB_TRACE_T, PCB_ARC_T, PCB_VIA_T, EOT };
|
||||
|
||||
for( int netCode : netcodeList )
|
||||
{
|
||||
for( BOARD_CONNECTED_ITEM* item : board()->GetConnectivity()->GetNetItems( netCode,
|
||||
trackViaType ) )
|
||||
for( BOARD_CONNECTED_ITEM* item :
|
||||
board()->GetConnectivity()->GetNetItems( netCode, trackViaType ) )
|
||||
localConnectionList.push_back( item );
|
||||
}
|
||||
|
||||
for( BOARD_ITEM* i : footprintList )
|
||||
{
|
||||
if( i != nullptr )
|
||||
select( i );
|
||||
}
|
||||
|
||||
for( BOARD_CONNECTED_ITEM* i : localConnectionList )
|
||||
{
|
||||
if( i != nullptr )
|
||||
|
@ -1442,27 +1540,55 @@ void PCB_SELECTION_TOOL::selectAllItemsOnSheet( wxString& aSheetPath )
|
|||
}
|
||||
|
||||
|
||||
void PCB_SELECTION_TOOL::zoomFitSelection()
|
||||
int PCB_SELECTION_TOOL::syncSelection( const TOOL_EVENT& aEvent )
|
||||
{
|
||||
// Should recalculate the view to zoom in on the selection.
|
||||
auto selectionBox = m_selection.GetBoundingBox();
|
||||
auto view = getView();
|
||||
std::vector<BOARD_ITEM*>* items = aEvent.Parameter<std::vector<BOARD_ITEM*>*>();
|
||||
|
||||
VECTOR2D screenSize = view->ToWorld( m_frame->GetCanvas()->GetClientSize(), false );
|
||||
screenSize.x = std::max( 10.0, screenSize.x );
|
||||
screenSize.y = std::max( 10.0, screenSize.y );
|
||||
if( items )
|
||||
doSyncSelection( *items, false );
|
||||
|
||||
if( selectionBox.GetWidth() != 0 || selectionBox.GetHeight() != 0 )
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
int PCB_SELECTION_TOOL::syncSelectionWithNets( const TOOL_EVENT& aEvent )
|
||||
{
|
||||
std::vector<BOARD_ITEM*>* items = aEvent.Parameter<std::vector<BOARD_ITEM*>*>();
|
||||
|
||||
if( items )
|
||||
doSyncSelection( *items, true );
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
void PCB_SELECTION_TOOL::doSyncSelection( const std::vector<BOARD_ITEM*>& aItems, bool aWithNets )
|
||||
{
|
||||
ClearSelection( true /*quiet mode*/ );
|
||||
|
||||
// Perform individual selection of each item before processing the event.
|
||||
for( BOARD_ITEM* item : aItems )
|
||||
select( item );
|
||||
|
||||
if( aWithNets )
|
||||
selectConnections( aItems );
|
||||
|
||||
EDA_RECT bbox = m_selection.GetBoundingBox();
|
||||
|
||||
if( m_frame->Settings().m_CrossProbing.center_on_items )
|
||||
{
|
||||
VECTOR2D vsize = selectionBox.GetSize();
|
||||
double scale = view->GetScale() / std::max( fabs( vsize.x / screenSize.x ),
|
||||
fabs( vsize.y / screenSize.y ) );
|
||||
view->SetScale( scale );
|
||||
view->SetCenter( selectionBox.Centre() );
|
||||
view->Add( &m_selection );
|
||||
if( m_frame->Settings().m_CrossProbing.zoom_to_fit )
|
||||
zoomFitCrossProbeBBox( bbox );
|
||||
|
||||
m_frame->FocusOnLocation( bbox.Centre() );
|
||||
}
|
||||
|
||||
view()->UpdateAllLayersColor();
|
||||
|
||||
m_frame->GetCanvas()->ForceRefresh();
|
||||
|
||||
if( m_selection.Size() > 0 )
|
||||
m_toolMgr->ProcessEvent( EVENTS::SelectedEvent );
|
||||
}
|
||||
|
||||
|
||||
|
@ -1519,6 +1645,158 @@ int PCB_SELECTION_TOOL::selectSameSheet( const TOOL_EVENT& aEvent )
|
|||
}
|
||||
|
||||
|
||||
void PCB_SELECTION_TOOL::zoomFitSelection()
|
||||
{
|
||||
// Should recalculate the view to zoom in on the selection.
|
||||
auto selectionBox = m_selection.GetBoundingBox();
|
||||
auto view = getView();
|
||||
|
||||
VECTOR2D screenSize = view->ToWorld( m_frame->GetCanvas()->GetClientSize(), false );
|
||||
screenSize.x = std::max( 10.0, screenSize.x );
|
||||
screenSize.y = std::max( 10.0, screenSize.y );
|
||||
|
||||
if( selectionBox.GetWidth() != 0 || selectionBox.GetHeight() != 0 )
|
||||
{
|
||||
VECTOR2D vsize = selectionBox.GetSize();
|
||||
double scale = view->GetScale()
|
||||
/ std::max( fabs( vsize.x / screenSize.x ), fabs( vsize.y / screenSize.y ) );
|
||||
view->SetScale( scale );
|
||||
view->SetCenter( selectionBox.Centre() );
|
||||
view->Add( &m_selection );
|
||||
}
|
||||
|
||||
m_frame->GetCanvas()->ForceRefresh();
|
||||
}
|
||||
|
||||
|
||||
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 )
|
||||
return;
|
||||
|
||||
//#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();
|
||||
auto screenSize = view->ToWorld( GetCanvas()->GetClientSize(), false );
|
||||
|
||||
// The "fabs" on x ensures the right answer when the view is flipped
|
||||
screenSize.x = std::max( 10.0, fabs( screenSize.x ) );
|
||||
screenSize.y = std::max( 10.0, screenSize.y );
|
||||
double ratio = std::max( fabs( bbSize.x / screenSize.x ), fabs( bbSize.y / screenSize.y ) );
|
||||
|
||||
// Try not to zoom on every cross-probe; it gets very noisy
|
||||
if( crossProbingSettings.zoom_to_fit && ( ratio < 0.5 || ratio > 1.0 ) )
|
||||
view->SetScale( view->GetScale() / ratio );
|
||||
#endif // DEFAULT_PCBNEW_CODE
|
||||
|
||||
#ifndef DEFAULT_PCBNEW_CODE // Do the scaled zoom
|
||||
auto bbSize = bbox.Inflate( bbox.GetWidth() * 0.2f ).GetSize();
|
||||
auto screenSize = view->ToWorld( m_frame->GetCanvas()->GetClientSize(), false );
|
||||
|
||||
// This code tries to come up with a zoom factor that doesn't simply zoom in
|
||||
// to the cross probed component, 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 footprint (like a processor) or a small footprint (like a resistor).
|
||||
// This ratio is not useful by itself as a scaling factor. It must be "bent" to
|
||||
// provide good scaling at varying component sizes. Bigger components need less
|
||||
// scaling than small ones.
|
||||
double currTextHeight = Millimeter2iu( DEFAULT_TEXT_SIZE );
|
||||
|
||||
double compRatio = bbSize.y / currTextHeight; // Ratio of component to text height
|
||||
|
||||
// This will end up as the scaling factor we apply to "ratio".
|
||||
double compRatioBent = 1.0;
|
||||
|
||||
// This is similar to the original KiCad code that scaled the zoom to make sure
|
||||
// components were visible on screen. It's simply a ratio of screen size to
|
||||
// component size, and its job is to zoom in to make the component fullscreen.
|
||||
// Earlier in the code the component BBox is given a 20% margin to add some
|
||||
// breathing room. We compare the height of this enlarged component bbox to the
|
||||
// default text height. If a component will end up with the sides clipped, we
|
||||
// adjust later to make sure it fits on screen.
|
||||
//
|
||||
// The "fabs" on x ensures the right answer when the view is flipped
|
||||
screenSize.x = std::max( 10.0, fabs( 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 ) );
|
||||
|
||||
// LUT to scale zoom ratio to provide reasonable schematic context. Must work
|
||||
// with footprints of varying sizes (e.g. 0402 package and 200 pin BGA).
|
||||
// "first" is used as the input and "second" as the output
|
||||
//
|
||||
// "first" = compRatio (footprint height / default text height)
|
||||
// "second" = Amount to scale ratio by
|
||||
std::vector<std::pair<double, double>> lut{
|
||||
{ 1, 8 }, { 1.5, 5 }, { 3, 3 }, { 4.5, 2.5 }, { 8, 2.0 },
|
||||
{ 12, 1.7 }, { 16, 1.5 }, { 24, 1.3 }, { 32, 1.0 },
|
||||
};
|
||||
|
||||
|
||||
std::vector<std::pair<double, double>>::iterator it;
|
||||
|
||||
compRatioBent = lut.back().second; // Large component default
|
||||
|
||||
if( compRatio >= lut.front().first )
|
||||
{
|
||||
// Use LUT to do linear interpolation of "compRatio" within "first", then
|
||||
// use that result to linearly interpolate "second" which gives the scaling
|
||||
// factor needed.
|
||||
|
||||
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 component default
|
||||
}
|
||||
|
||||
// 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. This will apply to parts that
|
||||
// are much wider than they are tall.
|
||||
|
||||
if( bbSize.x > screenSize.x * ratio * compRatioBent )
|
||||
{
|
||||
// Use standard KiCad zoom algorithm for parts too wide to fit 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 )
|
||||
view->SetScale( view->GetScale() / ratio );
|
||||
#endif // ifndef DEFAULT_PCBNEW_CODE
|
||||
}
|
||||
|
||||
|
||||
void PCB_SELECTION_TOOL::FindItem( BOARD_ITEM* aItem )
|
||||
{
|
||||
bool cleared = false;
|
||||
|
@ -2772,6 +3050,9 @@ void PCB_SELECTION_TOOL::setTransitions()
|
|||
Go( &PCB_SELECTION_TOOL::expandConnection, PCB_ACTIONS::selectConnection.MakeEvent() );
|
||||
Go( &PCB_SELECTION_TOOL::selectNet, PCB_ACTIONS::selectNet.MakeEvent() );
|
||||
Go( &PCB_SELECTION_TOOL::selectNet, PCB_ACTIONS::deselectNet.MakeEvent() );
|
||||
Go( &PCB_SELECTION_TOOL::syncSelection, PCB_ACTIONS::syncSelection.MakeEvent() );
|
||||
Go( &PCB_SELECTION_TOOL::syncSelectionWithNets,
|
||||
PCB_ACTIONS::syncSelectionWithNets.MakeEvent() );
|
||||
Go( &PCB_SELECTION_TOOL::selectSameSheet, PCB_ACTIONS::selectSameSheet.MakeEvent() );
|
||||
Go( &PCB_SELECTION_TOOL::selectSheetContents,
|
||||
PCB_ACTIONS::selectOnSheetFromEeschema.MakeEvent() );
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
* This program source code file is part of KiCad, a free EDA CAD application.
|
||||
*
|
||||
* Copyright (C) 2013-2017 CERN
|
||||
* Copyright (C) 2017-2021 KiCad Developers, see AUTHORS.TXT for contributors.
|
||||
* Copyright (C) 2017-2022 KiCad Developers, see AUTHORS.TXT for contributors.
|
||||
*
|
||||
* @author Tomasz Wlostowski <tomasz.wlostowski@cern.ch>
|
||||
* @author Maciej Suminski <maciej.suminski@cern.ch>
|
||||
|
@ -181,6 +181,9 @@ public:
|
|||
///< Zoom the screen to center and fit the current selection.
|
||||
void zoomFitSelection();
|
||||
|
||||
///< Zoom the screen to fit the bounding box for cross probing/selection sync.
|
||||
void zoomFitCrossProbeBBox( EDA_RECT bbox );
|
||||
|
||||
BOARD* GetBoard() const
|
||||
{
|
||||
return board();
|
||||
|
@ -304,7 +307,8 @@ private:
|
|||
*
|
||||
* @param aStopCondition where to stop selecting more items
|
||||
*/
|
||||
void selectConnectedTracks( BOARD_CONNECTED_ITEM& aSourceItem, STOP_CONDITION aStopCondition );
|
||||
void selectAllConnectedTracks( const std::vector<BOARD_CONNECTED_ITEM*>& aStartItems,
|
||||
STOP_CONDITION aStopCondition );
|
||||
|
||||
/**
|
||||
* Select all items with the given net code.
|
||||
|
@ -314,6 +318,11 @@ private:
|
|||
*/
|
||||
void selectAllItemsOnNet( int aNetCode, bool aSelect = true );
|
||||
|
||||
/*
|
||||
* Select tracks and vias connected to specified board items.
|
||||
*/
|
||||
void selectConnections( const std::vector<BOARD_ITEM*>& aItems );
|
||||
|
||||
/**
|
||||
* Select all items with the given sheet timestamp/UUID name (the sheet path).
|
||||
*
|
||||
|
@ -328,6 +337,12 @@ private:
|
|||
///< (same sheet path).
|
||||
int selectSameSheet( const TOOL_EVENT& aEvent );
|
||||
|
||||
///< Set selection to items passed by parameter and connected nets (optionally).
|
||||
///< Zooms to fit, if enabled
|
||||
int syncSelection( const TOOL_EVENT& aEvent );
|
||||
int syncSelectionWithNets( const TOOL_EVENT& aEvent );
|
||||
void doSyncSelection( const std::vector<BOARD_ITEM*>& aItems, bool aWithNets );
|
||||
|
||||
///< Invoke filter dialog and modify current selection
|
||||
int filterSelection( const TOOL_EVENT& aEvent );
|
||||
|
||||
|
|
|
@ -435,8 +435,8 @@ int PCB_SELECTION_TOOL::expandConnection( const TOOL_EVENT& aEvent )
|
|||
}
|
||||
|
||||
|
||||
void PCB_SELECTION_TOOL::selectConnectedTracks( BOARD_CONNECTED_ITEM& aStartItem,
|
||||
STOP_CONDITION aStopCondition )
|
||||
void PCB_SELECTION_TOOL::selectAllConnectedTracks(
|
||||
const std::vector<BOARD_CONNECTED_ITEM*>& aStartItems, STOP_CONDITION aStopCondition )
|
||||
{
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in New Issue