Browse Source

groups: commonize group tool

revert-0c36e162
Mike Williams 8 months ago
parent
commit
0c0dbc6271
  1. 1
      common/CMakeLists.txt
  2. 40
      common/dialogs/dialog_group_properties.cpp
  3. 4
      common/dialogs/dialog_group_properties.h
  4. 232
      common/tool/group_tool.cpp
  5. 41
      common/tool/group_tool.h
  6. 3
      eeschema/sch_item.h
  7. 8
      eeschema/tools/sch_edit_tool.cpp
  8. 4
      include/board_item.h
  9. 3
      include/eda_item.h
  10. 3
      include/tool/selection_tool.h
  11. 2
      pcbnew/CMakeLists.txt
  12. 29
      pcbnew/board.cpp
  13. 14
      pcbnew/board.h
  14. 1
      pcbnew/board_commit.cpp
  15. 3
      pcbnew/edit.cpp
  16. 4
      pcbnew/footprint_edit_frame.cpp
  17. 3
      pcbnew/footprint_editor_utils.cpp
  18. 4
      pcbnew/pcb_edit_frame.cpp
  19. 386
      pcbnew/tools/group_tool.cpp
  20. 192
      pcbnew/tools/pcb_group_tool.cpp
  21. 17
      pcbnew/tools/pcb_group_tool.h
  22. 4
      pcbnew/tools/pcb_selection_tool.h

1
common/CMakeLists.txt

