From d3e03c51bf4c7e7f5063ab35804d03daf3bc29d5 Mon Sep 17 00:00:00 2001 From: John Beard Date: Fri, 17 May 2024 11:20:07 +0800 Subject: [PATCH] Bus unfold: snap the entry to the bus, even if the cursor isn't right on the bus Fixes: https://gitlab.com/kicad/code/kicad/-/issues/18011 --- eeschema/sch_line.h | 9 +++ eeschema/tools/sch_line_wire_bus_tool.cpp | 69 +++++++++++++++++------ eeschema/tools/sch_line_wire_bus_tool.h | 15 ++++- 3 files changed, 75 insertions(+), 18 deletions(-) diff --git a/eeschema/sch_line.h b/eeschema/sch_line.h index fee983b133..ce7a99d714 100644 --- a/eeschema/sch_line.h +++ b/eeschema/sch_line.h @@ -28,6 +28,7 @@ #include #include // for wxPenStyle #include // for std::list +#include class NETLIST_OBJECT_LIST; @@ -140,6 +141,14 @@ public: VECTOR2I GetEndPoint() const { return m_end; } void SetEndPoint( const VECTOR2I& aPosition ) { m_end = aPosition; } + /** + * Get the geometric aspect of the wire as a SEG + */ + SEG GetSeg() const + { + return SEG{ m_start, m_end }; + } + void SetLastResolvedState( const SCH_ITEM* aItem ) override { const SCH_LINE* aLine = dynamic_cast( aItem ); diff --git a/eeschema/tools/sch_line_wire_bus_tool.cpp b/eeschema/tools/sch_line_wire_bus_tool.cpp index 984f720c1a..985d75b1b9 100644 --- a/eeschema/tools/sch_line_wire_bus_tool.cpp +++ b/eeschema/tools/sch_line_wire_bus_tool.cpp @@ -61,12 +61,20 @@ #include #include + +using BUS_GETTER = std::function; + class BUS_UNFOLD_MENU : public ACTION_MENU { public: - BUS_UNFOLD_MENU() : + /** + * @param aBusGetter Function to get the bus to unfold, which will probably + * be looking for a likely bus in a selection. + */ + BUS_UNFOLD_MENU( BUS_GETTER aBusGetter ) : ACTION_MENU( true ), - m_showTitle( false ) + m_showTitle( false ), + m_busGetter( aBusGetter ) { SetIcon( BITMAPS::add_line2bus ); SetTitle( _( "Unfold from Bus" ) ); @@ -82,21 +90,16 @@ public: protected: ACTION_MENU* create() const override { - return new BUS_UNFOLD_MENU(); + return new BUS_UNFOLD_MENU( m_busGetter ); } private: void update() override { - EE_SELECTION_TOOL* selTool = getToolManager()->GetTool(); - EE_SELECTION& selection = selTool->RequestSelection( { SCH_ITEM_LOCATE_BUS_T } ); - SCH_LINE* bus = (SCH_LINE*) selection.Front(); - + SCH_LINE* bus = m_busGetter(); Clear(); - // Pick up the pointer again because it may have been changed by SchematicCleanUp - selection = selTool->RequestSelection( { SCH_ITEM_LOCATE_BUS_T } ); - bus = (SCH_LINE*) selection.Front(); + bus = m_busGetter(); if( !bus ) { @@ -147,6 +150,7 @@ private: } bool m_showTitle; + BUS_GETTER m_busGetter; }; @@ -182,11 +186,17 @@ bool SCH_LINE_WIRE_BUS_TOOL::Init() { EE_TOOL_BASE::Init(); - std::shared_ptr busUnfoldMenu = std::make_shared(); + const auto busGetter = [this]() + { + return getBusForUnfolding(); + }; + + std::shared_ptr + busUnfoldMenu = std::make_shared( busGetter ); busUnfoldMenu->SetTool( this ); m_menu.RegisterSubMenu( busUnfoldMenu ); - std::shared_ptr selBusUnfoldMenu = std::make_shared(); + std::shared_ptr selBusUnfoldMenu = std::make_shared( busGetter ); selBusUnfoldMenu->SetTool( m_selectionTool ); m_selectionTool->GetToolMenu().RegisterSubMenu( selBusUnfoldMenu ); @@ -321,7 +331,11 @@ int SCH_LINE_WIRE_BUS_TOOL::UnfoldBus( const TOOL_EVENT& aEvent ) } else { - BUS_UNFOLD_MENU unfoldMenu; + const auto busGetter = [this]() + { + return getBusForUnfolding(); + }; + BUS_UNFOLD_MENU unfoldMenu( busGetter ); unfoldMenu.SetTool( this ); unfoldMenu.SetShowTitle(); @@ -366,15 +380,36 @@ int SCH_LINE_WIRE_BUS_TOOL::UnfoldBus( const TOOL_EVENT& aEvent ) } -SCH_LINE* SCH_LINE_WIRE_BUS_TOOL::doUnfoldBus( const wxString& aNet, const VECTOR2I& aPos ) +SCH_LINE* SCH_LINE_WIRE_BUS_TOOL::getBusForUnfolding() +{ + EE_SELECTION& selection = m_selectionTool->RequestSelection( { SCH_ITEM_LOCATE_BUS_T } ); + return static_cast( selection.Front() ); +} + + +SCH_LINE* SCH_LINE_WIRE_BUS_TOOL::doUnfoldBus( const wxString& aNet, + const std::optional& aPos ) { SCHEMATIC_SETTINGS& cfg = getModel()->Settings(); SCH_SCREEN* screen = m_frame->GetScreen(); + // use the same function as the menu selector, so we choose the same bus segment + SCH_LINE* const bus = getBusForUnfolding(); - VECTOR2I pos = aPos; + if ( bus == nullptr ) + { + wxASSERT_MSG( false, + wxString::Format( "Couldn't find the originating bus line (but had a net: %s )", + aNet ) ); + return nullptr; + } - if( aPos == VECTOR2I( 0, 0 ) ) - pos = static_cast( getViewControls()->GetCursorPosition() ); + VECTOR2I pos = aPos.value_or( static_cast( getViewControls()->GetCursorPosition() ) ); + + // It is possible for the position to be near the bus, but not exactly on it, but + // we need the bus entry to be on the bus exactly to connect. + // If the bus segment is H or V, this will be on the selection grid, if it's not, + // it might not be, but it won't be a broken connection (and the user asked for it!) + pos = bus->GetSeg().NearestPoint( pos ); m_toolMgr->RunAction( EE_ACTIONS::clearSelection ); diff --git a/eeschema/tools/sch_line_wire_bus_tool.h b/eeschema/tools/sch_line_wire_bus_tool.h index 33d59130a8..469259dbe2 100644 --- a/eeschema/tools/sch_line_wire_bus_tool.h +++ b/eeschema/tools/sch_line_wire_bus_tool.h @@ -100,7 +100,20 @@ private: SCH_LINE* startSegments( int aType, const VECTOR2D& aPos, SCH_LINE* aSegment = nullptr ); - SCH_LINE* doUnfoldBus( const wxString& aNet, const VECTOR2I& aPos = VECTOR2I( 0, 0 ) ); + /** + * Choose a bus to unfold based on the current tool selection. + */ + SCH_LINE* getBusForUnfolding(); + + /** + * Unfold the given bus from the given position. + * + * @param aNet The name of the net to unfold + * @param aPos The position to unfold the bus from, which will be the cursor if + * not provided, and will then be snapped to the selected bus segment. + */ + SCH_LINE* doUnfoldBus( const wxString& aNet, + const std::optional& aPos = std::nullopt ); void finishSegments();