ADDED: Autostart wires in eeschema

Allows wires to be automatically started by clicking over a connection point
This commit is contained in:
Mark Roszko 2020-10-01 23:53:47 +00:00 committed by Seth Hillbrand
parent daac95400f
commit c940a45937
19 changed files with 341 additions and 63 deletions

View File

@ -70,6 +70,8 @@ bool PANEL_EESCHEMA_SETTINGS::TransferDataToWindow()
m_mouseDragIsDrag->SetValue( !cfg->m_Input.drag_is_move ); m_mouseDragIsDrag->SetValue( !cfg->m_Input.drag_is_move );
m_cbPinSelectionOpt->SetValue( cfg->m_Selection.select_pin_selects_symbol ); m_cbPinSelectionOpt->SetValue( cfg->m_Selection.select_pin_selects_symbol );
m_cbAutoStartWires->SetValue( cfg->m_Drawing.auto_start_wires );
return true; return true;
} }
@ -99,6 +101,8 @@ bool PANEL_EESCHEMA_SETTINGS::TransferDataFromWindow()
cfg->m_Input.drag_is_move = !m_mouseDragIsDrag->GetValue(); cfg->m_Input.drag_is_move = !m_mouseDragIsDrag->GetValue();
cfg->m_Selection.select_pin_selects_symbol = m_cbPinSelectionOpt->GetValue(); cfg->m_Selection.select_pin_selects_symbol = m_cbPinSelectionOpt->GetValue();
cfg->m_Drawing.auto_start_wires = m_cbAutoStartWires->GetValue();
m_frame->SaveProjectSettings(); m_frame->SaveProjectSettings();
return true; return true;

View File

@ -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 = 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") ); 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 ); bLeftColumn->Add( sbSizerEditOpt, 0, wxEXPAND|wxTOP|wxBOTTOM, 5 );

View File

@ -281,7 +281,7 @@
</object> </object>
<object class="sizeritem" expanded="1"> <object class="sizeritem" expanded="1">
<property name="border">5</property> <property name="border">5</property>
<property name="flag">wxALL</property> <property name="flag">wxLEFT|wxRIGHT|wxTOP</property>
<property name="proportion">0</property> <property name="proportion">0</property>
<object class="wxCheckBox" expanded="1"> <object class="wxCheckBox" expanded="1">
<property name="BottomDockable">1</property> <property name="BottomDockable">1</property>
@ -343,6 +343,70 @@
<property name="window_style"></property> <property name="window_style"></property>
</object> </object>
</object> </object>
<object class="sizeritem" expanded="1">
<property name="border">5</property>
<property name="flag">wxALL</property>
<property name="proportion">0</property>
<object class="wxCheckBox" expanded="1">
<property name="BottomDockable">1</property>
<property name="LeftDockable">1</property>
<property name="RightDockable">1</property>
<property name="TopDockable">1</property>
<property name="aui_layer"></property>
<property name="aui_name"></property>
<property name="aui_position"></property>
<property name="aui_row"></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">0</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="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">Automatically start wires on junctions and unused anchors</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_cbAutoStartWires</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">; ; Not forward_declare</property>
<property name="toolbar_pane">0</property>
<property name="tooltip"></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>
</object> </object>
<object class="sizeritem" expanded="1"> <object class="sizeritem" expanded="1">

View File

@ -44,6 +44,7 @@ class PANEL_EESCHEMA_SETTINGS_BASE : public wxPanel
wxChoice* m_choiceUnits; wxChoice* m_choiceUnits;
wxCheckBox* m_checkHVOrientation; wxCheckBox* m_checkHVOrientation;
wxCheckBox* m_mouseDragIsDrag; wxCheckBox* m_mouseDragIsDrag;
wxCheckBox* m_cbAutoStartWires;
wxStaticText* m_borderColorLabel; wxStaticText* m_borderColorLabel;
COLOR_SWATCH* m_borderColorSwatch; COLOR_SWATCH* m_borderColorSwatch;
wxStaticText* m_backgroundColorLabel; wxStaticText* m_backgroundColorLabel;

View File