@ -665,6 +665,7 @@ set( COMMON_SRCS
tool/embed_tool.cpp
tool/grid_helper.cpp
tool/grid_menu.cpp
tool/group_tool.cpp
tool/library_editor_control.cpp
tool/picker_tool.cpp
tool/point_editor_behavior.cpp

40
common/dialogs/dialog_group_properties.cpp

@ -22,40 +22,33 @@
*/
#include <tool/tool_manager.h>
#include <tools/pcb_actions.h>
#include <tools/pcb_picker_tool.h>
#include <pcb_base_edit_frame.h>
#include <pcb_group.h>
#include <tool/actions.h>
#include <eda_draw_frame.h>
#include <eda_group.h>
#include <status_popup.h>
#include <board_commit.h>
#include <commit.h>
#include <bitmaps.h>
#include <widgets/std_bitmap_button.h>
#include <dialogs/dialog_group_properties.h>
DIALOG_GROUP_PROPERTIES::DIALOG_GROUP_PROPERTIES( EDA_DRAW_FRAME* aParent,
EDA_GROUP* aGroup ) :
EDA_GROUP* aGroup,
COMMIT& aCommit ) :
DIALOG_GROUP_PROPERTIES_BASE( aParent ),
m_frame( aParent ),
m_toolMgr( aParent->GetToolManager() ),
m_group( aGroup )
m_group( aGroup ),
m_commit( aCommit )
{
m_bpAddMember->SetBitmap( KiBitmapBundle( BITMAPS::small_plus ) );
m_bpRemoveMember->SetBitmap( KiBitmapBundle( BITMAPS::small_trash ) );
m_nameCtrl->SetValue( m_group->GetName() );
m_locked->SetValue( aGroup->AsEdaItem()->IsLocked() );
if( aGroup->AsEdaItem()->Type() == PCB_GROUP_T )
{
m_locked->SetValue( static_cast<PCB_GROUP*>( aGroup )->IsLocked() );
m_locked->Show( dynamic_cast<PCB_EDIT_FRAME*>( aParent ) != nullptr );
}
else
{
m_locked->SetValue( false );
if( aGroup->AsEdaItem()->Type() != PCB_GROUP_T )
m_locked->Hide();
}
for( EDA_ITEM* item : m_group->GetItems() )
m_membersList->Append( item->GetItemDescription( m_frame, true ), item );
@ -89,8 +82,7 @@ bool DIALOG_GROUP_PROPERTIES::TransferDataToWindow()
bool DIALOG_GROUP_PROPERTIES::TransferDataFromWindow()
{
BOARD_COMMIT commit( m_frame );
commit.Modify( m_group->AsEdaItem() );
m_commit.Modify( m_group->AsEdaItem() );
for( size_t ii = 0; ii < m_membersList->GetCount(); ++ii )
{
@ -99,19 +91,15 @@ bool DIALOG_GROUP_PROPERTIES::TransferDataFromWindow()
if( existingGroup != m_group )
{
commit.Modify( item );
m_commit.Modify( item );
if( existingGroup )
commit.Modify( existingGroup->AsEdaItem() );
m_commit.Modify( existingGroup->AsEdaItem() );
}
}
m_group->SetName( m_nameCtrl->GetValue() );
if( m_group->AsEdaItem()->Type() == PCB_GROUP_T )
{
static_cast<PCB_GROUP*>( m_group )->SetLocked( m_locked->GetValue() );
}
m_group->AsEdaItem()->SetLocked( m_locked->GetValue() );
m_toolMgr->RunAction( ACTIONS::selectionClear );
m_group->RemoveAll();
@ -124,7 +112,7 @@ bool DIALOG_GROUP_PROPERTIES::TransferDataFromWindow()
m_toolMgr->RunAction<EDA_ITEM*>( ACTIONS::selectItem, m_group->AsEdaItem() );
commit.Push( _( "Edit Group Properties" ) );
m_commit.Push( _( "Edit Group Properties" ) );
return true;
}

4
common/dialogs/dialog_group_properties.h

@ -30,12 +30,13 @@ class EDA_DRAW_FRAME;
class TOOL_MANAGER;
class EDA_GROUP;
class EDA_ITEM;
class COMMIT;
class DIALOG_GROUP_PROPERTIES : public DIALOG_GROUP_PROPERTIES_BASE
{
public:
DIALOG_GROUP_PROPERTIES( EDA_DRAW_FRAME* aParent, EDA_GROUP* aTarget );
DIALOG_GROUP_PROPERTIES( EDA_DRAW_FRAME* aParent, EDA_GROUP* aTarget, COMMIT& aCommit );
~DIALOG_GROUP_PROPERTIES() override;
void OnMemberSelected( wxCommandEvent& event ) override;
@ -51,6 +52,7 @@ private:
EDA_DRAW_FRAME* m_frame;
TOOL_MANAGER* m_toolMgr;
EDA_GROUP* m_group;
COMMIT& m_commit;
};
#endif // DIALOG_GROUP_PROPERTIES_H

232
common/tool/group_tool.cpp

@ -0,0 +1,232 @@
/*
* This program source code file is part of KiCad, a free EDA CAD application.
*
* Copyright The KiCad Developers, see AUTHORS.txt for contributors.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, you may find one here:
* http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
* or you may search the http://www.gnu.org website for the version 2 license,
* or you may write to the Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
*/
#include <eda_draw_frame.h>
#include <kiplatform/ui.h>
#include <tool/actions.h>
#include <tool/tool_manager.h>
#include <tool/picker_tool.h>
#include <tool/group_tool.h>
#include <tool/selection.h>
#include <status_popup.h>
#include <commit.h>
#include <bitmaps.h>
#include <dialogs/dialog_group_properties.h>
#include <eda_group.h>
class GROUP_CONTEXT_MENU : public ACTION_MENU
{
public:
GROUP_CONTEXT_MENU() : ACTION_MENU( true )
{
SetIcon( BITMAPS::group ); // fixme
SetTitle( _( "Grouping" ) );
Add( ACTIONS::group );
Add( ACTIONS::ungroup );
Add( ACTIONS::removeFromGroup );
}
ACTION_MENU* create() const override
{
GROUP_CONTEXT_MENU* menu = new GROUP_CONTEXT_MENU();
menu->SetSelectionTool( m_selectionTool );
return menu;
}
void SetSelectionTool( SELECTION_TOOL* aTool ) { m_selectionTool = aTool; }
private:
void update() override
{
bool canGroup = false;
bool hasGroup = false;
bool hasMember = false;
if( m_selectionTool != nullptr )
{
for( EDA_ITEM* item : m_selectionTool->GetSelection() )
{
canGroup = true;
if( item->Type() == PCB_GROUP_T || item->Type() == SCH_GROUP_T )
hasGroup = true;
if( item->GetParentGroup() )
hasMember = true;
}
}
Enable( ACTIONS::group.GetUIId(), canGroup );
Enable( ACTIONS::ungroup.GetUIId(), hasGroup );
Enable( ACTIONS::removeFromGroup.GetUIId(), hasMember );
}
private:
SELECTION_TOOL* m_selectionTool = nullptr;
};
GROUP_TOOL::GROUP_TOOL() : TOOL_INTERACTIVE( "common.Groups" )
{
}
void GROUP_TOOL::Reset( RESET_REASON aReason )
{
m_frame = getEditFrame<EDA_DRAW_FRAME>();
if( aReason != RUN )
m_commit = createCommit();
}
bool GROUP_TOOL::Init()
{
m_frame = getEditFrame<EDA_DRAW_FRAME>();
// Find the selection tool, so they can cooperate
m_selectionTool = static_cast<SELECTION_TOOL*>( m_toolMgr->FindTool( "common.InteractiveSelection" ) );
wxCHECK( m_selectionTool, false );
TOOL_MENU& selToolMenu = m_selectionTool->GetToolMenu();
std::shared_ptr<GROUP_CONTEXT_MENU> groupMenu = std::make_shared<GROUP_CONTEXT_MENU>();
groupMenu->SetTool( this );
groupMenu->SetSelectionTool( m_selectionTool );
selToolMenu.RegisterSubMenu( groupMenu );
selToolMenu.GetMenu().AddMenu( groupMenu.get(), SELECTION_CONDITIONS::NotEmpty, 100 );
return true;
}
int GROUP_TOOL::GroupProperties( const TOOL_EVENT& aEvent )
{
EDA_GROUP* group = aEvent.Parameter<EDA_GROUP*>();
if( m_propertiesDialog )
m_propertiesDialog->Destroy();
m_propertiesDialog = new DIALOG_GROUP_PROPERTIES( m_frame, group, *m_commit );
m_propertiesDialog->Show( true );
return 0;
}
int GROUP_TOOL::Ungroup( const TOOL_EVENT& aEvent )
{
const SELECTION& selection = m_selectionTool->GetSelection();
EDA_ITEMS toSelect;
if( selection.Empty() )
m_toolMgr->RunAction( ACTIONS::selectionCursor );
SELECTION selCopy = selection;
m_toolMgr->RunAction( ACTIONS::selectionClear );
for( EDA_ITEM* item : selCopy )
{
EDA_GROUP* group = dynamic_cast<EDA_GROUP*>( item );
if( group )
{
for( EDA_ITEM* member : group->GetItems() )
{
m_commit->Stage( member, CHT_UNGROUP );
toSelect.push_back( member );
}
group->AsEdaItem()->SetSelected();
m_commit->Remove( group->AsEdaItem() );
}
}
m_commit->Push( _( "Ungroup Items" ) );
m_toolMgr->RunAction<EDA_ITEMS*>( ACTIONS::selectItems, &toSelect );
m_toolMgr->PostEvent( EVENTS::SelectedItemsModified );
m_frame->OnModify();
return 0;
}
int GROUP_TOOL::RemoveFromGroup( const TOOL_EVENT& aEvent )
{
const SELECTION& selection = m_selectionTool->GetSelection();
if( selection.Empty() )
m_toolMgr->RunAction( ACTIONS::selectionCursor );
for( EDA_ITEM* item : selection )
{
if( item->GetParentGroup() )
m_commit->Stage( item, CHT_UNGROUP );
}
m_commit->Push( _( "Remove Group Items" ) );
m_toolMgr->PostEvent( EVENTS::SelectedItemsModified );
m_frame->OnModify();
return 0;
}
int GROUP_TOOL::EnterGroup( const TOOL_EVENT& aEvent )
{
const SELECTION& selection = m_selectionTool->GetSelection();
if( selection.GetSize() == 1 &&
(selection[0]->Type() == SCH_GROUP_T || selection[0]->Type() == PCB_GROUP_T) )
{
m_selectionTool->EnterGroup();
}
return 0;
}
int GROUP_TOOL::LeaveGroup( const TOOL_EVENT& aEvent )
{
m_selectionTool->ExitGroup( true /* Select the group */ );
return 0;
}
void GROUP_TOOL::setTransitions()
{
Go( &GROUP_TOOL::GroupProperties, ACTIONS::groupProperties.MakeEvent() );
Go( &GROUP_TOOL::PickNewMember, ACTIONS::pickNewGroupMember.MakeEvent() );
Go( &GROUP_TOOL::Group, ACTIONS::group.MakeEvent() );
Go( &GROUP_TOOL::Ungroup, ACTIONS::ungroup.MakeEvent() );
Go( &GROUP_TOOL::RemoveFromGroup, ACTIONS::removeFromGroup.MakeEvent() );
Go( &GROUP_TOOL::EnterGroup, ACTIONS::groupEnter.MakeEvent() );
Go( &GROUP_TOOL::LeaveGroup, ACTIONS::groupLeave.MakeEvent() );
}

41
pcbnew/tools/group_tool.h → common/tool/group_tool.h

@ -24,17 +24,12 @@
#ifndef GROUP_TOOL_H
#define GROUP_TOOL_H
#include <math/vector2d.h>
#include <tools/pcb_tool_base.h>
#include "pcb_selection_tool.h"
#include "dialogs/dialog_group_properties_base.h"
class BOARD_COMMIT;
class BOARD_ITEM;
class PCB_SELECTION_TOOL;
#include <tool/selection_tool.h>
class COMMIT;
class DIALOG_GROUP_PROPERTIES;
class GROUP_TOOL : public PCB_TOOL_BASE
class GROUP_TOOL : public TOOL_INTERACTIVE
{
public:
GROUP_TOOL();
@ -44,36 +39,40 @@ public:
/// @copydoc TOOL_BASE::Init()
bool Init() override;
int GroupProperties( const TOOL_EVENT& aEvent );
virtual int GroupProperties( const TOOL_EVENT& aEvent );
/**
* Invoke the picker tool to select a new member of the group.
*/
int PickNewMember( const TOOL_EVENT& aEvent );
virtual int PickNewMember( const TOOL_EVENT& aEvent ) = 0;
///< Group selected items.
int Group( const TOOL_EVENT& aEvent );
virtual int Group( const TOOL_EVENT& aEvent ) = 0;
///< Ungroup selected items.
int Ungroup( const TOOL_EVENT& aEvent );
virtual int Ungroup( const TOOL_EVENT& aEvent );
///< Remove selection from group.
int RemoveFromGroup( const TOOL_EVENT& aEvent );
virtual int RemoveFromGroup( const TOOL_EVENT& aEvent );
///< Restrict selection to only member of the group.
int EnterGroup( const TOOL_EVENT& aEvent );
virtual int EnterGroup( const TOOL_EVENT& aEvent );
///< Leave the current group (deselect its members and select the group as a whole).
int LeaveGroup( const TOOL_EVENT& aEvent );
virtual int LeaveGroup( const TOOL_EVENT& aEvent );
private:
protected:
///< Set up handlers for various events.
void setTransitions() override;
PCB_BASE_EDIT_FRAME* m_frame;
DIALOG_GROUP_PROPERTIES* m_propertiesDialog;
PCB_SELECTION_TOOL* m_selectionTool;
std::unique_ptr<BOARD_COMMIT> m_commit;
///< Subclasses implement to provide correct *_COMMIT object type
virtual std::unique_ptr<COMMIT> createCommit() = 0;
EDA_DRAW_FRAME* m_frame = nullptr;
DIALOG_GROUP_PROPERTIES* m_propertiesDialog = nullptr;
SELECTION_TOOL* m_selectionTool = nullptr;
std::unique_ptr<COMMIT> m_commit = nullptr;
bool m_isFootprintEditor = false;
};
#endif

3
eeschema/sch_item.h

@ -277,9 +277,6 @@ public:
const SYMBOL* GetParentSymbol() const;
SYMBOL* GetParentSymbol();
virtual bool IsLocked() const { return false; }
virtual void SetLocked( bool aLocked ) {}
/**
* Allow items to support hypertext actions when hovered/clicked.
*/

8
eeschema/tools/sch_edit_tool.cpp

@ -38,6 +38,7 @@
#include <sch_bitmap.h>
#include <sch_bus_entry.h>
#include <sch_commit.h>
#include <sch_group.h>
#include <sch_junction.h>
#include <sch_marker.h>
#include <sch_rule_area.h>
@ -414,6 +415,7 @@ bool SCH_EDIT_TOOL::Init()
case SCH_FIELD_T:
case SCH_SHAPE_T:
case SCH_BITMAP_T:
case SCH_GROUP_T:
return aSel.GetSize() == 1;
case SCH_LINE_T:
@ -2397,6 +2399,12 @@ int SCH_EDIT_TOOL::Properties( const TOOL_EVENT& aEvent )
case SCH_PIN_T:
break;
case SCH_GROUP_T:
m_toolMgr->RunAction( ACTIONS::groupProperties,
static_cast<EDA_GROUP*>( static_cast<SCH_GROUP*>( curr_item ) ) );
break;
default: // Unexpected item
wxFAIL_MSG( wxString( "Cannot edit schematic item type " ) + curr_item->GetClass() );
}

