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
This commit is contained in:
John Beard 2024-05-17 11:20:07 +08:00
parent 615f216ef6
commit d3e03c51bf
3 changed files with 75 additions and 18 deletions

View File

@ -28,6 +28,7 @@
#include <sch_item.h> #include <sch_item.h>
#include <wx/pen.h> // for wxPenStyle #include <wx/pen.h> // for wxPenStyle
#include <list> // for std::list #include <list> // for std::list
#include <geometry/seg.h>
class NETLIST_OBJECT_LIST; class NETLIST_OBJECT_LIST;
@ -140,6 +141,14 @@ public:
VECTOR2I GetEndPoint() const { return m_end; } VECTOR2I GetEndPoint() const { return m_end; }
void SetEndPoint( const VECTOR2I& aPosition ) { m_end = aPosition; } 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 void SetLastResolvedState( const SCH_ITEM* aItem ) override
{ {
const SCH_LINE* aLine = dynamic_cast<const SCH_LINE*>( aItem ); const SCH_LINE* aLine = dynamic_cast<const SCH_LINE*>( aItem );

View File

@ -61,12 +61,20 @@
#include <ee_selection.h> #include <ee_selection.h>
#include <ee_selection_tool.h> #include <ee_selection_tool.h>
using BUS_GETTER = std::function<SCH_LINE*()>;
class BUS_UNFOLD_MENU : public ACTION_MENU class BUS_UNFOLD_MENU : public ACTION_MENU
{ {
public: 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 ), ACTION_MENU( true ),
m_showTitle( false ) m_showTitle( false ),
m_busGetter( aBusGetter )
{ {
SetIcon( BITMAPS::add_line2bus ); SetIcon( BITMAPS::add_line2bus );
SetTitle( _( "Unfold from Bus" ) ); SetTitle( _( "Unfold from Bus" ) );
@ -82,21 +90,16 @@ public:
protected: protected:
ACTION_MENU* create() const override ACTION_MENU* create() const override
{ {
return new BUS_UNFOLD_MENU(); return new BUS_UNFOLD_MENU( m_busGetter );
} }
private: private:
void update() override void update() override
{ {
EE_SELECTION_TOOL* selTool = getToolManager()->GetTool<EE_SELECTION_TOOL>(); SCH_LINE* bus = m_busGetter();
EE_SELECTION& selection = selTool->RequestSelection( { SCH_ITEM_LOCATE_BUS_T } );
SCH_LINE* bus = (SCH_LINE*) selection.Front();
Clear(); Clear();
// Pick up the pointer again because it may have been changed by SchematicCleanUp // Pick up the pointer again because it may have been changed by SchematicCleanUp
selection = selTool->RequestSelection( { SCH_ITEM_LOCATE_BUS_T } ); bus = m_busGetter();
bus = (SCH_LINE*) selection.Front();
if( !bus ) if( !bus )
{ {
@ -147,6 +150,7 @@ private:
} }
bool m_showTitle; bool m_showTitle;
BUS_GETTER m_busGetter;
}; };
@ -182,11 +186,17 @@ bool SCH_LINE_WIRE_BUS_TOOL::Init()
{ {
EE_TOOL_BASE::Init(); EE_TOOL_BASE::Init();
std::shared_ptr<BUS_UNFOLD_MENU> busUnfoldMenu = std::make_shared<BUS_UNFOLD_MENU>(); const auto busGetter = [this]()
{
return getBusForUnfolding();
};
std::shared_ptr<BUS_UNFOLD_MENU>
busUnfoldMenu = std::make_shared<BUS_UNFOLD_MENU>( busGetter );
busUnfoldMenu->SetTool( this ); busUnfoldMenu->SetTool( this );
m_menu.RegisterSubMenu( busUnfoldMenu ); m_menu.RegisterSubMenu( busUnfoldMenu );
std::shared_ptr<BUS_UNFOLD_MENU> selBusUnfoldMenu = std::make_shared<BUS_UNFOLD_MENU>(); std::shared_ptr<BUS_UNFOLD_MENU> selBusUnfoldMenu = std::make_shared<BUS_UNFOLD_MENU>( busGetter );
selBusUnfoldMenu->SetTool( m_selectionTool ); selBusUnfoldMenu->SetTool( m_selectionTool );
m_selectionTool->GetToolMenu().RegisterSubMenu( selBusUnfoldMenu ); m_selectionTool->GetToolMenu().RegisterSubMenu( selBusUnfoldMenu );
@ -321,7 +331,11 @@ int SCH_LINE_WIRE_BUS_TOOL::UnfoldBus( const TOOL_EVENT& aEvent )
} }
else else
{ {
BUS_UNFOLD_MENU unfoldMenu; const auto busGetter = [this]()
{
return getBusForUnfolding();
};
BUS_UNFOLD_MENU unfoldMenu( busGetter );
unfoldMenu.SetTool( this ); unfoldMenu.SetTool( this );
unfoldMenu.SetShowTitle(); 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<SCH_LINE*>( selection.Front() );
}
SCH_LINE* SCH_LINE_WIRE_BUS_TOOL::doUnfoldBus( const wxString& aNet,
const std::optional<VECTOR2I>& aPos )
{ {
SCHEMATIC_SETTINGS& cfg = getModel<SCHEMATIC>()->Settings(); SCHEMATIC_SETTINGS& cfg = getModel<SCHEMATIC>()->Settings();
SCH_SCREEN* screen = m_frame->GetScreen(); 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 ) ) VECTOR2I pos = aPos.value_or( static_cast<VECTOR2I>( getViewControls()->GetCursorPosition() ) );
pos = static_cast<VECTOR2I>( 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 ); m_toolMgr->RunAction( EE_ACTIONS::clearSelection );

View File

@ -100,7 +100,20 @@ private:
SCH_LINE* startSegments( int aType, const VECTOR2D& aPos, SCH_LINE* aSegment = nullptr ); 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<VECTOR2I>& aPos = std::nullopt );
void finishSegments(); void finishSegments();