@ -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[] = { const KICAD_T EE_COLLECTOR::ComponentsOnly[] = {
SCH_COMPONENT_T, SCH_COMPONENT_T,
EOT EOT

View File

@ -46,6 +46,7 @@ public:
static const KICAD_T EditableItems[]; static const KICAD_T EditableItems[];
static const KICAD_T ComponentsOnly[]; static const KICAD_T ComponentsOnly[];
static const KICAD_T SheetsOnly[]; static const KICAD_T SheetsOnly[];
static const KICAD_T AnchorableItems[];
EE_COLLECTOR( const KICAD_T* aScanTypes = EE_COLLECTOR::AllItems ) : EE_COLLECTOR( const KICAD_T* aScanTypes = EE_COLLECTOR::AllItems ) :
m_Unit( 0 ), m_Unit( 0 ),

View File

@ -132,6 +132,9 @@ EESCHEMA_SETTINGS::EESCHEMA_SETTINGS() :
m_params.emplace_back( new PARAM<bool>( "drawing.hv_lines_only", m_params.emplace_back( new PARAM<bool>( "drawing.hv_lines_only",
&m_Drawing.hv_lines_only, true ) ); &m_Drawing.hv_lines_only, true ) );
m_params.emplace_back( new PARAM<bool>( "drawing.auto_start_wires",
&m_Drawing.auto_start_wires, true ) );
m_params.emplace_back( new PARAM<int>( "drawing.repeat_label_increment", m_params.emplace_back( new PARAM<int>( "drawing.repeat_label_increment",
&m_Drawing.repeat_label_increment, 1, -10, 10 ) ); &m_Drawing.repeat_label_increment, 1, -10, 10 ) );

View File

@ -77,6 +77,7 @@ public:
bool intersheets_ref_short; bool intersheets_ref_short;
wxString intersheets_ref_prefix; wxString intersheets_ref_prefix;
wxString intersheets_ref_suffix; wxString intersheets_ref_suffix;
bool auto_start_wires;
}; };
struct INPUT struct INPUT

View File

@ -376,6 +376,11 @@ public:
*/ */
virtual bool IsConnectable() const { return false; } 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. * Add all the connection points for this item to \a aPoints.
* *

View File

@ -95,6 +95,8 @@ public:
wxPoint GetPosition() const override { return m_pos; } wxPoint GetPosition() const override { return m_pos; }
void SetPosition( const wxPoint& aPosition ) override { m_pos = aPosition; } void SetPosition( const wxPoint& aPosition ) override { m_pos = aPosition; }
bool IsPointClickableAnchor( const wxPoint& aPos ) const override { return GetPosition() == aPos; }
int GetDiameter() const; int GetDiameter() const;
void SetDiameter( int aDiameter ) { m_diameter = aDiameter; } void SetDiameter( int aDiameter ) { m_diameter = aDiameter; }

View File

@ -212,6 +212,12 @@ public:
wxPoint GetPosition() const override { return m_start; } wxPoint GetPosition() const override { return m_start; }
void SetPosition( const wxPoint& aPosition ) override; 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 wxPoint& aPosition, int aAccuracy = 0 ) const override;
bool HitTest( const EDA_RECT& aRect, bool aContained, int aAccuracy = 0 ) const override; bool HitTest( const EDA_RECT& aRect, bool aContained, int aAccuracy = 0 ) const override;

View File