4
include/board_item.h

@ -316,8 +316,8 @@ public:
virtual bool IsKnockout() const { return m_isKnockout; }
virtual void SetIsKnockout( bool aKnockout ) { m_isKnockout = aKnockout; }
virtual bool IsLocked() const;
virtual void SetLocked( bool aLocked ) { m_isLocked = aLocked; }
bool IsLocked() const override;
void SetLocked( bool aLocked ) override { m_isLocked = aLocked; }
virtual void StyleFromSettings( const BOARD_DESIGN_SETTINGS& settings ) { }

3
include/eda_item.h

@ -113,6 +113,9 @@ public:
virtual void SetParentGroup( EDA_GROUP* aGroup ) { m_group = aGroup; }
EDA_GROUP* GetParentGroup() const { return m_group; }
virtual bool IsLocked() const { return false; }
virtual void SetLocked( bool aLocked ) {}
inline bool IsModified() const { return m_flags & IS_CHANGED; }
inline bool IsNew() const { return m_flags & IS_NEW; }
inline bool IsMoving() const { return m_flags & IS_MOVING; }

3
include/tool/selection_tool.h

@ -77,6 +77,9 @@ public:
SELECTION& GetSelection() { return selection(); }
virtual void EnterGroup() {}
virtual void ExitGroup( bool aSelectGroup = false ) {}
protected:
/**
* Return a reference to the selection.

2
pcbnew/CMakeLists.txt

@ -391,13 +391,13 @@ set( PCBNEW_CLASS_SRCS
tools/edit_tool_move_fct.cpp
tools/pcb_edit_table_tool.cpp
tools/global_edit_tool.cpp
tools/group_tool.cpp
tools/footprint_editor_control.cpp
tools/footprint_chooser_selection_tool.cpp
tools/item_modification_routine.cpp
tools/pad_tool.cpp
tools/pcb_control.cpp
tools/pcb_design_block_control.cpp
tools/pcb_group_tool.cpp
tools/pcb_picker_tool.cpp
tools/pcb_selection.cpp
tools/pcb_selection_conditions.cpp

29
pcbnew/board.cpp

@ -2855,35 +2855,6 @@ wxString BOARD::GroupsSanityCheckInternal( bool repair )
}
BOARD::GroupLegalOpsField BOARD::GroupLegalOps( const PCB_SELECTION& selection ) const
{
bool hasGroup = false;
bool hasMember = false;
for( EDA_ITEM* item : selection )
{
if( item->IsBOARD_ITEM() )
{
BOARD_ITEM* board_item = static_cast<BOARD_ITEM*>( item );
if( board_item->Type() == PCB_GROUP_T )
hasGroup = true;
if( board_item->GetParentGroup() )
hasMember = true;
}
}
GroupLegalOpsField legalOps;
legalOps.create = true;
legalOps.removeItems = hasMember;
legalOps.ungroup = hasGroup;
return legalOps;
}
bool BOARD::cmp_items::operator() ( const BOARD_ITEM* a, const BOARD_ITEM* b ) const
{
if( a->Type() != b->Type() )

14
pcbnew/board.h

@ -1264,20 +1264,6 @@ public:
*/
wxString GroupsSanityCheckInternal( bool repair );
struct GroupLegalOpsField
{
bool create : 1;
bool ungroup : 1;
bool removeItems : 1;
};
/**
* Check which selection tool group operations are legal given the selection.
*
* @return bit field of legal ops.
*/
GroupLegalOpsField GroupLegalOps( const PCB_SELECTION& selection ) const;
bool LegacyTeardrops() const { return m_legacyTeardrops; }
void SetLegacyTeardrops( bool aFlag ) { m_legacyTeardrops = aFlag; }

