mirror of
https://gitlab.com/kicad/code/kicad.git
synced 2025-09-13 17:53:11 +02:00
ADDED: Optional flashing with cross-probing
Sometimes it is hard to find an element especially if we do not zoom to the part. The flash should help draw your eye to the relevant part Fixes https://gitlab.com/kicad/code/kicad/-/issues/19842
This commit is contained in:
parent
f66cbaf43a
commit
0c35068e8d
@ -280,6 +280,9 @@ APP_SETTINGS_BASE::APP_SETTINGS_BASE( const std::string& aFilename, int aSchemaV
|
||||
|
||||
m_params.emplace_back( new PARAM<bool>( "cross_probing.auto_highlight",
|
||||
&m_CrossProbing.auto_highlight, true ) );
|
||||
|
||||
m_params.emplace_back( new PARAM<bool>( "cross_probing.flash_selection",
|
||||
&m_CrossProbing.flash_selection, false ) );
|
||||
}
|
||||
|
||||
|
||||
|
@ -931,6 +931,26 @@ void SCH_EDIT_FRAME::KiwayMailIn( KIWAY_EXPRESS& mail )
|
||||
items );
|
||||
|
||||
m_syncingPcbToSchSelection = false;
|
||||
|
||||
if( eeconfig()->m_CrossProbing.flash_selection )
|
||||
{
|
||||
wxLogTrace( "CROSS_PROBE_FLASH", "MAIL_SELECTION(_FORCE): flash enabled, items=%zu", items.size() );
|
||||
if( items.empty() )
|
||||
{
|
||||
wxLogTrace( "CROSS_PROBE_FLASH", "MAIL_SELECTION(_FORCE): nothing to flash" );
|
||||
}
|
||||
else
|
||||
{
|
||||
std::vector<SCH_ITEM*> itemPtrs;
|
||||
std::copy( items.begin(), items.end(), std::back_inserter( itemPtrs ) );
|
||||
|
||||
StartCrossProbeFlash( itemPtrs );
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
wxLogTrace( "CROSS_PROBE_FLASH", "MAIL_SELECTION(_FORCE): flash disabled" );
|
||||
}
|
||||
}
|
||||
|
||||
break;
|
||||
|
@ -75,6 +75,7 @@ void PANEL_EESCHEMA_DISPLAY_OPTIONS::loadEEschemaSettings( EESCHEMA_SETTINGS* cf
|
||||
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 );
|
||||
m_checkCrossProbeFlash->SetValue( cfg->m_CrossProbing.flash_selection );
|
||||
}
|
||||
|
||||
|
||||
@ -117,6 +118,7 @@ bool PANEL_EESCHEMA_DISPLAY_OPTIONS::TransferDataFromWindow()
|
||||
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.flash_selection = m_checkCrossProbeFlash->GetValue();
|
||||
}
|
||||
|
||||
m_galOptsPanel->TransferDataFromWindow();
|
||||
|
@ -62,6 +62,10 @@ PANEL_EESCHEMA_DISPLAY_OPTIONS_BASE::PANEL_EESCHEMA_DISPLAY_OPTIONS_BASE( wxWind
|
||||
|
||||
bCrossProbingSizer->Add( m_checkCrossProbeAutoHighlight, 0, wxBOTTOM|wxRIGHT|wxLEFT, 5 );
|
||||
|
||||
m_checkCrossProbeFlash = new wxCheckBox( this, wxID_ANY, _("Flash cross-probed selection"), wxDefaultPosition, wxDefaultSize, 0 );
|
||||
m_checkCrossProbeFlash->SetToolTip( _("Temporarily flash the newly cross-probed selection 3 times") );
|
||||
bCrossProbingSizer->Add( m_checkCrossProbeFlash, 0, wxBOTTOM|wxRIGHT|wxLEFT, 5 );
|
||||
|
||||
|
||||
bSizer8->Add( bCrossProbingSizer, 0, wxEXPAND|wxTOP|wxLEFT, 5 );
|
||||
|
||||
|
@ -293,6 +293,71 @@
|
||||
<property name="window_name"></property>
|
||||
<property name="window_style"></property>
|
||||
</object>
|
||||
<object class="sizeritem" expanded="false">
|
||||
<property name="border">5</property>
|
||||
<property name="flag">wxBOTTOM|wxRIGHT|wxLEFT</property>
|
||||
<property name="proportion">0</property>
|
||||
<object class="wxCheckBox" expanded="false">
|
||||
<property name="BottomDockable">1</property>
|
||||
<property name="LeftDockable">1</property>
|
||||
<property name="RightDockable">1</property>
|
||||
<property name="TopDockable">1</property>
|
||||
<property name="aui_layer">0</property>
|
||||
<property name="aui_name"></property>
|
||||
<property name="aui_position">0</property>
|
||||
<property name="aui_row">0</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="drag_accept_files">0</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">Flash cross-probed 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_checkCrossProbeFlash</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">Temporarily flash the newly cross-probed selection 3 times</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>
|
||||
<object class="sizeritem" expanded="false">
|
||||
<property name="border">5</property>
|
||||
|
@ -44,6 +44,7 @@ class PANEL_EESCHEMA_DISPLAY_OPTIONS_BASE : public RESETTABLE_PANEL
|
||||
wxCheckBox* m_checkCrossProbeCenter;
|
||||
wxCheckBox* m_checkCrossProbeZoom;
|
||||
wxCheckBox* m_checkCrossProbeAutoHighlight;
|
||||
wxCheckBox* m_checkCrossProbeFlash;
|
||||
wxStaticText* m_appearanceLabel;
|
||||
wxStaticLine* m_staticline1;
|
||||
wxStaticText* m_defaultFontLabel;
|
||||
|
@ -104,6 +104,7 @@
|
||||
#include <drawing_sheet/ds_proxy_view_item.h>
|
||||
#include <project/project_local_settings.h>
|
||||
#include <toolbars_sch_editor.h>
|
||||
#include <wx/log.h>
|
||||
|
||||
#ifdef KICAD_IPC_API
|
||||
#include <api/api_plugin_manager.h>
|
||||
@ -157,6 +158,9 @@ SCH_EDIT_FRAME::SCH_EDIT_FRAME( KIWAY* aKiway, wxWindow* aParent ) :
|
||||
m_syncingPcbToSchSelection = false;
|
||||
m_aboutTitle = _HKI( "KiCad Schematic Editor" );
|
||||
m_show_search = false;
|
||||
// Ensure timer has an owner before binding so it generates events.
|
||||
m_crossProbeFlashTimer.SetOwner( this );
|
||||
Bind( wxEVT_TIMER, &SCH_EDIT_FRAME::OnCrossProbeFlashTimer, this, m_crossProbeFlashTimer.GetId() );
|
||||
|
||||
// Give an icon
|
||||
wxIcon icon;
|
||||
@ -434,6 +438,95 @@ SCH_EDIT_FRAME::SCH_EDIT_FRAME( KIWAY* aKiway, wxWindow* aParent ) :
|
||||
Bind( EDA_EVT_CLOSE_DIALOG_SYMBOL_FIELDS_TABLE, &SCH_EDIT_FRAME::onCloseSymbolFieldsTableDialog, this );
|
||||
}
|
||||
|
||||
void SCH_EDIT_FRAME::StartCrossProbeFlash( const std::vector<SCH_ITEM*>& aItems )
|
||||
{
|
||||
if( !eeconfig()->m_CrossProbing.flash_selection )
|
||||
{
|
||||
wxLogTrace( "CROSS_PROBE_FLASH", "StartCrossProbeFlash: aborted (setting disabled) items=%zu", aItems.size() );
|
||||
return;
|
||||
}
|
||||
if( aItems.empty() )
|
||||
{
|
||||
wxLogTrace( "CROSS_PROBE_FLASH", "StartCrossProbeFlash: aborted (no items)" );
|
||||
return;
|
||||
}
|
||||
|
||||
if( m_crossProbeFlashing )
|
||||
{
|
||||
wxLogTrace( "CROSS_PROBE_FLASH", "StartCrossProbeFlash: restarting existing flash (phase=%d)", m_crossProbeFlashPhase );
|
||||
m_crossProbeFlashTimer.Stop();
|
||||
}
|
||||
|
||||
wxLogTrace( "CROSS_PROBE_FLASH", "StartCrossProbeFlash: starting with %zu items", aItems.size() );
|
||||
m_crossProbeFlashItems.clear();
|
||||
for( SCH_ITEM* it : aItems )
|
||||
m_crossProbeFlashItems.push_back( it->m_Uuid );
|
||||
|
||||
m_crossProbeFlashPhase = 0;
|
||||
m_crossProbeFlashing = true;
|
||||
if( !m_crossProbeFlashTimer.GetOwner() )
|
||||
m_crossProbeFlashTimer.SetOwner( this );
|
||||
|
||||
bool started = m_crossProbeFlashTimer.Start( 500, wxTIMER_CONTINUOUS );
|
||||
wxLogTrace( "CROSS_PROBE_FLASH", "StartCrossProbeFlash: timer start=%d id=%d", (int) started, m_crossProbeFlashTimer.GetId() );
|
||||
}
|
||||
|
||||
|
||||
void SCH_EDIT_FRAME::OnCrossProbeFlashTimer( wxTimerEvent& aEvent )
|
||||
{
|
||||
wxLogTrace( "CROSS_PROBE_FLASH", "Timer(SCH) fired: phase=%d running=%d items=%zu", m_crossProbeFlashPhase, (int) m_crossProbeFlashing, m_crossProbeFlashItems.size() );
|
||||
|
||||
if( !m_crossProbeFlashing )
|
||||
{
|
||||
wxLogTrace( "CROSS_PROBE_FLASH", "Timer fired but not flashing (ignored)" );
|
||||
return;
|
||||
}
|
||||
|
||||
SCH_SELECTION_TOOL* selTool = GetToolManager()->GetTool<SCH_SELECTION_TOOL>();
|
||||
if( !selTool )
|
||||
return;
|
||||
|
||||
bool prevGuard = m_syncingPcbToSchSelection;
|
||||
m_syncingPcbToSchSelection = true;
|
||||
|
||||
if( m_crossProbeFlashPhase % 2 == 0 )
|
||||
{
|
||||
selTool->ClearSelection( true );
|
||||
wxLogTrace( "CROSS_PROBE_FLASH", "Phase %d: cleared selection", m_crossProbeFlashPhase );
|
||||
}
|
||||
else
|
||||
{
|
||||
for( const KIID& id : m_crossProbeFlashItems )
|
||||
{
|
||||
if( SCH_ITEM* item = Schematic().ResolveItem( id, nullptr, true ) )
|
||||
selTool->AddItemToSel( item, true );
|
||||
}
|
||||
wxLogTrace( "CROSS_PROBE_FLASH", "Phase %d: restored %zu items", m_crossProbeFlashPhase, m_crossProbeFlashItems.size() );
|
||||
}
|
||||
|
||||
if( GetCanvas() )
|
||||
{
|
||||
GetCanvas()->ForceRefresh();
|
||||
wxLogTrace( "CROSS_PROBE_FLASH", "Phase %d: forced canvas refresh", m_crossProbeFlashPhase );
|
||||
}
|
||||
|
||||
m_syncingPcbToSchSelection = prevGuard;
|
||||
m_crossProbeFlashPhase++;
|
||||
|
||||
if( m_crossProbeFlashPhase > 6 )
|
||||
{
|
||||
for( const KIID& id : m_crossProbeFlashItems )
|
||||
{
|
||||
if( SCH_ITEM* item = Schematic().ResolveItem( id, nullptr, true ) )
|
||||
selTool->AddItemToSel( item, true );
|
||||
}
|
||||
|
||||
m_crossProbeFlashing = false;
|
||||
m_crossProbeFlashTimer.Stop();
|
||||
wxLogTrace( "CROSS_PROBE_FLASH", "Flashing complete. Final selection size=%zu", m_crossProbeFlashItems.size() );
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
SCH_EDIT_FRAME::~SCH_EDIT_FRAME()
|
||||
{
|
||||
|
@ -989,6 +989,9 @@ private:
|
||||
|
||||
void CaptureHierarchyPaneSize();
|
||||
|
||||
void StartCrossProbeFlash( const std::vector<SCH_ITEM*>& aItems );
|
||||
void OnCrossProbeFlashTimer( wxTimerEvent& aEvent );
|
||||
|
||||
private:
|
||||
// The schematic editor control class should be able to access some internal
|
||||
// functions of the editor frame.
|
||||
@ -1015,6 +1018,11 @@ private:
|
||||
wxTreeCtrl* m_netNavigator;
|
||||
|
||||
bool m_syncingPcbToSchSelection; // Recursion guard when synchronizing selection from PCB
|
||||
// Cross-probe flashing support
|
||||
wxTimer m_crossProbeFlashTimer; ///< Timer to toggle selection visibility
|
||||
int m_crossProbeFlashPhase = 0;
|
||||
std::vector<KIID> m_crossProbeFlashItems; ///< Items to flash
|
||||
bool m_crossProbeFlashing = false;
|
||||
bool m_show_search;
|
||||
bool m_highlightedConnChanged;
|
||||
|
||||
|
@ -34,6 +34,7 @@ struct KICOMMON_API CROSS_PROBING_SETTINGS
|
||||
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.
|
||||
bool flash_selection; ///< Flash newly cross-probed selection (visual attention aid).
|
||||
};
|
||||
|
||||
namespace KIGFX
|
||||
|
@ -645,6 +645,25 @@ void PCB_EDIT_FRAME::KiwayMailIn( KIWAY_EXPRESS& mail )
|
||||
Update3DView( false, GetPcbNewSettings()->m_Display.m_Live3DRefresh );
|
||||
|
||||
m_probingSchToPcb = false;
|
||||
|
||||
if( GetPcbNewSettings()->m_CrossProbing.flash_selection )
|
||||
{
|
||||
wxLogTrace( "CROSS_PROBE_FLASH", "MAIL_SELECTION(_FORCE) PCB: flash enabled, items=%zu", items.size() );
|
||||
if( items.empty() )
|
||||
{
|
||||
wxLogTrace( "CROSS_PROBE_FLASH", "MAIL_SELECTION(_FORCE) PCB: nothing to flash" );
|
||||
}
|
||||
else
|
||||
{
|
||||
std::vector<BOARD_ITEM*> boardItems;
|
||||
std::copy( items.begin(), items.end(), std::back_inserter( boardItems ) );
|
||||
StartCrossProbeFlash( boardItems );
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
wxLogTrace( "CROSS_PROBE_FLASH", "MAIL_SELECTION(_FORCE) PCB: flash disabled" );
|
||||
}
|
||||
}
|
||||
|
||||
break;
|
||||
|
@ -222,6 +222,7 @@ void PANEL_DISPLAY_OPTIONS::loadPCBSettings( PCBNEW_SETTINGS* aCfg )
|
||||
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 );
|
||||
m_checkCrossProbeFlash->SetValue( aCfg->m_CrossProbing.flash_selection );
|
||||
}
|
||||
|
||||
|
||||
@ -353,6 +354,7 @@ bool PANEL_DISPLAY_OPTIONS::TransferDataFromWindow()
|
||||
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.flash_selection = m_checkCrossProbeFlash->GetValue();
|
||||
}
|
||||
}
|
||||
else
|
||||
|
@ -244,6 +244,10 @@ PANEL_DISPLAY_OPTIONS_BASE::PANEL_DISPLAY_OPTIONS_BASE( wxWindow* parent, wxWind
|
||||
|
||||
bSizer8->Add( m_checkCrossProbeAutoHighlight, 0, wxBOTTOM|wxRIGHT|wxLEFT, 5 );
|
||||
|
||||
m_checkCrossProbeFlash = new wxCheckBox( pcbPage, wxID_ANY, _("Flash cross-probed selection"), wxDefaultPosition, wxDefaultSize, 0 );
|
||||
m_checkCrossProbeFlash->SetToolTip( _("Temporarily flash the newly cross-probed selection 3 times") );
|
||||
bSizer8->Add( m_checkCrossProbeFlash, 0, wxBOTTOM|wxRIGHT|wxLEFT, 5 );
|
||||
|
||||
m_live3Drefresh = new wxCheckBox( pcbPage, wxID_ANY, _("Refresh 3D view automatically"), wxDefaultPosition, wxDefaultSize, 0 );
|
||||
m_live3Drefresh->SetToolTip( _("When enabled, edits to the board will cause the 3D view to refresh (may be slow with larger boards)") );
|
||||
|
||||
|
@ -2135,6 +2135,71 @@
|
||||
<property name="window_style"></property>
|
||||
</object>
|
||||
</object>
|
||||
<object class="sizeritem" expanded="false">
|
||||
<property name="border">5</property>
|
||||
<property name="flag">wxBOTTOM|wxLEFT|wxRIGHT</property>
|
||||
<property name="proportion">0</property>
|
||||
<object class="wxCheckBox" expanded="false">
|
||||
<property name="BottomDockable">1</property>
|
||||
<property name="LeftDockable">1</property>
|
||||
<property name="RightDockable">1</property>
|
||||
<property name="TopDockable">1</property>
|
||||
<property name="aui_layer">0</property>
|
||||
<property name="aui_name"></property>
|
||||
<property name="aui_position">0</property>
|
||||
<property name="aui_row">0</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="drag_accept_files">0</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">Flash cross-probed 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_checkCrossProbeFlash</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">Temporarily flash the newly cross-probed selection 3 times</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="false">
|
||||
<property name="border">5</property>
|
||||
<property name="flag">wxBOTTOM|wxLEFT|wxRIGHT</property>
|
||||
|
@ -72,6 +72,7 @@ class PANEL_DISPLAY_OPTIONS_BASE : public RESETTABLE_PANEL
|
||||
wxCheckBox* m_checkCrossProbeCenter;
|
||||
wxCheckBox* m_checkCrossProbeZoom;
|
||||
wxCheckBox* m_checkCrossProbeAutoHighlight;
|
||||
wxCheckBox* m_checkCrossProbeFlash;
|
||||
wxCheckBox* m_live3Drefresh;
|
||||
|
||||
// Virtual event handlers, override them in your derived class
|
||||
|
@ -115,6 +115,7 @@
|
||||
#include <footprint_viewer_frame.h>
|
||||
#include <footprint_chooser_frame.h>
|
||||
#include <toolbars_pcb_editor.h>
|
||||
#include <wx/log.h>
|
||||
|
||||
#ifdef KICAD_IPC_API
|
||||
#include <api/api_server.h>
|
||||
@ -198,6 +199,9 @@ PCB_EDIT_FRAME::PCB_EDIT_FRAME( KIWAY* aKiway, wxWindow* aParent ) :
|
||||
m_probingSchToPcb = false;
|
||||
m_show_search = false;
|
||||
m_show_net_inspector = false;
|
||||
// Ensure timer has an owner before binding so it generates events.
|
||||
m_crossProbeFlashTimer.SetOwner( this );
|
||||
Bind( wxEVT_TIMER, &PCB_EDIT_FRAME::OnCrossProbeFlashTimer, this, m_crossProbeFlashTimer.GetId() );
|
||||
|
||||
// We don't know what state board was in when it was last saved, so we have to
|
||||
// assume dirty
|
||||
@ -569,6 +573,100 @@ PCB_EDIT_FRAME::PCB_EDIT_FRAME( KIWAY* aKiway, wxWindow* aParent ) :
|
||||
Bind( EDA_EVT_CLOSE_DIALOG_BOOK_REPORTER, &PCB_EDIT_FRAME::onCloseModelessBookReporterDialogs, this );
|
||||
}
|
||||
|
||||
void PCB_EDIT_FRAME::StartCrossProbeFlash( const std::vector<BOARD_ITEM*>& aItems )
|
||||
{
|
||||
if( !GetPcbNewSettings()->m_CrossProbing.flash_selection )
|
||||
{
|
||||
wxLogTrace( "CROSS_PROBE_FLASH", "StartCrossProbeFlash(PCB): aborted (setting disabled) items=%zu", aItems.size() );
|
||||
return;
|
||||
}
|
||||
|
||||
if( aItems.empty() )
|
||||
{
|
||||
wxLogTrace( "CROSS_PROBE_FLASH", "StartCrossProbeFlash(PCB): aborted (no items)" );
|
||||
return;
|
||||
}
|
||||
|
||||
if( m_crossProbeFlashing )
|
||||
{
|
||||
wxLogTrace( "CROSS_PROBE_FLASH", "StartCrossProbeFlash(PCB): restarting existing flash (phase=%d)" , m_crossProbeFlashPhase );
|
||||
m_crossProbeFlashTimer.Stop();
|
||||
}
|
||||
|
||||
wxLogTrace( "CROSS_PROBE_FLASH", "StartCrossProbeFlash(PCB): starting with %zu items", aItems.size() );
|
||||
// Store uuids
|
||||
m_crossProbeFlashItems.clear();
|
||||
for( BOARD_ITEM* it : aItems )
|
||||
m_crossProbeFlashItems.push_back( it->m_Uuid );
|
||||
|
||||
m_crossProbeFlashPhase = 0;
|
||||
m_crossProbeFlashing = true;
|
||||
if( !m_crossProbeFlashTimer.GetOwner() )
|
||||
m_crossProbeFlashTimer.SetOwner( this );
|
||||
|
||||
bool started = m_crossProbeFlashTimer.Start( 500, wxTIMER_CONTINUOUS ); // 0.5s intervals -> 3s total for 6 phases
|
||||
wxLogTrace( "CROSS_PROBE_FLASH", "StartCrossProbeFlash(PCB): timer start=%d id=%d", (int) started, m_crossProbeFlashTimer.GetId() );
|
||||
}
|
||||
|
||||
void PCB_EDIT_FRAME::OnCrossProbeFlashTimer( wxTimerEvent& aEvent )
|
||||
{
|
||||
wxLogTrace( "CROSS_PROBE_FLASH", "Timer(PCB) fired: phase=%d running=%d items=%zu", m_crossProbeFlashPhase, (int) m_crossProbeFlashing, m_crossProbeFlashItems.size() );
|
||||
|
||||
if( !m_crossProbeFlashing )
|
||||
{
|
||||
wxLogTrace( "CROSS_PROBE_FLASH", "Timer(PCB) fired but not flashing (ignored)" );
|
||||
return;
|
||||
}
|
||||
|
||||
PCB_SELECTION_TOOL* selTool = GetToolManager()->GetTool<PCB_SELECTION_TOOL>();
|
||||
if( !selTool )
|
||||
return;
|
||||
|
||||
// Prevent recursion / IPC during flashing
|
||||
bool prevGuard = m_probingSchToPcb;
|
||||
m_probingSchToPcb = true;
|
||||
|
||||
if( m_crossProbeFlashPhase % 2 == 0 )
|
||||
{
|
||||
// Hide selection
|
||||
selTool->ClearSelection( true );
|
||||
wxLogTrace( "CROSS_PROBE_FLASH", "Phase %d (PCB): cleared selection", m_crossProbeFlashPhase );
|
||||
}
|
||||
else
|
||||
{
|
||||
// Restore selection
|
||||
for( const KIID& id : m_crossProbeFlashItems )
|
||||
{
|
||||
if( EDA_ITEM* item = GetBoard()->ResolveItem( id, true ) )
|
||||
selTool->AddItemToSel( item, true );
|
||||
}
|
||||
wxLogTrace( "CROSS_PROBE_FLASH", "Phase %d (PCB): restored %zu items", m_crossProbeFlashPhase, m_crossProbeFlashItems.size() );
|
||||
}
|
||||
|
||||
// Force a redraw even if the canvas / frame does not currently have focus (mouse elsewhere)
|
||||
if( GetCanvas() )
|
||||
{
|
||||
GetCanvas()->ForceRefresh();
|
||||
wxLogTrace( "CROSS_PROBE_FLASH", "Phase %d (PCB): forced canvas refresh", m_crossProbeFlashPhase );
|
||||
}
|
||||
|
||||
m_probingSchToPcb = prevGuard;
|
||||
|
||||
m_crossProbeFlashPhase++;
|
||||
if( m_crossProbeFlashPhase > 6 )
|
||||
{
|
||||
// Ensure final state (selected)
|
||||
for( const KIID& id : m_crossProbeFlashItems )
|
||||
{
|
||||
if( EDA_ITEM* item = GetBoard()->ResolveItem( id, true ) )
|
||||
selTool->AddItemToSel( item, true );
|
||||
}
|
||||
m_crossProbeFlashing = false;
|
||||
m_crossProbeFlashTimer.Stop();
|
||||
wxLogTrace( "CROSS_PROBE_FLASH", "Flashing complete (PCB). Final selection size=%zu", m_crossProbeFlashItems.size() );
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
PCB_EDIT_FRAME::~PCB_EDIT_FRAME()
|
||||
{
|
||||
|
@ -823,6 +823,15 @@ public:
|
||||
|
||||
bool m_probingSchToPcb; // Recursion guard when synchronizing selection from schematic
|
||||
|
||||
// Cross-probe flashing support
|
||||
wxTimer m_crossProbeFlashTimer; ///< Timer to toggle selection visibility for flash
|
||||
int m_crossProbeFlashPhase = 0; ///< Phase counter
|
||||
std::vector<KIID> m_crossProbeFlashItems; ///< Items to flash (by UUID)
|
||||
bool m_crossProbeFlashing = false; ///< Currently flashing guard
|
||||
|
||||
void StartCrossProbeFlash( const std::vector<BOARD_ITEM*>& aItems );
|
||||
void OnCrossProbeFlashTimer( wxTimerEvent& aEvent );
|
||||
|
||||
private:
|
||||
friend struct PCB::IFACE;
|
||||
friend class APPEARANCE_CONTROLS;
|
||||
|
Loading…
x
Reference in New Issue
Block a user