@ -94,6 +94,8 @@ public:
bool IsDangling() const override { return m_isDangling; } bool IsDangling() const override { return m_isDangling; }
void SetIsDangling( bool isDangling ) { m_isDangling = 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 /// Returns the pin's position in global coordinates
wxPoint GetTransformedPosition() const; wxPoint GetTransformedPosition() const;

View File

@ -204,6 +204,8 @@ public:
void SetPosition( const wxPoint& aPosition ) override { ConstrainOnEdge( aPosition ); } 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; bool HitTest( const wxPoint& aPosition, int aAccuracy = 0 ) const override;
EDA_ITEM* Clone() const override; EDA_ITEM* Clone() const override;

View File

@ -369,6 +369,8 @@ public:
EDA_ITEM* Clone() const override; EDA_ITEM* Clone() const override;
bool IsPointClickableAnchor( const wxPoint& aPos ) const override { return m_isDangling && GetPosition() == aPos; }
private: private:
bool doIsConnected( const wxPoint& aPosition ) const override { return EDA_TEXT::GetTextPos() == aPosition; } bool doIsConnected( const wxPoint& aPosition ) const override { return EDA_TEXT::GetTextPos() == aPosition; }
}; };
@ -424,6 +426,8 @@ public:
wxPoint GetIrefSavedPosition() { return m_savedIrefPos; } wxPoint GetIrefSavedPosition() { return m_savedIrefPos; }
void SetIrefSavedPosition( wxPoint pos ) { m_savedIrefPos = pos; } void SetIrefSavedPosition( wxPoint pos ) { m_savedIrefPos = pos; }
bool IsPointClickableAnchor( const wxPoint& aPos ) const override { return m_isDangling && GetPosition() == aPos; }
private: private:
bool doIsConnected( const wxPoint& aPosition ) const override { return EDA_TEXT::GetTextPos() == aPosition; } bool doIsConnected( const wxPoint& aPosition ) const override { return EDA_TEXT::GetTextPos() == aPosition; }
SCH_IREF* m_iref; SCH_IREF* m_iref;
@ -476,6 +480,8 @@ public:
EDA_ITEM* Clone() const override; EDA_ITEM* Clone() const override;
bool IsPointClickableAnchor( const wxPoint& aPos ) const override { return m_isDangling && GetPosition() == aPos; }
private: private:
bool doIsConnected( const wxPoint& aPosition ) const override { return EDA_TEXT::GetTextPos() == aPosition; } bool doIsConnected( const wxPoint& aPosition ) const override { return EDA_TEXT::GetTextPos() == aPosition; }
}; };

View File