1
pcbnew/board_commit.cpp

@ -23,7 +23,6 @@
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
*/
#include "thread_pool.h"
#include <macros.h>
#include <board.h>
#include <footprint.h>

3
pcbnew/edit.cpp

@ -155,7 +155,8 @@ void PCB_EDIT_FRAME::OnEditItemRequest( BOARD_ITEM* aItem )
break;
case PCB_GROUP_T:
m_toolManager->RunAction( ACTIONS::groupProperties, static_cast<PCB_GROUP*>( aItem ) );
m_toolManager->RunAction( ACTIONS::groupProperties,
static_cast<EDA_GROUP*>( static_cast<PCB_GROUP*>( aItem ) ) );
break;
case PCB_GENERATOR_T:

4
pcbnew/footprint_edit_frame.cpp

@ -66,7 +66,7 @@
#include <tools/pcb_grid_helper.h>
#include <tools/pcb_editor_conditions.h>
#include <tools/pcb_viewer_tools.h>
#include <tools/group_tool.h>
#include <tools/pcb_group_tool.h>
#include <tools/position_relative_tool.h>
#include <widgets/appearance_controls.h>
#include <widgets/lib_tree.h>
@ -1197,7 +1197,7 @@ void FOOTPRINT_EDIT_FRAME::setupTools()
m_toolManager->RegisterTool( new POSITION_RELATIVE_TOOL );
m_toolManager->RegisterTool( new ARRAY_TOOL );
m_toolManager->RegisterTool( new PCB_VIEWER_TOOLS );
m_toolManager->RegisterTool( new GROUP_TOOL );
m_toolManager->RegisterTool( new PCB_GROUP_TOOL );
m_toolManager->RegisterTool( new CONVERT_TOOL );
m_toolManager->RegisterTool( new SCRIPTING_TOOL );
m_toolManager->RegisterTool( new PROPERTIES_TOOL );

