2019-04-14 00:44:05 +00:00
|
|
|
/*
|
|
|
|
* This program source code file is part of KiCad, a free EDA CAD application.
|
|
|
|
*
|
|
|
|
* Copyright (C) 1992-2019 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 Free Software Foundation; either version 2
|
|
|
|
* of the License, or (at your option) any later version.
|
|
|
|
*
|
|
|
|
* This program is distributed in the hope that it will be useful,
|
|
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
|
|
* GNU General Public License for more details.
|
|
|
|
*
|
|
|
|
* You should have received a copy of the GNU General Public License
|
|
|
|
* along with this program; if not, you may find one here:
|
|
|
|
* http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
|
|
|
|
* or you may search the http://www.gnu.org website for the version 2 license,
|
|
|
|
* or you may write to the Free Software Foundation, Inc.,
|
|
|
|
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
|
|
|
|
*/
|
|
|
|
|
|
|
|
#include <fctsys.h>
|
2019-04-23 17:12:26 +00:00
|
|
|
#include <kiway.h>
|
2019-04-14 00:44:05 +00:00
|
|
|
#include <sch_view.h>
|
|
|
|
#include <sch_edit_frame.h>
|
|
|
|
#include <sch_sheet.h>
|
2019-04-29 21:44:49 +00:00
|
|
|
#include <connection_graph.h>
|
2019-04-14 00:44:05 +00:00
|
|
|
#include <erc.h>
|
|
|
|
#include <eeschema_id.h>
|
|
|
|
#include <netlist_object.h>
|
|
|
|
#include <tool/tool_manager.h>
|
2019-05-10 17:19:48 +00:00
|
|
|
#include <tools/ee_actions.h>
|
|
|
|
#include <tools/ee_picker_tool.h>
|
2019-04-14 00:44:05 +00:00
|
|
|
#include <tools/sch_editor_control.h>
|
2019-05-10 17:19:48 +00:00
|
|
|
#include <tools/ee_selection_tool.h>
|
2019-05-07 18:49:53 +00:00
|
|
|
#include <tools/sch_drawing_tools.h>
|
2019-05-19 21:04:04 +00:00
|
|
|
#include <tools/sch_wire_bus_tool.h>
|
2019-05-10 17:19:48 +00:00
|
|
|
#include <ee_hotkeys.h>
|
2019-04-15 23:56:41 +00:00
|
|
|
#include <advanced_config.h>
|
2019-04-23 17:12:26 +00:00
|
|
|
#include <simulation_cursors.h>
|
|
|
|
#include <sim/sim_plot_frame.h>
|
2019-04-28 16:36:31 +00:00
|
|
|
#include <sch_legacy_plugin.h>
|
|
|
|
#include <class_library.h>
|
|
|
|
#include <confirm.h>
|
2019-05-13 20:42:40 +00:00
|
|
|
#include <sch_painter.h>
|
2019-05-19 21:04:04 +00:00
|
|
|
#include <status_popup.h>
|
2019-05-26 15:36:40 +00:00
|
|
|
#include <ws_proxy_undo_item.h>
|
|
|
|
#include <dialogs/dialog_page_settings.h>
|
2019-04-15 23:56:41 +00:00
|
|
|
|
2019-05-10 17:19:48 +00:00
|
|
|
TOOL_ACTION EE_ACTIONS::refreshPreview( "eeschema.EditorControl.refreshPreview",
|
2019-05-08 18:56:03 +00:00
|
|
|
AS_GLOBAL, 0, "", "" );
|
2019-04-14 00:44:05 +00:00
|
|
|
|
2019-05-10 17:19:48 +00:00
|
|
|
TOOL_ACTION EE_ACTIONS::simProbe( "eeschema.Simulation.probe",
|
2019-04-23 17:12:26 +00:00
|
|
|
AS_GLOBAL, 0,
|
|
|
|
_( "Add a simulator probe" ), "" );
|
|
|
|
|
2019-05-10 17:19:48 +00:00
|
|
|
TOOL_ACTION EE_ACTIONS::simTune( "eeschema.Simulation.tune",
|
2019-04-23 17:12:26 +00:00
|
|
|
AS_GLOBAL, 0,
|
|
|
|
_( "Select a value to be tuned" ), "" );
|
|
|
|
|
2019-05-10 17:19:48 +00:00
|
|
|
TOOL_ACTION EE_ACTIONS::highlightNet( "eeschema.EditorControl.highlightNet",
|
2019-04-15 23:56:41 +00:00
|
|
|
AS_GLOBAL, 0, "", "" );
|
2019-04-14 00:44:05 +00:00
|
|
|
|
2019-05-10 17:19:48 +00:00
|
|
|
TOOL_ACTION EE_ACTIONS::clearHighlight( "eeschema.EditorControl.clearHighlight",
|
2019-04-21 23:45:34 +00:00
|
|
|
AS_GLOBAL, 0, "", "" );
|
|
|
|
|
2019-05-12 17:03:17 +00:00
|
|
|
TOOL_ACTION EE_ACTIONS::updateNetHighlighting( "eeschema.EditorControl.updateNetHighlighting",
|
2019-04-15 23:56:41 +00:00
|
|
|
AS_GLOBAL, 0, "", "" );
|
2019-04-14 00:44:05 +00:00
|
|
|
|
2019-05-15 22:49:48 +00:00
|
|
|
TOOL_ACTION EE_ACTIONS::highlightNetCursor( "eeschema.EditorControl.highlightNetTool",
|
2019-04-15 23:56:41 +00:00
|
|
|
AS_GLOBAL, 0,
|
2019-05-14 19:21:10 +00:00
|
|
|
_( "Highlight Nets" ), _( "Highlight wires and pins of a net" ),
|
|
|
|
net_highlight_schematic_xpm, AF_ACTIVATE );
|
2019-04-15 14:34:58 +00:00
|
|
|
|
2019-05-14 19:21:10 +00:00
|
|
|
TOOL_ACTION EE_ACTIONS::showSymbolEditor( "eeschema.EditorControl.showSymbolEditor",
|
|
|
|
AS_GLOBAL, 0,
|
|
|
|
_( "Show Symbol Editor" ), _( "Create, delete and edit symbols" ),
|
|
|
|
libedit_xpm );
|
2019-04-23 13:06:37 +00:00
|
|
|
|
2019-05-17 15:44:58 +00:00
|
|
|
TOOL_ACTION EE_ACTIONS::editWithLibEdit( "eeschema.EditorControl.editWithSymbolEditor",
|
2019-04-29 22:24:30 +00:00
|
|
|
AS_GLOBAL, TOOL_ACTION::LegacyHotKey( HK_EDIT_COMPONENT_WITH_LIBEDIT ),
|
|
|
|
_( "Edit with Symbol Editor" ), _( "Open the symbol editor to edit the symbol" ),
|
|
|
|
libedit_xpm );
|
|
|
|
|
2019-05-13 20:42:40 +00:00
|
|
|
TOOL_ACTION EE_ACTIONS::showLibraryBrowser( "eeschema.EditorControl.showLibraryBrowser",
|
|
|
|
AS_GLOBAL, 0,
|
2019-05-22 08:04:34 +00:00
|
|
|
_( "Symbol Library Browser" ), _( "Browse symbol libraries" ),
|
2019-05-13 20:42:40 +00:00
|
|
|
library_browse_xpm );
|
|
|
|
|
2019-05-10 17:19:48 +00:00
|
|
|
TOOL_ACTION EE_ACTIONS::enterSheet( "eeschema.EditorControl.enterSheet",
|
2019-04-30 14:46:29 +00:00
|
|
|
AS_GLOBAL, 0,
|
|
|
|
_( "Enter Sheet" ), _( "Display the selected sheet's contents in the Eeschema window" ),
|
|
|
|
enter_sheet_xpm );
|
|
|
|
|
2019-05-10 17:19:48 +00:00
|
|
|
TOOL_ACTION EE_ACTIONS::leaveSheet( "eeschema.EditorControl.leaveSheet",
|
2019-04-30 14:46:29 +00:00
|
|
|
AS_GLOBAL, TOOL_ACTION::LegacyHotKey( HK_LEAVE_SHEET ),
|
|
|
|
_( "Leave Sheet" ), _( "Display the parent sheet in the Eeschema window" ),
|
|
|
|
leave_sheet_xpm );
|
|
|
|
|
2019-05-13 20:42:40 +00:00
|
|
|
TOOL_ACTION EE_ACTIONS::navigateHierarchy( "eeschema.EditorControl.navigateHierarchy",
|
|
|
|
AS_GLOBAL, 0,
|
|
|
|
_( "Show Hierarchy Navigator" ), "",
|
|
|
|
hierarchy_nav_xpm );
|
|
|
|
|
2019-05-10 17:19:48 +00:00
|
|
|
TOOL_ACTION EE_ACTIONS::explicitCrossProbe( "eeschema.EditorControl.explicitCrossProbe",
|
2019-04-30 18:36:11 +00:00
|
|
|
AS_GLOBAL, TOOL_ACTION::LegacyHotKey( HK_SELECT_ITEMS_ON_PCB ),
|
|
|
|
_( "Highlight on PCB" ), _( "Highlight corresponding items in PCBNew" ),
|
|
|
|
select_same_sheet_xpm );
|
|
|
|
|
2019-05-13 20:42:40 +00:00
|
|
|
TOOL_ACTION EE_ACTIONS::toggleHiddenPins( "eeschema.EditorControl.showHiddenPins",
|
|
|
|
AS_GLOBAL, 0,
|
|
|
|
_( "Show Hidden Pins" ), "",
|
|
|
|
hidden_pin_xpm );
|
|
|
|
|
2019-05-13 21:49:05 +00:00
|
|
|
TOOL_ACTION EE_ACTIONS::toggleForceHV( "eeschema.EditorControl.forceHVLines",
|
|
|
|
AS_GLOBAL, 0,
|
|
|
|
_( "Force H/V Wires and Busses" ), "",
|
|
|
|
lines90_xpm );
|
|
|
|
|
2019-04-14 00:44:05 +00:00
|
|
|
|
2019-05-24 23:36:31 +00:00
|
|
|
int SCH_EDITOR_CONTROL::New( const TOOL_EVENT& aEvent )
|
|
|
|
{
|
|
|
|
m_frame->NewProject();
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
int SCH_EDITOR_CONTROL::Open( const TOOL_EVENT& aEvent )
|
|
|
|
{
|
|
|
|
m_frame->LoadProject();
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
int SCH_EDITOR_CONTROL::Save( const TOOL_EVENT& aEvent )
|
|
|
|
{
|
|
|
|
m_frame->Save_File();
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
int SCH_EDITOR_CONTROL::SaveAs( const TOOL_EVENT& aEvent )
|
|
|
|
{
|
|
|
|
m_frame->Save_File( true );
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
int SCH_EDITOR_CONTROL::SaveAll( const TOOL_EVENT& aEvent )
|
|
|
|
{
|
|
|
|
m_frame->SaveProject();
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
int SCH_EDITOR_CONTROL::PageSetup( const TOOL_EVENT& aEvent )
|
|
|
|
{
|
2019-05-26 15:36:40 +00:00
|
|
|
PICKED_ITEMS_LIST undoCmd;
|
|
|
|
WS_PROXY_UNDO_ITEM* undoItem = new WS_PROXY_UNDO_ITEM( m_frame );
|
|
|
|
ITEM_PICKER wrapper( undoItem, UR_PAGESETTINGS );
|
|
|
|
|
|
|
|
undoCmd.PushItem( wrapper );
|
|
|
|
m_frame->SaveCopyInUndoList( undoCmd, UR_PAGESETTINGS );
|
|
|
|
|
|
|
|
DIALOG_PAGES_SETTINGS dlg( m_frame, wxSize( MAX_PAGE_SIZE_MILS, MAX_PAGE_SIZE_MILS ) );
|
|
|
|
dlg.SetWksFileName( BASE_SCREEN::m_PageLayoutDescrFileName );
|
|
|
|
|
|
|
|
if( dlg.ShowModal() == wxID_OK )
|
|
|
|
m_toolMgr->RunAction( ACTIONS::zoomFitScreen );
|
|
|
|
else
|
|
|
|
m_frame->RollbackSchematicFromUndo();
|
|
|
|
|
2019-05-24 23:36:31 +00:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
int SCH_EDITOR_CONTROL::Print( const TOOL_EVENT& aEvent )
|
|
|
|
{
|
|
|
|
m_frame->Print();
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
int SCH_EDITOR_CONTROL::Plot( const TOOL_EVENT& aEvent )
|
|
|
|
{
|
|
|
|
m_frame->PlotSchematic();
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
int SCH_EDITOR_CONTROL::Quit( const TOOL_EVENT& aEvent )
|
|
|
|
{
|
|
|
|
m_frame->Close( false );
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2019-05-19 21:04:04 +00:00
|
|
|
// A dummy wxFindReplaceData signalling any marker should be found
|
|
|
|
static wxFindReplaceData g_markersOnly;
|
|
|
|
|
|
|
|
|
|
|
|
int SCH_EDITOR_CONTROL::FindAndReplace( const TOOL_EVENT& aEvent )
|
|
|
|
{
|
|
|
|
m_frame->ShowFindReplaceDialog( aEvent.IsAction( &ACTIONS::findAndReplace ));
|
|
|
|
return UpdateFind( aEvent );
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
int SCH_EDITOR_CONTROL::UpdateFind( const TOOL_EVENT& aEvent )
|
|
|
|
{
|
|
|
|
wxFindReplaceData* data = m_frame->GetFindReplaceData();
|
|
|
|
|
|
|
|
if( aEvent.IsAction( &ACTIONS::find )
|
|
|
|
|| aEvent.IsAction( &ACTIONS::findAndReplace )
|
|
|
|
|| aEvent.IsAction( &ACTIONS::updateFind ) )
|
|
|
|
{
|
|
|
|
m_selectionTool->ClearSelection();
|
|
|
|
|
|
|
|
INSPECTOR_FUNC inspector = [&] ( EDA_ITEM* item, void* )
|
|
|
|
{
|
|
|
|
if( data && item->Matches( *data, nullptr ) )
|
|
|
|
{
|
|
|
|
m_selectionTool->BrightenItem( item );
|
|
|
|
|
|
|
|
if( m_selectionTool->GetSelection().GetSize() == 0 )
|
|
|
|
m_selectionTool->AddItemToSel( item );
|
|
|
|
}
|
|
|
|
else if( item->IsBrightened() )
|
|
|
|
{
|
|
|
|
m_selectionTool->UnbrightenItem( item );
|
|
|
|
}
|
|
|
|
|
|
|
|
return SEARCH_CONTINUE;
|
|
|
|
};
|
|
|
|
|
|
|
|
EDA_ITEM* start = m_frame->GetScreen()->GetDrawItems();
|
|
|
|
EDA_ITEM::IterateForward( start, inspector, nullptr, EE_COLLECTOR::AllItems );
|
|
|
|
}
|
|
|
|
else if( aEvent.Matches( EVENTS::SelectedItemsModified ) )
|
|
|
|
{
|
|
|
|
for( EDA_ITEM* item : m_selectionTool->GetSelection() )
|
|
|
|
{
|
|
|
|
if( data && item->Matches( *data, nullptr ) )
|
|
|
|
m_selectionTool->BrightenItem( item );
|
|
|
|
else if( item->IsBrightened() )
|
|
|
|
m_selectionTool->UnbrightenItem( item );
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
getView()->UpdateItems();
|
|
|
|
m_frame->GetCanvas()->Refresh();
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
EDA_ITEM* nextMatch( SCH_SCREEN* aScreen, EDA_ITEM* after, wxFindReplaceData* data )
|
|
|
|
{
|
|
|
|
EDA_ITEM* found = nullptr;
|
|
|
|
|
|
|
|
INSPECTOR_FUNC inspector = [&] ( EDA_ITEM* item, void* testData )
|
|
|
|
{
|
|
|
|
if( after )
|
|
|
|
{
|
|
|
|
if( after == item )
|
|
|
|
after = nullptr;
|
|
|
|
|
|
|
|
return SEARCH_CONTINUE;
|
|
|
|
}
|
|
|
|
|
|
|
|
if( ( data == &g_markersOnly && item->Type() == SCH_MARKER_T )
|
|
|
|
|| item->Matches( *data, nullptr ) )
|
|
|
|
{
|
|
|
|
found = item;
|
|
|
|
return SEARCH_QUIT;
|
|
|
|
}
|
|
|
|
|
|
|
|
return SEARCH_CONTINUE;
|
|
|
|
};
|
|
|
|
|
|
|
|
EDA_ITEM::IterateForward( aScreen->GetDrawItems(), inspector, nullptr, EE_COLLECTOR::AllItems );
|
|
|
|
|
|
|
|
return found;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
int SCH_EDITOR_CONTROL::FindNext( const TOOL_EVENT& aEvent )
|
|
|
|
{
|
2019-05-23 09:41:06 +00:00
|
|
|
// A timer during which a subsequent FindNext will result in a wrap-around
|
|
|
|
static wxTimer wrapAroundTimer;
|
|
|
|
|
2019-05-19 21:04:04 +00:00
|
|
|
wxFindReplaceData* data = m_frame->GetFindReplaceData();
|
|
|
|
|
|
|
|
if( aEvent.IsAction( &ACTIONS::findNextMarker ) )
|
|
|
|
{
|
|
|
|
if( data )
|
|
|
|
g_markersOnly.SetFlags( data->GetFlags() );
|
|
|
|
|
|
|
|
data = &g_markersOnly;
|
|
|
|
}
|
|
|
|
else if( !data )
|
|
|
|
{
|
|
|
|
return FindAndReplace( ACTIONS::find.MakeEvent() );
|
|
|
|
}
|
|
|
|
|
|
|
|
bool searchAllSheets = !( data->GetFlags() & FR_CURRENT_SHEET_ONLY );
|
|
|
|
SELECTION& selection = m_selectionTool->GetSelection();
|
|
|
|
SCH_SCREEN* afterScreen = m_frame->GetScreen();
|
|
|
|
EDA_ITEM* afterItem = selection.Front();
|
|
|
|
EDA_ITEM* item = nullptr;
|
|
|
|
|
2019-05-23 09:41:06 +00:00
|
|
|
if( wrapAroundTimer.IsRunning() )
|
2019-05-19 21:04:04 +00:00
|
|
|
{
|
|
|
|
afterScreen = nullptr;
|
|
|
|
afterItem = nullptr;
|
2019-05-23 09:41:06 +00:00
|
|
|
wrapAroundTimer.Stop();
|
2019-05-19 21:04:04 +00:00
|
|
|
m_frame->ClearFindReplaceStatus();
|
|
|
|
}
|
|
|
|
|
|
|
|
m_selectionTool->ClearSelection();
|
|
|
|
|
|
|
|
if( afterScreen || !searchAllSheets )
|
|
|
|
item = nextMatch( m_frame->GetScreen(), afterItem, data );
|
|
|
|
|
|
|
|
if( !item && searchAllSheets )
|
|
|
|
{
|
|
|
|
SCH_SHEET_LIST schematic( g_RootSheet );
|
|
|
|
SCH_SCREENS screens;
|
|
|
|
|
|
|
|
for( SCH_SCREEN* screen = screens.GetFirst(); screen; screen = screens.GetNext() )
|
|
|
|
{
|
|
|
|
if( afterScreen )
|
|
|
|
{
|
|
|
|
if( afterScreen == screen )
|
|
|
|
afterScreen = nullptr;
|
|
|
|
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
item = nextMatch( screen, nullptr, data );
|
|
|
|
|
|
|
|
if( item )
|
|
|
|
{
|
|
|
|
SCH_SHEET_PATH* sheet = schematic.FindSheetForScreen( screen );
|
|
|
|
wxCHECK_MSG( sheet, 0, "Sheet not found for " + screen->GetFileName() );
|
|
|
|
|
|
|
|
*g_CurrentSheet = *sheet;
|
|
|
|
g_CurrentSheet->UpdateAllScreenReferences();
|
|
|
|
|
|
|
|
screen->SetZoom( m_frame->GetScreen()->GetZoom() );
|
|
|
|
screen->TestDanglingEnds();
|
|
|
|
|
|
|
|
m_frame->SetScreen( screen );
|
|
|
|
UpdateFind( ACTIONS::updateFind.MakeEvent() );
|
|
|
|
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if( item )
|
|
|
|
{
|
|
|
|
m_selectionTool->AddItemToSel( item );
|
|
|
|
getView()->SetCenter( item->GetBoundingBox().GetCenter() );
|
|
|
|
m_frame->GetCanvas()->Refresh();
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
wxString msg;
|
|
|
|
|
|
|
|
if( searchAllSheets )
|
|
|
|
msg = _( "Reached end of schematic." );
|
|
|
|
else
|
|
|
|
msg = _( "Reached end of sheet." );
|
|
|
|
|
|
|
|
m_frame->ShowFindReplaceStatus( msg + _( "\nFind again to wrap around to the start." ) );
|
2019-05-23 09:41:06 +00:00
|
|
|
wrapAroundTimer.StartOnce( 4000 );
|
2019-05-19 21:04:04 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
bool SCH_EDITOR_CONTROL::HasMatch()
|
|
|
|
{
|
|
|
|
wxFindReplaceData* data = m_frame->GetFindReplaceData();
|
|
|
|
EDA_ITEM* item = m_selectionTool->GetSelection().Front();
|
|
|
|
|
|
|
|
return data && item && item->Matches( *data, nullptr );
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
int SCH_EDITOR_CONTROL::ReplaceAndFindNext( const TOOL_EVENT& aEvent )
|
|
|
|
{
|
|
|
|
wxFindReplaceData* data = m_frame->GetFindReplaceData();
|
|
|
|
EDA_ITEM* item = m_selectionTool->GetSelection().Front();
|
|
|
|
|
|
|
|
if( !data )
|
|
|
|
return FindAndReplace( ACTIONS::find.MakeEvent() );
|
|
|
|
|
|
|
|
if( item && item->Matches( *data, nullptr ) )
|
|
|
|
{
|
|
|
|
item->Replace( *data, g_CurrentSheet );
|
|
|
|
FindNext( ACTIONS::findNext.MakeEvent() );
|
|
|
|
}
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
int SCH_EDITOR_CONTROL::ReplaceAll( const TOOL_EVENT& aEvent )
|
|
|
|
{
|
|
|
|
wxFindReplaceData* data = m_frame->GetFindReplaceData();
|
|
|
|
|
|
|
|
if( !data )
|
|
|
|
return FindAndReplace( ACTIONS::find.MakeEvent() );
|
|
|
|
|
|
|
|
SCH_SHEET_LIST schematic( g_RootSheet );
|
|
|
|
SCH_SCREENS screens;
|
|
|
|
|
|
|
|
for( SCH_SCREEN* screen = screens.GetFirst(); screen; screen = screens.GetNext() )
|
|
|
|
{
|
|
|
|
for( EDA_ITEM* item = nextMatch( screen, nullptr, data );
|
|
|
|
item;
|
|
|
|
item = nextMatch( screen, item, data ) )
|
|
|
|
{
|
|
|
|
item->Replace( *data, schematic.FindSheetForScreen( screen ) );
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2019-04-30 18:36:11 +00:00
|
|
|
int SCH_EDITOR_CONTROL::CrossProbeToPcb( const TOOL_EVENT& aEvent )
|
|
|
|
{
|
|
|
|
doCrossProbeSchToPcb( aEvent, false );
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
int SCH_EDITOR_CONTROL::ExplicitCrossProbeToPcb( const TOOL_EVENT& aEvent )
|
|
|
|
{
|
|
|
|
doCrossProbeSchToPcb( aEvent, true );
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void SCH_EDITOR_CONTROL::doCrossProbeSchToPcb( const TOOL_EVENT& aEvent, bool aForce )
|
2019-04-21 23:45:34 +00:00
|
|
|
{
|
|
|
|
// Don't get in an infinite loop SCH -> PCB -> SCH -> PCB -> SCH -> ...
|
|
|
|
if( m_probingSchToPcb )
|
|
|
|
{
|
|
|
|
m_probingSchToPcb = false;
|
2019-04-30 18:36:11 +00:00
|
|
|
return;
|
2019-04-21 23:45:34 +00:00
|
|
|
}
|
|
|
|
|
2019-05-10 17:19:48 +00:00
|
|
|
EE_SELECTION_TOOL* selTool = m_toolMgr->GetTool<EE_SELECTION_TOOL>();
|
|
|
|
SCH_ITEM* item = nullptr;
|
|
|
|
SCH_COMPONENT* component = nullptr;
|
2019-04-21 23:45:34 +00:00
|
|
|
|
2019-04-30 18:36:11 +00:00
|
|
|
if( aForce )
|
2019-04-21 23:45:34 +00:00
|
|
|
{
|
2019-04-30 18:36:11 +00:00
|
|
|
SELECTION& selection = selTool->RequestSelection();
|
2019-04-21 23:45:34 +00:00
|
|
|
|
2019-04-30 18:36:11 +00:00
|
|
|
if( selection.GetSize() >= 1 )
|
|
|
|
item = (SCH_ITEM*) selection.Front();
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
SELECTION& selection = selTool->GetSelection();
|
2019-04-21 23:45:34 +00:00
|
|
|
|
2019-04-30 18:36:11 +00:00
|
|
|
if( selection.GetSize() >= 1 )
|
|
|
|
item = (SCH_ITEM*) selection.Front();
|
|
|
|
}
|
2019-04-21 23:45:34 +00:00
|
|
|
|
2019-04-30 18:36:11 +00:00
|
|
|
if( !item )
|
|
|
|
{
|
|
|
|
if( aForce )
|
|
|
|
m_frame->SendMessageToPCBNEW( nullptr, nullptr );
|
2019-04-21 23:45:34 +00:00
|
|
|
|
2019-04-30 18:36:11 +00:00
|
|
|
return;
|
2019-04-21 23:45:34 +00:00
|
|
|
}
|
|
|
|
|
2019-04-30 18:36:11 +00:00
|
|
|
|
|
|
|
switch( item->Type() )
|
|
|
|
{
|
|
|
|
case SCH_FIELD_T:
|
|
|
|
case LIB_FIELD_T:
|
|
|
|
component = (SCH_COMPONENT*) item->GetParent();
|
|
|
|
m_frame->SendMessageToPCBNEW( item, component );
|
|
|
|
break;
|
|
|
|
|
|
|
|
case SCH_COMPONENT_T:
|
|
|
|
component = (SCH_COMPONENT*) item;
|
|
|
|
m_frame->SendMessageToPCBNEW( item, component );
|
|
|
|
break;
|
|
|
|
|
|
|
|
case SCH_PIN_T:
|
|
|
|
component = (SCH_COMPONENT*) item->GetParent();
|
|
|
|
m_frame->SendMessageToPCBNEW( static_cast<SCH_PIN*>( item ), component );
|
|
|
|
break;
|
|
|
|
|
|
|
|
case SCH_SHEET_T:
|
|
|
|
if( aForce )
|
|
|
|
m_frame->SendMessageToPCBNEW( item, nullptr );
|
|
|
|
break;
|
|
|
|
|
|
|
|
default:
|
|
|
|
break;
|
|
|
|
}
|
2019-04-21 23:45:34 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2019-04-23 17:12:26 +00:00
|
|
|
#ifdef KICAD_SPICE
|
|
|
|
static bool probeSimulation( SCH_EDIT_FRAME* aFrame, const VECTOR2D& aPosition )
|
|
|
|
{
|
|
|
|
constexpr KICAD_T wiresAndComponents[] = { SCH_LINE_T, SCH_COMPONENT_T, SCH_SHEET_PIN_T, EOT };
|
2019-05-10 17:19:48 +00:00
|
|
|
EE_SELECTION_TOOL* selTool = aFrame->GetToolManager()->GetTool<EE_SELECTION_TOOL>();
|
2019-04-23 17:12:26 +00:00
|
|
|
|
2019-05-05 10:33:34 +00:00
|
|
|
EDA_ITEM* item = selTool->SelectPoint( aPosition, wiresAndComponents );
|
2019-04-23 17:12:26 +00:00
|
|
|
|
|
|
|
if( !item )
|
|
|
|
return false;
|
|
|
|
|
|
|
|
std::unique_ptr<NETLIST_OBJECT_LIST> netlist( aFrame->BuildNetListBase() );
|
|
|
|
|
|
|
|
for( NETLIST_OBJECT* obj : *netlist )
|
|
|
|
{
|
|
|
|
if( obj->m_Comp == item )
|
|
|
|
{
|
|
|
|
auto simFrame = (SIM_PLOT_FRAME*) aFrame->Kiway().Player( FRAME_SIMULATOR, false );
|
|
|
|
|
|
|
|
if( simFrame )
|
|
|
|
simFrame->AddVoltagePlot( obj->GetNetName() );
|
|
|
|
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
int SCH_EDITOR_CONTROL::SimProbe( const TOOL_EVENT& aEvent )
|
|
|
|
{
|
|
|
|
Activate();
|
|
|
|
|
2019-05-10 17:19:48 +00:00
|
|
|
EE_PICKER_TOOL* picker = m_toolMgr->GetTool<EE_PICKER_TOOL>();
|
2019-04-23 17:12:26 +00:00
|
|
|
assert( picker );
|
|
|
|
|
|
|
|
m_frame->SetToolID( ID_SIM_PROBE, wxCURSOR_DEFAULT, _( "Add a simulator probe" ) );
|
|
|
|
m_frame->GetCanvas()->SetCursor( SIMULATION_CURSORS::GetCursor( SIMULATION_CURSORS::CURSOR::PROBE ) );
|
|
|
|
|
|
|
|
picker->SetClickHandler( std::bind( probeSimulation, m_frame, std::placeholders::_1 ) );
|
|
|
|
picker->Activate();
|
|
|
|
Wait();
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
static bool tuneSimulation( SCH_EDIT_FRAME* aFrame, const VECTOR2D& aPosition )
|
|
|
|
{
|
|
|
|
constexpr KICAD_T fieldsAndComponents[] = { SCH_COMPONENT_T, SCH_FIELD_T, EOT };
|
2019-05-10 17:19:48 +00:00
|
|
|
EE_SELECTION_TOOL* selTool = aFrame->GetToolManager()->GetTool<EE_SELECTION_TOOL>();
|
|
|
|
EDA_ITEM* item = selTool->SelectPoint( aPosition, fieldsAndComponents );
|
2019-04-23 17:12:26 +00:00
|
|
|
|
|
|
|
if( !item )
|
|
|
|
return false;
|
|
|
|
|
|
|
|
if( item->Type() != SCH_COMPONENT_T )
|
|
|
|
{
|
2019-05-05 10:33:34 +00:00
|
|
|
item = item->GetParent();
|
2019-04-23 17:12:26 +00:00
|
|
|
|
|
|
|
if( item->Type() != SCH_COMPONENT_T )
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
auto simFrame = (SIM_PLOT_FRAME*) aFrame->Kiway().Player( FRAME_SIMULATOR, false );
|
|
|
|
|
|
|
|
if( simFrame )
|
|
|
|
simFrame->AddTuner( static_cast<SCH_COMPONENT*>( item ) );
|
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
int SCH_EDITOR_CONTROL::SimTune( const TOOL_EVENT& aEvent )
|
|
|
|
{
|
|
|
|
Activate();
|
|
|
|
|
2019-05-10 17:19:48 +00:00
|
|
|
EE_PICKER_TOOL* picker = m_toolMgr->GetTool<EE_PICKER_TOOL>();
|
2019-04-23 17:12:26 +00:00
|
|
|
assert( picker );
|
|
|
|
|
|
|
|
m_frame->SetToolID( ID_SIM_TUNE, wxCURSOR_DEFAULT, _( "Select a value to be tuned" ) );
|
|
|
|
m_frame->GetCanvas()->SetCursor( SIMULATION_CURSORS::GetCursor( SIMULATION_CURSORS::CURSOR::TUNE ) );
|
|
|
|
|
|
|
|
picker->SetClickHandler( std::bind( tuneSimulation, m_frame, std::placeholders::_1 ) );
|
|
|
|
picker->Activate();
|
|
|
|
Wait();
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
#endif /* KICAD_SPICE */
|
|
|
|
|
|
|
|
|
2019-04-30 13:54:32 +00:00
|
|
|
// A singleton reference for clearing the highlight
|
2019-04-21 23:45:34 +00:00
|
|
|
static VECTOR2D CLEAR;
|
|
|
|
|
|
|
|
|
2019-04-14 00:44:05 +00:00
|
|
|
// TODO(JE) Probably use netcode rather than connection name here eventually
|
|
|
|
static bool highlightNet( TOOL_MANAGER* aToolMgr, const VECTOR2D& aPosition )
|
|
|
|
{
|
2019-05-10 23:13:40 +00:00
|
|
|
SCH_EDIT_FRAME* editFrame = static_cast<SCH_EDIT_FRAME*>( aToolMgr->GetEditFrame() );
|
|
|
|
EE_SELECTION_TOOL* selTool = aToolMgr->GetTool<EE_SELECTION_TOOL>();
|
|
|
|
SCH_EDITOR_CONTROL* editorControl = aToolMgr->GetTool<SCH_EDITOR_CONTROL>();
|
|
|
|
wxString netName;
|
|
|
|
bool retVal = true;
|
2019-04-14 00:44:05 +00:00
|
|
|
|
2019-04-30 13:54:32 +00:00
|
|
|
if( aPosition != CLEAR )
|
2019-04-14 00:44:05 +00:00
|
|
|
{
|
|
|
|
if( TestDuplicateSheetNames( false ) > 0 )
|
|
|
|
{
|
|
|
|
wxMessageBox( _( "Error: duplicate sub-sheet names found in current sheet." ) );
|
|
|
|
retVal = false;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2019-05-05 10:33:34 +00:00
|
|
|
SCH_ITEM* item = (SCH_ITEM*) selTool->GetNode( aPosition );
|
2019-04-30 13:54:32 +00:00
|
|
|
|
|
|
|
if( item && item->Connection( *g_CurrentSheet ) )
|
|
|
|
netName = item->Connection( *g_CurrentSheet )->Name();
|
2019-04-14 00:44:05 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-05-04 20:18:41 +00:00
|
|
|
if( netName.empty() )
|
|
|
|
{
|
|
|
|
editFrame->SetStatusText( wxT( "" ) );
|
|
|
|
editFrame->SendCrossProbeClearHighlight();
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
editFrame->SendCrossProbeNetName( netName );
|
2019-04-30 13:54:32 +00:00
|
|
|
editFrame->SetStatusText( wxString::Format( _( "Highlighted net: %s" ),
|
2019-05-16 21:58:47 +00:00
|
|
|
UnescapeString( netName ) ) );
|
2019-05-04 20:18:41 +00:00
|
|
|
}
|
|
|
|
|
2019-04-14 00:44:05 +00:00
|
|
|
editFrame->SetSelectedNetName( netName );
|
2019-05-10 23:13:40 +00:00
|
|
|
TOOL_EVENT dummy;
|
2019-05-12 17:03:17 +00:00
|
|
|
editorControl->UpdateNetHighlighting( dummy );
|
2019-04-14 00:44:05 +00:00
|
|
|
|
|
|
|
return retVal;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
int SCH_EDITOR_CONTROL::HighlightNet( const TOOL_EVENT& aEvent )
|
|
|
|
{
|
|
|
|
KIGFX::VIEW_CONTROLS* controls = getViewControls();
|
2019-04-30 13:54:32 +00:00
|
|
|
VECTOR2D cursorPos = controls->GetCursorPosition( !aEvent.Modifier( MD_ALT ) );
|
2019-04-14 00:44:05 +00:00
|
|
|
|
2019-04-30 13:54:32 +00:00
|
|
|
highlightNet( m_toolMgr, cursorPos );
|
2019-04-14 00:44:05 +00:00
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2019-04-21 23:45:34 +00:00
|
|
|
int SCH_EDITOR_CONTROL::ClearHighlight( const TOOL_EVENT& aEvent )
|
|
|
|
{
|
|
|
|
highlightNet( m_toolMgr, CLEAR );
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2019-05-12 17:03:17 +00:00
|
|
|
int SCH_EDITOR_CONTROL::UpdateNetHighlighting( const TOOL_EVENT& aEvent )
|
2019-04-14 00:44:05 +00:00
|
|
|
{
|
|
|
|
SCH_SCREEN* screen = g_CurrentSheet->LastScreen();
|
|
|
|
std::vector<EDA_ITEM*> itemsToRedraw;
|
|
|
|
wxString selectedNetName = m_frame->GetSelectedNetName();
|
|
|
|
|
|
|
|
if( !screen )
|
|
|
|
return 0;
|
|
|
|
|
2019-04-19 16:15:14 +00:00
|
|
|
for( SCH_ITEM* item = screen->GetDrawItems(); item; item = item->Next() )
|
2019-04-14 00:44:05 +00:00
|
|
|
{
|
2019-04-19 16:15:14 +00:00
|
|
|
SCH_CONNECTION* conn = item->Connection( *g_CurrentSheet );
|
|
|
|
bool redraw = item->IsBrightened();
|
2019-04-14 00:44:05 +00:00
|
|
|
|
2019-04-19 16:15:14 +00:00
|
|
|
if( conn && conn->Name() == selectedNetName )
|
|
|
|
item->SetBrightened();
|
|
|
|
else
|
|
|
|
item->ClearBrightened();
|
2019-04-14 00:44:05 +00:00
|
|
|
|
2019-04-19 16:15:14 +00:00
|
|
|
redraw |= item->IsBrightened();
|
2019-04-14 00:44:05 +00:00
|
|
|
|
2019-04-19 16:15:14 +00:00
|
|
|
if( item->Type() == SCH_COMPONENT_T )
|
2019-04-14 00:44:05 +00:00
|
|
|
{
|
2019-04-19 16:15:14 +00:00
|
|
|
SCH_COMPONENT* comp = static_cast<SCH_COMPONENT*>( item );
|
2019-04-14 00:44:05 +00:00
|
|
|
|
|
|
|
redraw |= comp->HasBrightenedPins();
|
|
|
|
|
|
|
|
comp->ClearBrightenedPins();
|
|
|
|
std::vector<LIB_PIN*> pins;
|
|
|
|
comp->GetPins( pins );
|
|
|
|
|
|
|
|
for( LIB_PIN* pin : pins )
|
|
|
|
{
|
|
|
|
auto pin_conn = comp->GetConnectionForPin( pin, *g_CurrentSheet );
|
|
|
|
|
|
|
|
if( pin_conn && pin_conn->Name( false ) == selectedNetName )
|
|
|
|
{
|
|
|
|
comp->BrightenPin( pin );
|
|
|
|
redraw = true;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2019-04-19 16:15:14 +00:00
|
|
|
else if( item->Type() == SCH_SHEET_T )
|
2019-04-14 00:44:05 +00:00
|
|
|
{
|
2019-04-19 16:15:14 +00:00
|
|
|
for( SCH_SHEET_PIN& pin : static_cast<SCH_SHEET*>( item )->GetPins() )
|
2019-04-14 00:44:05 +00:00
|
|
|
{
|
|
|
|
auto pin_conn = pin.Connection( *g_CurrentSheet );
|
2019-04-19 16:15:14 +00:00
|
|
|
bool redrawPin = pin.IsBrightened();
|
2019-04-14 00:44:05 +00:00
|
|
|
|
2019-04-19 16:15:14 +00:00
|
|
|
if( pin_conn && pin_conn->Name() == selectedNetName )
|
|
|
|
pin.SetBrightened();
|
|
|
|
else
|
|
|
|
pin.ClearBrightened();
|
2019-04-14 00:44:05 +00:00
|
|
|
|
2019-04-19 16:15:14 +00:00
|
|
|
redrawPin |= pin.IsBrightened();
|
2019-04-14 00:44:05 +00:00
|
|
|
|
|
|
|
if( redrawPin )
|
|
|
|
itemsToRedraw.push_back( &pin );
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if( redraw )
|
2019-04-19 16:15:14 +00:00
|
|
|
itemsToRedraw.push_back( item );
|
2019-04-14 00:44:05 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// Be sure hightlight change will be redrawn
|
|
|
|
KIGFX::VIEW* view = getView();
|
|
|
|
|
2019-04-19 16:15:14 +00:00
|
|
|
for( auto redrawItem : itemsToRedraw )
|
|
|
|
view->Update( (KIGFX::VIEW_ITEM*)redrawItem, KIGFX::VIEW_UPDATE_FLAGS::REPAINT );
|
2019-04-14 00:44:05 +00:00
|
|
|
|
|
|
|
m_frame->GetGalCanvas()->Refresh();
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
int SCH_EDITOR_CONTROL::HighlightNetCursor( const TOOL_EVENT& aEvent )
|
|
|
|
{
|
2019-04-15 23:56:41 +00:00
|
|
|
// TODO(JE) remove once real-time connectivity is a given
|
2019-04-29 21:44:49 +00:00
|
|
|
if( !ADVANCED_CFG::GetCfg().m_realTimeConnectivity || !CONNECTION_GRAPH::m_allowRealTime )
|
2019-04-15 23:56:41 +00:00
|
|
|
m_frame->RecalculateConnections();
|
|
|
|
|
2019-04-14 00:44:05 +00:00
|
|
|
Activate();
|
|
|
|
|
2019-05-10 17:19:48 +00:00
|
|
|
EE_PICKER_TOOL* picker = m_toolMgr->GetTool<EE_PICKER_TOOL>();
|
2019-04-14 00:44:05 +00:00
|
|
|
assert( picker );
|
|
|
|
|
2019-05-14 19:21:10 +00:00
|
|
|
m_frame->SetToolID( ID_HIGHLIGHT_TOOL, wxCURSOR_HAND, _( "Highlight specific net" ) );
|
2019-04-14 00:44:05 +00:00
|
|
|
picker->SetClickHandler( std::bind( highlightNet, m_toolMgr, std::placeholders::_1 ) );
|
|
|
|
picker->Activate();
|
|
|
|
Wait();
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2019-05-14 19:21:10 +00:00
|
|
|
int SCH_EDITOR_CONTROL::Undo( const TOOL_EVENT& aEvent )
|
|
|
|
{
|
|
|
|
if( m_frame->GetScreen()->GetUndoCommandCount() <= 0 )
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
// Inform tools that undo command was issued
|
|
|
|
m_toolMgr->ProcessEvent( { TC_MESSAGE, TA_UNDO_REDO_PRE, AS_GLOBAL } );
|
|
|
|
|
|
|
|
/* Get the old list */
|
|
|
|
PICKED_ITEMS_LIST* List = m_frame->GetScreen()->PopCommandFromUndoList();
|
|
|
|
|
|
|
|
/* Undo the command */
|
|
|
|
m_frame->PutDataInPreviousState( List, false );
|
|
|
|
|
|
|
|
/* Put the old list in RedoList */
|
|
|
|
List->ReversePickersListOrder();
|
|
|
|
m_frame->GetScreen()->PushCommandToRedoList( List );
|
|
|
|
|
|
|
|
m_frame->SetSheetNumberAndCount();
|
|
|
|
m_frame->TestDanglingEnds();
|
|
|
|
|
|
|
|
m_frame->SyncView();
|
|
|
|
m_frame->GetCanvas()->Refresh();
|
|
|
|
m_frame->OnModify();
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
int SCH_EDITOR_CONTROL::Redo( const TOOL_EVENT& aEvent )
|
|
|
|
{
|
|
|
|
if( m_frame->GetScreen()->GetRedoCommandCount() == 0 )
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
// Inform tools that undo command was issued
|
|
|
|
m_toolMgr->ProcessEvent( { TC_MESSAGE, TA_UNDO_REDO_PRE, AS_GLOBAL } );
|
|
|
|
|
|
|
|
/* Get the old list */
|
|
|
|
PICKED_ITEMS_LIST* List = m_frame->GetScreen()->PopCommandFromRedoList();
|
|
|
|
|
|
|
|
/* Redo the command: */
|
|
|
|
m_frame->PutDataInPreviousState( List, true );
|
|
|
|
|
|
|
|
/* Put the old list in UndoList */
|
|
|
|
List->ReversePickersListOrder();
|
|
|
|
m_frame->GetScreen()->PushCommandToUndoList( List );
|
|
|
|
|
|
|
|
m_frame->SetSheetNumberAndCount();
|
|
|
|
|
|
|
|
m_frame->TestDanglingEnds();
|
|
|
|
|
|
|
|
m_frame->SyncView();
|
|
|
|
m_frame->GetCanvas()->Refresh();
|
|
|
|
m_frame->OnModify();
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2019-04-28 16:36:31 +00:00
|
|
|
bool SCH_EDITOR_CONTROL::doCopy()
|
|
|
|
{
|
2019-05-10 17:19:48 +00:00
|
|
|
EE_SELECTION_TOOL* selTool = m_toolMgr->GetTool<EE_SELECTION_TOOL>();
|
|
|
|
SELECTION& selection = selTool->GetSelection();
|
2019-04-28 16:36:31 +00:00
|
|
|
|
|
|
|
if( !selection.GetSize() )
|
|
|
|
return false;
|
|
|
|
|
|
|
|
STRING_FORMATTER formatter;
|
|
|
|
SCH_LEGACY_PLUGIN plugin;
|
|
|
|
|
|
|
|
plugin.Format( &selection, &formatter );
|
|
|
|
|
|
|
|
return m_toolMgr->SaveClipboard( formatter.GetString() );
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
int SCH_EDITOR_CONTROL::Cut( const TOOL_EVENT& aEvent )
|
2019-04-23 13:06:37 +00:00
|
|
|
{
|
2019-04-28 16:36:31 +00:00
|
|
|
if( doCopy() )
|
2019-05-10 17:19:48 +00:00
|
|
|
m_toolMgr->RunAction( EE_ACTIONS::doDelete, true );
|
2019-04-28 16:36:31 +00:00
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
int SCH_EDITOR_CONTROL::Copy( const TOOL_EVENT& aEvent )
|
|
|
|
{
|
|
|
|
doCopy();
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
int SCH_EDITOR_CONTROL::Paste( const TOOL_EVENT& aEvent )
|
|
|
|
{
|
2019-05-10 17:19:48 +00:00
|
|
|
EE_SELECTION_TOOL* selTool = m_toolMgr->GetTool<EE_SELECTION_TOOL>();
|
2019-04-28 16:36:31 +00:00
|
|
|
|
2019-05-10 17:19:48 +00:00
|
|
|
DLIST<SCH_ITEM>& dlist = m_frame->GetScreen()->GetDrawList();
|
|
|
|
SCH_ITEM* last = dlist.GetLast();
|
2019-04-28 16:36:31 +00:00
|
|
|
|
2019-05-10 17:19:48 +00:00
|
|
|
std::string text = m_toolMgr->GetClipboard();
|
|
|
|
STRING_LINE_READER reader( text, "Clipboard" );
|
|
|
|
SCH_LEGACY_PLUGIN plugin;
|
2019-04-28 16:36:31 +00:00
|
|
|
|
|
|
|
try
|
|
|
|
{
|
|
|
|
plugin.LoadContent( reader, m_frame->GetScreen() );
|
|
|
|
}
|
|
|
|
catch( IO_ERROR& e )
|
|
|
|
{
|
|
|
|
wxLogError( wxString::Format( "Malformed clipboard: %s" ), GetChars( e.What() ) );
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
// SCH_LEGACY_PLUGIN added the items to the DLIST, but not to the view or anything
|
|
|
|
// else. Pull them back out to start with.
|
|
|
|
//
|
2019-05-03 22:46:44 +00:00
|
|
|
EDA_ITEMS loadedItems;
|
2019-04-28 16:36:31 +00:00
|
|
|
SCH_ITEM* next = nullptr;
|
2019-04-23 13:06:37 +00:00
|
|
|
|
2019-04-28 16:36:31 +00:00
|
|
|
// We also make sure any pasted sheets will not cause recursion in the destination.
|
|
|
|
// Moreover new sheets create new sheetpaths, and component alternate references must
|
|
|
|
// be created and cleared
|
|
|
|
//
|
2019-05-03 11:49:59 +00:00
|
|
|
bool sheetsPasted = false;
|
2019-04-28 16:36:31 +00:00
|
|
|
SCH_SHEET_LIST hierarchy( g_RootSheet );
|
|
|
|
SCH_SHEET_LIST initialHierarchy( g_RootSheet );
|
2019-04-23 13:06:37 +00:00
|
|
|
|
2019-04-28 16:36:31 +00:00
|
|
|
wxFileName destFn = g_CurrentSheet->Last()->GetFileName();
|
2019-04-23 13:06:37 +00:00
|
|
|
|
2019-04-28 16:36:31 +00:00
|
|
|
if( destFn.IsRelative() )
|
|
|
|
destFn.MakeAbsolute( m_frame->Prj().GetProjectPath() );
|
|
|
|
|
|
|
|
for( SCH_ITEM* item = last ? last->Next() : dlist.GetFirst(); item; item = next )
|
2019-04-23 13:06:37 +00:00
|
|
|
{
|
2019-04-28 16:36:31 +00:00
|
|
|
next = item->Next();
|
|
|
|
dlist.Remove( item );
|
|
|
|
|
|
|
|
loadedItems.push_back( item );
|
|
|
|
|
|
|
|
if( item->Type() == SCH_COMPONENT_T )
|
2019-04-23 13:06:37 +00:00
|
|
|
{
|
2019-04-28 16:36:31 +00:00
|
|
|
SCH_COMPONENT* component = (SCH_COMPONENT*) item;
|
|
|
|
|
|
|
|
component->SetTimeStamp( GetNewTimeStamp() );
|
|
|
|
|
|
|
|
// clear the annotation, but preserve the selected unit
|
|
|
|
int unit = component->GetUnit();
|
|
|
|
component->ClearAnnotation( nullptr );
|
|
|
|
component->SetUnit( unit );
|
2019-04-23 13:06:37 +00:00
|
|
|
}
|
2019-04-28 16:36:31 +00:00
|
|
|
if( item->Type() == SCH_SHEET_T )
|
2019-04-23 13:06:37 +00:00
|
|
|
{
|
2019-04-28 16:36:31 +00:00
|
|
|
SCH_SHEET* sheet = (SCH_SHEET*) item;
|
|
|
|
wxFileName srcFn = sheet->GetFileName();
|
|
|
|
|
|
|
|
if( srcFn.IsRelative() )
|
|
|
|
srcFn.MakeAbsolute( m_frame->Prj().GetProjectPath() );
|
|
|
|
|
|
|
|
SCH_SHEET_LIST sheetHierarchy( sheet );
|
|
|
|
|
|
|
|
if( hierarchy.TestForRecursion( sheetHierarchy, destFn.GetFullPath( wxPATH_UNIX ) ) )
|
|
|
|
{
|
|
|
|
auto msg = wxString::Format( _( "The pasted sheet \"%s\"\n"
|
|
|
|
"was dropped because the destination already has "
|
|
|
|
"the sheet or one of its subsheets as a parent." ),
|
|
|
|
sheet->GetFileName() );
|
|
|
|
DisplayError( m_frame, msg );
|
|
|
|
loadedItems.pop_back();
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
// Duplicate sheet names and sheet time stamps are not valid. Use a time stamp
|
|
|
|
// based sheet name and update the time stamp for each sheet in the block.
|
|
|
|
timestamp_t uid = GetNewTimeStamp();
|
|
|
|
|
|
|
|
sheet->SetName( wxString::Format( wxT( "sheet%8.8lX" ), (unsigned long)uid ) );
|
|
|
|
sheet->SetTimeStamp( uid );
|
2019-05-03 11:49:59 +00:00
|
|
|
sheetsPasted = true;
|
2019-04-28 16:36:31 +00:00
|
|
|
}
|
2019-04-23 13:06:37 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-04-28 16:36:31 +00:00
|
|
|
// Now we can resolve the components and add everything to the screen, view, etc.
|
|
|
|
//
|
|
|
|
SYMBOL_LIB_TABLE* symLibTable = m_frame->Prj().SchSymbolLibTable();
|
|
|
|
PART_LIB* partLib = m_frame->Prj().SchLibs()->GetCacheLibrary();
|
2019-04-23 13:06:37 +00:00
|
|
|
|
2019-05-11 09:12:39 +00:00
|
|
|
for( unsigned i = 0; i < loadedItems.size(); ++i )
|
2019-04-28 16:36:31 +00:00
|
|
|
{
|
2019-05-03 22:46:44 +00:00
|
|
|
EDA_ITEM* item = loadedItems[i];
|
2019-04-23 13:06:37 +00:00
|
|
|
|
2019-04-28 16:36:31 +00:00
|
|
|
if( item->Type() == SCH_COMPONENT_T )
|
|
|
|
{
|
|
|
|
SCH_COMPONENT* component = (SCH_COMPONENT*) item;
|
|
|
|
component->Resolve( *symLibTable, partLib );
|
|
|
|
}
|
2019-05-03 11:49:59 +00:00
|
|
|
else if( item->Type() == SCH_SHEET_T )
|
|
|
|
{
|
|
|
|
SCH_SHEET* sheet = (SCH_SHEET*) item;
|
|
|
|
m_frame->InitSheet( sheet, sheet->GetFileName() );
|
|
|
|
}
|
2019-04-23 13:06:37 +00:00
|
|
|
|
2019-05-16 22:50:54 +00:00
|
|
|
item->SetFlags( IS_NEW | IS_PASTED | IS_MOVED );
|
2019-05-03 22:46:44 +00:00
|
|
|
m_frame->AddItemToScreenAndUndoList( (SCH_ITEM*) item, i > 0 );
|
2019-05-06 15:58:53 +00:00
|
|
|
|
|
|
|
// Reset flags for subsequent move operation
|
2019-05-16 22:50:54 +00:00
|
|
|
item->SetFlags( IS_NEW | IS_PASTED | IS_MOVED );
|
2019-04-28 16:36:31 +00:00
|
|
|
}
|
2019-04-23 13:06:37 +00:00
|
|
|
|
2019-05-03 11:49:59 +00:00
|
|
|
if( sheetsPasted )
|
2019-04-28 16:36:31 +00:00
|
|
|
{
|
|
|
|
// We clear annotation of new sheet paths.
|
|
|
|
SCH_SCREENS screensList( g_RootSheet );
|
|
|
|
screensList.ClearAnnotationOfNewSheetPaths( initialHierarchy );
|
2019-05-03 11:49:59 +00:00
|
|
|
m_frame->SetSheetNumberAndCount();
|
2019-04-28 16:36:31 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// Now clear the previous selection, select the pasted items, and fire up the "move"
|
|
|
|
// tool.
|
|
|
|
//
|
2019-05-10 17:19:48 +00:00
|
|
|
m_toolMgr->RunAction( EE_ACTIONS::clearSelection, true );
|
|
|
|
m_toolMgr->RunAction( EE_ACTIONS::addItemsToSel, true, &loadedItems );
|
2019-04-28 16:36:31 +00:00
|
|
|
|
|
|
|
SELECTION& selection = selTool->GetSelection();
|
|
|
|
|
|
|
|
if( !selection.Empty() )
|
|
|
|
{
|
|
|
|
SCH_ITEM* item = (SCH_ITEM*) selection.GetTopLeftItem();
|
|
|
|
|
|
|
|
selection.SetReferencePoint( item->GetPosition() );
|
2019-05-10 17:19:48 +00:00
|
|
|
m_toolMgr->RunAction( EE_ACTIONS::move, false );
|
2019-04-28 16:36:31 +00:00
|
|
|
}
|
2019-04-23 13:06:37 +00:00
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2019-05-17 15:44:58 +00:00
|
|
|
int SCH_EDITOR_CONTROL::EditWithLibEdit( const TOOL_EVENT& aEvent )
|
2019-04-29 22:24:30 +00:00
|
|
|
{
|
2019-05-10 17:19:48 +00:00
|
|
|
EE_SELECTION_TOOL* selTool = m_toolMgr->GetTool<EE_SELECTION_TOOL>();
|
2019-05-10 19:22:26 +00:00
|
|
|
SELECTION& selection = selTool->RequestSelection( EE_COLLECTOR::ComponentsOnly );
|
2019-05-10 17:19:48 +00:00
|
|
|
SCH_COMPONENT* comp = nullptr;
|
2019-04-29 22:24:30 +00:00
|
|
|
|
|
|
|
if( selection.GetSize() >= 1 )
|
2019-05-01 21:50:11 +00:00
|
|
|
comp = (SCH_COMPONENT*) selection.Front();
|
2019-04-29 22:24:30 +00:00
|
|
|
|
|
|
|
if( !comp || comp->GetEditFlags() != 0 )
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
wxCommandEvent dummy;
|
|
|
|
m_frame->OnOpenLibraryEditor( dummy );
|
|
|
|
|
|
|
|
auto libeditFrame = (LIB_EDIT_FRAME*) m_frame->Kiway().Player( FRAME_SCH_LIB_EDITOR, false );
|
|
|
|
|
|
|
|
if( libeditFrame )
|
|
|
|
{
|
|
|
|
const LIB_ID& id = comp->GetLibId();
|
|
|
|
libeditFrame->LoadComponentAndSelectLib( id, comp->GetUnit(), comp->GetConvert() );
|
|
|
|
}
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2019-05-14 19:21:10 +00:00
|
|
|
int SCH_EDITOR_CONTROL::ShowSymbolEditor( const TOOL_EVENT& aEvent )
|
|
|
|
{
|
|
|
|
wxCommandEvent dummy;
|
|
|
|
m_frame->OnOpenLibraryEditor( dummy );
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2019-05-13 20:42:40 +00:00
|
|
|
int SCH_EDITOR_CONTROL::ShowLibraryBrowser( const TOOL_EVENT& aEvent )
|
|
|
|
{
|
|
|
|
wxCommandEvent dummy;
|
|
|
|
m_frame->OnOpenLibraryViewer( dummy );
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2019-04-30 14:46:29 +00:00
|
|
|
int SCH_EDITOR_CONTROL::EnterSheet( const TOOL_EVENT& aEvent )
|
|
|
|
{
|
2019-05-10 17:19:48 +00:00
|
|
|
EE_SELECTION_TOOL* selTool = m_toolMgr->GetTool<EE_SELECTION_TOOL>();
|
2019-05-10 19:22:26 +00:00
|
|
|
const SELECTION& selection = selTool->RequestSelection( EE_COLLECTOR::SheetsOnly );
|
2019-04-30 14:46:29 +00:00
|
|
|
|
|
|
|
if( selection.GetSize() == 1 )
|
|
|
|
{
|
2019-05-01 21:50:11 +00:00
|
|
|
g_CurrentSheet->push_back( (SCH_SHEET*) selection.Front() );
|
2019-04-30 14:46:29 +00:00
|
|
|
m_frame->DisplayCurrentSheet();
|
|
|
|
}
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
int SCH_EDITOR_CONTROL::LeaveSheet( const TOOL_EVENT& aEvent )
|
|
|
|
{
|
|
|
|
if( g_CurrentSheet->Last() != g_RootSheet )
|
|
|
|
{
|
|
|
|
g_CurrentSheet->pop_back();
|
|
|
|
m_frame->DisplayCurrentSheet();
|
|
|
|
}
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2019-05-13 20:42:40 +00:00
|
|
|
int SCH_EDITOR_CONTROL::ToggleHiddenPins( const TOOL_EVENT& aEvent )
|
|
|
|
{
|
|
|
|
m_frame->SetShowAllPins( !m_frame->GetShowAllPins() );
|
|
|
|
|
|
|
|
auto painter = static_cast<KIGFX::SCH_PAINTER*>( getView()->GetPainter() );
|
|
|
|
painter->GetSettings()->m_ShowHiddenPins = m_frame->GetShowAllPins();
|
|
|
|
|
|
|
|
getView()->UpdateAllItems( KIGFX::REPAINT );
|
|
|
|
m_frame->GetCanvas()->Refresh();
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2019-05-13 21:49:05 +00:00
|
|
|
int SCH_EDITOR_CONTROL::ToggleForceHV( const TOOL_EVENT& aEvent )
|
|
|
|
{
|
|
|
|
m_frame->SetForceHVLines( !m_frame->GetForceHVLines() );
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
2019-04-14 00:44:05 +00:00
|
|
|
void SCH_EDITOR_CONTROL::setTransitions()
|
|
|
|
{
|
2019-05-24 23:36:31 +00:00
|
|
|
Go( &SCH_EDITOR_CONTROL::New, ACTIONS::doNew.MakeEvent() );
|
|
|
|
Go( &SCH_EDITOR_CONTROL::Open, ACTIONS::open.MakeEvent() );
|
|
|
|
Go( &SCH_EDITOR_CONTROL::Save, ACTIONS::save.MakeEvent() );
|
|
|
|
Go( &SCH_EDITOR_CONTROL::SaveAs, ACTIONS::saveAs.MakeEvent() );
|
2019-05-26 23:00:27 +00:00
|
|
|
Go( &SCH_EDITOR_CONTROL::SaveAll, ACTIONS::saveAll.MakeEvent() );
|
2019-05-26 15:36:40 +00:00
|
|
|
Go( &SCH_EDITOR_CONTROL::PageSetup, ACTIONS::pageSettings.MakeEvent() );
|
2019-05-24 23:36:31 +00:00
|
|
|
Go( &SCH_EDITOR_CONTROL::Print, ACTIONS::print.MakeEvent() );
|
|
|
|
Go( &SCH_EDITOR_CONTROL::Plot, ACTIONS::plot.MakeEvent() );
|
|
|
|
Go( &SCH_EDITOR_CONTROL::Quit, ACTIONS::quit.MakeEvent() );
|
|
|
|
|
2019-05-19 21:04:04 +00:00
|
|
|
Go( &SCH_EDITOR_CONTROL::FindAndReplace, ACTIONS::find.MakeEvent() );
|
|
|
|
Go( &SCH_EDITOR_CONTROL::FindAndReplace, ACTIONS::findAndReplace.MakeEvent() );
|
|
|
|
Go( &SCH_EDITOR_CONTROL::FindNext, ACTIONS::findNext.MakeEvent() );
|
|
|
|
Go( &SCH_EDITOR_CONTROL::FindNext, ACTIONS::findNextMarker.MakeEvent() );
|
|
|
|
Go( &SCH_EDITOR_CONTROL::ReplaceAndFindNext, ACTIONS::replaceAndFindNext.MakeEvent() );
|
|
|
|
Go( &SCH_EDITOR_CONTROL::ReplaceAll, ACTIONS::replaceAll.MakeEvent() );
|
|
|
|
Go( &SCH_EDITOR_CONTROL::UpdateFind, ACTIONS::updateFind.MakeEvent() );
|
|
|
|
Go( &SCH_EDITOR_CONTROL::UpdateFind, EVENTS::SelectedItemsModified );
|
|
|
|
|
2019-04-14 00:44:05 +00:00
|
|
|
/*
|
2019-05-10 17:19:48 +00:00
|
|
|
Go( &SCH_EDITOR_CONTROL::ToggleLockSelected, EE_ACTIONS::toggleLock.MakeEvent() );
|
|
|
|
Go( &SCH_EDITOR_CONTROL::LockSelected, EE_ACTIONS::lock.MakeEvent() );
|
|
|
|
Go( &SCH_EDITOR_CONTROL::UnlockSelected, EE_ACTIONS::unlock.MakeEvent() );
|
2019-04-14 00:44:05 +00:00
|
|
|
*/
|
|
|
|
|
2019-04-30 18:36:11 +00:00
|
|
|
Go( &SCH_EDITOR_CONTROL::CrossProbeToPcb, EVENTS::SelectedEvent );
|
|
|
|
Go( &SCH_EDITOR_CONTROL::CrossProbeToPcb, EVENTS::UnselectedEvent );
|
|
|
|
Go( &SCH_EDITOR_CONTROL::CrossProbeToPcb, EVENTS::ClearedEvent );
|
2019-05-10 17:19:48 +00:00
|
|
|
Go( &SCH_EDITOR_CONTROL::ExplicitCrossProbeToPcb, EE_ACTIONS::explicitCrossProbe.MakeEvent() );
|
2019-04-29 21:17:26 +00:00
|
|
|
|
2019-04-23 17:12:26 +00:00
|
|
|
#ifdef KICAD_SPICE
|
2019-05-10 17:19:48 +00:00
|
|
|
Go( &SCH_EDITOR_CONTROL::SimProbe, EE_ACTIONS::simProbe.MakeEvent() );
|
|
|
|
Go( &SCH_EDITOR_CONTROL::SimTune, EE_ACTIONS::simTune.MakeEvent() );
|
2019-04-23 17:12:26 +00:00
|
|
|
#endif /* KICAD_SPICE */
|
|
|
|
|
2019-05-10 17:19:48 +00:00
|
|
|
Go( &SCH_EDITOR_CONTROL::HighlightNet, EE_ACTIONS::highlightNet.MakeEvent() );
|
|
|
|
Go( &SCH_EDITOR_CONTROL::ClearHighlight, EE_ACTIONS::clearHighlight.MakeEvent() );
|
|
|
|
Go( &SCH_EDITOR_CONTROL::HighlightNetCursor, EE_ACTIONS::highlightNetCursor.MakeEvent() );
|
2019-05-12 17:03:17 +00:00
|
|
|
Go( &SCH_EDITOR_CONTROL::UpdateNetHighlighting, EVENTS::SelectedItemsModified );
|
|
|
|
Go( &SCH_EDITOR_CONTROL::UpdateNetHighlighting, EE_ACTIONS::updateNetHighlighting.MakeEvent() );
|
2019-04-23 13:06:37 +00:00
|
|
|
|
2019-05-14 19:21:10 +00:00
|
|
|
Go( &SCH_EDITOR_CONTROL::Undo, ACTIONS::undo.MakeEvent() );
|
|
|
|
Go( &SCH_EDITOR_CONTROL::Redo, ACTIONS::redo.MakeEvent() );
|
|
|
|
Go( &SCH_EDITOR_CONTROL::Cut, ACTIONS::cut.MakeEvent() );
|
|
|
|
Go( &SCH_EDITOR_CONTROL::Copy, ACTIONS::copy.MakeEvent() );
|
|
|
|
Go( &SCH_EDITOR_CONTROL::Paste, ACTIONS::paste.MakeEvent() );
|
2019-04-29 22:24:30 +00:00
|
|
|
|
2019-05-17 15:44:58 +00:00
|
|
|
Go( &SCH_EDITOR_CONTROL::EditWithLibEdit, EE_ACTIONS::editWithLibEdit.MakeEvent() );
|
2019-05-14 19:21:10 +00:00
|
|
|
Go( &SCH_EDITOR_CONTROL::ShowSymbolEditor, EE_ACTIONS::showSymbolEditor.MakeEvent() );
|
2019-05-13 20:42:40 +00:00
|
|
|
Go( &SCH_EDITOR_CONTROL::ShowLibraryBrowser, EE_ACTIONS::showLibraryBrowser.MakeEvent() );
|
2019-04-30 14:46:29 +00:00
|
|
|
|
2019-05-10 17:19:48 +00:00
|
|
|
Go( &SCH_EDITOR_CONTROL::EnterSheet, EE_ACTIONS::enterSheet.MakeEvent() );
|
|
|
|
Go( &SCH_EDITOR_CONTROL::LeaveSheet, EE_ACTIONS::leaveSheet.MakeEvent() );
|
2019-05-13 20:42:40 +00:00
|
|
|
Go( &SCH_EDITOR_CONTROL::NavigateHierarchy, EE_ACTIONS::navigateHierarchy.MakeEvent() );
|
|
|
|
|
|
|
|
Go( &SCH_EDITOR_CONTROL::ToggleHiddenPins, EE_ACTIONS::toggleHiddenPins.MakeEvent() );
|
2019-05-13 21:49:05 +00:00
|
|
|
Go( &SCH_EDITOR_CONTROL::ToggleForceHV, EE_ACTIONS::toggleForceHV.MakeEvent() );
|
2019-04-14 00:44:05 +00:00
|
|
|
}
|