mirror of
https://gitlab.com/kicad/code/kicad.git
synced 2025-09-14 02:03:12 +02:00
Using a boolean argument just leads to a lot of trailing booleans in the function calls and is not user friendly. Instead, introduce PostAction() to send an action that runs after the coroutine (equivalent to passing false or the default argument), and leave RunAction as the immediate execution function.
369 lines
11 KiB
C++
369 lines
11 KiB
C++
/*
|
|
* KiRouter - a push-and-(sometimes-)shove PCB router
|
|
*
|
|
* Copyright (C) 2013-2017 CERN
|
|
* Copyright (C) 2016-2022 KiCad Developers, see AUTHORS.txt for contributors.
|
|
* Author: Tomasz Wlostowski <tomasz.wlostowski@cern.ch>
|
|
*
|
|
* 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/>.
|
|
*/
|
|
|
|
#include <class_draw_panel_gal.h>
|
|
#include <dialogs/dialog_pns_length_tuning_settings.h>
|
|
#include <tool/tool_manager.h>
|
|
#include <tools/pcb_actions.h>
|
|
#include <tools/zone_filler_tool.h>
|
|
#include "pns_router.h"
|
|
#include "pns_meander_placer.h" // fixme: move settings to separate header
|
|
#include "pns_tune_status_popup.h"
|
|
|
|
#include "length_tuner_tool.h"
|
|
#include <bitmaps.h>
|
|
#include <tools/tool_event_utils.h>
|
|
|
|
using namespace KIGFX;
|
|
|
|
// Actions, being statically-defined, require specialized I18N handling. We continue to
|
|
// use the _() macro so that string harvesting by the I18N framework doesn't have to be
|
|
// specialized, but we don't translate on initialization and instead do it in the getters.
|
|
|
|
#undef _
|
|
#define _(s) s
|
|
|
|
static TOOL_ACTION ACT_StartTuning( "pcbnew.LengthTuner.StartTuning",
|
|
AS_CONTEXT,
|
|
'X', LEGACY_HK_NAME( "Add New Track" ),
|
|
_( "New Track" ), _( "Starts laying a new track." ) );
|
|
|
|
static TOOL_ACTION ACT_EndTuning( "pcbnew.LengthTuner.EndTuning",
|
|
AS_CONTEXT,
|
|
WXK_END, LEGACY_HK_NAME( "Stop laying the current track." ),
|
|
_( "End Track" ), _( "Stops laying the current meander." ) );
|
|
|
|
static TOOL_ACTION ACT_SpacingIncrease( "pcbnew.LengthTuner.SpacingIncrease",
|
|
AS_CONTEXT,
|
|
'1', LEGACY_HK_NAME( "Increase meander spacing by one step." ),
|
|
_( "Increase Spacing" ), _( "Increase meander spacing by one step." ),
|
|
BITMAPS::router_len_tuner_dist_incr );
|
|
|
|
static TOOL_ACTION ACT_SpacingDecrease( "pcbnew.LengthTuner.SpacingDecrease",
|
|
AS_CONTEXT,
|
|
'2', LEGACY_HK_NAME( "Decrease meander spacing by one step." ),
|
|
_( "Decrease Spacing" ), _( "Decrease meander spacing by one step." ),
|
|
BITMAPS::router_len_tuner_dist_decr );
|
|
|
|
static TOOL_ACTION ACT_AmplIncrease( "pcbnew.LengthTuner.AmplIncrease",
|
|
AS_CONTEXT,
|
|
'3', LEGACY_HK_NAME( "Increase meander amplitude by one step." ),
|
|
_( "Increase Amplitude" ), _( "Increase meander amplitude by one step." ),
|
|
BITMAPS::router_len_tuner_amplitude_incr );
|
|
|
|
static TOOL_ACTION ACT_AmplDecrease( "pcbnew.LengthTuner.AmplDecrease",
|
|
AS_CONTEXT,
|
|
'4', LEGACY_HK_NAME( "Decrease meander amplitude by one step." ),
|
|
_( "Decrease Amplitude" ), _( "Decrease meander amplitude by one step." ),
|
|
BITMAPS::router_len_tuner_amplitude_decr );
|
|
|
|
#undef _
|
|
#define _(s) wxGetTranslation((s))
|
|
|
|
|
|
LENGTH_TUNER_TOOL::LENGTH_TUNER_TOOL() :
|
|
TOOL_BASE( "pcbnew.LengthTuner" )
|
|
{
|
|
// set the initial tune mode for the settings dialog,
|
|
// in case the dialog is opened before the tool is activated the first time
|
|
m_lastTuneMode = PNS::ROUTER_MODE::PNS_MODE_TUNE_SINGLE;
|
|
}
|
|
|
|
|
|
LENGTH_TUNER_TOOL::~LENGTH_TUNER_TOOL()
|
|
{
|
|
}
|
|
|
|
|
|
bool LENGTH_TUNER_TOOL::Init()
|
|
{
|
|
auto& menu = m_menu.GetMenu();
|
|
|
|
menu.SetTitle( _( "Length Tuner" ) );
|
|
menu.SetIcon( BITMAPS::router_len_tuner );
|
|
menu.DisplayTitle( true );
|
|
|
|
menu.AddItem( ACTIONS::cancelInteractive, SELECTION_CONDITIONS::ShowAlways );
|
|
|
|
menu.AddSeparator();
|
|
|
|
menu.AddItem( ACT_SpacingIncrease, SELECTION_CONDITIONS::ShowAlways );
|
|
menu.AddItem( ACT_SpacingDecrease, SELECTION_CONDITIONS::ShowAlways );
|
|
menu.AddItem( ACT_AmplIncrease, SELECTION_CONDITIONS::ShowAlways );
|
|
menu.AddItem( ACT_AmplDecrease, SELECTION_CONDITIONS::ShowAlways );
|
|
menu.AddItem( PCB_ACTIONS::lengthTunerSettingsDialog, SELECTION_CONDITIONS::ShowAlways );
|
|
|
|
return true;
|
|
}
|
|
|
|
|
|
void LENGTH_TUNER_TOOL::Reset( RESET_REASON aReason )
|
|
{
|
|
if( aReason == RUN )
|
|
TOOL_BASE::Reset( aReason );
|
|
}
|
|
|
|
|
|
void LENGTH_TUNER_TOOL::updateStatusPopup( PNS_TUNE_STATUS_POPUP& aPopup )
|
|
{
|
|
// fixme: wx code not allowed inside tools!
|
|
wxPoint p = wxGetMousePosition();
|
|
|
|
p.x += 20;
|
|
p.y += 20;
|
|
|
|
aPopup.UpdateStatus( m_router );
|
|
aPopup.Move( p );
|
|
}
|
|
|
|
|
|
void LENGTH_TUNER_TOOL::performTuning()
|
|
{
|
|
if( m_startItem )
|
|
{
|
|
frame()->SetActiveLayer( ToLAYER_ID ( m_startItem->Layers().Start() ) );
|
|
|
|
if( m_startItem->Net() >= 0 )
|
|
highlightNets( true, { m_startItem->Net() } );
|
|
}
|
|
|
|
controls()->ForceCursorPosition( false );
|
|
controls()->SetAutoPan( true );
|
|
|
|
int layer = m_startItem ? m_startItem->Layer() : static_cast<int>( frame()->GetActiveLayer() );
|
|
|
|
if( !m_router->StartRouting( m_startSnapPoint, m_startItem, layer ) )
|
|
{
|
|
frame()->ShowInfoBarMsg( m_router->FailureReason() );
|
|
highlightNets( false );
|
|
return;
|
|
}
|
|
|
|
auto placer = static_cast<PNS::MEANDER_PLACER_BASE*>( m_router->Placer() );
|
|
|
|
placer->UpdateSettings( m_savedMeanderSettings );
|
|
frame()->UndoRedoBlock( true );
|
|
|
|
VECTOR2I end = getViewControls()->GetMousePosition();
|
|
|
|
// Create an instance of PNS_TUNE_STATUS_POPUP.
|
|
PNS_TUNE_STATUS_POPUP statusPopup( frame() );
|
|
statusPopup.Popup();
|
|
canvas()->SetStatusPopup( statusPopup.GetPanel() );
|
|
|
|
m_router->Move( end, nullptr );
|
|
updateStatusPopup( statusPopup );
|
|
|
|
auto setCursor =
|
|
[&]()
|
|
{
|
|
frame()->GetCanvas()->SetCurrentCursor( KICURSOR::ARROW );
|
|
};
|
|
|
|
// Set initial cursor
|
|
setCursor();
|
|
|
|
while( TOOL_EVENT* evt = Wait() )
|
|
{
|
|
setCursor();
|
|
|
|
if( evt->IsCancelInteractive() || evt->IsActivate() )
|
|
{
|
|
break;
|
|
}
|
|
else if( evt->IsMotion() )
|
|
{
|
|
end = evt->Position();
|
|
m_router->Move( end, nullptr );
|
|
updateStatusPopup( statusPopup );
|
|
}
|
|
else if( evt->IsClick( BUT_LEFT ) )
|
|
{
|
|
if( m_router->FixRoute( evt->Position(), nullptr ) )
|
|
break;
|
|
}
|
|
else if( evt->IsClick( BUT_RIGHT ) )
|
|
{
|
|
m_menu.ShowContextMenu( selection() );
|
|
}
|
|
else if( evt->IsAction( &ACT_EndTuning ) )
|
|
{
|
|
if( m_router->FixRoute( end, nullptr ) )
|
|
break;
|
|
}
|
|
else if( evt->IsAction( &ACT_AmplDecrease ) )
|
|
{
|
|
placer->AmplitudeStep( -1 );
|
|
m_router->Move( end, nullptr );
|
|
updateStatusPopup( statusPopup );
|
|
}
|
|
else if( evt->IsAction( &ACT_AmplIncrease ) )
|
|
{
|
|
placer->AmplitudeStep( 1 );
|
|
m_router->Move( end, nullptr );
|
|
updateStatusPopup( statusPopup );
|
|
}
|
|
else if(evt->IsAction( &ACT_SpacingDecrease ) )
|
|
{
|
|
placer->SpacingStep( -1 );
|
|
m_router->Move( end, nullptr );
|
|
updateStatusPopup( statusPopup );
|
|
}
|
|
else if( evt->IsAction( &ACT_SpacingIncrease ) )
|
|
{
|
|
placer->SpacingStep( 1 );
|
|
m_router->Move( end, nullptr );
|
|
updateStatusPopup( statusPopup );
|
|
}
|
|
else if( evt->IsAction( &PCB_ACTIONS::lengthTunerSettingsDialog ) )
|
|
{
|
|
statusPopup.Hide();
|
|
TOOL_EVENT dummy;
|
|
meanderSettingsDialog( dummy );
|
|
statusPopup.Show();
|
|
}
|
|
// TODO: It'd be nice to be able to say "don't allow any non-trivial editing actions",
|
|
// but we don't at present have that, so we just knock out some of the egregious ones.
|
|
else if( ZONE_FILLER_TOOL::IsZoneFillAction( evt ) )
|
|
{
|
|
wxBell();
|
|
}
|
|
else
|
|
{
|
|
evt->SetPassEvent();
|
|
}
|
|
}
|
|
|
|
m_router->StopRouting();
|
|
frame()->UndoRedoBlock( false );
|
|
|
|
canvas()->SetStatusPopup( nullptr );
|
|
controls()->SetAutoPan( false );
|
|
controls()->ForceCursorPosition( false );
|
|
frame()->GetCanvas()->SetCurrentCursor( KICURSOR::ARROW );
|
|
highlightNets( false );
|
|
}
|
|
|
|
|
|
void LENGTH_TUNER_TOOL::setTransitions()
|
|
{
|
|
Go( &LENGTH_TUNER_TOOL::MainLoop, PCB_ACTIONS::routerTuneSingleTrace.MakeEvent() );
|
|
Go( &LENGTH_TUNER_TOOL::MainLoop, PCB_ACTIONS::routerTuneDiffPair.MakeEvent() );
|
|
Go( &LENGTH_TUNER_TOOL::MainLoop,
|
|
PCB_ACTIONS::routerTuneDiffPairSkew.MakeEvent() );
|
|
|
|
// in case tool is inactive, otherwise the event is handled in the tool loop
|
|
Go( &LENGTH_TUNER_TOOL::meanderSettingsDialog,
|
|
PCB_ACTIONS::lengthTunerSettingsDialog.MakeEvent() );
|
|
}
|
|
|
|
|
|
int LENGTH_TUNER_TOOL::MainLoop( const TOOL_EVENT& aEvent )
|
|
{
|
|
// Deselect all items
|
|
m_toolMgr->RunAction( PCB_ACTIONS::selectionClear );
|
|
|
|
frame()->PushTool( aEvent );
|
|
|
|
auto setCursor =
|
|
[&]()
|
|
{
|
|
frame()->GetCanvas()->SetCurrentCursor( KICURSOR::ARROW );
|
|
};
|
|
|
|
Activate();
|
|
// Must be done after Activate() so that it gets set into the correct context
|
|
controls()->ShowCursor( true );
|
|
// Set initial cursor
|
|
setCursor();
|
|
|
|
// Router mode must be set after Activate()
|
|
m_lastTuneMode = aEvent.Parameter<PNS::ROUTER_MODE>();
|
|
m_router->SetMode( m_lastTuneMode );
|
|
|
|
// Main loop: keep receiving events
|
|
while( TOOL_EVENT* evt = Wait() )
|
|
{
|
|
setCursor();
|
|
|
|
if( evt->IsCancelInteractive() || evt->IsActivate() )
|
|
{
|
|
break; // Finish
|
|
}
|
|
else if( evt->Action() == TA_UNDO_REDO_PRE )
|
|
{
|
|
m_router->ClearWorld();
|
|
}
|
|
else if( evt->Action() == TA_UNDO_REDO_POST || evt->Action() == TA_MODEL_CHANGE )
|
|
{
|
|
m_router->SyncWorld();
|
|
}
|
|
else if( evt->IsMotion() )
|
|
{
|
|
updateStartItem( *evt );
|
|
}
|
|
else if( evt->IsClick( BUT_LEFT ) || evt->IsAction( &ACT_StartTuning ) )
|
|
{
|
|
updateStartItem( *evt );
|
|
performTuning();
|
|
}
|
|
else if( evt->IsAction( &PCB_ACTIONS::lengthTunerSettingsDialog ) )
|
|
{
|
|
TOOL_EVENT dummy;
|
|
meanderSettingsDialog( dummy );
|
|
}
|
|
else if( evt->IsClick( BUT_RIGHT ) )
|
|
{
|
|
m_menu.ShowContextMenu( selection() );
|
|
}
|
|
else
|
|
{
|
|
evt->SetPassEvent();
|
|
}
|
|
}
|
|
|
|
// Store routing settings till the next invocation
|
|
m_savedSizes = m_router->Sizes();
|
|
|
|
frame()->GetCanvas()->SetCurrentCursor( KICURSOR::ARROW );
|
|
frame()->PopTool( aEvent );
|
|
return 0;
|
|
}
|
|
|
|
|
|
int LENGTH_TUNER_TOOL::meanderSettingsDialog( const TOOL_EVENT& aEvent )
|
|
{
|
|
PNS::MEANDER_PLACER_BASE* placer = static_cast<PNS::MEANDER_PLACER_BASE*>( m_router->Placer() );
|
|
|
|
PNS::MEANDER_SETTINGS settings = placer ? placer->MeanderSettings() : m_savedMeanderSettings;
|
|
DIALOG_PNS_LENGTH_TUNING_SETTINGS settingsDlg( frame(), settings, m_lastTuneMode );
|
|
|
|
if( settingsDlg.ShowModal() == wxID_OK )
|
|
{
|
|
if( placer )
|
|
placer->UpdateSettings( settings );
|
|
|
|
m_savedMeanderSettings = settings;
|
|
}
|
|
|
|
return 0;
|
|
}
|