3
pcbnew/footprint_editor_utils.cpp

@ -244,7 +244,8 @@ void FOOTPRINT_EDIT_FRAME::OnEditItemRequest( BOARD_ITEM* aItem )
}
case PCB_GROUP_T:
m_toolManager->RunAction( ACTIONS::groupProperties, static_cast<PCB_GROUP*>( aItem ) );
m_toolManager->RunAction( ACTIONS::groupProperties,
static_cast<EDA_GROUP*>( static_cast<PCB_GROUP*>( aItem ) ) );
break;
case PCB_MARKER_T:

4
pcbnew/pcb_edit_frame.cpp

@ -74,7 +74,7 @@
#include <tools/pcb_point_editor.h>
#include <tools/edit_tool.h>
#include <tools/pcb_edit_table_tool.h>
#include <tools/group_tool.h>
#include <tools/pcb_group_tool.h>
#include <tools/generator_tool.h>
#include <tools/drc_tool.h>
#include <tools/global_edit_tool.h>
@ -776,7 +776,7 @@ void PCB_EDIT_FRAME::setupTools()
m_toolManager->RegisterTool( new DRC_TOOL );
m_toolManager->RegisterTool( new PCB_VIEWER_TOOLS );
m_toolManager->RegisterTool( new CONVERT_TOOL );
m_toolManager->RegisterTool( new GROUP_TOOL );
m_toolManager->RegisterTool( new PCB_GROUP_TOOL );
m_toolManager->RegisterTool( new GENERATOR_TOOL );
m_toolManager->RegisterTool( new SCRIPTING_TOOL );
m_toolManager->RegisterTool( new PROPERTIES_TOOL );

386
pcbnew/tools/group_tool.cpp

