diff --git a/eeschema/dialogs/dialog_choose_component.cpp b/eeschema/dialogs/dialog_choose_component.cpp index fd7c20a131..ea9e266836 100644 --- a/eeschema/dialogs/dialog_choose_component.cpp +++ b/eeschema/dialogs/dialog_choose_component.cpp @@ -42,10 +42,12 @@ #include #include -#define SYM_CHOOSER_HSASH wxT( "SymbolChooserHSashPosition" ) -#define SYM_CHOOSER_VSASH wxT( "SymbolChooserVSashPosition" ) -#define SYM_CHOOSER_WIDTH_KEY wxT( "SymbolChooserWidth" ) -#define SYM_CHOOSER_HEIGHT_KEY wxT( "SymbolChooserHeight" ) +#define SYM_CHOOSER_HSASH wxT( "SymbolChooserHSashPosition" ) +#define SYM_CHOOSER_VSASH wxT( "SymbolChooserVSashPosition" ) +#define SYM_CHOOSER_WIDTH_KEY wxT( "SymbolChooserWidth" ) +#define SYM_CHOOSER_HEIGHT_KEY wxT( "SymbolChooserHeight" ) +#define SYM_CHOOSER_KEEP_SYM_KEY wxT( "SymbolChooserKeepSymbol" ) +#define SYM_CHOOSER_USE_UNITS_KEY wxT( "SymbolChooserUseUnits" ) std::mutex DIALOG_CHOOSE_COMPONENT::g_Mutex; @@ -206,6 +208,9 @@ DIALOG_CHOOSE_COMPONENT::~DIALOG_CHOOSE_COMPONENT() m_config->Write( SYM_CHOOSER_WIDTH_KEY, GetSize().x ); m_config->Write( SYM_CHOOSER_HEIGHT_KEY, GetSize().y ); + m_config->Write( SYM_CHOOSER_KEEP_SYM_KEY, m_keepSymbol->GetValue() ); + m_config->Write( SYM_CHOOSER_USE_UNITS_KEY, m_useUnits->GetValue() ); + m_config->Write( SYM_CHOOSER_HSASH, m_hsplitter->GetSashPosition() ); if( m_vsplitter ) @@ -247,6 +252,27 @@ wxPanel* DIALOG_CHOOSE_COMPONENT::ConstructRightPanel( wxWindow* aParent ) sizer->Add( m_symbol_preview, 1, wxEXPAND | wxTOP | wxRIGHT, 5 ); } + m_keepSymbol = new wxCheckBox( panel, 1000, _("Multi-Symbol Placement"), wxDefaultPosition, + wxDefaultSize, wxALIGN_RIGHT ); + m_keepSymbol->SetValue( m_config->ReadBool( SYM_CHOOSER_KEEP_SYM_KEY, false ) ); + m_keepSymbol->SetToolTip( _( "Place multiple copies of the symbol." ) ); + + m_useUnits = new wxCheckBox( panel, 1000, _("Place all units"), wxDefaultPosition, + wxDefaultSize, wxALIGN_RIGHT ); + m_useUnits->SetValue( m_config->ReadBool( SYM_CHOOSER_USE_UNITS_KEY, true ) ); + m_useUnits->SetToolTip( _( "Sequentially place all units of the symbol." ) ); + + auto fgSizer = new wxFlexGridSizer( 0, 2, 0, 1 ); + fgSizer->AddGrowableCol( 0 ); + fgSizer->SetFlexibleDirection( wxBOTH ); + fgSizer->SetNonFlexibleGrowMode( wxFLEX_GROWMODE_SPECIFIED ); + + fgSizer->Add( 0, 0, 1, wxEXPAND ); + fgSizer->Add( m_keepSymbol, 0, wxALIGN_CENTER_VERTICAL|wxALIGN_RIGHT|wxBOTTOM|wxRIGHT|wxLEFT, 5 ); + fgSizer->Add( 0, 0, 1, wxEXPAND ); + fgSizer->Add( m_useUnits, 0, wxALIGN_CENTER_VERTICAL|wxALIGN_RIGHT|wxBOTTOM|wxRIGHT|wxLEFT, 5 ); + + sizer->Add( fgSizer, 0, wxALL | wxEXPAND, 5 ); panel->SetSizer( sizer ); panel->Layout(); sizer->Fit( panel ); diff --git a/eeschema/dialogs/dialog_choose_component.h b/eeschema/dialogs/dialog_choose_component.h index 429a94a3a2..3186bae98c 100644 --- a/eeschema/dialogs/dialog_choose_component.h +++ b/eeschema/dialogs/dialog_choose_component.h @@ -122,6 +122,25 @@ public: */ LIB_ID GetSelectedLibId( int* aUnit = nullptr ) const; + /** + * To be called after this dialog returns from ShowModal() + * + * In the case of multi-unit symbols, this preferences asks to iterate through + * all units of the symbol, one per click + * @return The value of the dialog preference checkbox + */ + bool GetUseAllUnits() const { return m_useUnits->GetValue(); } + + /** + * To be called after this dialog returns from ShowModal() + * + * Keeps a new copy of the symbol on the mouse cursor, allowing the user to rapidly + * place multiple copies of the same symbol on their schematic + * + * @return The value of the keep symbol preference checkbox + */ + bool GetKeepSymbol() const { return m_keepSymbol->GetValue(); } + /** * Get a list of fields edited by the user. * @return vector of pairs; each.first = field ID, each.second = new value @@ -191,6 +210,8 @@ protected: FOOTPRINT_SELECT_WIDGET* m_fp_sel_ctrl; FOOTPRINT_PREVIEW_WIDGET* m_fp_preview; + wxCheckBox* m_keepSymbol; + wxCheckBox* m_useUnits; LIB_TREE* m_tree; wxHtmlWindow* m_details; diff --git a/eeschema/getpart.cpp b/eeschema/getpart.cpp index dd13e9287f..e951fabd4f 100644 --- a/eeschema/getpart.cpp +++ b/eeschema/getpart.cpp @@ -181,6 +181,9 @@ SCH_BASE_FRAME::COMPONENT_SELECTION SCH_BASE_FRAME::SelectCompFromLibTree( // but no symbol selected return COMPONENT_SELECTION(); + SetUseAllUnits( dlg.GetUseAllUnits() ); + SetRepeatComponent( dlg.GetKeepSymbol() ); + if( sel.Unit == 0 ) sel.Unit = 1; diff --git a/eeschema/sch_base_frame.cpp b/eeschema/sch_base_frame.cpp index b5aec87450..f15f77e132 100644 --- a/eeschema/sch_base_frame.cpp +++ b/eeschema/sch_base_frame.cpp @@ -97,6 +97,8 @@ SCH_BASE_FRAME::SCH_BASE_FRAME( KIWAY* aKiway, wxWindow* aParent, FRAME_T aWindo m_repeatStep = wxPoint( DEFAULT_REPEAT_OFFSET_X, DEFAULT_REPEAT_OFFSET_Y ); m_repeatDeltaLabel = DEFAULT_REPEAT_LABEL_INC; m_showPinElectricalTypeName = false; + m_repeatComponent = false; + m_useAllUnits = false; } diff --git a/eeschema/sch_base_frame.h b/eeschema/sch_base_frame.h index 8b27f0cc94..d9067a1470 100644 --- a/eeschema/sch_base_frame.h +++ b/eeschema/sch_base_frame.h @@ -93,6 +93,9 @@ protected: bool m_showPinElectricalTypeName; bool m_dragActionIsMove; // drag action defaults to move, otherwise it's drag + bool m_repeatComponent; // After placing one component, reload a sequential + bool m_useAllUnits; // After placing unit A, place unit B of the same + public: SCH_BASE_FRAME( KIWAY* aKiway, wxWindow* aParent, FRAME_T aWindowType, @@ -147,6 +150,28 @@ public: */ void SetRepeatDeltaLabel( int aDelta ) { m_repeatDeltaLabel = aDelta; } + /** + * @return the current setting of placing copies of the same symbol for each click + */ + const bool GetRepeatComponent() { return m_repeatComponent; } + + /** + * If true, keep placing new copies of the same symbol on each click + * @param aRepeat True to repeat the same symbol, False to only set one + */ + void SetRepeatComponent( bool aRepeat ) { m_repeatComponent = aRepeat; } + + /** + * @return the current setting to use all units when placing a component + */ + const bool GetUseAllUnits() { return m_useAllUnits; } + + /** + * Sets whether to utilize all units of a component when placing + * @param aUseAll True to iterate through Units A, B, ... + */ + void SetUseAllUnits( bool aUseAll ) { m_useAllUnits = aUseAll; } + /** * Function GetZoomLevelIndicator diff --git a/eeschema/tools/sch_drawing_tools.cpp b/eeschema/tools/sch_drawing_tools.cpp index e2945d54a2..471c7b5702 100644 --- a/eeschema/tools/sch_drawing_tools.cpp +++ b/eeschema/tools/sch_drawing_tools.cpp @@ -188,10 +188,38 @@ int SCH_DRAWING_TOOLS::PlaceComponent( const TOOL_EVENT& aEvent ) } else { - m_frame->AddItemToScreenAndUndoList( component ); - component = nullptr; + SCH_COMPONENT* next_comp = nullptr; m_view->ClearPreview(); + m_frame->AddItemToScreenAndUndoList( component ); + + if( m_frame->GetUseAllUnits() || m_frame->GetRepeatComponent() ) + { + int new_unit = component->GetUnit(); + + if( m_frame->GetUseAllUnits() + && component->GetUnit() < component->GetUnitCount() ) + new_unit++; + else + new_unit = 1; + + // We are either stepping to the next unit or next component + if( m_frame->GetRepeatComponent() || new_unit > 1 ) + { + next_comp = static_cast( component->Duplicate() ); + next_comp->SetFlags( IS_NEW | IS_MOVED ); + next_comp->SetUnit( new_unit ); + + if( m_frame->GetAutoplaceFields() ) + component->AutoplaceFields( /* aScreen */ NULL, /* aManual */ false ); + + m_frame->SaveCopyForRepeatItem( next_comp ); + m_view->AddToPreview( next_comp->Clone() ); + m_selectionTool->AddItemToSel( next_comp ); + } + } + + component = next_comp; } } else if( evt->IsClick( BUT_RIGHT ) )