2019-07-18 21:47:01 +00:00
|
|
|
/*
|
|
|
|
* This program source code file is part of KiCad, a free EDA CAD application.
|
|
|
|
*
|
|
|
|
* Copyright (C) 2019 Ian McInerney <Ian.S.McInerney@ieee.org>
|
2023-05-30 18:01:44 +00:00
|
|
|
* Copyright (C) 2023 KiCad Developers, see AUTHORS.txt for contributors.
|
2019-07-18 21:47:01 +00:00
|
|
|
*
|
|
|
|
* 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 3 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, see <http://www.gnu.org/licenses/>.
|
|
|
|
*/
|
|
|
|
|
2019-07-24 20:56:17 +00:00
|
|
|
#include <confirm.h>
|
2019-07-18 21:47:01 +00:00
|
|
|
#include <cstdint>
|
|
|
|
#include <functional>
|
2021-09-14 22:45:14 +00:00
|
|
|
#include <kiface_base.h>
|
2019-07-18 21:47:01 +00:00
|
|
|
#include <kiway_express.h>
|
2019-07-24 20:56:17 +00:00
|
|
|
#include <lib_id.h>
|
2019-07-18 21:47:01 +00:00
|
|
|
#include <tool/actions.h>
|
2019-08-08 22:11:59 +00:00
|
|
|
#include <tool/tool_manager.h>
|
2019-07-18 21:47:01 +00:00
|
|
|
|
|
|
|
#include <cvpcb_mainframe.h>
|
|
|
|
#include <dialogs/dialog_config_equfiles.h>
|
|
|
|
#include <display_footprints_frame.h>
|
|
|
|
#include <listboxes.h>
|
|
|
|
#include <tools/cvpcb_actions.h>
|
|
|
|
#include <tools/cvpcb_control.h>
|
2021-05-01 18:04:11 +00:00
|
|
|
#include <wx/settings.h>
|
2019-07-18 21:47:01 +00:00
|
|
|
|
|
|
|
using namespace std::placeholders;
|
|
|
|
|
|
|
|
|
|
|
|
CVPCB_CONTROL::CVPCB_CONTROL() :
|
|
|
|
TOOL_INTERACTIVE( "cvpcb.Control" ),
|
|
|
|
m_frame( nullptr )
|
|
|
|
{
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void CVPCB_CONTROL::Reset( RESET_REASON aReason )
|
|
|
|
{
|
|
|
|
m_frame = getEditFrame<CVPCB_MAINFRAME>();
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2019-08-08 22:11:59 +00:00
|
|
|
int CVPCB_CONTROL::Main( const TOOL_EVENT& aEvent )
|
|
|
|
{
|
|
|
|
// Main loop: keep receiving events
|
|
|
|
while( TOOL_EVENT* evt = Wait() )
|
|
|
|
{
|
|
|
|
bool handled = false;
|
|
|
|
|
|
|
|
// The escape key maps to the cancel event, which is used to close the window
|
|
|
|
if( evt->IsCancel() )
|
|
|
|
{
|
2019-10-06 10:19:41 +00:00
|
|
|
m_frame->Close( false );
|
2019-08-08 22:11:59 +00:00
|
|
|
handled = true;
|
|
|
|
}
|
|
|
|
else if( evt->IsKeyPressed() )
|
|
|
|
{
|
|
|
|
switch( evt->KeyCode() )
|
|
|
|
{
|
|
|
|
// The right arrow moves focus to the focusable object to the right
|
|
|
|
case WXK_RIGHT:
|
2023-06-26 22:16:51 +00:00
|
|
|
m_toolMgr->PostAction( CVPCB_ACTIONS::changeFocusRight );
|
2019-08-08 22:11:59 +00:00
|
|
|
handled = true;
|
|
|
|
break;
|
|
|
|
|
|
|
|
// The left arrow moves focus to the focusable object to the left
|
|
|
|
case WXK_LEFT:
|
2023-06-26 22:16:51 +00:00
|
|
|
m_toolMgr->PostAction( CVPCB_ACTIONS::changeFocusLeft );
|
2019-08-08 22:11:59 +00:00
|
|
|
handled = true;
|
|
|
|
break;
|
|
|
|
|
|
|
|
default:
|
|
|
|
// Let every other key continue processing to the controls of the window
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if( !handled )
|
|
|
|
evt->SetPassEvent();
|
|
|
|
}
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
int CVPCB_CONTROL::ChangeFocus( const TOOL_EVENT& aEvent )
|
|
|
|
{
|
2022-09-28 01:15:19 +00:00
|
|
|
CVPCB_MAINFRAME::FOCUS_DIR dir = aEvent.Parameter<CVPCB_MAINFRAME::FOCUS_DIR>();
|
2019-08-08 22:11:59 +00:00
|
|
|
|
|
|
|
switch( dir )
|
|
|
|
{
|
|
|
|
case CVPCB_MAINFRAME::CHANGE_FOCUS_RIGHT:
|
|
|
|
switch( m_frame->GetFocusedControl() )
|
|
|
|
{
|
|
|
|
case CVPCB_MAINFRAME::CONTROL_LIBRARY:
|
|
|
|
m_frame->SetFocusedControl( CVPCB_MAINFRAME::CONTROL_COMPONENT );
|
|
|
|
break;
|
|
|
|
|
|
|
|
case CVPCB_MAINFRAME::CONTROL_COMPONENT:
|
|
|
|
m_frame->SetFocusedControl( CVPCB_MAINFRAME::CONTROL_FOOTPRINT );
|
|
|
|
break;
|
|
|
|
|
|
|
|
case CVPCB_MAINFRAME::CONTROL_FOOTPRINT:
|
|
|
|
m_frame->SetFocusedControl( CVPCB_MAINFRAME::CONTROL_LIBRARY );
|
|
|
|
break;
|
|
|
|
|
|
|
|
case CVPCB_MAINFRAME::CONTROL_NONE:
|
|
|
|
default:
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
case CVPCB_MAINFRAME::CHANGE_FOCUS_LEFT:
|
|
|
|
switch( m_frame->GetFocusedControl() )
|
|
|
|
{
|
|
|
|
case CVPCB_MAINFRAME::CONTROL_LIBRARY:
|
|
|
|
m_frame->SetFocusedControl( CVPCB_MAINFRAME::CONTROL_FOOTPRINT );
|
|
|
|
break;
|
|
|
|
|
|
|
|
case CVPCB_MAINFRAME::CONTROL_COMPONENT:
|
|
|
|
m_frame->SetFocusedControl( CVPCB_MAINFRAME::CONTROL_LIBRARY );
|
|
|
|
break;
|
|
|
|
|
|
|
|
case CVPCB_MAINFRAME::CONTROL_FOOTPRINT:
|
|
|
|
m_frame->SetFocusedControl( CVPCB_MAINFRAME::CONTROL_COMPONENT );
|
|
|
|
break;
|
|
|
|
|
|
|
|
case CVPCB_MAINFRAME::CONTROL_NONE:
|
|
|
|
default:
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
default:
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2019-07-18 21:47:01 +00:00
|
|
|
int CVPCB_CONTROL::ShowFootprintViewer( const TOOL_EVENT& aEvent )
|
|
|
|
{
|
|
|
|
|
|
|
|
DISPLAY_FOOTPRINTS_FRAME* fpframe = m_frame->GetFootprintViewerFrame();
|
|
|
|
|
|
|
|
if( !fpframe )
|
|
|
|
{
|
2023-05-30 18:01:44 +00:00
|
|
|
// DISPLAY_FOOTPRINTS_FRAME needs a PCBNEW_SETTINGS because most of its settings
|
|
|
|
// come from it, and needs _pcbnew.dll/so code. So load it if the dll is not yet loaded
|
|
|
|
// (for instance if the board editor was never loaded)
|
|
|
|
if( !m_frame->Kiway().KiFACE( KIWAY::FACE_PCB, false ) )
|
|
|
|
{
|
|
|
|
try
|
|
|
|
{
|
|
|
|
m_frame->Kiway().KiFACE( KIWAY::FACE_PCB, true );
|
|
|
|
}
|
|
|
|
catch( ... )
|
|
|
|
{
|
|
|
|
// _pcbnew.dll/so is not available (install problem).
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2022-07-25 12:29:18 +00:00
|
|
|
fpframe = (DISPLAY_FOOTPRINTS_FRAME*) m_frame->Kiway().Player( FRAME_CVPCB_DISPLAY, true,
|
|
|
|
m_frame );
|
2023-05-30 18:01:44 +00:00
|
|
|
if( !fpframe )
|
|
|
|
{
|
|
|
|
wxMessageBox( _( "Unable to create the footprint viewer frame" ) );
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2019-07-18 21:47:01 +00:00
|
|
|
fpframe->Show( true );
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2022-07-12 21:44:53 +00:00
|
|
|
if( wxWindow* blocking_win = fpframe->Kiway().GetBlockingDialog() )
|
|
|
|
blocking_win->Close( true );
|
|
|
|
|
2019-07-18 21:47:01 +00:00
|
|
|
if( fpframe->IsIconized() )
|
|
|
|
fpframe->Iconize( false );
|
|
|
|
|
|
|
|
// The display footprint window might be buried under some other
|
|
|
|
// windows, so CreateScreenCmp() on an existing window would not
|
|
|
|
// show any difference, leaving the user confused.
|
|
|
|
// So we want to put it to front, second after our CVPCB_MAINFRAME.
|
|
|
|
// We do this by a little dance of bringing it to front then the main
|
|
|
|
// frame back.
|
|
|
|
wxWindow* focus = m_frame->FindFocus();
|
|
|
|
|
|
|
|
fpframe->Raise(); // Make sure that is visible.
|
|
|
|
m_frame->Raise(); // .. but still we want the focus.
|
|
|
|
|
|
|
|
if( focus )
|
|
|
|
focus->SetFocus();
|
|
|
|
}
|
|
|
|
|
|
|
|
fpframe->InitDisplay();
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
int CVPCB_CONTROL::ToggleFootprintFilter( const TOOL_EVENT& aEvent )
|
|
|
|
{
|
2022-09-28 01:15:19 +00:00
|
|
|
m_frame->SetFootprintFilter( aEvent.Parameter<FOOTPRINTS_LISTBOX::FP_FILTER_T>(),
|
|
|
|
CVPCB_MAINFRAME::FILTER_TOGGLE );
|
2019-07-18 21:47:01 +00:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
int CVPCB_CONTROL::ShowEquFileTable( const TOOL_EVENT& aEvent )
|
|
|
|
{
|
|
|
|
DIALOG_CONFIG_EQUFILES dlg( m_frame );
|
|
|
|
dlg.ShowModal();
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2022-04-30 07:43:28 +00:00
|
|
|
int CVPCB_CONTROL::SaveAssociationsToFile( const TOOL_EVENT& aEvent )
|
2019-07-18 21:47:01 +00:00
|
|
|
{
|
|
|
|
m_frame->SaveFootprintAssociation( true );
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2022-04-30 07:43:28 +00:00
|
|
|
int CVPCB_CONTROL::SaveAssociationsToSchematic( const TOOL_EVENT& aEvent )
|
|
|
|
{
|
|
|
|
m_frame->SaveFootprintAssociation( false );
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2019-08-08 21:10:37 +00:00
|
|
|
int CVPCB_CONTROL::ToNA( const TOOL_EVENT& aEvent )
|
2019-07-18 21:47:01 +00:00
|
|
|
{
|
2022-09-28 01:15:19 +00:00
|
|
|
CVPCB_MAINFRAME::ITEM_DIR dir = aEvent.Parameter<CVPCB_MAINFRAME::ITEM_DIR>();
|
2019-07-18 21:47:01 +00:00
|
|
|
|
2019-08-08 21:10:37 +00:00
|
|
|
std::vector<unsigned int> naComp = m_frame->GetComponentIndices( CVPCB_MAINFRAME::NA_COMPONENTS );
|
|
|
|
std::vector<unsigned int> tempSel = m_frame->GetComponentIndices( CVPCB_MAINFRAME::SEL_COMPONENTS );
|
|
|
|
|
|
|
|
// No unassociated components
|
|
|
|
if( naComp.empty() )
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
// Extract the current selection
|
2022-04-30 09:07:07 +00:00
|
|
|
bool changeSel = false;
|
|
|
|
unsigned int newSel = UINT_MAX;
|
|
|
|
|
2019-08-08 21:10:37 +00:00
|
|
|
switch( dir )
|
|
|
|
{
|
|
|
|
case CVPCB_MAINFRAME::ITEM_NEXT:
|
|
|
|
if( !tempSel.empty() )
|
|
|
|
newSel = tempSel.front();
|
|
|
|
|
|
|
|
// Find the next index in the component list
|
2022-04-30 09:07:07 +00:00
|
|
|
for( unsigned int idx : naComp )
|
2019-08-08 21:10:37 +00:00
|
|
|
{
|
2022-04-30 09:07:07 +00:00
|
|
|
if( idx > newSel )
|
2019-08-08 21:10:37 +00:00
|
|
|
{
|
2022-04-30 09:07:07 +00:00
|
|
|
changeSel = true;
|
|
|
|
newSel = idx;
|
2019-08-08 21:10:37 +00:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
case CVPCB_MAINFRAME::ITEM_PREV:
|
|
|
|
if( !tempSel.empty() )
|
|
|
|
{
|
|
|
|
newSel = tempSel.front();
|
2022-04-30 09:07:07 +00:00
|
|
|
|
|
|
|
// Find the previous index in the component list
|
|
|
|
for( int jj = naComp.size()-1; jj >= 0; jj-- )
|
|
|
|
{
|
|
|
|
unsigned idx = naComp[jj];
|
|
|
|
|
|
|
|
if( idx < newSel )
|
|
|
|
{
|
|
|
|
changeSel = true;
|
|
|
|
newSel = idx;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
2019-08-08 21:10:37 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
default:
|
|
|
|
wxASSERT_MSG( false, "Invalid direction" );
|
|
|
|
}
|
|
|
|
|
2022-04-30 09:07:07 +00:00
|
|
|
// Set the new component selection
|
|
|
|
if( changeSel )
|
|
|
|
m_frame->SetSelectedComponent( newSel );
|
2019-07-18 21:47:01 +00:00
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2019-07-26 18:58:20 +00:00
|
|
|
int CVPCB_CONTROL::UpdateMenu( const TOOL_EVENT& aEvent )
|
|
|
|
{
|
|
|
|
ACTION_MENU* actionMenu = aEvent.Parameter<ACTION_MENU*>();
|
|
|
|
CONDITIONAL_MENU* conditionalMenu = dynamic_cast<CONDITIONAL_MENU*>( actionMenu );
|
|
|
|
SELECTION dummySel;
|
|
|
|
|
|
|
|
if( conditionalMenu )
|
|
|
|
conditionalMenu->Evaluate( dummySel );
|
|
|
|
|
|
|
|
if( actionMenu )
|
|
|
|
actionMenu->UpdateAll();
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2019-07-18 21:47:01 +00:00
|
|
|
void CVPCB_CONTROL::setTransitions()
|
|
|
|
{
|
2019-08-08 22:11:59 +00:00
|
|
|
// Control actions
|
2019-07-26 18:58:20 +00:00
|
|
|
Go( &CVPCB_CONTROL::UpdateMenu, ACTIONS::updateMenu.MakeEvent() );
|
2019-08-08 22:11:59 +00:00
|
|
|
Go( &CVPCB_CONTROL::Main, CVPCB_ACTIONS::controlActivate.MakeEvent() );
|
|
|
|
Go( &CVPCB_CONTROL::ChangeFocus, CVPCB_ACTIONS::changeFocusRight.MakeEvent() );
|
|
|
|
Go( &CVPCB_CONTROL::ChangeFocus, CVPCB_ACTIONS::changeFocusLeft.MakeEvent() );
|
2019-07-26 18:58:20 +00:00
|
|
|
|
2019-07-18 21:47:01 +00:00
|
|
|
// Run the footprint viewer
|
|
|
|
Go( &CVPCB_CONTROL::ShowFootprintViewer, CVPCB_ACTIONS::showFootprintViewer.MakeEvent() );
|
|
|
|
|
|
|
|
// Management actions
|
|
|
|
Go( &CVPCB_CONTROL::ShowEquFileTable, CVPCB_ACTIONS::showEquFileTable.MakeEvent() );
|
2022-04-30 07:43:28 +00:00
|
|
|
Go( &CVPCB_CONTROL::SaveAssociationsToSchematic, CVPCB_ACTIONS::saveAssociationsToSchematic.MakeEvent() );
|
|
|
|
Go( &CVPCB_CONTROL::SaveAssociationsToFile,CVPCB_ACTIONS::saveAssociationsToFile.MakeEvent() );
|
2019-07-18 21:47:01 +00:00
|
|
|
|
|
|
|
// Navigation actions
|
2019-08-08 21:10:37 +00:00
|
|
|
Go( &CVPCB_CONTROL::ToNA, CVPCB_ACTIONS::gotoNextNA.MakeEvent() );
|
|
|
|
Go( &CVPCB_CONTROL::ToNA, CVPCB_ACTIONS::gotoPreviousNA.MakeEvent() );
|
2019-07-18 21:47:01 +00:00
|
|
|
|
|
|
|
// Filter the footprints
|
2019-09-03 18:32:39 +00:00
|
|
|
Go( &CVPCB_CONTROL::ToggleFootprintFilter, CVPCB_ACTIONS::FilterFPbyFPFilters.MakeEvent() );
|
|
|
|
Go( &CVPCB_CONTROL::ToggleFootprintFilter, CVPCB_ACTIONS::FilterFPbyLibrary.MakeEvent() );
|
2019-07-18 21:47:01 +00:00
|
|
|
Go( &CVPCB_CONTROL::ToggleFootprintFilter, CVPCB_ACTIONS::filterFPbyPin.MakeEvent() );
|
|
|
|
}
|