@ -1,386 +0,0 @@
/*
* This program source code file is part of KiCad, a free EDA CAD application.
*
* Copyright The KiCad Developers, see AUTHORS.txt for contributors.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, you may find one here:
* http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
* or you may search the http://www.gnu.org website for the version 2 license,
* or you may write to the Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
*/
#include <kiplatform/ui.h>
#include <tool/tool_manager.h>
#include <tools/pcb_actions.h>
#include <tools/pcb_selection_tool.h>
#include <tools/group_tool.h>
#include <tools/pcb_picker_tool.h>
#include <status_popup.h>
#include <board_commit.h>
#include <bitmaps.h>
#include <dialogs/dialog_group_properties.h>
#include <pcb_group.h>
#include <collectors.h>
#include <footprint.h>
class GROUP_CONTEXT_MENU : public ACTION_MENU
{
public:
GROUP_CONTEXT_MENU( ) : ACTION_MENU( true )
{
SetIcon( BITMAPS::group ); // fixme
SetTitle( _( "Grouping" ) );
Add( ACTIONS::group );
Add( ACTIONS::ungroup );
Add( ACTIONS::removeFromGroup );
}
ACTION_MENU* create() const override
{
return new GROUP_CONTEXT_MENU();
}
private:
void update() override
{
PCB_SELECTION_TOOL* selTool = getToolManager()->GetTool<PCB_SELECTION_TOOL>();
BOARD* board = static_cast<BOARD*>( getToolManager()->GetModel() );
const auto& selection = selTool->GetSelection();
wxString check = board->GroupsSanityCheck();
wxCHECK_RET( check == wxEmptyString, _( "Group is in inconsistent state:" ) + wxS( " " ) + check );
BOARD::GroupLegalOpsField legalOps = board->GroupLegalOps( selection );
Enable( ACTIONS::group.GetUIId(), legalOps.create );
Enable( ACTIONS::ungroup.GetUIId(), legalOps.ungroup );
Enable( ACTIONS::removeFromGroup.GetUIId(), legalOps.removeItems );
}
};
GROUP_TOOL::GROUP_TOOL() :
PCB_TOOL_BASE( "pcbnew.Groups" ),
m_frame( nullptr ),
m_propertiesDialog( nullptr ),
m_selectionTool( nullptr )
{
}
void GROUP_TOOL::Reset( RESET_REASON aReason )
{
m_frame = getEditFrame<PCB_BASE_EDIT_FRAME>();
if( aReason != RUN )
m_commit = std::make_unique<BOARD_COMMIT>( this );
}
bool GROUP_TOOL::Init()
{
m_frame = getEditFrame<PCB_BASE_EDIT_FRAME>();
// Find the selection tool, so they can cooperate
m_selectionTool = m_toolMgr->GetTool<PCB_SELECTION_TOOL>();
// Add the group control menus to relevant other tools
if( m_selectionTool )
{
TOOL_MENU& selToolMenu = m_selectionTool->GetToolMenu();
std::shared_ptr<GROUP_CONTEXT_MENU> groupMenu = std::make_shared<GROUP_CONTEXT_MENU>();
groupMenu->SetTool( this );
selToolMenu.RegisterSubMenu( groupMenu );
selToolMenu.GetMenu().AddMenu( groupMenu.get(), SELECTION_CONDITIONS::NotEmpty, 100 );
}
return true;
}
int GROUP_TOOL::GroupProperties( const TOOL_EVENT& aEvent )
{
PCB_BASE_EDIT_FRAME* editFrame = getEditFrame<PCB_BASE_EDIT_FRAME>();
PCB_GROUP* group = aEvent.Parameter<PCB_GROUP*>();
if( m_propertiesDialog )
m_propertiesDialog->Destroy();
m_propertiesDialog = new DIALOG_GROUP_PROPERTIES( editFrame, group );
m_propertiesDialog->Show( true );
return 0;
}
int GROUP_TOOL::PickNewMember( const TOOL_EVENT& aEvent )
{
PCB_PICKER_TOOL* picker = m_toolMgr->GetTool<PCB_PICKER_TOOL>();
STATUS_TEXT_POPUP statusPopup( frame() );
bool done = false;
if( m_propertiesDialog )
m_propertiesDialog->Show( false );
Activate();
statusPopup.SetText( _( "Click on new member..." ) );
picker->SetClickHandler(
[&]( const VECTOR2D& aPoint ) -> bool
{
m_toolMgr->RunAction( ACTIONS::selectionClear );
const PCB_SELECTION& sel = m_selectionTool->RequestSelection(
[]( const VECTOR2I& aPt, GENERAL_COLLECTOR& aCollector,
PCB_SELECTION_TOOL* sTool )
{
} );
if( sel.Empty() )
return true; // still looking for an item
statusPopup.Hide();
if( m_propertiesDialog )
{
EDA_ITEM* elem = sel.Front();
if( !m_isFootprintEditor )
{
while( elem->GetParent() && elem->GetParent()->Type() != PCB_T )
elem = elem->GetParent();
}
m_propertiesDialog->DoAddMember( elem );
m_propertiesDialog->Show( true );
}
return false; // got our item; don't need any more
} );
picker->SetMotionHandler(
[&] ( const VECTOR2D& aPos )
{
statusPopup.Move( KIPLATFORM::UI::GetMousePosition() + wxPoint( 20, -50 ) );
} );
picker->SetCancelHandler(
[&]()
{
if( m_propertiesDialog )
m_propertiesDialog->Show( true );
statusPopup.Hide();
} );
picker->SetFinalizeHandler(
[&]( const int& aFinalState )
{
done = true;
} );
statusPopup.Move( KIPLATFORM::UI::GetMousePosition() + wxPoint( 20, -50 ) );
statusPopup.Popup();
canvas()->SetStatusPopup( statusPopup.GetPanel() );
m_toolMgr->RunAction( ACTIONS::pickerTool, &aEvent );
while( !done )
{
// Pass events unless we receive a null event, then we must shut down
if( TOOL_EVENT* evt = Wait() )
evt->SetPassEvent();
else
break;
}
canvas()->SetStatusPopup( nullptr );
return 0;
}
int GROUP_TOOL::Group( const TOOL_EVENT& aEvent )
{
PCB_SELECTION_TOOL* selTool = m_toolMgr->GetTool<PCB_SELECTION_TOOL>();
PCB_SELECTION selection;
if( m_isFootprintEditor )
{
selection = selTool->RequestSelection(
[]( const VECTOR2I& , GENERAL_COLLECTOR& aCollector, PCB_SELECTION_TOOL* )
{
} );
}
else
{
selection = selTool->RequestSelection(
[]( const VECTOR2I& , GENERAL_COLLECTOR& aCollector, PCB_SELECTION_TOOL* )
{
// Iterate from the back so we don't have to worry about removals.
for( int i = aCollector.GetCount() - 1; i >= 0; --i )
{
BOARD_ITEM* item = aCollector[ i ];
if( item->GetParentFootprint() )
aCollector.Remove( item );
}
} );
}
if( selection.Empty() )
return 0;
BOARD* board = getModel<BOARD>();
BOARD_COMMIT commit( m_toolMgr );
PCB_GROUP* group = nullptr;
if( m_isFootprintEditor )
group = new PCB_GROUP( board->GetFirstFootprint() );
else
group = new PCB_GROUP( board );
for( EDA_ITEM* eda_item : selection )
{
if( eda_item->IsBOARD_ITEM() )
{
if( static_cast<BOARD_ITEM*>( eda_item )->IsLocked() )
group->SetLocked( true );
}
}
commit.Add( group );
for( EDA_ITEM* eda_item : selection )
{
if( eda_item->IsBOARD_ITEM() )
commit.Stage( static_cast<BOARD_ITEM*>( eda_item ), CHT_GROUP );
}
commit.Push( _( "Group Items" ) );
selTool->ClearSelection();
selTool->select( group );
m_toolMgr->PostEvent( EVENTS::SelectedItemsModified );
m_frame->OnModify();
return 0;
}
int GROUP_TOOL::Ungroup( const TOOL_EVENT& aEvent )
{
const PCB_SELECTION& selection = m_toolMgr->GetTool<PCB_SELECTION_TOOL>()->GetSelection();
BOARD_COMMIT commit( m_toolMgr );
EDA_ITEMS toSelect;
if( selection.Empty() )
m_toolMgr->RunAction( ACTIONS::selectionCursor );
PCB_SELECTION selCopy = selection;
m_toolMgr->RunAction( ACTIONS::selectionClear );
for( EDA_ITEM* item : selCopy )
{
PCB_GROUP* group = dynamic_cast<PCB_GROUP*>( item );
if( group )
{
for( EDA_ITEM* member : group->GetItems() )
{
commit.Stage( member, CHT_UNGROUP );
toSelect.push_back( member );
}
group->SetSelected();
commit.Remove( group );
}
}
commit.Push( _( "Ungroup Items" ) );
m_toolMgr->RunAction<EDA_ITEMS*>( ACTIONS::selectItems, &toSelect );
m_toolMgr->PostEvent( EVENTS::SelectedItemsModified );
m_frame->OnModify();
return 0;
}
int GROUP_TOOL::RemoveFromGroup( const TOOL_EVENT& aEvent )
{
PCB_SELECTION_TOOL* selTool = m_toolMgr->GetTool<PCB_SELECTION_TOOL>();
const PCB_SELECTION& selection = selTool->GetSelection();
BOARD_COMMIT commit( m_frame );
if( selection.Empty() )
m_toolMgr->RunAction( ACTIONS::selectionCursor );
for( EDA_ITEM* item : selection )
{
BOARD_ITEM* boardItem = static_cast<BOARD_ITEM*>( item );
EDA_GROUP* group = boardItem->GetParentGroup();
if( group )
commit.Stage( boardItem, CHT_UNGROUP );
}
commit.Push( _( "Remove Group Items" ) );
m_toolMgr->PostEvent( EVENTS::SelectedItemsModified );
m_frame->OnModify();
return 0;
}
int GROUP_TOOL::EnterGroup( const TOOL_EVENT& aEvent )
{
PCB_SELECTION_TOOL* selTool = m_toolMgr->GetTool<PCB_SELECTION_TOOL>();
const PCB_SELECTION& selection = selTool->GetSelection();
if( selection.GetSize() == 1 && selection[0]->Type() == PCB_GROUP_T )
selTool->EnterGroup();
return 0;
}
int GROUP_TOOL::LeaveGroup( const TOOL_EVENT& aEvent )
{
m_toolMgr->GetTool<PCB_SELECTION_TOOL>()->ExitGroup( true /* Select the group */ );
return 0;
}
void GROUP_TOOL::setTransitions()
{
Go( &GROUP_TOOL::GroupProperties, ACTIONS::groupProperties.MakeEvent() );
Go( &GROUP_TOOL::PickNewMember, ACTIONS::pickNewGroupMember.MakeEvent() );
Go( &GROUP_TOOL::Group, ACTIONS::group.MakeEvent() );
Go( &GROUP_TOOL::Ungroup, ACTIONS::ungroup.MakeEvent() );
Go( &GROUP_TOOL::RemoveFromGroup, ACTIONS::removeFromGroup.MakeEvent() );
Go( &GROUP_TOOL::EnterGroup, ACTIONS::groupEnter.MakeEvent() );
Go( &GROUP_TOOL::LeaveGroup, ACTIONS::groupLeave.MakeEvent() );
}