@ -22,11 +22,12 @@
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
*/ */
#include <tool/tool_action.h>
#include <bitmaps.h> #include <bitmaps.h>
#include <tools/ee_actions.h>
#include <core/typeinfo.h> #include <core/typeinfo.h>
#include <layers_id_colors_and_visibility.h> #include <layers_id_colors_and_visibility.h>
#include <sch_line_wire_bus_tool.h>
#include <tools/ee_actions.h>
#include <tool/tool_action.h>
// Actions, being statically-defined, require specialized I18N handling. We continue to // 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, "", "eeschema.InteractiveDrawingLineWireBus.addNeededJunctions", AS_ACTIVE, 0, "",
_( "Add Junctions to Selection where needed" ), "", nullptr, AF_ACTIVATE ); _( "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", TOOL_ACTION EE_ACTIONS::drawWire( "eeschema.InteractiveDrawingLineWireBus.drawWires",
AS_GLOBAL, AS_GLOBAL,
'W', LEGACY_HK_NAME( "Begin Wire" ), 'W', LEGACY_HK_NAME( "Begin Wire" ),
_( "Add Wire" ), _( "Add a 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", TOOL_ACTION EE_ACTIONS::drawBus( "eeschema.InteractiveDrawingLineWireBus.drawBuses",
AS_GLOBAL, AS_GLOBAL,
'B', LEGACY_HK_NAME( "Begin Bus" ), 'B', LEGACY_HK_NAME( "Begin Bus" ),
_( "Add Bus" ), _( "Add a 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", TOOL_ACTION EE_ACTIONS::unfoldBus( "eeschema.InteractiveDrawingLineWireBus.unfoldBus",
AS_GLOBAL, AS_GLOBAL,
@ -663,11 +667,12 @@ TOOL_ACTION EE_ACTIONS::unfoldBus( "eeschema.InteractiveDrawingLineWireBus.unfol
_( "Unfold from Bus" ), _( "Break a wire out of a bus" ), _( "Unfold from Bus" ), _( "Break a wire out of a bus" ),
nullptr, AF_ACTIVATE ); nullptr, AF_ACTIVATE );
const DRAW_SEGMENT_EVENT_PARAMS drawLinesActionParam = { LAYER_NOTES, false };
TOOL_ACTION EE_ACTIONS::drawLines( "eeschema.InteractiveDrawingLineWireBus.drawLines", TOOL_ACTION EE_ACTIONS::drawLines( "eeschema.InteractiveDrawingLineWireBus.drawLines",
AS_GLOBAL, AS_GLOBAL,
'I', LEGACY_HK_NAME( "Add Graphic PolyLine" ), 'I', LEGACY_HK_NAME( "Add Graphic PolyLine" ),
_( "Add Lines" ), _( "Add connected graphic lines" ), _( "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", TOOL_ACTION EE_ACTIONS::finishLineWireOrBus( "eeschema.InteractiveDrawingLineWireBus.finish",
AS_GLOBAL, AS_GLOBAL,

View File

@ -46,6 +46,7 @@
#include <schematic.h> #include <schematic.h>
#include <tool/tool_event.h> #include <tool/tool_event.h>
#include <tool/tool_manager.h> #include <tool/tool_manager.h>
#include <tools/ee_grid_helper.h>
#include <tools/sch_line_wire_bus_tool.h> #include <tools/sch_line_wire_bus_tool.h>
#include <view/view.h> #include <view/view.h>
#include <view/view_controls.h> #include <view/view_controls.h>
@ -295,13 +296,12 @@ const KICAD_T movableSymbolItems[] =
int EE_SELECTION_TOOL::Main( const TOOL_EVENT& aEvent ) int EE_SELECTION_TOOL::Main( const TOOL_EVENT& aEvent )
{ {
m_frame->GetCanvas()->SetCurrentCursor( wxCURSOR_ARROW );
// Main loop: keep receiving events // Main loop: keep receiving events
while( TOOL_EVENT* evt = Wait() ) while( TOOL_EVENT* evt = Wait() )
{ {
if( m_frame->ToolStackIsEmpty() ) bool displayPencil = false;
m_frame->GetCanvas()->SetCurrentCursor( wxCURSOR_ARROW );
m_additive = m_subtractive = m_exclusive_or = false; m_additive = m_subtractive = m_exclusive_or = false;
if( evt->Modifier( MD_SHIFT ) && evt->Modifier( MD_CTRL ) ) 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<SCH_EDIT_FRAME*>( m_frame ) ) if( auto schframe = dynamic_cast<SCH_EDIT_FRAME*>( m_frame ) )
schframe->FocusOnItem( nullptr ); schframe->FocusOnItem( nullptr );
SelectPoint( evt->Position(), EE_COLLECTOR::AllItems, nullptr, nullptr, false, EE_COLLECTOR collector;
m_additive, m_subtractive, m_exclusive_or );
// 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*>();
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 // 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<SCH_EDIT_FRAME*>( m_frame ) ) if( auto schframe = dynamic_cast<SCH_EDIT_FRAME*>( m_frame ) )
schframe->FocusOnItem( nullptr ); 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(); selectMultiple();
} }
@ -442,8 +481,45 @@ int EE_SELECTION_TOOL::Main( const TOOL_EVENT& aEvent )
ClearSelection(); 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<wxPoint>(
getViewControls()->GetCursorPosition( true ) ) ) )
{
displayPencil = true;
}
}
}
}
}
else else
evt->SetPassEvent(); evt->SetPassEvent();
if( m_frame->ToolStackIsEmpty() )
{
if( displayPencil )
{
m_frame->GetCanvas()->SetCurrentCursor( wxCURSOR_PENCIL );
}
else
{
m_frame->GetCanvas()->SetCurrentCursor( wxCURSOR_ARROW );
}
}
} }
return 0; return 0;
@ -456,13 +532,10 @@ EE_SELECTION& EE_SELECTION_TOOL::GetSelection()
} }
bool EE_SELECTION_TOOL::SelectPoint( const VECTOR2I& aWhere, const KICAD_T* aFilterList, bool EE_SELECTION_TOOL::CollectHits( const VECTOR2I& aWhere, EE_COLLECTOR& aCollector,
EDA_ITEM** aItem, bool* aSelectionCancelledFlag, bool aCheckLocked, bool aAdd, const KICAD_T* aFilterList, bool aCheckLocked )
bool aSubtract, bool aExclusiveOr )
{ {
EE_COLLECTOR collector; aCollector.m_Threshold = KiROUND( getView()->ToWorld( HITTEST_THRESHOLD_PIXELS ) );
collector.m_Threshold = KiROUND( getView()->ToWorld( HITTEST_THRESHOLD_PIXELS ) );
if( m_isLibEdit ) if( m_isLibEdit )
{ {
@ -471,57 +544,68 @@ bool EE_SELECTION_TOOL::SelectPoint( const VECTOR2I& aWhere, const KICAD_T* aFil
if( !part ) if( !part )
return false; 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 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 // 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; continue;
} }
if( aCheckLocked && collector[ i ]->IsLocked() ) if( aCheckLocked && aCollector[i]->IsLocked() )
{ {
collector.Remove( i ); aCollector.Remove( i );
continue; continue;
} }
// SelectPoint, unlike other selection routines, can select line ends // 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 ); 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 ); 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 ); line->SetFlags( ENDPOINT );
else else
line->SetFlags( STARTPOINT | ENDPOINT ); line->SetFlags( STARTPOINT | ENDPOINT );
} }
} }
m_selection.ClearReferencePoint();
// Apply some ugly heuristics to avoid disambiguation menus whenever possible // 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. return true;
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 );
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 ) if( aSelectionCancelledFlag )
*aSelectionCancelledFlag = true; *aSelectionCancelledFlag = true;
@ -536,18 +620,18 @@ bool EE_SELECTION_TOOL::SelectPoint( const VECTOR2I& aWhere, const KICAD_T* aFil
bool anyAdded = false; bool anyAdded = false;
bool anySubtracted = 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; anySubtracted = true;
} }
else else
{ {
select( collector[i] ); select( aCollector[i] );
anyAdded = true; anyAdded = true;
} }
} }
@ -557,8 +641,8 @@ bool EE_SELECTION_TOOL::SelectPoint( const VECTOR2I& aWhere, const KICAD_T* aFil
{ {
m_toolMgr->ProcessEvent( EVENTS::SelectedEvent ); m_toolMgr->ProcessEvent( EVENTS::SelectedEvent );
if( aItem && collector.GetCount() == 1 ) if( aItem && aCollector.GetCount() == 1 )
*aItem = collector[0]; *aItem = aCollector[0];
return true; 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 ) int EE_SELECTION_TOOL::SelectAll( const TOOL_EVENT& aEvent )
{ {
m_multiple = true; // Multiple selection mode is active 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 // itself is never selected
for( int i = 0; collector.GetCount() == 2 && i < 2; ++i ) for( int i = 0; collector.GetCount() == 2 && i < 2; ++i )
{ {
EDA_ITEM* item = collector[ i ]; SCH_ITEM* item = collector[i];
EDA_ITEM* other = collector[ ( i + 1 ) % 2 ]; SCH_ITEM* other = collector[( i + 1 ) % 2];
if( item->Type() == SCH_COMPONENT_T && other->Type() == SCH_PIN_T ) 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 ); collector.Transfer( other );
else else
collector.Transfer( item ); collector.Transfer( item );

View File

@ -88,21 +88,55 @@ public:
/** /**
* Function SelectPoint() * Function SelectPoint()
* Selects one or all items pointed by the parameter aWhere. * This overload of SelectPoint will create an EE_COLLECTOR and collect hits at location aWhere
* If there is more than one item at that place, * before calling the primary SelectPoint method.
* there is a menu displayed that allows one to choose the item or all of them.
* *
* @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 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 * @param aSelectionCancelledFlag allows the function to inform its caller that a selection
* was cancelled (for instance, by clicking outside of the disambiguation menu). * was cancelled (for instance, by clicking outside of the disambiguation menu).
* @param aCheckLocked indicates if locked items should be excluded. * @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, bool SelectPoint( const VECTOR2I& aWhere, const KICAD_T* aFilterList = EE_COLLECTOR::AllItems,
EDA_ITEM** aItem = nullptr, bool* aSelectionCancelledFlag = nullptr, EDA_ITEM** aItem = nullptr, bool* aSelectionCancelledFlag = nullptr,
bool aCheckLocked = false, bool aAdd = false, bool aSubtract = false, bool aCheckLocked = false, bool aAdd = false, bool aSubtract = false,
bool aExclusiveOr = 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 ); int AddItemToSel( const TOOL_EVENT& aEvent );
void AddItemToSel( EDA_ITEM* aItem, bool aQuietMode = false ); void AddItemToSel( EDA_ITEM* aItem, bool aQuietMode = false );
int AddItemsToSel( const TOOL_EVENT& aEvent ); int AddItemsToSel( const TOOL_EVENT& aEvent );

View File

@ -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 ) int SCH_LINE_WIRE_BUS_TOOL::DrawSegments( const TOOL_EVENT& aEvent )
{ {
SCH_LAYER_ID layer = aEvent.Parameter<SCH_LAYER_ID>(); DRAW_SEGMENT_EVENT_PARAMS* params = aEvent.Parameter<DRAW_SEGMENT_EVENT_PARAMS*>();
if( aEvent.HasPosition() ) if( aEvent.HasPosition() )
getViewControls()->WarpCursor( aEvent.Position(), true ); getViewControls()->WarpCursor( aEvent.Position(), true );
@ -287,10 +287,10 @@ int SCH_LINE_WIRE_BUS_TOOL::DrawSegments( const TOOL_EVENT& aEvent )
if( aEvent.HasPosition() ) if( aEvent.HasPosition() )
{ {
VECTOR2D cursorPos = getViewControls()->GetCursorPosition( !aEvent.Modifier( MD_ALT ) ); 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 we have an unfolded wire to draw, then draw it
if( segment ) if( segment )
return doDrawSegments( tool, LAYER_WIRE ); return doDrawSegments( tool, LAYER_WIRE, false );
else else
{ {
m_frame->PopTool( tool ); m_frame->PopTool( tool );
@ -458,7 +458,7 @@ void SCH_LINE_WIRE_BUS_TOOL::computeBreakPoint( const std::pair<SCH_LINE*, SCH_L
} }
int SCH_LINE_WIRE_BUS_TOOL::doDrawSegments( const std::string& aTool, int aType ) int SCH_LINE_WIRE_BUS_TOOL::doDrawSegments( const std::string& aTool, int aType, bool aQuitOnDraw )
{ {
SCH_SCREEN* screen = m_frame->GetScreen(); SCH_SCREEN* screen = m_frame->GetScreen();
EE_POINT_EDITOR* pointEditor = m_toolMgr->GetTool<EE_POINT_EDITOR>(); EE_POINT_EDITOR* pointEditor = m_toolMgr->GetTool<EE_POINT_EDITOR>();
@ -561,6 +561,12 @@ int SCH_LINE_WIRE_BUS_TOOL::doDrawSegments( const std::string& aTool, int aType
{ {
finishSegments(); finishSegments();
segment = nullptr; 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(); finishSegments();
segment = nullptr; segment = nullptr;
if( aQuitOnDraw )
{
m_frame->PopTool( aTool );
break;
}
} }
else else
{ {
@ -614,6 +626,12 @@ int SCH_LINE_WIRE_BUS_TOOL::doDrawSegments( const std::string& aTool, int aType
finishSegments(); finishSegments();
segment = nullptr; 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; return 0;
} }
void SCH_LINE_WIRE_BUS_TOOL::setTransitions() void SCH_LINE_WIRE_BUS_TOOL::setTransitions()
{ {
Go( &SCH_LINE_WIRE_BUS_TOOL::AddJunctionsIfNeeded, EE_ACTIONS::addNeededJunctions.MakeEvent() ); Go( &SCH_LINE_WIRE_BUS_TOOL::AddJunctionsIfNeeded, EE_ACTIONS::addNeededJunctions.MakeEvent() );

View File

@ -60,6 +60,12 @@ struct BUS_UNFOLDING_T
}; };
struct DRAW_SEGMENT_EVENT_PARAMS
{
SCH_LAYER_ID layer;
bool quitOnDraw;
};
/** /**
* SCH_LINE_DRAWING_TOOL * SCH_LINE_DRAWING_TOOL
* *
@ -90,7 +96,7 @@ public:
int AddJunctionsIfNeeded( const TOOL_EVENT& aEvent ); int AddJunctionsIfNeeded( const TOOL_EVENT& aEvent );
private: 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* startSegments( int aType, const VECTOR2D& aPos );
SCH_LINE* doUnfoldBus( const wxString& aNet ); SCH_LINE* doUnfoldBus( const wxString& aNet );
void finishSegments(); void finishSegments();