From c940a4593754f1df94715db4b5910e112ad25c1a Mon Sep 17 00:00:00 2001 From: Mark Roszko Date: Thu, 1 Oct 2020 23:53:47 +0000 Subject: [PATCH] ADDED: Autostart wires in eeschema Allows wires to be automatically started by clicking over a connection point --- eeschema/dialogs/panel_eeschema_settings.cpp | 4 + .../dialogs/panel_eeschema_settings_base.cpp | 5 +- .../dialogs/panel_eeschema_settings_base.fbp | 66 +++++- .../dialogs/panel_eeschema_settings_base.h | 1 + eeschema/ee_collectors.cpp | 12 ++ eeschema/ee_collectors.h | 1 + eeschema/eeschema_settings.cpp | 3 + eeschema/eeschema_settings.h | 1 + eeschema/sch_item.h | 5 + eeschema/sch_junction.h | 2 + eeschema/sch_line.h | 6 + eeschema/sch_pin.h | 2 + eeschema/sch_sheet.h | 2 + eeschema/sch_text.h | 6 + eeschema/tools/ee_actions.cpp | 15 +- eeschema/tools/ee_selection_tool.cpp | 193 ++++++++++++++---- eeschema/tools/ee_selection_tool.h | 42 +++- eeschema/tools/sch_line_wire_bus_tool.cpp | 30 ++- eeschema/tools/sch_line_wire_bus_tool.h | 8 +- 19 files changed, 341 insertions(+), 63 deletions(-) diff --git a/eeschema/dialogs/panel_eeschema_settings.cpp b/eeschema/dialogs/panel_eeschema_settings.cpp index d29af18f02..726ffd20df 100644 --- a/eeschema/dialogs/panel_eeschema_settings.cpp +++ b/eeschema/dialogs/panel_eeschema_settings.cpp @@ -70,6 +70,8 @@ bool PANEL_EESCHEMA_SETTINGS::TransferDataToWindow() m_mouseDragIsDrag->SetValue( !cfg->m_Input.drag_is_move ); m_cbPinSelectionOpt->SetValue( cfg->m_Selection.select_pin_selects_symbol ); + m_cbAutoStartWires->SetValue( cfg->m_Drawing.auto_start_wires ); + return true; } @@ -99,6 +101,8 @@ bool PANEL_EESCHEMA_SETTINGS::TransferDataFromWindow() cfg->m_Input.drag_is_move = !m_mouseDragIsDrag->GetValue(); cfg->m_Selection.select_pin_selects_symbol = m_cbPinSelectionOpt->GetValue(); + cfg->m_Drawing.auto_start_wires = m_cbAutoStartWires->GetValue(); + m_frame->SaveProjectSettings(); return true; diff --git a/eeschema/dialogs/panel_eeschema_settings_base.cpp b/eeschema/dialogs/panel_eeschema_settings_base.cpp index 976fc6c904..7ea2a26635 100644 --- a/eeschema/dialogs/panel_eeschema_settings_base.cpp +++ b/eeschema/dialogs/panel_eeschema_settings_base.cpp @@ -47,7 +47,10 @@ PANEL_EESCHEMA_SETTINGS_BASE::PANEL_EESCHEMA_SETTINGS_BASE( wxWindow* parent, wx m_mouseDragIsDrag = new wxCheckBox( sbSizerEditOpt->GetStaticBox(), wxID_ANY, _("Mouse drag performs drag (G) operation"), wxDefaultPosition, wxDefaultSize, 0 ); m_mouseDragIsDrag->SetToolTip( _("If unchecked, mouse drag will perform move (M) operation") ); - sbSizerEditOpt->Add( m_mouseDragIsDrag, 0, wxALL, 5 ); + sbSizerEditOpt->Add( m_mouseDragIsDrag, 0, wxLEFT|wxRIGHT|wxTOP, 5 ); + + m_cbAutoStartWires = new wxCheckBox( sbSizerEditOpt->GetStaticBox(), wxID_ANY, _("Automatically start wires on junctions and unused anchors"), wxDefaultPosition, wxDefaultSize, 0 ); + sbSizerEditOpt->Add( m_cbAutoStartWires, 0, wxALL, 5 ); bLeftColumn->Add( sbSizerEditOpt, 0, wxEXPAND|wxTOP|wxBOTTOM, 5 ); diff --git a/eeschema/dialogs/panel_eeschema_settings_base.fbp b/eeschema/dialogs/panel_eeschema_settings_base.fbp index 885d26ba74..ca1dde5498 100644 --- a/eeschema/dialogs/panel_eeschema_settings_base.fbp +++ b/eeschema/dialogs/panel_eeschema_settings_base.fbp @@ -281,7 +281,7 @@ 5 - wxALL + wxLEFT|wxRIGHT|wxTOP 0 1 @@ -343,6 +343,70 @@ + + 5 + wxALL + 0 + + 1 + 1 + 1 + 1 + + + + + + + + 1 + 0 + 0 + 1 + + 1 + 0 + Dock + 0 + Left + 1 + + 1 + + 0 + 0 + wxID_ANY + Automatically start wires on junctions and unused anchors + + 0 + + + 0 + + 1 + m_cbAutoStartWires + 1 + + + protected + 1 + + Resizable + 1 + + + ; ; Not forward_declare + 0 + + + wxFILTER_NONE + wxDefaultValidator + + + + + + diff --git a/eeschema/dialogs/panel_eeschema_settings_base.h b/eeschema/dialogs/panel_eeschema_settings_base.h index 9d758d3054..6b978e6204 100644 --- a/eeschema/dialogs/panel_eeschema_settings_base.h +++ b/eeschema/dialogs/panel_eeschema_settings_base.h @@ -44,6 +44,7 @@ class PANEL_EESCHEMA_SETTINGS_BASE : public wxPanel wxChoice* m_choiceUnits; wxCheckBox* m_checkHVOrientation; wxCheckBox* m_mouseDragIsDrag; + wxCheckBox* m_cbAutoStartWires; wxStaticText* m_borderColorLabel; COLOR_SWATCH* m_borderColorSwatch; wxStaticText* m_backgroundColorLabel; diff --git a/eeschema/ee_collectors.cpp b/eeschema/ee_collectors.cpp index 9e6b84f0a3..66f9afc025 100644 --- a/eeschema/ee_collectors.cpp +++ b/eeschema/ee_collectors.cpp @@ -59,6 +59,18 @@ const KICAD_T EE_COLLECTOR::EditableItems[] = { }; +const KICAD_T EE_COLLECTOR::AnchorableItems[] = { + SCH_PIN_T, + SCH_LABEL_T, + SCH_GLOBAL_LABEL_T, + SCH_HIER_LABEL_T, + SCH_SHEET_PIN_T, + SCH_JUNCTION_T, + SCH_LINE_T, + EOT +}; + + const KICAD_T EE_COLLECTOR::ComponentsOnly[] = { SCH_COMPONENT_T, EOT diff --git a/eeschema/ee_collectors.h b/eeschema/ee_collectors.h index 9e29bd19d9..af8c455c65 100644 --- a/eeschema/ee_collectors.h +++ b/eeschema/ee_collectors.h @@ -46,6 +46,7 @@ public: static const KICAD_T EditableItems[]; static const KICAD_T ComponentsOnly[]; static const KICAD_T SheetsOnly[]; + static const KICAD_T AnchorableItems[]; EE_COLLECTOR( const KICAD_T* aScanTypes = EE_COLLECTOR::AllItems ) : m_Unit( 0 ), diff --git a/eeschema/eeschema_settings.cpp b/eeschema/eeschema_settings.cpp index fdb7916afc..d0a8506518 100644 --- a/eeschema/eeschema_settings.cpp +++ b/eeschema/eeschema_settings.cpp @@ -132,6 +132,9 @@ EESCHEMA_SETTINGS::EESCHEMA_SETTINGS() : m_params.emplace_back( new PARAM( "drawing.hv_lines_only", &m_Drawing.hv_lines_only, true ) ); + m_params.emplace_back( new PARAM( "drawing.auto_start_wires", + &m_Drawing.auto_start_wires, true ) ); + m_params.emplace_back( new PARAM( "drawing.repeat_label_increment", &m_Drawing.repeat_label_increment, 1, -10, 10 ) ); diff --git a/eeschema/eeschema_settings.h b/eeschema/eeschema_settings.h index c67c41aee3..b81fc88c27 100644 --- a/eeschema/eeschema_settings.h +++ b/eeschema/eeschema_settings.h @@ -77,6 +77,7 @@ public: bool intersheets_ref_short; wxString intersheets_ref_prefix; wxString intersheets_ref_suffix; + bool auto_start_wires; }; struct INPUT diff --git a/eeschema/sch_item.h b/eeschema/sch_item.h index ff8a822ac7..4bb58a87f4 100644 --- a/eeschema/sch_item.h +++ b/eeschema/sch_item.h @@ -376,6 +376,11 @@ public: */ virtual bool IsConnectable() const { return false; } + /** + * @return true if the given point can start drawing (usually means the anchor is unused/free/dangling) + */ + virtual bool IsPointClickableAnchor( const wxPoint& aPos ) const { return false; } + /** * Add all the connection points for this item to \a aPoints. * diff --git a/eeschema/sch_junction.h b/eeschema/sch_junction.h index c5104dd9a3..b88dfd57d5 100644 --- a/eeschema/sch_junction.h +++ b/eeschema/sch_junction.h @@ -95,6 +95,8 @@ public: wxPoint GetPosition() const override { return m_pos; } void SetPosition( const wxPoint& aPosition ) override { m_pos = aPosition; } + bool IsPointClickableAnchor( const wxPoint& aPos ) const override { return GetPosition() == aPos; } + int GetDiameter() const; void SetDiameter( int aDiameter ) { m_diameter = aDiameter; } diff --git a/eeschema/sch_line.h b/eeschema/sch_line.h index 97a603f79b..5827bf8106 100644 --- a/eeschema/sch_line.h +++ b/eeschema/sch_line.h @@ -212,6 +212,12 @@ public: wxPoint GetPosition() const override { return m_start; } void SetPosition( const wxPoint& aPosition ) override; + bool IsPointClickableAnchor( const wxPoint& aPos ) const override + { + return ( GetStartPoint() == aPos && IsStartDangling() ) + || ( GetEndPoint() == aPos && IsEndDangling() ); + } + bool HitTest( const wxPoint& aPosition, int aAccuracy = 0 ) const override; bool HitTest( const EDA_RECT& aRect, bool aContained, int aAccuracy = 0 ) const override; diff --git a/eeschema/sch_pin.h b/eeschema/sch_pin.h index e16f2dbdc0..c8e2b66942 100644 --- a/eeschema/sch_pin.h +++ b/eeschema/sch_pin.h @@ -94,6 +94,8 @@ public: bool IsDangling() const override { return m_isDangling; } void SetIsDangling( bool isDangling ) { m_isDangling = isDangling; } + bool IsPointClickableAnchor( const wxPoint& aPos ) const override { return m_isDangling && GetPosition() == aPos; } + /// Returns the pin's position in global coordinates wxPoint GetTransformedPosition() const; diff --git a/eeschema/sch_sheet.h b/eeschema/sch_sheet.h index 606017fb89..01ccae87ac 100644 --- a/eeschema/sch_sheet.h +++ b/eeschema/sch_sheet.h @@ -204,6 +204,8 @@ public: void SetPosition( const wxPoint& aPosition ) override { ConstrainOnEdge( aPosition ); } + bool IsPointClickableAnchor( const wxPoint& aPos ) const override { return m_isDangling && GetPosition() == aPos; } + bool HitTest( const wxPoint& aPosition, int aAccuracy = 0 ) const override; EDA_ITEM* Clone() const override; diff --git a/eeschema/sch_text.h b/eeschema/sch_text.h index 1566d491a4..12a2d469ed 100644 --- a/eeschema/sch_text.h +++ b/eeschema/sch_text.h @@ -369,6 +369,8 @@ public: EDA_ITEM* Clone() const override; + bool IsPointClickableAnchor( const wxPoint& aPos ) const override { return m_isDangling && GetPosition() == aPos; } + private: bool doIsConnected( const wxPoint& aPosition ) const override { return EDA_TEXT::GetTextPos() == aPosition; } }; @@ -424,6 +426,8 @@ public: wxPoint GetIrefSavedPosition() { return m_savedIrefPos; } void SetIrefSavedPosition( wxPoint pos ) { m_savedIrefPos = pos; } + bool IsPointClickableAnchor( const wxPoint& aPos ) const override { return m_isDangling && GetPosition() == aPos; } + private: bool doIsConnected( const wxPoint& aPosition ) const override { return EDA_TEXT::GetTextPos() == aPosition; } SCH_IREF* m_iref; @@ -476,6 +480,8 @@ public: EDA_ITEM* Clone() const override; + bool IsPointClickableAnchor( const wxPoint& aPos ) const override { return m_isDangling && GetPosition() == aPos; } + private: bool doIsConnected( const wxPoint& aPosition ) const override { return EDA_TEXT::GetTextPos() == aPosition; } }; diff --git a/eeschema/tools/ee_actions.cpp b/eeschema/tools/ee_actions.cpp index 9f0ec2a5d6..454c2ef767 100644 --- a/eeschema/tools/ee_actions.cpp +++ b/eeschema/tools/ee_actions.cpp @@ -22,11 +22,12 @@ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA */ -#include #include -#include #include #include +#include +#include +#include // Actions, being statically-defined, require specialized I18N handling. We continue to @@ -645,17 +646,20 @@ TOOL_ACTION EE_ACTIONS::addNeededJunctions( "eeschema.InteractiveDrawingLineWireBus.addNeededJunctions", AS_ACTIVE, 0, "", _( "Add Junctions to Selection where needed" ), "", nullptr, AF_ACTIVATE ); + +const DRAW_SEGMENT_EVENT_PARAMS drawWireActionParam = { LAYER_WIRE, false }; TOOL_ACTION EE_ACTIONS::drawWire( "eeschema.InteractiveDrawingLineWireBus.drawWires", AS_GLOBAL, 'W', LEGACY_HK_NAME( "Begin Wire" ), _( "Add Wire" ), _( "Add a wire" ), - add_line_xpm, AF_ACTIVATE, (void*) LAYER_WIRE ); + add_line_xpm, AF_ACTIVATE, (void*) &drawWireActionParam ); +const DRAW_SEGMENT_EVENT_PARAMS drawBusActionParam = { LAYER_BUS, false }; TOOL_ACTION EE_ACTIONS::drawBus( "eeschema.InteractiveDrawingLineWireBus.drawBuses", AS_GLOBAL, 'B', LEGACY_HK_NAME( "Begin Bus" ), _( "Add Bus" ), _( "Add a bus" ), - add_bus_xpm, AF_ACTIVATE, (void*) LAYER_BUS ); + add_bus_xpm, AF_ACTIVATE, (void*) &drawBusActionParam ); TOOL_ACTION EE_ACTIONS::unfoldBus( "eeschema.InteractiveDrawingLineWireBus.unfoldBus", AS_GLOBAL, @@ -663,11 +667,12 @@ TOOL_ACTION EE_ACTIONS::unfoldBus( "eeschema.InteractiveDrawingLineWireBus.unfol _( "Unfold from Bus" ), _( "Break a wire out of a bus" ), nullptr, AF_ACTIVATE ); +const DRAW_SEGMENT_EVENT_PARAMS drawLinesActionParam = { LAYER_NOTES, false }; TOOL_ACTION EE_ACTIONS::drawLines( "eeschema.InteractiveDrawingLineWireBus.drawLines", AS_GLOBAL, 'I', LEGACY_HK_NAME( "Add Graphic PolyLine" ), _( "Add Lines" ), _( "Add connected graphic lines" ), - add_dashed_line_xpm, AF_ACTIVATE, (void*) LAYER_NOTES ); + add_dashed_line_xpm, AF_ACTIVATE, (void*) &drawLinesActionParam ); TOOL_ACTION EE_ACTIONS::finishLineWireOrBus( "eeschema.InteractiveDrawingLineWireBus.finish", AS_GLOBAL, diff --git a/eeschema/tools/ee_selection_tool.cpp b/eeschema/tools/ee_selection_tool.cpp index 7f09bf43b0..517fc9e7c0 100644 --- a/eeschema/tools/ee_selection_tool.cpp +++ b/eeschema/tools/ee_selection_tool.cpp @@ -46,6 +46,7 @@ #include #include #include +#include #include #include #include @@ -295,13 +296,12 @@ const KICAD_T movableSymbolItems[] = int EE_SELECTION_TOOL::Main( const TOOL_EVENT& aEvent ) { + m_frame->GetCanvas()->SetCurrentCursor( wxCURSOR_ARROW ); // Main loop: keep receiving events while( TOOL_EVENT* evt = Wait() ) { - if( m_frame->ToolStackIsEmpty() ) - m_frame->GetCanvas()->SetCurrentCursor( wxCURSOR_ARROW ); - + bool displayPencil = false; m_additive = m_subtractive = m_exclusive_or = false; if( evt->Modifier( MD_SHIFT ) && evt->Modifier( MD_CTRL ) ) @@ -321,8 +321,46 @@ int EE_SELECTION_TOOL::Main( const TOOL_EVENT& aEvent ) if( auto schframe = dynamic_cast( m_frame ) ) schframe->FocusOnItem( nullptr ); - SelectPoint( evt->Position(), EE_COLLECTOR::AllItems, nullptr, nullptr, false, - m_additive, m_subtractive, m_exclusive_or ); + EE_COLLECTOR collector; + + // Collect items at the clicked location (doesn't select them yet) + if( !CollectHits( evt->Position(), collector, EE_COLLECTOR::AllItems, false ) ) + { + return false; + } + + // Check if we want to auto start wires if we clicked on anchors of items + bool continueSelect = true; + if( collector.GetCount() == 1 && m_frame->eeconfig()->m_Drawing.auto_start_wires ) + { + EE_GRID_HELPER grid( m_toolMgr ); + + wxPoint cursorPos = wxPoint( grid.BestSnapAnchor( + evt->IsPrime() ? evt->Position() : getViewControls()->GetMousePosition(), + nullptr ) ); + if( collector[0]->IsPointClickableAnchor( cursorPos ) ) + { + OPT_TOOL_EVENT newEvt = EE_ACTIONS::drawWire.MakeEvent(); + + DRAW_SEGMENT_EVENT_PARAMS* params = + newEvt->Parameter(); + DRAW_SEGMENT_EVENT_PARAMS* newParams = new DRAW_SEGMENT_EVENT_PARAMS(); + *newParams = *params; + newParams->quitOnDraw = true; + newEvt->SetParameter( newParams ); + + newEvt->SetMousePosition( newEvt->Position() ); + m_toolMgr->ProcessEvent( *newEvt ); + continueSelect = false; + } + } + + if( continueSelect ) + { + // If we didn't click on an anchor, we perform a normal select, pass in the items we previously collected + SelectPoint( + collector, nullptr, nullptr, m_additive, m_subtractive, m_exclusive_or ); + } } // right click? if there is any object - show the context menu @@ -375,7 +413,8 @@ int EE_SELECTION_TOOL::Main( const TOOL_EVENT& aEvent ) if( auto schframe = dynamic_cast( m_frame ) ) schframe->FocusOnItem( nullptr ); - if( m_additive || m_subtractive || m_exclusive_or || m_frame->GetDragSelects() ) + if( m_additive || m_subtractive || m_exclusive_or + || ( m_selection.Empty() && m_frame->GetDragSelects() ) ) { selectMultiple(); } @@ -442,8 +481,45 @@ int EE_SELECTION_TOOL::Main( const TOOL_EVENT& aEvent ) ClearSelection(); } + else if( evt->IsMotion() ) + { + if( m_frame->eeconfig()->m_Drawing.auto_start_wires ) + { + EE_COLLECTOR collector; + + // We are checking if we should display a pencil when hovering over anchors for "auto starting" wires when clicked + if( CollectHits( + evt->Position(), collector, EE_COLLECTOR::AnchorableItems, false ) ) + { + if( collector.GetCount() == 1 ) + { + SCH_ITEM* item = collector[0]; + + if( item + && item->IsPointClickableAnchor( static_cast( + getViewControls()->GetCursorPosition( true ) ) ) ) + { + displayPencil = true; + } + } + } + } + } + else evt->SetPassEvent(); + + if( m_frame->ToolStackIsEmpty() ) + { + if( displayPencil ) + { + m_frame->GetCanvas()->SetCurrentCursor( wxCURSOR_PENCIL ); + } + else + { + m_frame->GetCanvas()->SetCurrentCursor( wxCURSOR_ARROW ); + } + } } return 0; @@ -456,13 +532,10 @@ EE_SELECTION& EE_SELECTION_TOOL::GetSelection() } -bool EE_SELECTION_TOOL::SelectPoint( const VECTOR2I& aWhere, const KICAD_T* aFilterList, - EDA_ITEM** aItem, bool* aSelectionCancelledFlag, bool aCheckLocked, bool aAdd, - bool aSubtract, bool aExclusiveOr ) +bool EE_SELECTION_TOOL::CollectHits( const VECTOR2I& aWhere, EE_COLLECTOR& aCollector, + const KICAD_T* aFilterList, bool aCheckLocked ) { - EE_COLLECTOR collector; - - collector.m_Threshold = KiROUND( getView()->ToWorld( HITTEST_THRESHOLD_PIXELS ) ); + aCollector.m_Threshold = KiROUND( getView()->ToWorld( HITTEST_THRESHOLD_PIXELS ) ); if( m_isLibEdit ) { @@ -471,57 +544,68 @@ bool EE_SELECTION_TOOL::SelectPoint( const VECTOR2I& aWhere, const KICAD_T* aFil if( !part ) return false; - collector.Collect( part->GetDrawItems(), aFilterList, (wxPoint) aWhere, m_unit, m_convert ); + aCollector.Collect( + part->GetDrawItems(), aFilterList, (wxPoint) aWhere, m_unit, m_convert ); } else - collector.Collect( m_frame->GetScreen(), aFilterList, (wxPoint) aWhere, m_unit, m_convert ); + { + aCollector.Collect( + m_frame->GetScreen(), aFilterList, (wxPoint) aWhere, m_unit, m_convert ); + } // Post-process collected items - for( int i = collector.GetCount() - 1; i >= 0; --i ) + for( int i = aCollector.GetCount() - 1; i >= 0; --i ) { - if( !Selectable( collector[ i ] ) ) + if( !Selectable( aCollector[i] ) ) { - collector.Remove( i ); + aCollector.Remove( i ); continue; } - if( aCheckLocked && collector[ i ]->IsLocked() ) + if( aCheckLocked && aCollector[i]->IsLocked() ) { - collector.Remove( i ); + aCollector.Remove( i ); continue; } // SelectPoint, unlike other selection routines, can select line ends - if( collector[ i ]->Type() == SCH_LINE_T ) + if( aCollector[i]->Type() == SCH_LINE_T ) { - SCH_LINE* line = (SCH_LINE*) collector[ i ]; + SCH_LINE* line = (SCH_LINE*) aCollector[i]; line->ClearFlags( STARTPOINT | ENDPOINT ); - if( HitTestPoints( line->GetStartPoint(), (wxPoint) aWhere, collector.m_Threshold ) ) + if( HitTestPoints( line->GetStartPoint(), (wxPoint) aWhere, aCollector.m_Threshold ) ) line->SetFlags( STARTPOINT ); - else if (HitTestPoints( line->GetEndPoint(), (wxPoint) aWhere, collector.m_Threshold ) ) + else if( HitTestPoints( line->GetEndPoint(), (wxPoint) aWhere, aCollector.m_Threshold ) ) line->SetFlags( ENDPOINT ); else line->SetFlags( STARTPOINT | ENDPOINT ); } } - m_selection.ClearReferencePoint(); - // Apply some ugly heuristics to avoid disambiguation menus whenever possible - if( collector.GetCount() > 1 && !m_skip_heuristics ) + if( aCollector.GetCount() > 1 && !m_skip_heuristics ) { - GuessSelectionCandidates( collector, aWhere ); + GuessSelectionCandidates( aCollector, aWhere ); } - // If still more than one item we're going to have to ask the user. - if( collector.GetCount() > 1 ) - { - collector.m_MenuTitle = wxEmptyString; - // Must call selectionMenu via RunAction() to avoid event-loop contention - m_toolMgr->RunAction( EE_ACTIONS::selectionMenu, true, &collector ); + return true; +} - if( collector.m_MenuCancelled ) + +bool EE_SELECTION_TOOL::SelectPoint( EE_COLLECTOR& aCollector, EDA_ITEM** aItem, + bool* aSelectionCancelledFlag, bool aAdd, bool aSubtract, bool aExclusiveOr ) +{ + m_selection.ClearReferencePoint(); + + // If still more than one item we're going to have to ask the user. + if( aCollector.GetCount() > 1 ) + { + aCollector.m_MenuTitle = wxEmptyString; + // Must call selectionMenu via RunAction() to avoid event-loop contention + m_toolMgr->RunAction( EE_ACTIONS::selectionMenu, true, &aCollector ); + + if( aCollector.m_MenuCancelled ) { if( aSelectionCancelledFlag ) *aSelectionCancelledFlag = true; @@ -536,18 +620,18 @@ bool EE_SELECTION_TOOL::SelectPoint( const VECTOR2I& aWhere, const KICAD_T* aFil bool anyAdded = false; bool anySubtracted = false; - if( collector.GetCount() > 0 ) + if( aCollector.GetCount() > 0 ) { - for( int i = 0; i < collector.GetCount(); ++i ) + for( int i = 0; i < aCollector.GetCount(); ++i ) { - if( aSubtract || ( aExclusiveOr && collector[i]->IsSelected() ) ) + if( aSubtract || ( aExclusiveOr && aCollector[i]->IsSelected() ) ) { - unselect( collector[i] ); + unselect( aCollector[i] ); anySubtracted = true; } else { - select( collector[i] ); + select( aCollector[i] ); anyAdded = true; } } @@ -557,8 +641,8 @@ bool EE_SELECTION_TOOL::SelectPoint( const VECTOR2I& aWhere, const KICAD_T* aFil { m_toolMgr->ProcessEvent( EVENTS::SelectedEvent ); - if( aItem && collector.GetCount() == 1 ) - *aItem = collector[0]; + if( aItem && aCollector.GetCount() == 1 ) + *aItem = aCollector[0]; return true; } @@ -572,6 +656,21 @@ bool EE_SELECTION_TOOL::SelectPoint( const VECTOR2I& aWhere, const KICAD_T* aFil } +bool EE_SELECTION_TOOL::SelectPoint( const VECTOR2I& aWhere, const KICAD_T* aFilterList, + EDA_ITEM** aItem, bool* aSelectionCancelledFlag, bool aCheckLocked, bool aAdd, + bool aSubtract, bool aExclusiveOr ) +{ + EE_COLLECTOR collector; + + if( !CollectHits( aWhere, collector, aFilterList, aCheckLocked ) ) + { + return false; + } + + return SelectPoint( collector, aItem, aSelectionCancelledFlag, aAdd, aSubtract, aExclusiveOr ); +} + + int EE_SELECTION_TOOL::SelectAll( const TOOL_EVENT& aEvent ) { m_multiple = true; // Multiple selection mode is active @@ -663,12 +762,18 @@ void EE_SELECTION_TOOL::GuessSelectionCandidates( EE_COLLECTOR& collector, const // itself is never selected for( int i = 0; collector.GetCount() == 2 && i < 2; ++i ) { - EDA_ITEM* item = collector[ i ]; - EDA_ITEM* other = collector[ ( i + 1 ) % 2 ]; + SCH_ITEM* item = collector[i]; + SCH_ITEM* other = collector[( i + 1 ) % 2]; if( item->Type() == SCH_COMPONENT_T && other->Type() == SCH_PIN_T ) { - if( !m_isLibEdit && m_frame->eeconfig()->m_Selection.select_pin_selects_symbol ) + // Make sure we aren't clicking on the pin anchor itself, only the rest of the pin should select the symbol with this setting + // To avoid conflict with the auto-start wires option + EE_GRID_HELPER grid( m_toolMgr ); + wxPoint cursorPos = wxPoint( grid.BestSnapAnchor( aPos, nullptr ) ); + + if( !m_isLibEdit && m_frame->eeconfig()->m_Selection.select_pin_selects_symbol + && !other->IsPointClickableAnchor( cursorPos ) ) collector.Transfer( other ); else collector.Transfer( item ); diff --git a/eeschema/tools/ee_selection_tool.h b/eeschema/tools/ee_selection_tool.h index 79a19396aa..bd011061c9 100644 --- a/eeschema/tools/ee_selection_tool.h +++ b/eeschema/tools/ee_selection_tool.h @@ -88,21 +88,55 @@ public: /** * Function SelectPoint() - * Selects one or all items pointed by the parameter aWhere. - * If there is more than one item at that place, - * there is a menu displayed that allows one to choose the item or all of them. + * This overload of SelectPoint will create an EE_COLLECTOR and collect hits at location aWhere + * before calling the primary SelectPoint method. * - * @param aWhere is the place where the item should be selected. + * @param aWhere is the location where the item(s) should be collected * @param aItem is set to the newly selected item if only one was selected, otherwise is unchanged. * @param aSelectionCancelledFlag allows the function to inform its caller that a selection * was cancelled (for instance, by clicking outside of the disambiguation menu). * @param aCheckLocked indicates if locked items should be excluded. + * @param aAdd indicates if found item(s) should be added to the selection + * @param aSubtract indicates if found item(s) should be subtracted from the selection + * @param aExclusiveOr indicates if found item(s) should be toggle in the selection */ bool SelectPoint( const VECTOR2I& aWhere, const KICAD_T* aFilterList = EE_COLLECTOR::AllItems, EDA_ITEM** aItem = nullptr, bool* aSelectionCancelledFlag = nullptr, bool aCheckLocked = false, bool aAdd = false, bool aSubtract = false, bool aExclusiveOr = false ); + /** + * Function SelectPoint() + * This is the primary SelectPoint method that will prompt the user with a menu to disambiguate multiple selections + * and then finish by adding, subtracting or toggling the item(s) to the actual selection group. + * + * @param aCollector is an EE_COLLECTOR that already has collected items + * @param aItem is set to the newly selected item if only one was selected, otherwise is unchanged. + * @param aSelectionCancelledFlag allows the function to inform its caller that a selection + * was cancelled (for instance, by clicking outside of the disambiguation menu). + * @param aAdd indicates if found item(s) should be added to the selection + * @param aSubtract indicates if found item(s) should be subtracted from the selection + * @param aExclusiveOr indicates if found item(s) should be toggle in the selection + */ + bool SelectPoint( EE_COLLECTOR& aCollector, EDA_ITEM** aItem = nullptr, + bool* aSelectionCancelledFlag = nullptr, bool aAdd = false, + bool aSubtract = false, bool aExclusiveOr = false ); + + /** + * Function CollectHits() + * Selects one or more items at the location given by parameter aWhere. + * + * This method does not attempt to disambiguate multiple items and is simply "collecting" + * + * @param aWhere is the place where the item should be selected. + * @param aCollector is the collector object that will store found item(s) + * @param aFilterList is a list of items that are acceptable for collection + * @param aCheckLocked indicates if locked items should be excluded. + */ + bool CollectHits( const VECTOR2I& aWhere, EE_COLLECTOR& aCollector, + const KICAD_T* aFilterList = EE_COLLECTOR::AllItems, + bool aCheckLocked = false ); + int AddItemToSel( const TOOL_EVENT& aEvent ); void AddItemToSel( EDA_ITEM* aItem, bool aQuietMode = false ); int AddItemsToSel( const TOOL_EVENT& aEvent ); diff --git a/eeschema/tools/sch_line_wire_bus_tool.cpp b/eeschema/tools/sch_line_wire_bus_tool.cpp index 0bc0150759..a450b2bb5a 100644 --- a/eeschema/tools/sch_line_wire_bus_tool.cpp +++ b/eeschema/tools/sch_line_wire_bus_tool.cpp @@ -276,7 +276,7 @@ bool SCH_LINE_WIRE_BUS_TOOL::IsDrawingLineWireOrBus( const SELECTION& aSelection int SCH_LINE_WIRE_BUS_TOOL::DrawSegments( const TOOL_EVENT& aEvent ) { - SCH_LAYER_ID layer = aEvent.Parameter(); + DRAW_SEGMENT_EVENT_PARAMS* params = aEvent.Parameter(); if( aEvent.HasPosition() ) getViewControls()->WarpCursor( aEvent.Position(), true ); @@ -287,10 +287,10 @@ int SCH_LINE_WIRE_BUS_TOOL::DrawSegments( const TOOL_EVENT& aEvent ) if( aEvent.HasPosition() ) { VECTOR2D cursorPos = getViewControls()->GetCursorPosition( !aEvent.Modifier( MD_ALT ) ); - startSegments( layer, cursorPos ); + startSegments( params->layer, cursorPos ); } - return doDrawSegments( tool, layer ); + return doDrawSegments( tool, params->layer, params->quitOnDraw ); } @@ -345,7 +345,7 @@ int SCH_LINE_WIRE_BUS_TOOL::UnfoldBus( const TOOL_EVENT& aEvent ) // If we have an unfolded wire to draw, then draw it if( segment ) - return doDrawSegments( tool, LAYER_WIRE ); + return doDrawSegments( tool, LAYER_WIRE, false ); else { m_frame->PopTool( tool ); @@ -458,7 +458,7 @@ void SCH_LINE_WIRE_BUS_TOOL::computeBreakPoint( const std::pairGetScreen(); EE_POINT_EDITOR* pointEditor = m_toolMgr->GetTool(); @@ -561,6 +561,12 @@ int SCH_LINE_WIRE_BUS_TOOL::doDrawSegments( const std::string& aTool, int aType { finishSegments(); segment = nullptr; + + if( aQuitOnDraw ) + { + m_frame->PopTool( aTool ); + break; + } } } //------------------------------------------------------------------------ @@ -592,6 +598,12 @@ int SCH_LINE_WIRE_BUS_TOOL::doDrawSegments( const std::string& aTool, int aType { finishSegments(); segment = nullptr; + + if( aQuitOnDraw ) + { + m_frame->PopTool( aTool ); + break; + } } else { @@ -614,6 +626,12 @@ int SCH_LINE_WIRE_BUS_TOOL::doDrawSegments( const std::string& aTool, int aType finishSegments(); segment = nullptr; + + if( aQuitOnDraw ) + { + m_frame->PopTool( aTool ); + break; + } } } //------------------------------------------------------------------------ @@ -950,8 +968,6 @@ int SCH_LINE_WIRE_BUS_TOOL::AddJunctionsIfNeeded( const TOOL_EVENT& aEvent ) return 0; } - - void SCH_LINE_WIRE_BUS_TOOL::setTransitions() { Go( &SCH_LINE_WIRE_BUS_TOOL::AddJunctionsIfNeeded, EE_ACTIONS::addNeededJunctions.MakeEvent() ); diff --git a/eeschema/tools/sch_line_wire_bus_tool.h b/eeschema/tools/sch_line_wire_bus_tool.h index 83b06b64ba..98090f3c86 100644 --- a/eeschema/tools/sch_line_wire_bus_tool.h +++ b/eeschema/tools/sch_line_wire_bus_tool.h @@ -60,6 +60,12 @@ struct BUS_UNFOLDING_T }; +struct DRAW_SEGMENT_EVENT_PARAMS +{ + SCH_LAYER_ID layer; + bool quitOnDraw; +}; + /** * SCH_LINE_DRAWING_TOOL * @@ -90,7 +96,7 @@ public: int AddJunctionsIfNeeded( const TOOL_EVENT& aEvent ); private: - int doDrawSegments( const std::string& aTool, int aType ); + int doDrawSegments( const std::string& aTool, int aType, bool aQuitOnDraw ); SCH_LINE* startSegments( int aType, const VECTOR2D& aPos ); SCH_LINE* doUnfoldBus( const wxString& aNet ); void finishSegments();