192
pcbnew/tools/pcb_group_tool.cpp

@ -0,0 +1,192 @@
/*
* This program source code file is part of KiCad, a free EDA CAD application.
*
* Copyright The KiCad Developers, see AUTHORS.txt for contributors.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, you may find one here:
* http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
* or you may search the http://www.gnu.org website for the version 2 license,
* or you may write to the Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
*/
#include <kiplatform/ui.h>
#include <tool/tool_manager.h>
#include <tools/pcb_group_tool.h>
#include <tools/pcb_picker_tool.h>
#include <tools/pcb_selection_tool.h>
#include <status_popup.h>
#include <board_commit.h>
#include <dialogs/dialog_group_properties.h>
#include <pcb_group.h>
#include <collectors.h>
#include <footprint.h>
int PCB_GROUP_TOOL::PickNewMember( const TOOL_EVENT& aEvent )
{
bool isFootprintEditor = m_frame->GetFrameType() == FRAME_FOOTPRINT_EDITOR;
PCB_SELECTION_TOOL* selTool = m_toolMgr->GetTool<PCB_SELECTION_TOOL>();
PCB_PICKER_TOOL* picker = m_toolMgr->GetTool<PCB_PICKER_TOOL>();
STATUS_TEXT_POPUP statusPopup( m_frame );
bool done = false;
if( m_propertiesDialog )
m_propertiesDialog->Show( false );
Activate();
statusPopup.SetText( _( "Click on new member..." ) );
picker->SetClickHandler(
[&]( const VECTOR2D& aPoint ) -> bool
{
m_toolMgr->RunAction( ACTIONS::selectionClear );
const PCB_SELECTION& sel = selTool->RequestSelection(
[]( const VECTOR2I& aPt, GENERAL_COLLECTOR& aCollector, PCB_SELECTION_TOOL* sTool )
{
} );
if( sel.Empty() )
return true; // still looking for an item
statusPopup.Hide();
if( m_propertiesDialog )
{
EDA_ITEM* elem = sel.Front();
if( !isFootprintEditor )
{
while( elem->GetParent() && elem->GetParent()->Type() != PCB_T )
elem = elem->GetParent();
}
m_propertiesDialog->DoAddMember( elem );
m_propertiesDialog->Show( true );
}
return false; // got our item; don't need any more
} );
picker->SetMotionHandler(
[&]( const VECTOR2D& aPos )
{
statusPopup.Move( KIPLATFORM::UI::GetMousePosition() + wxPoint( 20, -50 ) );
} );
picker->SetCancelHandler(
[&]()
{
if( m_propertiesDialog )
m_propertiesDialog->Show( true );
statusPopup.Hide();
} );
picker->SetFinalizeHandler(
[&]( const int& aFinalState )
{
done = true;
} );
statusPopup.Move( KIPLATFORM::UI::GetMousePosition() + wxPoint( 20, -50 ) );
statusPopup.Popup();
m_frame->GetCanvas()->SetStatusPopup( statusPopup.GetPanel() );
m_toolMgr->RunAction( ACTIONS::pickerTool, &aEvent );
while( !done )
{
// Pass events unless we receive a null event, then we must shut down
if( TOOL_EVENT* evt = Wait() )
evt->SetPassEvent();
else
break;
}
m_frame->GetCanvas()->SetStatusPopup( nullptr );
return 0;
}
int PCB_GROUP_TOOL::Group( const TOOL_EVENT& aEvent )
{
bool isFootprintEditor = m_frame->GetFrameType() == FRAME_FOOTPRINT_EDITOR;
PCB_SELECTION_TOOL* selTool = m_toolMgr->GetTool<PCB_SELECTION_TOOL>();
PCB_SELECTION selection;
if( isFootprintEditor )
{
selection = selTool->RequestSelection(
[]( const VECTOR2I&, GENERAL_COLLECTOR& aCollector, PCB_SELECTION_TOOL* )
{
} );
}
else
{
selection = selTool->RequestSelection(
[]( const VECTOR2I&, GENERAL_COLLECTOR& aCollector, PCB_SELECTION_TOOL* )
{
// Iterate from the back so we don't have to worry about removals.
for( int i = aCollector.GetCount() - 1; i >= 0; --i )
{
BOARD_ITEM* item = aCollector[i];
if( item->GetParentFootprint() )
aCollector.Remove( item );
}
} );
}
if( selection.Empty() )
return 0;
BOARD* board = getModel<BOARD>();
PCB_GROUP* group = nullptr;
if( isFootprintEditor )
group = new PCB_GROUP( board->GetFirstFootprint() );
else
group = new PCB_GROUP( board );
for( EDA_ITEM* eda_item : selection )
{
if( eda_item->IsBOARD_ITEM() )
{
if( static_cast<BOARD_ITEM*>( eda_item )->IsLocked() )
group->SetLocked( true );
}
}
m_commit->Add( group );
for( EDA_ITEM* eda_item : selection )
{
if( eda_item->IsBOARD_ITEM() )
m_commit->Stage( static_cast<BOARD_ITEM*>( eda_item ), CHT_GROUP );
}
m_commit->Push( _( "Group Items" ) );
m_toolMgr->RunAction( ACTIONS::selectionClear );
m_toolMgr->RunAction( ACTIONS::selectItem, group->AsEdaItem() );
m_toolMgr->PostEvent( EVENTS::SelectedItemsModified );
m_frame->OnModify();
return 0;
}

17
pcbnew/tools/pcb_group_tool.h

@ -0,0 +1,17 @@
#include <tool/group_tool.h>
#include <board_commit.h>
class PCB_GROUP_TOOL : public GROUP_TOOL
{
public:
/**
* Invoke the picker tool to select a new member of the group.
*/
int PickNewMember( const TOOL_EVENT& aEvent ) override;
///< Group selected items.
int Group( const TOOL_EVENT& aEvent ) override;
protected:
std::unique_ptr<COMMIT> createCommit() override { return std::make_unique<BOARD_COMMIT>( this ); }
};

4
pcbnew/tools/pcb_selection_tool.h

@ -180,14 +180,14 @@ public:
/**
* Enter the group at the head of the current selection.
*/
void EnterGroup();
void EnterGroup() override;
/**
* Leave the currently-entered group.
*
* @param aSelectGroup [optional] Select the group after leaving.
*/
void ExitGroup( bool aSelectGroup = false );
void ExitGroup( bool aSelectGroup = false ) override;
/**
* @return the currently-entered group.

Loading…
Cancel
Save