Tighten parent/child undo/redo architecture.

Always look for pre-existing undo/redo record.  Checking for IsNew()
is less robust and should be avoided.  Also moves the checking to a
location where it will be easier to ensure that it's uniform.

Push get-undo-level-item processing down a level so it is uniformly
called.

Make sure tables & labels are uniformly handled.

Remove incorrect usage of Get/SetGroupId() for storing lastPin
(which we don't use anyway).

Lists of deleted and changed items MUST include the screen pointer.
An item could be changed on one screen but not on another.

Also tightens handling of PCB_NETINFO_T items, which are not in the
view.

Also fixes a bug where there is no increment parameter if you assign
the base increment command to a hotkey.
(This was discovered while testing the above changes.)

Also fixes a bug where delete during a move in PCB Editor did an
undo instead of a delete.
(Again, found while testing above.)

An experiment was also run to collapse shared parts of SCH_EDIT_FRAME
and SYMBOL_EDITOR_FRAME into SCH_BASE_EDIT_FRAME.  However, sharing the
undo code actually increased complexity, and there was very little else
of value in SCH_BASE_EDIT_FRAME (other than the Increment() routines).
This commit is contained in:
Jeff Young 2025-08-18 12:43:57 +01:00
parent 30637e65b0
commit 6f389fd320
28 changed files with 670 additions and 832 deletions

View File

@ -38,52 +38,63 @@ COMMIT::COMMIT()
COMMIT::~COMMIT() COMMIT::~COMMIT()
{ {
for( COMMIT_LINE& ent : m_changes ) for( COMMIT_LINE& ent : m_entries )
delete ent.m_copy; delete ent.m_copy;
} }
COMMIT& COMMIT::Stage( EDA_ITEM* aItem, CHANGE_TYPE aChangeType, BASE_SCREEN* aScreen, COMMIT& COMMIT::Stage( EDA_ITEM* aItem, CHANGE_TYPE aChangeType, BASE_SCREEN* aScreen, RECURSE_MODE aRecurse )
RECURSE_MODE aRecurse )
{ {
int flags = aChangeType & CHT_FLAGS;
int changeType = aChangeType & CHT_TYPE;
EDA_ITEM* undoItem = undoLevelItem( aItem );
if( undoItem != aItem )
changeType = CHT_MODIFY;
// CHT_MODIFY and CHT_DONE are not compatible // CHT_MODIFY and CHT_DONE are not compatible
wxASSERT( ( aChangeType & ( CHT_MODIFY | CHT_DONE ) ) != ( CHT_MODIFY | CHT_DONE ) ); if( changeType == CHT_MODIFY )
wxASSERT( ( flags & CHT_DONE ) == 0 );
int flag = aChangeType & CHT_FLAGS; switch( changeType )
switch( aChangeType & CHT_TYPE )
{ {
case CHT_ADD: case CHT_ADD:
makeEntry( aItem, CHT_ADD | flag, nullptr, aScreen ); if( m_addedItems.find( { aItem, aScreen } ) != m_addedItems.end() )
break;
makeEntry( aItem, CHT_ADD | flags, nullptr, aScreen );
break; break;
case CHT_REMOVE: case CHT_REMOVE:
if( m_deletedItems.insert( aItem ).second ) if( m_deletedItems.find( { aItem, aScreen } ) != m_deletedItems.end() )
{ break;
makeEntry( aItem, CHT_REMOVE | flag, makeImage( aItem ), aScreen );
makeEntry( aItem, CHT_REMOVE | flags, makeImage( aItem ), aScreen );
if( EDA_GROUP* parentGroup = aItem->GetParentGroup() ) if( EDA_GROUP* parentGroup = aItem->GetParentGroup() )
Modify( parentGroup->AsEdaItem(), aScreen, RECURSE_MODE::NO_RECURSE ); Modify( parentGroup->AsEdaItem(), aScreen, RECURSE_MODE::NO_RECURSE );
}
break; break;
case CHT_MODIFY: case CHT_MODIFY:
if( EDA_ITEM* parent = parentObject( aItem ) ) if( m_addedItems.find( { aItem, aScreen } ) != m_addedItems.end() )
createModified( parent, makeImage( parent ), flag, aScreen ); break;
if( m_changedItems.find( { undoItem, aScreen } ) != m_changedItems.end() )
break;
makeEntry( undoItem, CHT_MODIFY | flags, makeImage( undoItem ), aScreen );
break; break;
default: default:
wxFAIL; UNIMPLEMENTED_FOR( undoItem->GetClass() );
} }
return *this; return *this;
} }
COMMIT& COMMIT::Stage( std::vector<EDA_ITEM*> &container, CHANGE_TYPE aChangeType, COMMIT& COMMIT::Stage( std::vector<EDA_ITEM*> &container, CHANGE_TYPE aChangeType, BASE_SCREEN *aScreen )
BASE_SCREEN *aScreen )
{ {
for( EDA_ITEM* item : container ) for( EDA_ITEM* item : container )
Stage( item, aChangeType, aScreen); Stage( item, aChangeType, aScreen);
@ -121,7 +132,7 @@ COMMIT& COMMIT::Stage( const PICKED_ITEMS_LIST &aItems, UNDO_REDO aModFlag, BASE
void COMMIT::Unstage( EDA_ITEM* aItem, BASE_SCREEN* aScreen ) void COMMIT::Unstage( EDA_ITEM* aItem, BASE_SCREEN* aScreen )
{ {
std::erase_if( m_changes, std::erase_if( m_entries,
[&]( COMMIT_LINE& line ) [&]( COMMIT_LINE& line )
{ {
if( line.m_item == aItem && line.m_screen == aScreen ) if( line.m_item == aItem && line.m_screen == aScreen )
@ -139,31 +150,25 @@ void COMMIT::Unstage( EDA_ITEM* aItem, BASE_SCREEN* aScreen )
} }
int COMMIT::GetStatus( EDA_ITEM* aItem, BASE_SCREEN *aScreen ) COMMIT& COMMIT::Modified( EDA_ITEM* aItem, EDA_ITEM* aCopy, BASE_SCREEN *aScreen )
{ {
COMMIT_LINE* entry = findEntry( parentObject( aItem ), aScreen ); if( undoLevelItem( aItem ) != aItem )
wxFAIL_MSG( "We've no way to get a copy of the undo level item at this point" );
return entry ? entry->m_type : 0; else
} makeEntry( aItem, CHT_MODIFY, aCopy, aScreen );
COMMIT& COMMIT::createModified( EDA_ITEM* aItem, EDA_ITEM* aCopy, int aExtraFlags,
BASE_SCREEN* aScreen )
{
EDA_ITEM* parent = parentObject( aItem );
if( m_changedItems.find( parent ) != m_changedItems.end() )
{
delete aCopy;
return *this; // item has been already modified once
}
makeEntry( parent, CHT_MODIFY | aExtraFlags, aCopy, aScreen );
return *this; return *this;
} }
int COMMIT::GetStatus( EDA_ITEM* aItem, BASE_SCREEN *aScreen )
{
COMMIT_LINE* entry = findEntry( undoLevelItem( aItem ), aScreen );
return entry ? entry->m_type : 0;
}
void COMMIT::makeEntry( EDA_ITEM* aItem, CHANGE_TYPE aType, EDA_ITEM* aCopy, BASE_SCREEN *aScreen ) void COMMIT::makeEntry( EDA_ITEM* aItem, CHANGE_TYPE aType, EDA_ITEM* aCopy, BASE_SCREEN *aScreen )
{ {
COMMIT_LINE ent; COMMIT_LINE ent;
@ -176,17 +181,24 @@ void COMMIT::makeEntry( EDA_ITEM* aItem, CHANGE_TYPE aType, EDA_ITEM* aCopy, BAS
// N.B. Do not throw an assertion for multiple changed items. An item can be changed // N.B. Do not throw an assertion for multiple changed items. An item can be changed
// multiple times in a single commit such as when importing graphics and grouping them. // multiple times in a single commit such as when importing graphics and grouping them.
m_changedItems.insert( aItem ); switch( aType )
m_changes.push_back( ent ); {
case CHT_ADD: m_addedItems.insert( { aItem, aScreen } ); break;
case CHT_REMOVE: m_deletedItems.insert( { aItem, aScreen } ); break;
case CHT_MODIFY: m_changedItems.insert( { aItem, aScreen } ); break;
default: wxFAIL; break;
}
m_entries.push_back( ent );
} }
COMMIT::COMMIT_LINE* COMMIT::findEntry( EDA_ITEM* aItem, BASE_SCREEN *aScreen ) COMMIT::COMMIT_LINE* COMMIT::findEntry( EDA_ITEM* aItem, BASE_SCREEN *aScreen )
{ {
for( COMMIT_LINE& change : m_changes ) for( COMMIT_LINE& entry : m_entries )
{ {
if( change.m_item == aItem && change.m_screen == aScreen ) if( entry.m_item == aItem && entry.m_screen == aScreen )
return &change; return &entry;
} }
return nullptr; return nullptr;
@ -200,7 +212,7 @@ CHANGE_TYPE COMMIT::convert( UNDO_REDO aType ) const
case UNDO_REDO::NEWITEM: return CHT_ADD; case UNDO_REDO::NEWITEM: return CHT_ADD;
case UNDO_REDO::DELETED: return CHT_REMOVE; case UNDO_REDO::DELETED: return CHT_REMOVE;
case UNDO_REDO::CHANGED: return CHT_MODIFY; case UNDO_REDO::CHANGED: return CHT_MODIFY;
default: wxASSERT( false ); return CHT_MODIFY; default: wxFAIL; return CHT_MODIFY;
} }
} }
@ -212,7 +224,7 @@ UNDO_REDO COMMIT::convert( CHANGE_TYPE aType ) const
case CHT_ADD: return UNDO_REDO::NEWITEM; case CHT_ADD: return UNDO_REDO::NEWITEM;
case CHT_REMOVE: return UNDO_REDO::DELETED; case CHT_REMOVE: return UNDO_REDO::DELETED;
case CHT_MODIFY: return UNDO_REDO::CHANGED; case CHT_MODIFY: return UNDO_REDO::CHANGED;
default: wxASSERT( false ); return UNDO_REDO::CHANGED; default: wxFAIL; return UNDO_REDO::CHANGED;
} }
} }

View File

@ -79,7 +79,6 @@ protected:
DIALOG_GROUP_PROPERTIES* m_propertiesDialog = nullptr; DIALOG_GROUP_PROPERTIES* m_propertiesDialog = nullptr;
SELECTION_TOOL* m_selectionTool = nullptr; SELECTION_TOOL* m_selectionTool = nullptr;
std::shared_ptr<COMMIT> m_commit; std::shared_ptr<COMMIT> m_commit;
bool m_isFootprintEditor = false;
}; };
#endif #endif

View File

@ -73,17 +73,6 @@ COMMIT& SCH_COMMIT::Stage( EDA_ITEM *aItem, CHANGE_TYPE aChangeType, BASE_SCREEN
{ {
wxCHECK( aItem, *this ); wxCHECK( aItem, *this );
// If aItem belongs a symbol, sheet or label, the full parent will be saved because undo/redo
// does not handle "sub items" modifications.
if( aItem->Type() != SCH_SHEET_T
&& aItem->GetParent() && aItem->GetParent()->IsType( { SCH_SYMBOL_T, LIB_SYMBOL_T,
SCH_SHEET_T,
SCH_LABEL_LOCATE_ANY_T } ) )
{
aItem = aItem->GetParent();
aChangeType = CHT_MODIFY;
}
if( aRecurse == RECURSE_MODE::RECURSE ) if( aRecurse == RECURSE_MODE::RECURSE )
{ {
if( SCH_GROUP* group = dynamic_cast<SCH_GROUP*>( aItem ) ) if( SCH_GROUP* group = dynamic_cast<SCH_GROUP*>( aItem ) )
@ -93,8 +82,7 @@ COMMIT& SCH_COMMIT::Stage( EDA_ITEM *aItem, CHANGE_TYPE aChangeType, BASE_SCREEN
} }
} }
// IS_SELECTED flag should not be set on undo items which were added for // IS_SELECTED flag should not be set on undo items which were added for a drag operation.
// a drag operation.
if( aItem->IsSelected() && aItem->HasFlag( SELECTED_BY_DRAG ) ) if( aItem->IsSelected() && aItem->HasFlag( SELECTED_BY_DRAG ) )
{ {
aItem->ClearSelected(); aItem->ClearSelected();
@ -120,18 +108,11 @@ COMMIT& SCH_COMMIT::Stage( std::vector<EDA_ITEM*> &container, CHANGE_TYPE aChang
} }
COMMIT& SCH_COMMIT::Stage( const PICKED_ITEMS_LIST &aItems, UNDO_REDO aModFlag,
BASE_SCREEN *aScreen )
{
return COMMIT::Stage( aItems, aModFlag, aScreen );
}
void SCH_COMMIT::pushLibEdit( const wxString& aMessage, int aCommitFlags ) void SCH_COMMIT::pushLibEdit( const wxString& aMessage, int aCommitFlags )
{ {
// Symbol editor just saves copies of the whole symbol, so grab the first and discard the rest // Symbol editor just saves copies of the whole symbol, so grab the first and discard the rest
LIB_SYMBOL* symbol = dynamic_cast<LIB_SYMBOL*>( m_changes.front().m_item ); LIB_SYMBOL* symbol = dynamic_cast<LIB_SYMBOL*>( m_entries.front().m_item );
LIB_SYMBOL* copy = dynamic_cast<LIB_SYMBOL*>( m_changes.front().m_copy ); LIB_SYMBOL* copy = dynamic_cast<LIB_SYMBOL*>( m_entries.front().m_copy );
if( symbol ) if( symbol )
{ {
@ -220,10 +201,10 @@ void SCH_COMMIT::pushSchEdit( const wxString& aMessage, int aCommitFlags )
Modify( enteredGroup ); Modify( enteredGroup );
// Handle wires with Hop Over shapes: // Handle wires with Hop Over shapes:
for( COMMIT_LINE& ent : m_changes ) for( COMMIT_LINE& entry : m_entries )
{ {
SCH_ITEM* schCopyItem = dynamic_cast<SCH_ITEM*>( ent.m_copy ); SCH_ITEM* schCopyItem = dynamic_cast<SCH_ITEM*>( entry.m_copy );
SCH_ITEM* schItem = dynamic_cast<SCH_ITEM*>( ent.m_item ); SCH_ITEM* schItem = dynamic_cast<SCH_ITEM*>( entry.m_item );
if( schCopyItem && schCopyItem->Type() == SCH_LINE_T ) if( schCopyItem && schCopyItem->Type() == SCH_LINE_T )
frame->UpdateHopOveredWires( schCopyItem ); frame->UpdateHopOveredWires( schCopyItem );
@ -233,10 +214,10 @@ void SCH_COMMIT::pushSchEdit( const wxString& aMessage, int aCommitFlags )
} }
for( COMMIT_LINE& ent : m_changes ) for( COMMIT_LINE& entry : m_entries )
{ {
SCH_ITEM* schItem = dynamic_cast<SCH_ITEM*>( ent.m_item ); SCH_ITEM* schItem = dynamic_cast<SCH_ITEM*>( entry.m_item );
int changeType = ent.m_type & CHT_TYPE; int changeType = entry.m_type & CHT_TYPE;
wxCHECK2( schItem, continue ); wxCHECK2( schItem, continue );
@ -244,12 +225,12 @@ void SCH_COMMIT::pushSchEdit( const wxString& aMessage, int aCommitFlags )
Modify( schItem->GetParentGroup()->AsEdaItem() ); Modify( schItem->GetParentGroup()->AsEdaItem() );
} }
for( COMMIT_LINE& ent : m_changes ) for( COMMIT_LINE& entry : m_entries )
{ {
int changeType = ent.m_type & CHT_TYPE; int changeType = entry.m_type & CHT_TYPE;
int changeFlags = ent.m_type & CHT_FLAGS; int changeFlags = entry.m_type & CHT_FLAGS;
SCH_ITEM* schItem = dynamic_cast<SCH_ITEM*>( ent.m_item ); SCH_ITEM* schItem = dynamic_cast<SCH_ITEM*>( entry.m_item );
SCH_SCREEN* screen = dynamic_cast<SCH_SCREEN*>( ent.m_screen ); SCH_SCREEN* screen = dynamic_cast<SCH_SCREEN*>( entry.m_screen );
wxCHECK2( schItem, continue ); wxCHECK2( schItem, continue );
wxCHECK2( screen, continue ); wxCHECK2( screen, continue );
@ -311,8 +292,8 @@ void SCH_COMMIT::pushSchEdit( const wxString& aMessage, int aCommitFlags )
if( !( aCommitFlags & SKIP_UNDO ) ) if( !( aCommitFlags & SKIP_UNDO ) )
{ {
ITEM_PICKER itemWrapper( screen, schItem, UNDO_REDO::DELETED ); ITEM_PICKER itemWrapper( screen, schItem, UNDO_REDO::DELETED );
itemWrapper.SetLink( ent.m_copy ); itemWrapper.SetLink( entry.m_copy );
ent.m_copy = nullptr; // We've transferred ownership to the undo list entry.m_copy = nullptr; // We've transferred ownership to the undo list
undoList.PushItem( itemWrapper ); undoList.PushItem( itemWrapper );
} }
@ -353,7 +334,7 @@ void SCH_COMMIT::pushSchEdit( const wxString& aMessage, int aCommitFlags )
case CHT_MODIFY: case CHT_MODIFY:
{ {
const SCH_ITEM* itemCopy = static_cast<const SCH_ITEM*>( ent.m_copy ); const SCH_ITEM* itemCopy = static_cast<const SCH_ITEM*>( entry.m_copy );
SCH_SHEET_PATH currentSheet; SCH_SHEET_PATH currentSheet;
if( frame ) if( frame )
@ -368,8 +349,8 @@ void SCH_COMMIT::pushSchEdit( const wxString& aMessage, int aCommitFlags )
if( !( aCommitFlags & SKIP_UNDO ) ) if( !( aCommitFlags & SKIP_UNDO ) )
{ {
ITEM_PICKER itemWrapper( screen, schItem, UNDO_REDO::CHANGED ); ITEM_PICKER itemWrapper( screen, schItem, UNDO_REDO::CHANGED );
itemWrapper.SetLink( ent.m_copy ); itemWrapper.SetLink( entry.m_copy );
ent.m_copy = nullptr; // We've transferred ownership to the undo list entry.m_copy = nullptr; // We've transferred ownership to the undo list
undoList.PushItem( itemWrapper ); undoList.PushItem( itemWrapper );
} }
@ -396,8 +377,8 @@ void SCH_COMMIT::pushSchEdit( const wxString& aMessage, int aCommitFlags )
} }
// Delete any copies we still have ownership of // Delete any copies we still have ownership of
delete ent.m_copy; delete entry.m_copy;
ent.m_copy = nullptr; entry.m_copy = nullptr;
// Clear all flags but SELECTED and others used to move and rotate commands, // Clear all flags but SELECTED and others used to move and rotate commands,
// after edition (selected items must keep their selection flag). // after edition (selected items must keep their selection flag).
@ -484,16 +465,16 @@ void SCH_COMMIT::Push( const wxString& aMessage, int aCommitFlags )
} }
EDA_ITEM* SCH_COMMIT::parentObject( EDA_ITEM* aItem ) const EDA_ITEM* SCH_COMMIT::undoLevelItem( EDA_ITEM* aItem ) const
{ {
EDA_ITEM* parent = aItem->GetParent(); EDA_ITEM* parent = aItem->GetParent();
if( parent && ( parent->Type() == SCH_SYMBOL_T || parent->Type() == LIB_SYMBOL_T ) )
return parent;
if( m_isLibEditor ) if( m_isLibEditor )
return static_cast<SYMBOL_EDIT_FRAME*>( m_toolMgr->GetToolHolder() )->GetCurSymbol(); return static_cast<SYMBOL_EDIT_FRAME*>( m_toolMgr->GetToolHolder() )->GetCurSymbol();
if( parent && parent->IsType( { SCH_SYMBOL_T, SCH_TABLE_T, SCH_SHEET_T, SCH_LABEL_LOCATE_ANY_T } ) )
return parent;
return aItem; return aItem;
} }
@ -536,7 +517,7 @@ void SCH_COMMIT::revertLibEdit()
// Symbol editor just saves copies of the whole symbol, so grab the first and discard the rest // Symbol editor just saves copies of the whole symbol, so grab the first and discard the rest
SYMBOL_EDIT_FRAME* frame = dynamic_cast<SYMBOL_EDIT_FRAME*>( m_toolMgr->GetToolHolder() ); SYMBOL_EDIT_FRAME* frame = dynamic_cast<SYMBOL_EDIT_FRAME*>( m_toolMgr->GetToolHolder() );
LIB_SYMBOL* copy = dynamic_cast<LIB_SYMBOL*>( m_changes.front().m_copy ); LIB_SYMBOL* copy = dynamic_cast<LIB_SYMBOL*>( m_entries.front().m_copy );
SCH_SELECTION_TOOL* selTool = m_toolMgr->GetTool<SCH_SELECTION_TOOL>(); SCH_SELECTION_TOOL* selTool = m_toolMgr->GetTool<SCH_SELECTION_TOOL>();
if( frame && copy ) if( frame && copy )
@ -545,9 +526,6 @@ void SCH_COMMIT::revertLibEdit()
m_toolMgr->ResetTools( TOOL_BASE::MODEL_RELOAD ); m_toolMgr->ResetTools( TOOL_BASE::MODEL_RELOAD );
} }
for( size_t ii = 1; ii < m_changes.size(); ++ii )
delete m_changes[ii].m_copy;
if( selTool ) if( selTool )
selTool->RebuildSelection(); selTool->RebuildSelection();
@ -562,7 +540,7 @@ void SCH_COMMIT::Revert()
SCH_SELECTION_TOOL* selTool = m_toolMgr->GetTool<SCH_SELECTION_TOOL>(); SCH_SELECTION_TOOL* selTool = m_toolMgr->GetTool<SCH_SELECTION_TOOL>();
SCH_SHEET_LIST sheets; SCH_SHEET_LIST sheets;
if( m_changes.empty() ) if( m_entries.empty() )
return; return;
if( m_isLibEditor ) if( m_isLibEditor )
@ -576,7 +554,7 @@ void SCH_COMMIT::Revert()
std::vector<SCH_ITEM*> bulkRemovedItems; std::vector<SCH_ITEM*> bulkRemovedItems;
std::vector<SCH_ITEM*> itemsChanged; std::vector<SCH_ITEM*> itemsChanged;
for( COMMIT_LINE& ent : m_changes ) for( COMMIT_LINE& ent : m_entries )
{ {
int changeType = ent.m_type & CHT_TYPE; int changeType = ent.m_type & CHT_TYPE;
int changeFlags = ent.m_type & CHT_FLAGS; int changeFlags = ent.m_type & CHT_FLAGS;
@ -703,9 +681,7 @@ void SCH_COMMIT::Revert()
selTool->RebuildSelection(); selTool->RebuildSelection();
if( frame ) if( frame )
{
frame->RecalculateConnections( nullptr, NO_CLEANUP ); frame->RecalculateConnections( nullptr, NO_CLEANUP );
}
clear(); clear();
} }

View File

@ -23,8 +23,7 @@
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
*/ */
#ifndef SCHEMATIC_COMMIT_H #pragma once
#define SCHEMATIC_COMMIT_H
#include <commit.h> #include <commit.h>
@ -51,19 +50,16 @@ public:
virtual ~SCH_COMMIT(); virtual ~SCH_COMMIT();
virtual void Push( const wxString& aMessage = wxT( "A commit" ), virtual void Push( const wxString& aMessage = wxT( "A commit" ), int aCommitFlags = 0 ) override;
int aCommitFlags = 0 ) override;
virtual void Revert() override; virtual void Revert() override;
COMMIT& Stage( EDA_ITEM *aItem, CHANGE_TYPE aChangeType, BASE_SCREEN *aScreen = nullptr, COMMIT& Stage( EDA_ITEM *aItem, CHANGE_TYPE aChangeType, BASE_SCREEN *aScreen = nullptr,
RECURSE_MODE aRecurse = RECURSE_MODE::NO_RECURSE ) override; RECURSE_MODE aRecurse = RECURSE_MODE::NO_RECURSE ) override;
COMMIT& Stage( std::vector<EDA_ITEM*> &container, CHANGE_TYPE aChangeType, COMMIT& Stage( std::vector<EDA_ITEM*> &container, CHANGE_TYPE aChangeType,
BASE_SCREEN *aScreen = nullptr ) override; BASE_SCREEN *aScreen = nullptr ) override;
COMMIT& Stage( const PICKED_ITEMS_LIST &aItems, UNDO_REDO aModFlag = UNDO_REDO::UNSPECIFIED,
BASE_SCREEN *aScreen = nullptr ) override;
private: private:
EDA_ITEM* parentObject( EDA_ITEM* aItem ) const override; EDA_ITEM* undoLevelItem( EDA_ITEM* aItem ) const override;
EDA_ITEM* makeImage( EDA_ITEM* aItem ) const override; EDA_ITEM* makeImage( EDA_ITEM* aItem ) const override;
@ -76,5 +72,3 @@ private:
TOOL_MANAGER* m_toolMgr; TOOL_MANAGER* m_toolMgr;
bool m_isLibEditor; bool m_isLibEditor;
}; };
#endif

View File

@ -25,7 +25,6 @@
#include <symbol_edit_frame.h> #include <symbol_edit_frame.h>
#include <lib_symbol_library_manager.h> #include <lib_symbol_library_manager.h>
#include <widgets/lib_tree.h> #include <widgets/lib_tree.h>
#include <symbol_tree_pane.h>
#include <tool/tool_manager.h> #include <tool/tool_manager.h>
#include <tools/sch_selection_tool.h> #include <tools/sch_selection_tool.h>
#include <tools/symbol_editor_drawing_tools.h> #include <tools/symbol_editor_drawing_tools.h>
@ -67,8 +66,6 @@ void SYMBOL_EDIT_FRAME::GetSymbolFromRedoList()
if( GetRedoCommandCount() <= 0 ) if( GetRedoCommandCount() <= 0 )
return; return;
auto* drawingTool = GetToolManager()->GetTool<SYMBOL_EDITOR_DRAWING_TOOLS>();
// Load the last redo entry // Load the last redo entry
PICKED_ITEMS_LIST* redoCommand = PopCommandFromRedoList(); PICKED_ITEMS_LIST* redoCommand = PopCommandFromRedoList();
ITEM_PICKER redoWrapper = redoCommand->PopItem(); ITEM_PICKER redoWrapper = redoCommand->PopItem();
@ -77,7 +74,6 @@ void SYMBOL_EDIT_FRAME::GetSymbolFromRedoList()
delete redoCommand; delete redoCommand;
LIB_SYMBOL* symbol = (LIB_SYMBOL*) redoWrapper.GetItem(); LIB_SYMBOL* symbol = (LIB_SYMBOL*) redoWrapper.GetItem();
KIID lastPin = redoWrapper.GetGroupId();
UNDO_REDO undoRedoType = redoWrapper.GetStatus(); UNDO_REDO undoRedoType = redoWrapper.GetStatus();
wxCHECK( symbol, /* void */ ); wxCHECK( symbol, /* void */ );
symbol->ClearFlags( UR_TRANSIENT ); symbol->ClearFlags( UR_TRANSIENT );
@ -97,7 +93,6 @@ void SYMBOL_EDIT_FRAME::GetSymbolFromRedoList()
// <previous symbol> is now put in undo list and is owned by this list // <previous symbol> is now put in undo list and is owned by this list
// Just set the current symbol to the symbol which come from the redo list // Just set the current symbol to the symbol which come from the redo list
m_symbol = symbol; m_symbol = symbol;
drawingTool->SetLastPin( lastPin );
if( undoRedoType == UNDO_REDO::LIB_RENAME ) if( undoRedoType == UNDO_REDO::LIB_RENAME )
{ {
@ -122,8 +117,6 @@ void SYMBOL_EDIT_FRAME::GetSymbolFromUndoList()
if( GetUndoCommandCount() <= 0 ) if( GetUndoCommandCount() <= 0 )
return; return;
auto* drawingTool = GetToolManager()->GetTool<SYMBOL_EDITOR_DRAWING_TOOLS>();
// Load the last undo entry // Load the last undo entry
PICKED_ITEMS_LIST* undoCommand = PopCommandFromUndoList(); PICKED_ITEMS_LIST* undoCommand = PopCommandFromUndoList();
wxString description = undoCommand->GetDescription(); wxString description = undoCommand->GetDescription();
@ -132,7 +125,6 @@ void SYMBOL_EDIT_FRAME::GetSymbolFromUndoList()
delete undoCommand; delete undoCommand;
LIB_SYMBOL* symbol = (LIB_SYMBOL*) undoWrapper.GetItem(); LIB_SYMBOL* symbol = (LIB_SYMBOL*) undoWrapper.GetItem();
KIID lastPin = undoWrapper.GetGroupId();
UNDO_REDO undoRedoType = undoWrapper.GetStatus(); UNDO_REDO undoRedoType = undoWrapper.GetStatus();
wxCHECK( symbol, /* void */ ); wxCHECK( symbol, /* void */ );
symbol->ClearFlags( UR_TRANSIENT ); symbol->ClearFlags( UR_TRANSIENT );
@ -152,7 +144,6 @@ void SYMBOL_EDIT_FRAME::GetSymbolFromUndoList()
// <previous symbol> is now put in redo list and is owned by this list. // <previous symbol> is now put in redo list and is owned by this list.
// Just set the current symbol to the symbol which come from the undo list // Just set the current symbol to the symbol which come from the undo list
m_symbol = symbol; m_symbol = symbol;
drawingTool->SetLastPin( lastPin );
if( undoRedoType == UNDO_REDO::LIB_RENAME ) if( undoRedoType == UNDO_REDO::LIB_RENAME )
{ {

View File

@ -51,9 +51,6 @@
#include <sch_line.h> #include <sch_line.h>
#include <sch_junction.h> #include <sch_junction.h>
#include <sch_bus_entry.h> #include <sch_bus_entry.h>
#include <sch_rule_area.h>
#include <sch_text.h>
#include <sch_textbox.h>
#include <sch_table.h> #include <sch_table.h>
#include <sch_tablecell.h> #include <sch_tablecell.h>
#include <sch_sheet.h> #include <sch_sheet.h>
@ -73,7 +70,7 @@
#include <import_gfx/dialog_import_gfx_sch.h> #include <import_gfx/dialog_import_gfx_sch.h>
#include <sync_sheet_pin/sheet_synchronization_agent.h> #include <sync_sheet_pin/sheet_synchronization_agent.h>
#include <string_utils.h> #include <string_utils.h>
#include <wildcards_and_files_ext.h> //#include <wildcards_and_files_ext.h>
#include <wx/filedlg.h> #include <wx/filedlg.h>
#include <wx/msgdlg.h> #include <wx/msgdlg.h>
@ -2101,8 +2098,7 @@ int SCH_DRAWING_TOOLS::TwoClickPlace( const TOOL_EVENT& aEvent )
{ {
m_statusPopup = std::make_unique<STATUS_TEXT_POPUP>( m_frame ); m_statusPopup = std::make_unique<STATUS_TEXT_POPUP>( m_frame );
m_statusPopup->SetText( _( "No new hierarchical labels found." ) ); m_statusPopup->SetText( _( "No new hierarchical labels found." ) );
m_statusPopup->Move( KIPLATFORM::UI::GetMousePosition() m_statusPopup->Move( KIPLATFORM::UI::GetMousePosition() + wxPoint( 20, 20 ) );
+ wxPoint( 20, 20 ) );
m_statusPopup->PopupFor( 2000 ); m_statusPopup->PopupFor( 2000 );
item = nullptr; item = nullptr;
@ -2237,10 +2233,12 @@ int SCH_DRAWING_TOOLS::TwoClickPlace( const TOOL_EVENT& aEvent )
} }
else if( evt->IsAction( &ACTIONS::increment ) ) else if( evt->IsAction( &ACTIONS::increment ) )
{ {
if( evt->HasParameter() )
m_toolMgr->RunSynchronousAction( ACTIONS::increment, &commit, evt->Parameter<ACTIONS::INCREMENT>() ); m_toolMgr->RunSynchronousAction( ACTIONS::increment, &commit, evt->Parameter<ACTIONS::INCREMENT>() );
else
m_toolMgr->RunSynchronousAction( ACTIONS::increment, &commit, ACTIONS::INCREMENT { 1, 0 } );
} }
else if( evt->IsAction( &ACTIONS::duplicate ) else if( evt->IsAction( &ACTIONS::duplicate ) || evt->IsAction( &SCH_ACTIONS::repeatDrawItem ) )
|| evt->IsAction( &SCH_ACTIONS::repeatDrawItem ) )
{ {
if( item ) if( item )
{ {
@ -2616,8 +2614,7 @@ int SCH_DRAWING_TOOLS::DrawRuleArea( const TOOL_EVENT& aEvent )
cursorPos = grid.Align( controls->GetMousePosition(), GRID_HELPER_GRIDS::GRID_CONNECTABLE ); cursorPos = grid.Align( controls->GetMousePosition(), GRID_HELPER_GRIDS::GRID_CONNECTABLE );
controls->ForceCursorPosition( true, cursorPos ); controls->ForceCursorPosition( true, cursorPos );
polyGeomMgr.SetLeaderMode( m_frame->eeconfig()->m_Drawing.line_mode == LINE_MODE_FREE polyGeomMgr.SetLeaderMode( m_frame->eeconfig()->m_Drawing.line_mode == LINE_MODE_FREE ? LEADER_MODE::DIRECT
? LEADER_MODE::DIRECT
: LEADER_MODE::DEG45 ); : LEADER_MODE::DEG45 );
if( evt->IsCancelInteractive() ) if( evt->IsCancelInteractive() )
@ -2663,7 +2660,8 @@ int SCH_DRAWING_TOOLS::DrawRuleArea( const TOOL_EVENT& aEvent )
m_menu->ShowContextMenu( m_selectionTool->GetSelection() ); m_menu->ShowContextMenu( m_selectionTool->GetSelection() );
} }
// events that lock in nodes // events that lock in nodes
else if( evt->IsClick( BUT_LEFT ) || evt->IsDblClick( BUT_LEFT ) else if( evt->IsClick( BUT_LEFT )
|| evt->IsDblClick( BUT_LEFT )
|| evt->IsAction( &SCH_ACTIONS::closeOutline ) ) || evt->IsAction( &SCH_ACTIONS::closeOutline ) )
{ {
// Check if it is double click / closing line (so we have to finish the zone) // Check if it is double click / closing line (so we have to finish the zone)
@ -2692,8 +2690,7 @@ int SCH_DRAWING_TOOLS::DrawRuleArea( const TOOL_EVENT& aEvent )
} }
} }
} }
else if( started else if( started && ( evt->IsAction( &SCH_ACTIONS::deleteLastPoint )
&& ( evt->IsAction( &SCH_ACTIONS::deleteLastPoint )
|| evt->IsAction( &ACTIONS::doDelete ) || evt->IsAction( &ACTIONS::doDelete )
|| evt->IsAction( &ACTIONS::undo ) ) ) || evt->IsAction( &ACTIONS::undo ) ) )
{ {

View File

@ -1632,6 +1632,7 @@ int SCH_EDIT_TOOL::RepeatDrawItem( const TOOL_EVENT& aEvent )
static std::vector<KICAD_T> deletableItems = static std::vector<KICAD_T> deletableItems =
{ {
LIB_SYMBOL_T,
SCH_MARKER_T, SCH_MARKER_T,
SCH_JUNCTION_T, SCH_JUNCTION_T,
SCH_LINE_T, SCH_LINE_T,
@ -1762,78 +1763,6 @@ int SCH_EDIT_TOOL::DoDelete( const TOOL_EVENT& aEvent )
} }
#define HITTEST_THRESHOLD_PIXELS 5
int SCH_EDIT_TOOL::InteractiveDelete( const TOOL_EVENT& aEvent )
{
PICKER_TOOL* picker = m_toolMgr->GetTool<PICKER_TOOL>();
m_toolMgr->RunAction( ACTIONS::selectionClear );
m_pickerItem = nullptr;
// Deactivate other tools; particularly important if another PICKER is currently running
Activate();
picker->SetCursor( KICURSOR::REMOVE );
picker->SetSnapping( false );
picker->ClearHandlers();
picker->SetClickHandler(
[this]( const VECTOR2D& aPosition ) -> bool
{
if( m_pickerItem )
{
SCH_SELECTION_TOOL* selectionTool = m_toolMgr->GetTool<SCH_SELECTION_TOOL>();
selectionTool->UnbrightenItem( m_pickerItem );
selectionTool->AddItemToSel( m_pickerItem, true /*quiet mode*/ );
m_toolMgr->RunAction( ACTIONS::doDelete );
m_pickerItem = nullptr;
}
return true;
} );
picker->SetMotionHandler(
[this]( const VECTOR2D& aPos )
{
SCH_COLLECTOR collector;
collector.m_Threshold = KiROUND( getView()->ToWorld( HITTEST_THRESHOLD_PIXELS ) );
collector.Collect( m_frame->GetScreen(), deletableItems, aPos );
SCH_SELECTION_TOOL* selectionTool = m_toolMgr->GetTool<SCH_SELECTION_TOOL>();
selectionTool->GuessSelectionCandidates( collector, aPos );
EDA_ITEM* item = collector.GetCount() == 1 ? collector[ 0 ] : nullptr;
if( m_pickerItem != item )
{
if( m_pickerItem )
selectionTool->UnbrightenItem( m_pickerItem );
m_pickerItem = item;
if( m_pickerItem )
selectionTool->BrightenItem( m_pickerItem );
}
} );
picker->SetFinalizeHandler(
[this]( const int& aFinalState )
{
if( m_pickerItem )
m_toolMgr->GetTool<SCH_SELECTION_TOOL>()->UnbrightenItem( m_pickerItem );
// Wake the selection tool after exiting to ensure the cursor gets updated
m_toolMgr->PostAction( ACTIONS::selectionActivate );
} );
m_toolMgr->RunAction( ACTIONS::pickerTool, &aEvent );
return 0;
}
void SCH_EDIT_TOOL::editFieldText( SCH_FIELD* aField ) void SCH_EDIT_TOOL::editFieldText( SCH_FIELD* aField )
{ {
KICAD_T parentType = aField->GetParent() ? aField->GetParent()->Type() : SCHEMATIC_T; KICAD_T parentType = aField->GetParent() ? aField->GetParent()->Type() : SCHEMATIC_T;
@ -2814,20 +2743,21 @@ int SCH_EDIT_TOOL::ChangeTextType( const TOOL_EVENT& aEvent )
m_frame->RemoveFromScreen( item, m_frame->GetScreen() ); m_frame->RemoveFromScreen( item, m_frame->GetScreen() );
if( item->IsNew() ) if( commit->GetStatus( item, m_frame->GetScreen() ) == CHT_ADD )
{
commit->Unstage( item, m_frame->GetScreen() ); commit->Unstage( item, m_frame->GetScreen() );
delete item;
}
else else
{
commit->Removed( item, m_frame->GetScreen() ); commit->Removed( item, m_frame->GetScreen() );
}
m_frame->AddToScreen( newtext, m_frame->GetScreen() ); m_frame->AddToScreen( newtext, m_frame->GetScreen() );
commit->Added( newtext, m_frame->GetScreen() ); commit->Added( newtext, m_frame->GetScreen() );
if( selected ) if( selected )
m_toolMgr->RunAction<EDA_ITEM*>( ACTIONS::selectItem, newtext ); m_toolMgr->RunAction<EDA_ITEM*>( ACTIONS::selectItem, newtext );
// Otherwise, pointer is owned by the undo stack
if( item->IsNew() )
delete item;
} }
} }
@ -3137,91 +3067,6 @@ int SCH_EDIT_TOOL::EditPageNumber( const TOOL_EVENT& aEvent )
} }
int SCH_EDIT_TOOL::Increment( const TOOL_EVENT& aEvent )
{
const ACTIONS::INCREMENT incParam = aEvent.Parameter<ACTIONS::INCREMENT>();
static const std::vector<KICAD_T> incrementable = { SCH_LABEL_T, SCH_GLOBAL_LABEL_T,
SCH_HIER_LABEL_T, SCH_TEXT_T };
SCH_SELECTION& selection = m_selectionTool->RequestSelection( incrementable );
if( selection.Empty() )
return 0;
KICAD_T type = selection.Front()->Type();
bool allSameType = true;
for( EDA_ITEM* item : selection )
{
if( item->Type() != type )
{
allSameType = false;
break;
}
}
// Incrementing multiple types at once seems confusing
// though it would work.
if( !allSameType )
return 0;
STRING_INCREMENTER incrementer;
// In schematics, it's probably less common to be operating
// on pin numbers which are usually IOSQXZ-skippy.
incrementer.SetSkipIOSQXZ( false );
// If we're coming via another action like 'Move', use that commit
SCH_COMMIT localCommit( m_toolMgr );
SCH_COMMIT* commit = dynamic_cast<SCH_COMMIT*>( aEvent.Commit() );
if( !commit )
commit = &localCommit;
const auto modifyItem =
[&]( EDA_ITEM& aItem )
{
if( aItem.IsNew() )
m_toolMgr->PostAction( ACTIONS::refreshPreview );
else
commit->Modify( &aItem, m_frame->GetScreen() );
};
for( EDA_ITEM* item : selection )
{
switch( item->Type() )
{
case SCH_LABEL_T:
case SCH_GLOBAL_LABEL_T:
case SCH_HIER_LABEL_T:
case SCH_TEXT_T:
{
SCH_TEXT& label = static_cast<SCH_TEXT&>( *item );
std::optional<wxString> newLabel = incrementer.Increment( label.GetText(),
incParam.Delta,
incParam.Index );
if( newLabel )
{
modifyItem( label );
label.SetText( *newLabel );
}
break;
}
default:
// No increment for other items (yet)
break;
}
}
commit->Push( _( "Increment" ) );
if( selection.IsHover() )
m_toolMgr->RunAction( ACTIONS::selectionClear );
return 0;
}
int SCH_EDIT_TOOL::DdAppendFile( const TOOL_EVENT& aEvent ) int SCH_EDIT_TOOL::DdAppendFile( const TOOL_EVENT& aEvent )
{ {
return m_toolMgr->RunAction( SCH_ACTIONS::importSheet, aEvent.Parameter<wxString*>() ); return m_toolMgr->RunAction( SCH_ACTIONS::importSheet, aEvent.Parameter<wxString*>() );

View File

@ -22,22 +22,17 @@
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
*/ */
#ifndef KICAD_SCH_EDIT_TOOL_H #pragma once
#define KICAD_SCH_EDIT_TOOL_H
#include <tools/sch_tool_base.h> #include <tools/sch_tool_base.h>
#include <sch_base_frame.h> #include <sch_base_frame.h>
class SCH_EDIT_FRAME;
class SCH_SELECTION_TOOL;
class SCH_EDIT_TOOL : public SCH_TOOL_BASE<SCH_EDIT_FRAME> class SCH_EDIT_TOOL : public SCH_TOOL_BASE<SCH_EDIT_FRAME>
{ {
public: public:
SCH_EDIT_TOOL(); SCH_EDIT_TOOL();
~SCH_EDIT_TOOL() override { } ~SCH_EDIT_TOOL() = default;
static const std::vector<KICAD_T> RotatableItems; static const std::vector<KICAD_T> RotatableItems;
@ -57,11 +52,6 @@ public:
int ChangeBodyStyle( const TOOL_EVENT& aEvent ); int ChangeBodyStyle( const TOOL_EVENT& aEvent );
int EditPageNumber( const TOOL_EVENT& aEvent ); int EditPageNumber( const TOOL_EVENT& aEvent );
/**
* Increment/decrement something about an item.
*/
int Increment( const TOOL_EVENT& aEvent );
/** /**
* Change a text type to another one. * Change a text type to another one.
* *
@ -84,9 +74,6 @@ public:
///< Delete the selected items, or the item under the cursor. ///< Delete the selected items, or the item under the cursor.
int DoDelete( const TOOL_EVENT& aEvent ); int DoDelete( const TOOL_EVENT& aEvent );
///< Run the deletion tool.
int InteractiveDelete( const TOOL_EVENT& aEvent );
/// Drag and drop /// Drag and drop
int DdAppendFile( const TOOL_EVENT& aEvent ); int DdAppendFile( const TOOL_EVENT& aEvent );
@ -102,9 +89,4 @@ private:
///< Set up handlers for various events. ///< Set up handlers for various events.
void setTransitions() override; void setTransitions() override;
private:
EDA_ITEM* m_pickerItem;
}; };
#endif //KICAD_SCH_EDIT_TOOL_H

View File

@ -936,7 +936,10 @@ bool SCH_MOVE_TOOL::doMoveSelection( const TOOL_EVENT& aEvent, SCH_COMMIT* aComm
} }
else if( evt->IsAction( &ACTIONS::increment ) ) else if( evt->IsAction( &ACTIONS::increment ) )
{ {
if( evt->HasParameter() )
m_toolMgr->RunSynchronousAction( ACTIONS::increment, aCommit, evt->Parameter<ACTIONS::INCREMENT>() ); m_toolMgr->RunSynchronousAction( ACTIONS::increment, aCommit, evt->Parameter<ACTIONS::INCREMENT>() );
else
m_toolMgr->RunSynchronousAction( ACTIONS::increment, aCommit, ACTIONS::INCREMENT { 1, 0 } );
} }
else if( evt->IsAction( &SCH_ACTIONS::toCLabel ) ) else if( evt->IsAction( &SCH_ACTIONS::toCLabel ) )
{ {
@ -1461,7 +1464,6 @@ void SCH_MOVE_TOOL::getConnectedDragItems( SCH_COMMIT* aCommit, SCH_ITEM* aSelec
if( aPoint != line->GetStartPoint() && aPoint != line->GetEndPoint() ) if( aPoint != line->GetStartPoint() && aPoint != line->GetEndPoint() )
{ {
// Split line in half // Split line in half
if( !line->IsNew() )
aCommit->Modify( line, m_frame->GetScreen() ); aCommit->Modify( line, m_frame->GetScreen() );
VECTOR2I oldEnd = line->GetEndPoint(); VECTOR2I oldEnd = line->GetEndPoint();

View File

@ -745,10 +745,7 @@ int SCH_SELECTION_TOOL::Main( const TOOL_EVENT& aEvent )
if( field >= 0 ) if( field >= 0 )
{ {
const int delta = evt->Parameter<int>(); const int delta = evt->Parameter<int>();
ACTIONS::INCREMENT incParams{ ACTIONS::INCREMENT incParams{ delta > 0 ? 1 : -1, field };
delta > 0 ? 1 : -1,
field,
};
m_toolMgr->RunAction( ACTIONS::increment, incParams ); m_toolMgr->RunAction( ACTIONS::increment, incParams );
} }

View File

@ -24,6 +24,7 @@
#pragma once #pragma once
#include "increment.h"
#include <math/vector2d.h> #include <math/vector2d.h>
#include <tool/tool_event.h> #include <tool/tool_event.h>
#include <tool/tool_interactive.h> #include <tool/tool_interactive.h>
@ -35,6 +36,9 @@
#include <sch_view.h> #include <sch_view.h>
#include <symbol_edit_frame.h> #include <symbol_edit_frame.h>
#include <sch_shape.h> #include <sch_shape.h>
#include <pin_layout_cache.h>
#include <sch_commit.h>
#include <tool/picker_tool.h>
class SCH_SELECTION; class SCH_SELECTION;
@ -55,7 +59,8 @@ public:
m_frame( nullptr ), m_frame( nullptr ),
m_view( nullptr ), m_view( nullptr ),
m_selectionTool( nullptr ), m_selectionTool( nullptr ),
m_isSymbolEditor( false ) m_isSymbolEditor( false ),
m_pickerItem( nullptr )
{}; {};
~SCH_TOOL_BASE() override {}; ~SCH_TOOL_BASE() override {};
@ -101,6 +106,247 @@ public:
return m_isSymbolEditor; return m_isSymbolEditor;
} }
int Increment( const TOOL_EVENT& aEvent )
{
static const std::vector<KICAD_T> incrementable = { SCH_LABEL_T,
SCH_GLOBAL_LABEL_T,
SCH_HIER_LABEL_T,
SCH_PIN_T,
SCH_TEXT_T };
const ACTIONS::INCREMENT param = { 1, 0 };
if( aEvent.HasParameter() )
aEvent.Parameter<ACTIONS::INCREMENT>();
SCH_SELECTION& selection = m_selectionTool->RequestSelection( incrementable );
if( selection.Empty() )
return 0;
KICAD_T type = selection.Front()->Type();
bool allSameType = true;
for( EDA_ITEM* item : selection )
{
if( item->Type() != type )
{
allSameType = false;
break;
}
}
// Incrementing multiple types at once seems confusing though it would work.
if( !allSameType )
return 0;
const VECTOR2I mousePosition = getViewControls()->GetMousePosition();
STRING_INCREMENTER incrementer;
// In schematics, it's probably less common to be operating
// on pin numbers which are usually IOSQXZ-skippy.
incrementer.SetSkipIOSQXZ( m_isSymbolEditor );
// If we're coming via another action like 'Move', use that commit
SCH_COMMIT localCommit( m_toolMgr );
SCH_COMMIT* commit = dynamic_cast<SCH_COMMIT*>( aEvent.Commit() );
if( !commit )
commit = &localCommit;
const auto modifyItem =
[&]( EDA_ITEM& aItem )
{
if( aItem.IsNew() )
m_toolMgr->PostAction( ACTIONS::refreshPreview );
commit->Modify( &aItem, m_frame->GetScreen() );
};
for( EDA_ITEM* item : selection )
{
switch( item->Type() )
{
case SCH_PIN_T:
{
SCH_PIN& pin = static_cast<SCH_PIN&>( *item );
PIN_LAYOUT_CACHE& layout = pin.GetLayoutCache();
bool found = false;
OPT_BOX2I bbox = layout.GetPinNumberBBox();
if( bbox && bbox->Contains( mousePosition ) )
{
std::optional<wxString> nextNumber = incrementer.Increment( pin.GetNumber(), param.Delta,
param.Index );
if( nextNumber )
{
modifyItem( pin );
pin.SetNumber( *nextNumber );
}
found = true;
}
if( !found )
{
bbox = layout.GetPinNameBBox();
if( bbox && bbox->Contains( mousePosition ) )
{
std::optional<wxString> nextName = incrementer.Increment( pin.GetName(), param.Delta,
param.Index );
if( nextName )
{
modifyItem( pin );
pin.SetName( *nextName );
}
found = true;
}
}
break;
}
case SCH_LABEL_T:
case SCH_GLOBAL_LABEL_T:
case SCH_HIER_LABEL_T:
case SCH_TEXT_T:
{
SCH_TEXT& label = static_cast<SCH_TEXT&>( *item );
std::optional<wxString> newLabel = incrementer.Increment( label.GetText(), param.Delta,
param.Index );
if( newLabel )
{
modifyItem( label );
label.SetText( *newLabel );
}
break;
}
default:
// No increment for other items
break;
}
}
commit->Push( _( "Increment" ) );
if( selection.IsHover() )
m_toolMgr->RunAction( ACTIONS::selectionClear );
return 0;
}
int InteractiveDelete( const TOOL_EVENT& aEvent )
{
static std::vector<KICAD_T> deletableItems =
{
LIB_SYMBOL_T,
SCH_MARKER_T,
SCH_JUNCTION_T,
SCH_LINE_T,
SCH_BUS_BUS_ENTRY_T,
SCH_BUS_WIRE_ENTRY_T,
SCH_SHAPE_T,
SCH_RULE_AREA_T,
SCH_TEXT_T,
SCH_TEXTBOX_T,
SCH_TABLECELL_T, // Clear contents
SCH_TABLE_T,
SCH_LABEL_T,
SCH_GLOBAL_LABEL_T,
SCH_HIER_LABEL_T,
SCH_DIRECTIVE_LABEL_T,
SCH_NO_CONNECT_T,
SCH_SHEET_T,
SCH_SHEET_PIN_T,
SCH_SYMBOL_T,
SCH_FIELD_T, // Will be hidden
SCH_BITMAP_T,
SCH_GROUP_T
};
PICKER_TOOL* picker = m_toolMgr->GetTool<PICKER_TOOL>();
m_toolMgr->RunAction( ACTIONS::selectionClear );
m_pickerItem = nullptr;
// Deactivate other tools; particularly important if another PICKER is currently running
Activate();
picker->SetCursor( KICURSOR::REMOVE );
picker->SetSnapping( false );
picker->ClearHandlers();
picker->SetClickHandler(
[this]( const VECTOR2D& aPosition ) -> bool
{
if( m_pickerItem )
{
SCH_SELECTION_TOOL* selectionTool = m_toolMgr->GetTool<SCH_SELECTION_TOOL>();
selectionTool->UnbrightenItem( m_pickerItem );
selectionTool->AddItemToSel( m_pickerItem, true /*quiet mode*/ );
m_toolMgr->RunAction( ACTIONS::doDelete );
m_pickerItem = nullptr;
}
return true;
} );
picker->SetMotionHandler(
[this]( const VECTOR2D& aPos )
{
SCH_SELECTION_TOOL* selectionTool = m_toolMgr->GetTool<SCH_SELECTION_TOOL>();
SCH_COLLECTOR collector;
selectionTool->CollectHits( collector, aPos, deletableItems );
// Remove unselectable items
for( int i = collector.GetCount() - 1; i >= 0; --i )
{
if( !selectionTool->Selectable( collector[ i ] ) )
collector.Remove( i );
}
if( collector.GetCount() > 1 )
selectionTool->GuessSelectionCandidates( collector, aPos );
EDA_ITEM* item = collector.GetCount() == 1 ? collector[ 0 ] : nullptr;
if( m_pickerItem != item )
{
if( m_pickerItem )
selectionTool->UnbrightenItem( m_pickerItem );
m_pickerItem = item;
if( m_pickerItem )
selectionTool->BrightenItem( m_pickerItem );
}
} );
picker->SetFinalizeHandler(
[this]( const int& aFinalState )
{
if( m_pickerItem )
m_toolMgr->GetTool<SCH_SELECTION_TOOL>()->UnbrightenItem( m_pickerItem );
// Wake the selection tool after exiting to ensure the cursor gets updated
m_toolMgr->PostAction( ACTIONS::selectionActivate );
} );
m_toolMgr->RunAction( ACTIONS::pickerTool, &aEvent );
return 0;
}
protected: protected:
/** /**
* Similar to getView()->Update(), but also updates the SCH_SCREEN's RTree. * Similar to getView()->Update(), but also updates the SCH_SCREEN's RTree.
@ -155,4 +401,5 @@ protected:
KIGFX::SCH_VIEW* m_view; KIGFX::SCH_VIEW* m_view;
SCH_SELECTION_TOOL* m_selectionTool; SCH_SELECTION_TOOL* m_selectionTool;
bool m_isSymbolEditor; bool m_isSymbolEditor;
EDA_ITEM* m_pickerItem;
}; };

View File

@ -323,8 +323,10 @@ int SYMBOL_EDITOR_DRAWING_TOOLS::TwoClickPlace( const TOOL_EVENT& aEvent )
} }
else if( evt->IsAction( &ACTIONS::increment ) ) else if( evt->IsAction( &ACTIONS::increment ) )
{ {
m_toolMgr->RunSynchronousAction( ACTIONS::increment, &commit, if( evt->HasParameter() )
evt->Parameter<ACTIONS::INCREMENT>() ); m_toolMgr->RunSynchronousAction( ACTIONS::increment, &commit, evt->Parameter<ACTIONS::INCREMENT>() );
else
m_toolMgr->RunSynchronousAction( ACTIONS::increment, &commit, ACTIONS::INCREMENT { 1, 0 } );
} }
else if( item && ( evt->IsAction( &ACTIONS::refreshPreview ) || evt->IsMotion() ) ) else if( item && ( evt->IsAction( &ACTIONS::refreshPreview ) || evt->IsMotion() ) )
{ {

View File

@ -65,9 +65,6 @@ public:
void SetDrawSpecificUnit( bool aSpecific ) { m_drawSpecificUnit = aSpecific; } void SetDrawSpecificUnit( bool aSpecific ) { m_drawSpecificUnit = aSpecific; }
bool GetDrawSpecificUnit() const { return m_drawSpecificUnit; } bool GetDrawSpecificUnit() const { return m_drawSpecificUnit; }
KIID GetLastPin() { return g_lastPin; }
void SetLastPin( KIID aPin ) { g_lastPin = aPin; }
private: private:
int doDrawShape( const TOOL_EVENT& aEvent, std::optional<SHAPE_T> aDrawingShape ); int doDrawShape( const TOOL_EVENT& aEvent, std::optional<SHAPE_T> aDrawingShape );

View File

@ -52,8 +52,7 @@
#include <io/kicad/kicad_io_utils.h> #include <io/kicad/kicad_io_utils.h>
SYMBOL_EDITOR_EDIT_TOOL::SYMBOL_EDITOR_EDIT_TOOL() : SYMBOL_EDITOR_EDIT_TOOL::SYMBOL_EDITOR_EDIT_TOOL() :
SCH_TOOL_BASE( "eeschema.SymbolEditTool" ), SCH_TOOL_BASE( "eeschema.SymbolEditTool" )
m_pickerItem( nullptr )
{ {
} }
@ -483,86 +482,6 @@ int SYMBOL_EDITOR_EDIT_TOOL::DoDelete( const TOOL_EVENT& aEvent )
} }
#define HITTEST_THRESHOLD_PIXELS 5
int SYMBOL_EDITOR_EDIT_TOOL::InteractiveDelete( const TOOL_EVENT& aEvent )
{
PICKER_TOOL* picker = m_toolMgr->GetTool<PICKER_TOOL>();
m_toolMgr->RunAction( ACTIONS::selectionClear );
m_pickerItem = nullptr;
// Deactivate other tools; particularly important if another PICKER is currently running
Activate();
picker->SetCursor( KICURSOR::REMOVE );
picker->SetSnapping( false );
picker->ClearHandlers();
picker->SetClickHandler(
[this]( const VECTOR2D& aPosition ) -> bool
{
if( m_pickerItem )
{
SCH_SELECTION_TOOL* selectionTool = m_toolMgr->GetTool<SCH_SELECTION_TOOL>();
selectionTool->UnbrightenItem( m_pickerItem );
selectionTool->AddItemToSel( m_pickerItem, true /*quiet mode*/ );
m_toolMgr->RunAction( ACTIONS::doDelete );
m_pickerItem = nullptr;
}
return true;
} );
picker->SetMotionHandler(
[this]( const VECTOR2D& aPos )
{
SCH_SELECTION_TOOL* selectionTool = m_toolMgr->GetTool<SCH_SELECTION_TOOL>();
SCH_COLLECTOR collector;
selectionTool->CollectHits( collector, aPos, nonFields );
// Remove unselectable items
for( int i = collector.GetCount() - 1; i >= 0; --i )
{
if( !selectionTool->Selectable( collector[ i ] ) )
collector.Remove( i );
}
if( collector.GetCount() > 1 )
selectionTool->GuessSelectionCandidates( collector, aPos );
EDA_ITEM* item = collector.GetCount() == 1 ? collector[ 0 ] : nullptr;
if( m_pickerItem != item )
{
if( m_pickerItem )
selectionTool->UnbrightenItem( m_pickerItem );
m_pickerItem = item;
if( m_pickerItem )
selectionTool->BrightenItem( m_pickerItem );
}
} );
picker->SetFinalizeHandler(
[this]( const int& aFinalState )
{
if( m_pickerItem )
m_toolMgr->GetTool<SCH_SELECTION_TOOL>()->UnbrightenItem( m_pickerItem );
// Wake the selection tool after exiting to ensure the cursor gets updated
m_toolMgr->PostAction( ACTIONS::selectionActivate );
} );
m_toolMgr->RunAction( ACTIONS::pickerTool, &aEvent );
return 0;
}
int SYMBOL_EDITOR_EDIT_TOOL::Properties( const TOOL_EVENT& aEvent ) int SYMBOL_EDITOR_EDIT_TOOL::Properties( const TOOL_EVENT& aEvent )
{ {
SCH_SELECTION& selection = m_selectionTool->RequestSelection(); SCH_SELECTION& selection = m_selectionTool->RequestSelection();
@ -1123,117 +1042,6 @@ int SYMBOL_EDITOR_EDIT_TOOL::Duplicate( const TOOL_EVENT& aEvent )
} }
int SYMBOL_EDITOR_EDIT_TOOL::Increment( const TOOL_EVENT& aEvent )
{
const ACTIONS::INCREMENT incParam = aEvent.Parameter<ACTIONS::INCREMENT>();
SCH_SELECTION& selection = m_selectionTool->RequestSelection( { SCH_PIN_T, SCH_TEXT_T } );
if( selection.Empty() )
return 0;
KICAD_T type = selection.Front()->Type();
bool allSameType = true;
for( EDA_ITEM* item : selection )
{
if( item->Type() != type )
{
allSameType = false;
break;
}
}
// Incrementing multiple types at once seems confusing
// though it would work.
if( !allSameType )
return 0;
const VECTOR2I mousePosition = getViewControls()->GetMousePosition();
STRING_INCREMENTER incrementer;
incrementer.SetSkipIOSQXZ( true );
// If we're coming via another action like 'Move', use that commit
SCH_COMMIT localCommit( m_toolMgr );
SCH_COMMIT* commit = dynamic_cast<SCH_COMMIT*>( aEvent.Commit() );
if( !commit )
commit = &localCommit;
const auto modifyItem = [&]( EDA_ITEM& aItem )
{
if( aItem.IsNew() )
m_toolMgr->PostAction( ACTIONS::refreshPreview );
else
commit->Modify( &aItem, m_frame->GetScreen() );
};
for( EDA_ITEM* item : selection )
{
switch( item->Type() )
{
case SCH_PIN_T:
{
SCH_PIN& pin = static_cast<SCH_PIN&>( *item );
PIN_LAYOUT_CACHE& layout = pin.GetLayoutCache();
bool found = false;
OPT_BOX2I bbox = layout.GetPinNumberBBox();
if( bbox && bbox->Contains( mousePosition ) )
{
std::optional<wxString> nextNumber =
incrementer.Increment( pin.GetNumber(), incParam.Delta, incParam.Index );
if( nextNumber )
{
modifyItem( pin );
pin.SetNumber( *nextNumber );
}
found = true;
}
if( !found )
{
bbox = layout.GetPinNameBBox();
if( bbox && bbox->Contains( mousePosition ) )
{
std::optional<wxString> nextName =
incrementer.Increment( pin.GetName(), incParam.Delta, incParam.Index );
if( nextName )
{
modifyItem( pin );
pin.SetName( *nextName );
}
found = true;
}
}
break;
}
case SCH_TEXT_T:
{
SCH_TEXT& label = static_cast<SCH_TEXT&>( *item );
std::optional<wxString> newLabel =
incrementer.Increment( label.GetText(), incParam.Delta, incParam.Index );
if( newLabel )
{
modifyItem( label );
label.SetText( *newLabel );
}
break;
}
default:
// No increment for other items
break;
}
}
commit->Push( _( "Increment" ) );
return 0;
}
void SYMBOL_EDITOR_EDIT_TOOL::setTransitions() void SYMBOL_EDITOR_EDIT_TOOL::setTransitions()
{ {
// clang-format off // clang-format off

View File

@ -36,7 +36,7 @@ class SYMBOL_EDITOR_EDIT_TOOL : public SCH_TOOL_BASE<SYMBOL_EDIT_FRAME>
{ {
public: public:
SYMBOL_EDITOR_EDIT_TOOL(); SYMBOL_EDITOR_EDIT_TOOL();
~SYMBOL_EDITOR_EDIT_TOOL() override { } ~SYMBOL_EDITOR_EDIT_TOOL() = default;
/// @copydoc TOOL_INTERACTIVE::Init() /// @copydoc TOOL_INTERACTIVE::Init()
bool Init() override; bool Init() override;
@ -59,16 +59,11 @@ public:
int CopyAsText( const TOOL_EVENT& aEvent ); int CopyAsText( const TOOL_EVENT& aEvent );
int Paste( const TOOL_EVENT& aEvent ); int Paste( const TOOL_EVENT& aEvent );
int Increment( const TOOL_EVENT& aEvent );
/** /**
* Delete the selected items, or the item under the cursor. * Delete the selected items, or the item under the cursor.
*/ */
int DoDelete( const TOOL_EVENT& aEvent ); int DoDelete( const TOOL_EVENT& aEvent );
///< Run the deletion tool.
int InteractiveDelete( const TOOL_EVENT& aEvent );
private: private:
void editShapeProperties( SCH_SHAPE* aShape ); void editShapeProperties( SCH_SHAPE* aShape );
void editTextProperties( SCH_ITEM* aItem ); void editTextProperties( SCH_ITEM* aItem );
@ -79,6 +74,4 @@ private:
///< Set up handlers for various events. ///< Set up handlers for various events.
void setTransitions() override; void setTransitions() override;
EDA_ITEM* m_pickerItem;
}; };

View File

@ -153,7 +153,6 @@ bool SYMBOL_EDITOR_MOVE_TOOL::doMoveSelection( const TOOL_EVENT& aEvent, SCH_COM
VECTOR2I prevPos; VECTOR2I prevPos;
VECTOR2I moveOffset; VECTOR2I moveOffset;
if( !selection.Front()->IsNew() )
aCommit->Modify( m_frame->GetCurSymbol(), m_frame->GetScreen() ); aCommit->Modify( m_frame->GetCurSymbol(), m_frame->GetScreen() );
m_cursor = controls->GetCursorPosition( !aEvent.DisableGridSnapping() ); m_cursor = controls->GetCursorPosition( !aEvent.DisableGridSnapping() );

View File

@ -25,8 +25,7 @@
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
*/ */
#ifndef __COMMIT_H #pragma once
#define __COMMIT_H
#include <set> #include <set>
#include <vector> #include <vector>
@ -115,20 +114,7 @@ public:
* *
* @note Requires a copy done before the modification. * @note Requires a copy done before the modification.
*/ */
COMMIT& Modified( EDA_ITEM* aItem, EDA_ITEM* aCopy, BASE_SCREEN *aScreen = nullptr ) COMMIT& Modified( EDA_ITEM* aItem, EDA_ITEM* aCopy, BASE_SCREEN *aScreen = nullptr );
{
return createModified( aItem, aCopy, 0, aScreen );
}
template<class Range>
COMMIT& StageItems( const Range& aRange, CHANGE_TYPE aChangeType )
{
for( const auto& item : aRange )
Stage( item, aChangeType );
return *this;
}
/// Add a change of the item aItem of type aChangeType to the change list. /// Add a change of the item aItem of type aChangeType to the change list.
virtual COMMIT& Stage( EDA_ITEM* aItem, CHANGE_TYPE aChangeType, BASE_SCREEN *aScreen = nullptr, virtual COMMIT& Stage( EDA_ITEM* aItem, CHANGE_TYPE aChangeType, BASE_SCREEN *aScreen = nullptr,
@ -137,8 +123,7 @@ public:
virtual COMMIT& Stage( std::vector<EDA_ITEM*>& container, CHANGE_TYPE aChangeType, virtual COMMIT& Stage( std::vector<EDA_ITEM*>& container, CHANGE_TYPE aChangeType,
BASE_SCREEN *aScreen = nullptr ); BASE_SCREEN *aScreen = nullptr );
virtual COMMIT& Stage( const PICKED_ITEMS_LIST& aItems, virtual COMMIT& Stage( const PICKED_ITEMS_LIST& aItems, UNDO_REDO aModFlag = UNDO_REDO::UNSPECIFIED,
UNDO_REDO aModFlag = UNDO_REDO::UNSPECIFIED,
BASE_SCREEN *aScreen = nullptr ); BASE_SCREEN *aScreen = nullptr );
void Unstage( EDA_ITEM* aItem, BASE_SCREEN* aScreen ); void Unstage( EDA_ITEM* aItem, BASE_SCREEN* aScreen );
@ -151,13 +136,13 @@ public:
bool Empty() const bool Empty() const
{ {
return m_changes.empty(); return m_entries.empty();
} }
/// Returns status of an item. /// Returns status of an item.
int GetStatus( EDA_ITEM* aItem, BASE_SCREEN *aScreen = nullptr ); int GetStatus( EDA_ITEM* aItem, BASE_SCREEN *aScreen = nullptr );
EDA_ITEM* GetFirst() const { return m_changes.empty() ? nullptr : m_changes[0].m_item; } EDA_ITEM* GetFirst() const { return m_entries.empty() ? nullptr : m_entries[0].m_item; }
protected: protected:
struct COMMIT_LINE struct COMMIT_LINE
@ -165,7 +150,6 @@ protected:
EDA_ITEM* m_item; ///< Main item that is added/deleted/modified EDA_ITEM* m_item; ///< Main item that is added/deleted/modified
EDA_ITEM* m_copy; ///< Optional copy of the item EDA_ITEM* m_copy; ///< Optional copy of the item
CHANGE_TYPE m_type; ///< Modification type CHANGE_TYPE m_type; ///< Modification type
KIID m_parent = NilUuid(); ///< Parent item (primarily for undo of deleted items)
BASE_SCREEN* m_screen; BASE_SCREEN* m_screen;
}; };
@ -174,12 +158,9 @@ protected:
{ {
m_changedItems.clear(); m_changedItems.clear();
m_deletedItems.clear(); m_deletedItems.clear();
m_changes.clear(); m_entries.clear();
} }
COMMIT& createModified( EDA_ITEM* aItem, EDA_ITEM* aCopy, int aExtraFlags = 0,
BASE_SCREEN *aScreen = nullptr );
virtual void makeEntry( EDA_ITEM* aItem, CHANGE_TYPE aType, EDA_ITEM* aCopy = nullptr, virtual void makeEntry( EDA_ITEM* aItem, CHANGE_TYPE aType, EDA_ITEM* aCopy = nullptr,
BASE_SCREEN *aScreen = nullptr ); BASE_SCREEN *aScreen = nullptr );
@ -190,7 +171,7 @@ protected:
*/ */
COMMIT_LINE* findEntry( EDA_ITEM* aItem, BASE_SCREEN *aScreen = nullptr ); COMMIT_LINE* findEntry( EDA_ITEM* aItem, BASE_SCREEN *aScreen = nullptr );
virtual EDA_ITEM* parentObject( EDA_ITEM* aItem ) const = 0; virtual EDA_ITEM* undoLevelItem( EDA_ITEM* aItem ) const = 0;
virtual EDA_ITEM* makeImage( EDA_ITEM* aItem ) const = 0; virtual EDA_ITEM* makeImage( EDA_ITEM* aItem ) const = 0;
@ -198,9 +179,9 @@ protected:
UNDO_REDO convert( CHANGE_TYPE aType ) const; UNDO_REDO convert( CHANGE_TYPE aType ) const;
protected: protected:
std::set<EDA_ITEM*> m_changedItems; std::set<std::pair<EDA_ITEM*, BASE_SCREEN*>> m_addedItems;
std::set<EDA_ITEM*> m_deletedItems; std::set<std::pair<EDA_ITEM*, BASE_SCREEN*>> m_changedItems;
std::vector<COMMIT_LINE> m_changes; std::set<std::pair<EDA_ITEM*, BASE_SCREEN*>> m_deletedItems;
std::vector<COMMIT_LINE> m_entries;
}; };
#endif

View File

@ -458,6 +458,11 @@ public:
*/ */
bool IsSimulator() const; bool IsSimulator() const;
bool HasParameter() const
{
return m_param.has_value();
}
/** /**
* Return a parameter assigned to the event. Its meaning depends on the target tool. * Return a parameter assigned to the event. Its meaning depends on the target tool.
*/ */

View File

@ -50,6 +50,7 @@ using namespace std::placeholders;
BOARD_COMMIT::BOARD_COMMIT( TOOL_BASE* aTool ) : BOARD_COMMIT::BOARD_COMMIT( TOOL_BASE* aTool ) :
COMMIT(),
m_toolMgr( aTool->GetManager() ), m_toolMgr( aTool->GetManager() ),
m_isBoardEditor( false ), m_isBoardEditor( false ),
m_isFootprintEditor( false ) m_isFootprintEditor( false )
@ -63,6 +64,7 @@ BOARD_COMMIT::BOARD_COMMIT( TOOL_BASE* aTool ) :
BOARD_COMMIT::BOARD_COMMIT( EDA_DRAW_FRAME* aFrame ) : BOARD_COMMIT::BOARD_COMMIT( EDA_DRAW_FRAME* aFrame ) :
COMMIT(),
m_toolMgr( aFrame->GetToolManager() ), m_toolMgr( aFrame->GetToolManager() ),
m_isBoardEditor( aFrame->IsType( FRAME_PCB_EDITOR ) ), m_isBoardEditor( aFrame->IsType( FRAME_PCB_EDITOR ) ),
m_isFootprintEditor( aFrame->IsType( FRAME_FOOTPRINT_EDITOR ) ) m_isFootprintEditor( aFrame->IsType( FRAME_FOOTPRINT_EDITOR ) )
@ -71,6 +73,7 @@ BOARD_COMMIT::BOARD_COMMIT( EDA_DRAW_FRAME* aFrame ) :
BOARD_COMMIT::BOARD_COMMIT( TOOL_MANAGER* aMgr ) : BOARD_COMMIT::BOARD_COMMIT( TOOL_MANAGER* aMgr ) :
COMMIT(),
m_toolMgr( aMgr ), m_toolMgr( aMgr ),
m_isBoardEditor( false ), m_isBoardEditor( false ),
m_isFootprintEditor( false ) m_isFootprintEditor( false )
@ -83,10 +86,12 @@ BOARD_COMMIT::BOARD_COMMIT( TOOL_MANAGER* aMgr ) :
m_isFootprintEditor = true; m_isFootprintEditor = true;
} }
BOARD_COMMIT::BOARD_COMMIT( TOOL_MANAGER* aMgr, bool aIsBoardEditor ) :
BOARD_COMMIT::BOARD_COMMIT( TOOL_MANAGER* aMgr, bool aIsBoardEditor, bool aIsFootprintEditor ) :
COMMIT(),
m_toolMgr( aMgr ), m_toolMgr( aMgr ),
m_isBoardEditor( aIsBoardEditor ), m_isBoardEditor( aIsBoardEditor ),
m_isFootprintEditor( false ) m_isFootprintEditor( aIsFootprintEditor )
{ {
} }
@ -97,8 +102,7 @@ BOARD* BOARD_COMMIT::GetBoard() const
} }
COMMIT& BOARD_COMMIT::Stage( EDA_ITEM* aItem, CHANGE_TYPE aChangeType, BASE_SCREEN* aScreen, COMMIT& BOARD_COMMIT::Stage( EDA_ITEM* aItem, CHANGE_TYPE aChangeType, BASE_SCREEN* aScreen, RECURSE_MODE aRecurse )
RECURSE_MODE aRecurse )
{ {
if( aRecurse == RECURSE_MODE::RECURSE ) if( aRecurse == RECURSE_MODE::RECURSE )
{ {
@ -113,15 +117,13 @@ COMMIT& BOARD_COMMIT::Stage( EDA_ITEM* aItem, CHANGE_TYPE aChangeType, BASE_SCRE
} }
COMMIT& BOARD_COMMIT::Stage( std::vector<EDA_ITEM*>& container, CHANGE_TYPE aChangeType, COMMIT& BOARD_COMMIT::Stage( std::vector<EDA_ITEM*>& container, CHANGE_TYPE aChangeType, BASE_SCREEN* aScreen )
BASE_SCREEN* aScreen )
{ {
return COMMIT::Stage( container, aChangeType, aScreen ); return COMMIT::Stage( container, aChangeType, aScreen );
} }
COMMIT& BOARD_COMMIT::Stage( const PICKED_ITEMS_LIST& aItems, UNDO_REDO aModFlag, COMMIT& BOARD_COMMIT::Stage( const PICKED_ITEMS_LIST& aItems, UNDO_REDO aModFlag, BASE_SCREEN* aScreen )
BASE_SCREEN* aScreen )
{ {
return COMMIT::Stage( aItems, aModFlag, aScreen ); return COMMIT::Stage( aItems, aModFlag, aScreen );
} }
@ -163,15 +165,12 @@ void BOARD_COMMIT::propagateDamage( BOARD_ITEM* aChangedItem, std::vector<ZONE*>
if( zone->GetIsRuleArea() ) if( zone->GetIsRuleArea() )
continue; continue;
if( ( zone->GetLayerSet() & damageLayers ).any() if( ( zone->GetLayerSet() & damageLayers ).any() && zone->GetBoundingBox().Intersects( damageBBox ) )
&& zone->GetBoundingBox().Intersects( damageBBox ) )
{
aStaleZones->push_back( zone ); aStaleZones->push_back( zone );
} }
} }
} }
} }
}
void BOARD_COMMIT::Push( const wxString& aMessage, int aCommitFlags ) void BOARD_COMMIT::Push( const wxString& aMessage, int aCommitFlags )
@ -211,8 +210,7 @@ void BOARD_COMMIT::Push( const wxString& aMessage, int aCommitFlags )
std::vector<BOARD_ITEM*> bulkRemovedItems; std::vector<BOARD_ITEM*> bulkRemovedItems;
std::vector<BOARD_ITEM*> itemsChanged; std::vector<BOARD_ITEM*> itemsChanged;
if( m_isBoardEditor if( m_isBoardEditor && !( aCommitFlags & ZONE_FILL_OP )
&& !( aCommitFlags & ZONE_FILL_OP )
&& ( frame && frame->GetPcbNewSettings()->m_AutoRefillZones ) ) && ( frame && frame->GetPcbNewSettings()->m_AutoRefillZones ) )
{ {
autofillZones = true; autofillZones = true;
@ -222,12 +220,12 @@ void BOARD_COMMIT::Push( const wxString& aMessage, int aCommitFlags )
zone->CacheBoundingBox(); zone->CacheBoundingBox();
} }
for( COMMIT_LINE& ent : m_changes ) for( COMMIT_LINE& entry : m_entries )
{ {
if( !ent.m_item || !ent.m_item->IsBOARD_ITEM() ) if( !entry.m_item || !entry.m_item->IsBOARD_ITEM() )
continue; continue;
BOARD_ITEM* boardItem = static_cast<BOARD_ITEM*>( ent.m_item ); BOARD_ITEM* boardItem = static_cast<BOARD_ITEM*>( entry.m_item );
if( m_isBoardEditor ) if( m_isBoardEditor )
{ {
@ -297,14 +295,14 @@ void BOARD_COMMIT::Push( const wxString& aMessage, int aCommitFlags )
Modify( enteredGroup ); Modify( enteredGroup );
for( COMMIT_LINE& ent : m_changes ) for( COMMIT_LINE& entry : m_entries )
{ {
if( !ent.m_item || !ent.m_item->IsBOARD_ITEM() ) if( !entry.m_item || !entry.m_item->IsBOARD_ITEM() )
continue; continue;
BOARD_ITEM* boardItem = static_cast<BOARD_ITEM*>( ent.m_item ); BOARD_ITEM* boardItem = static_cast<BOARD_ITEM*>( entry.m_item );
int changeType = ent.m_type & CHT_TYPE; int changeType = entry.m_type & CHT_TYPE;
int changeFlags = ent.m_type & CHT_FLAGS; int changeFlags = entry.m_type & CHT_FLAGS;
switch( changeType ) switch( changeType )
{ {
@ -319,13 +317,7 @@ void BOARD_COMMIT::Push( const wxString& aMessage, int aCommitFlags )
{ {
if( m_isFootprintEditor ) if( m_isFootprintEditor )
{ {
FOOTPRINT* parentFP = board->GetFirstFootprint(); if( FOOTPRINT* parentFP = board->GetFirstFootprint() )
wxCHECK2_MSG( parentFP, continue, "Commit thinks this is footprint editor, but "
"there is no first footprint!" );
parentFP->Add( boardItem );
}
else if( FOOTPRINT* parentFP = boardItem->GetParentFootprint() )
{
parentFP->Add( boardItem ); parentFP->Add( boardItem );
} }
else else
@ -347,14 +339,13 @@ void BOARD_COMMIT::Push( const wxString& aMessage, int aCommitFlags )
case CHT_REMOVE: case CHT_REMOVE:
{ {
FOOTPRINT* parentFP = boardItem->GetParentFootprint();
EDA_GROUP* parentGroup = boardItem->GetParentGroup(); EDA_GROUP* parentGroup = boardItem->GetParentGroup();
if( !( aCommitFlags & SKIP_UNDO ) ) if( !( aCommitFlags & SKIP_UNDO ) )
{ {
ITEM_PICKER itemWrapper( nullptr, boardItem, UNDO_REDO::DELETED ); ITEM_PICKER itemWrapper( nullptr, boardItem, UNDO_REDO::DELETED );
itemWrapper.SetLink( ent.m_copy ); itemWrapper.SetLink( entry.m_copy );
ent.m_copy = nullptr; // We've transferred ownership to the undo list entry.m_copy = nullptr; // We've transferred ownership to the undo list
undoList.PushItem( itemWrapper ); undoList.PushItem( itemWrapper );
} }
@ -369,9 +360,6 @@ void BOARD_COMMIT::Push( const wxString& aMessage, int aCommitFlags )
if( parentGroup && !( parentGroup->AsEdaItem()->GetFlags() & STRUCT_DELETED ) ) if( parentGroup && !( parentGroup->AsEdaItem()->GetFlags() & STRUCT_DELETED ) )
parentGroup->RemoveItem( boardItem ); parentGroup->RemoveItem( boardItem );
if( parentFP && !( parentFP->GetFlags() & STRUCT_DELETED ) )
ent.m_parent = parentFP->m_Uuid;
if( boardItem->Type() != PCB_MARKER_T ) if( boardItem->Type() != PCB_MARKER_T )
propagateDamage( boardItem, staleZones, staleRuleAreas ); propagateDamage( boardItem, staleZones, staleRuleAreas );
@ -383,21 +371,21 @@ void BOARD_COMMIT::Push( const wxString& aMessage, int aCommitFlags )
case PCB_TEXT_T: case PCB_TEXT_T:
case PCB_PAD_T: case PCB_PAD_T:
case PCB_SHAPE_T: // a shape (normally not on copper layers) case PCB_SHAPE_T:
case PCB_REFERENCE_IMAGE_T: // a bitmap on an associated layer case PCB_REFERENCE_IMAGE_T:
case PCB_GENERATOR_T: // a generator on a layer case PCB_GENERATOR_T:
case PCB_TEXTBOX_T: // a line-wrapped (and optionally bordered) text item case PCB_TEXTBOX_T:
case PCB_TABLE_T: // rows and columns of tablecells case PCB_TABLE_T:
case PCB_TRACE_T: // a track segment (segment on a copper layer) case PCB_TRACE_T:
case PCB_ARC_T: // an arced track segment (segment on a copper layer) case PCB_ARC_T:
case PCB_VIA_T: // a via (like track segment on a copper layer) case PCB_VIA_T:
case PCB_DIM_ALIGNED_T: // a dimension (graphic item) case PCB_DIM_ALIGNED_T:
case PCB_DIM_CENTER_T: case PCB_DIM_CENTER_T:
case PCB_DIM_RADIAL_T: case PCB_DIM_RADIAL_T:
case PCB_DIM_ORTHOGONAL_T: case PCB_DIM_ORTHOGONAL_T:
case PCB_DIM_LEADER_T: // a leader dimension case PCB_DIM_LEADER_T:
case PCB_TARGET_T: // a target (graphic item) case PCB_TARGET_T:
case PCB_MARKER_T: // a marker used to show something case PCB_MARKER_T:
case PCB_ZONE_T: case PCB_ZONE_T:
case PCB_FOOTPRINT_T: case PCB_FOOTPRINT_T:
case PCB_GROUP_T: case PCB_GROUP_T:
@ -406,8 +394,9 @@ void BOARD_COMMIT::Push( const wxString& aMessage, int aCommitFlags )
if( !( changeFlags & CHT_DONE ) ) if( !( changeFlags & CHT_DONE ) )
{ {
if( parentFP ) if( m_isFootprintEditor )
{ {
if( FOOTPRINT* parentFP = board->GetFirstFootprint() )
parentFP->Remove( boardItem ); parentFP->Remove( boardItem );
} }
else else
@ -437,13 +426,13 @@ void BOARD_COMMIT::Push( const wxString& aMessage, int aCommitFlags )
case CHT_MODIFY: case CHT_MODIFY:
{ {
BOARD_ITEM* boardItemCopy = static_cast<BOARD_ITEM*>( ent.m_copy ); BOARD_ITEM* boardItemCopy = static_cast<BOARD_ITEM*>( entry.m_copy );
if( !( aCommitFlags & SKIP_UNDO ) ) if( !( aCommitFlags & SKIP_UNDO ) )
{ {
ITEM_PICKER itemWrapper( nullptr, boardItem, UNDO_REDO::CHANGED ); ITEM_PICKER itemWrapper( nullptr, boardItem, UNDO_REDO::CHANGED );
itemWrapper.SetLink( ent.m_copy ); itemWrapper.SetLink( entry.m_copy );
ent.m_copy = nullptr; // We've transferred ownership to the undo list entry.m_copy = nullptr; // We've transferred ownership to the undo list
undoList.PushItem( itemWrapper ); undoList.PushItem( itemWrapper );
} }
@ -461,7 +450,7 @@ void BOARD_COMMIT::Push( const wxString& aMessage, int aCommitFlags )
updateComponentClasses( boardItem ); updateComponentClasses( boardItem );
if( view ) if( view && boardItem->Type() != PCB_NETINFO_T )
view->Update( boardItem ); view->Update( boardItem );
itemsChanged.push_back( boardItem ); itemsChanged.push_back( boardItem );
@ -474,8 +463,8 @@ void BOARD_COMMIT::Push( const wxString& aMessage, int aCommitFlags )
} }
// Delete any copies we still have ownership of // Delete any copies we still have ownership of
delete ent.m_copy; delete entry.m_copy;
ent.m_copy = nullptr; entry.m_copy = nullptr;
boardItem->ClearEditFlags(); boardItem->ClearEditFlags();
boardItem->RunOnChildren( boardItem->RunOnChildren(
@ -491,7 +480,7 @@ void BOARD_COMMIT::Push( const wxString& aMessage, int aCommitFlags )
if( m_isBoardEditor ) if( m_isBoardEditor )
{ {
size_t num_changes = m_changes.size(); size_t originalCount = m_entries.size();
if( aCommitFlags & SKIP_CONNECTIVITY ) if( aCommitFlags & SKIP_CONNECTIVITY )
{ {
@ -548,36 +537,36 @@ void BOARD_COMMIT::Push( const wxString& aMessage, int aCommitFlags )
} }
// Log undo items for any connectivity or teardrop changes // Log undo items for any connectivity or teardrop changes
for( size_t i = num_changes; i < m_changes.size(); ++i ) for( size_t i = originalCount; i < m_entries.size(); ++i )
{ {
COMMIT_LINE& ent = m_changes[i]; COMMIT_LINE& entry = m_entries[i];
BOARD_ITEM* boardItem = nullptr; BOARD_ITEM* boardItem = nullptr;
BOARD_ITEM* boardItemCopy = nullptr; BOARD_ITEM* boardItemCopy = nullptr;
if( ent.m_item && ent.m_item->IsBOARD_ITEM() ) if( entry.m_item && entry.m_item->IsBOARD_ITEM() )
boardItem = static_cast<BOARD_ITEM*>( ent.m_item ); boardItem = static_cast<BOARD_ITEM*>( entry.m_item );
if( ent.m_copy && ent.m_copy->IsBOARD_ITEM() ) if( entry.m_copy && entry.m_copy->IsBOARD_ITEM() )
boardItemCopy = static_cast<BOARD_ITEM*>( ent.m_copy ); boardItemCopy = static_cast<BOARD_ITEM*>( entry.m_copy );
wxCHECK2( boardItem, continue ); wxCHECK2( boardItem, continue );
if( !( aCommitFlags & SKIP_UNDO ) ) if( !( aCommitFlags & SKIP_UNDO ) )
{ {
ITEM_PICKER itemWrapper( nullptr, boardItem, convert( ent.m_type & CHT_TYPE ) ); ITEM_PICKER itemWrapper( nullptr, boardItem, convert( entry.m_type & CHT_TYPE ) );
itemWrapper.SetLink( boardItemCopy ); itemWrapper.SetLink( boardItemCopy );
undoList.PushItem( itemWrapper ); undoList.PushItem( itemWrapper );
} }
else else
{ {
delete ent.m_copy; delete entry.m_copy;
} }
if( view ) if( view && boardItem->Type() != PCB_NETINFO_T )
{ {
if( ( ent.m_type & CHT_TYPE ) == CHT_ADD ) if( ( entry.m_type & CHT_TYPE ) == CHT_ADD )
view->Add( boardItem ); view->Add( boardItem );
else if( ( ent.m_type & CHT_TYPE ) == CHT_REMOVE ) else if( ( entry.m_type & CHT_TYPE ) == CHT_REMOVE )
view->Remove( boardItem ); view->Remove( boardItem );
else else
view->Update( boardItem ); view->Update( boardItem );
@ -640,8 +629,21 @@ void BOARD_COMMIT::Push( const wxString& aMessage, int aCommitFlags )
} }
EDA_ITEM* BOARD_COMMIT::parentObject( EDA_ITEM* aItem ) const EDA_ITEM* BOARD_COMMIT::undoLevelItem( EDA_ITEM* aItem ) const
{ {
// Easiest way to disallow both a parent and one of its children appearing in the list
// is to only ever add the parent when either can be legal (ie: in the board editor).
if( m_isBoardEditor && aItem->IsBOARD_ITEM() )
{
if( FOOTPRINT* footprint = static_cast<BOARD_ITEM*>( aItem )->GetParentFootprint() )
return footprint;
}
EDA_ITEM* parent = aItem->GetParent();
if( parent && parent->Type() == PCB_TABLE_T )
return parent;
return aItem; return aItem;
} }
@ -670,7 +672,8 @@ void BOARD_COMMIT::Revert()
board->IncrementTimeStamp(); // clear caches board->IncrementTimeStamp(); // clear caches
auto updateComponentClasses = [this]( BOARD_ITEM* boardItem ) auto updateComponentClasses =
[this]( BOARD_ITEM* boardItem )
{ {
if( boardItem->Type() != PCB_FOOTPRINT_T ) if( boardItem->Type() != PCB_FOOTPRINT_T )
return; return;
@ -683,7 +686,7 @@ void BOARD_COMMIT::Revert()
std::vector<BOARD_ITEM*> bulkRemovedItems; std::vector<BOARD_ITEM*> bulkRemovedItems;
std::vector<BOARD_ITEM*> itemsChanged; std::vector<BOARD_ITEM*> itemsChanged;
for( COMMIT_LINE& entry : m_changes ) for( COMMIT_LINE& entry : m_entries )
{ {
if( !entry.m_item || !entry.m_item->IsBOARD_ITEM() ) if( !entry.m_item || !entry.m_item->IsBOARD_ITEM() )
continue; continue;
@ -698,10 +701,12 @@ void BOARD_COMMIT::Revert()
if( !( changeFlags & CHT_DONE ) ) if( !( changeFlags & CHT_DONE ) )
break; break;
if( boardItem->Type() != PCB_NETINFO_T )
view->Remove( boardItem ); view->Remove( boardItem );
if( FOOTPRINT* parentFP = boardItem->GetParentFootprint() ) if( m_isFootprintEditor )
{ {
if( FOOTPRINT* parentFP = board->GetFirstFootprint() )
parentFP->Remove( boardItem ); parentFP->Remove( boardItem );
} }
else else
@ -717,36 +722,38 @@ void BOARD_COMMIT::Revert()
if( !( changeFlags & CHT_DONE ) ) if( !( changeFlags & CHT_DONE ) )
break; break;
if( boardItem->Type() != PCB_NETINFO_T )
view->Add( boardItem ); view->Add( boardItem );
if( BOARD_ITEM* parent = board->ResolveItem( entry.m_parent, true ) ) if( m_isFootprintEditor )
{ {
if( parent->Type() == PCB_FOOTPRINT_T ) if( FOOTPRINT* parentFP = board->GetFirstFootprint() )
{ parentFP->Add( boardItem, ADD_MODE::INSERT );
static_cast<FOOTPRINT*>( parent )->Add( boardItem, ADD_MODE::INSERT );
} }
else else
{ {
board->Add( boardItem, ADD_MODE::INSERT ); board->Add( boardItem, ADD_MODE::INSERT );
bulkAddedItems.push_back( boardItem ); bulkAddedItems.push_back( boardItem );
} }
}
updateComponentClasses( boardItem ); updateComponentClasses( boardItem );
break; break;
} }
case CHT_MODIFY: case CHT_MODIFY:
{ {
if( boardItem->Type() != PCB_NETINFO_T )
view->Remove( boardItem ); view->Remove( boardItem );
connectivity->Remove( boardItem ); connectivity->Remove( boardItem );
wxASSERT( entry.m_copy && entry.m_copy->IsBOARD_ITEM() ); wxASSERT( entry.m_copy && entry.m_copy->IsBOARD_ITEM() );
BOARD_ITEM* boardItemCopy = static_cast<BOARD_ITEM*>( entry.m_copy ); BOARD_ITEM* boardItemCopy = static_cast<BOARD_ITEM*>( entry.m_copy );
boardItem->SwapItemData( boardItemCopy ); boardItem->SwapItemData( boardItemCopy );
if( boardItem->Type() != PCB_NETINFO_T )
view->Add( boardItem ); view->Add( boardItem );
connectivity->Add( boardItem ); connectivity->Add( boardItem );
itemsChanged.push_back( boardItem ); itemsChanged.push_back( boardItem );

View File

@ -23,8 +23,7 @@
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
*/ */
#ifndef BOARD_COMMIT_H #pragma once
#define BOARD_COMMIT_H
#include <commit.h> #include <commit.h>
@ -51,7 +50,7 @@ public:
BOARD_COMMIT( EDA_DRAW_FRAME* aFrame ); BOARD_COMMIT( EDA_DRAW_FRAME* aFrame );
BOARD_COMMIT( TOOL_BASE* aTool ); BOARD_COMMIT( TOOL_BASE* aTool );
BOARD_COMMIT( TOOL_MANAGER* aMgr ); BOARD_COMMIT( TOOL_MANAGER* aMgr );
BOARD_COMMIT( TOOL_MANAGER* aMgr, bool aIsBoardEditor ); BOARD_COMMIT( TOOL_MANAGER* aMgr, bool aIsBoardEditor, bool aIsFootprintEditor );
virtual ~BOARD_COMMIT() {} virtual ~BOARD_COMMIT() {}
@ -72,7 +71,7 @@ public:
static EDA_ITEM* MakeImage( EDA_ITEM* aItem ); static EDA_ITEM* MakeImage( EDA_ITEM* aItem );
private: private:
EDA_ITEM* parentObject( EDA_ITEM* aItem ) const override; EDA_ITEM* undoLevelItem( EDA_ITEM* aItem ) const override;
EDA_ITEM* makeImage( EDA_ITEM* aItem ) const override; EDA_ITEM* makeImage( EDA_ITEM* aItem ) const override;
@ -84,5 +83,3 @@ private:
bool m_isBoardEditor; bool m_isBoardEditor;
bool m_isFootprintEditor; bool m_isFootprintEditor;
}; };
#endif

View File

@ -134,6 +134,9 @@ bool FOOTPRINT_EDIT_FRAME::Clear_Pcb( bool doAskAboutUnsavedChanges )
ClearUndoRedoList(); ClearUndoRedoList();
GetScreen()->SetContentModified( false ); GetScreen()->SetContentModified( false );
// Clear the view so we don't attempt redraws
GetCanvas()->GetView()->Clear();
if( !m_isClosing ) if( !m_isClosing )
{ {
SetBoard( new BOARD ); SetBoard( new BOARD );
@ -169,9 +172,6 @@ bool FOOTPRINT_EDIT_FRAME::Clear_Pcb( bool doAskAboutUnsavedChanges )
{ {
if( m_toolManager ) if( m_toolManager )
m_toolManager->ResetTools( TOOL_BASE::MODEL_RELOAD ); m_toolManager->ResetTools( TOOL_BASE::MODEL_RELOAD );
// Clear the view so we don't attempt redraws
GetCanvas()->GetView()->Clear();
} }

View File

@ -2182,7 +2182,6 @@ int EDIT_TOOL::Rotate( const TOOL_EVENT& aEvent )
{ {
for( EDA_ITEM* item : selection ) for( EDA_ITEM* item : selection )
{ {
if( !item->IsNew() && !item->IsMoving() )
commit->Modify( item, nullptr, RECURSE_MODE::RECURSE ); commit->Modify( item, nullptr, RECURSE_MODE::RECURSE );
if( item->IsBOARD_ITEM() ) if( item->IsBOARD_ITEM() )
@ -2262,6 +2261,7 @@ const std::vector<KICAD_T> EDIT_TOOL::MirrorableItems = {
PCB_GENERATOR_T, PCB_GENERATOR_T,
}; };
int EDIT_TOOL::Mirror( const TOOL_EVENT& aEvent ) int EDIT_TOOL::Mirror( const TOOL_EVENT& aEvent )
{ {
if( isRouterActive() ) if( isRouterActive() )
@ -2318,7 +2318,6 @@ int EDIT_TOOL::Mirror( const TOOL_EVENT& aEvent )
if( !item->IsType( MirrorableItems ) ) if( !item->IsType( MirrorableItems ) )
continue; continue;
if( !item->IsNew() && !item->IsMoving() )
commit->Modify( item, nullptr, RECURSE_MODE::RECURSE ); commit->Modify( item, nullptr, RECURSE_MODE::RECURSE );
// modify each object as necessary // modify each object as necessary
@ -2426,16 +2425,12 @@ int EDIT_TOOL::JustifyText( const TOOL_EVENT& aEvent )
{ {
if( item->Type() == PCB_FIELD_T || item->Type() == PCB_TEXT_T ) if( item->Type() == PCB_FIELD_T || item->Type() == PCB_TEXT_T )
{ {
if( !item->IsNew() && !item->IsMoving() )
commit->Modify( item ); commit->Modify( item );
setJustify( static_cast<PCB_TEXT*>( item ) ); setJustify( static_cast<PCB_TEXT*>( item ) );
} }
else if( item->Type() == PCB_TEXTBOX_T ) else if( item->Type() == PCB_TEXTBOX_T )
{ {
if( !item->IsNew() && !item->IsMoving() )
commit->Modify( item ); commit->Modify( item );
setJustify( static_cast<PCB_TEXTBOX*>( item ) ); setJustify( static_cast<PCB_TEXTBOX*>( item ) );
} }
} }
@ -2524,7 +2519,6 @@ int EDIT_TOOL::Flip( const TOOL_EVENT& aEvent )
BOARD_ITEM* boardItem = static_cast<BOARD_ITEM*>( item ); BOARD_ITEM* boardItem = static_cast<BOARD_ITEM*>( item );
if( !boardItem->IsNew() && !boardItem->IsMoving() )
commit->Modify( boardItem, nullptr, RECURSE_MODE::RECURSE ); commit->Modify( boardItem, nullptr, RECURSE_MODE::RECURSE );
boardItem->Flip( refPt, flipDirection ); boardItem->Flip( refPt, flipDirection );
@ -2862,7 +2856,6 @@ int EDIT_TOOL::MoveExact( const TOOL_EVENT& aEvent )
BOARD_ITEM* boardItem = static_cast<BOARD_ITEM*>( item ); BOARD_ITEM* boardItem = static_cast<BOARD_ITEM*>( item );
if( !boardItem->IsNew() )
commit.Modify( boardItem, nullptr, RECURSE_MODE::RECURSE ); commit.Modify( boardItem, nullptr, RECURSE_MODE::RECURSE );
if( !boardItem->GetParent() || !boardItem->GetParent()->IsSelected() ) if( !boardItem->GetParent() || !boardItem->GetParent()->IsSelected() )
@ -3101,7 +3094,10 @@ int EDIT_TOOL::Increment( const TOOL_EVENT& aEvent )
if( selection.Empty() ) if( selection.Empty() )
return 0; return 0;
const ACTIONS::INCREMENT incParam = aEvent.Parameter<ACTIONS::INCREMENT>(); ACTIONS::INCREMENT param = { 1, 0 };
if( aEvent.HasParameter() )
param = aEvent.Parameter<ACTIONS::INCREMENT>();
STRING_INCREMENTER incrementer; STRING_INCREMENTER incrementer;
incrementer.SetSkipIOSQXZ( true ); incrementer.SetSkipIOSQXZ( true );
@ -3129,14 +3125,11 @@ int EDIT_TOOL::Increment( const TOOL_EVENT& aEvent )
continue; continue;
// Increment on the pad numbers // Increment on the pad numbers
std::optional<wxString> newNumber = incrementer.Increment( pad.GetNumber(), incParam.Delta, std::optional<wxString> newNumber = incrementer.Increment( pad.GetNumber(), param.Delta, param.Index );
incParam.Index );
if( newNumber ) if( newNumber )
{ {
if( !pad.IsNew() )
commit->Modify( &pad ); commit->Modify( &pad );
pad.SetNumber( *newNumber ); pad.SetNumber( *newNumber );
} }
@ -3146,14 +3139,11 @@ int EDIT_TOOL::Increment( const TOOL_EVENT& aEvent )
{ {
PCB_TEXT& text = static_cast<PCB_TEXT&>( *item ); PCB_TEXT& text = static_cast<PCB_TEXT&>( *item );
std::optional<wxString> newText = incrementer.Increment( text.GetText(), incParam.Delta, std::optional<wxString> newText = incrementer.Increment( text.GetText(), param.Delta, param.Index );
incParam.Index );
if( newText ) if( newText )
{ {
if( !text.IsNew() )
commit->Modify( &text ); commit->Modify( &text );
text.SetText( *newText ); text.SetText( *newText );
} }

View File

@ -47,8 +47,6 @@
#include <dialogs/dialog_move_exact.h> #include <dialogs/dialog_move_exact.h>
#include <zone_filler.h> #include <zone_filler.h>
#include <drc/drc_engine.h> #include <drc/drc_engine.h>
#include <drc/drc_item.h>
#include <drc/drc_rule.h>
#include <drc/drc_interactive_courtyard_clearance.h> #include <drc/drc_interactive_courtyard_clearance.h>
#include <view/view_controls.h> #include <view/view_controls.h>
@ -92,10 +90,7 @@ int EDIT_TOOL::Swap( const TOOL_EVENT& aEvent )
// Save items, so changes can be undone // Save items, so changes can be undone
for( EDA_ITEM* item : selection ) for( EDA_ITEM* item : selection )
{
if( !item->IsNew() && !item->IsMoving() )
commit->Modify( item, nullptr, RECURSE_MODE::RECURSE ); commit->Modify( item, nullptr, RECURSE_MODE::RECURSE );
}
for( size_t i = 0; i < sorted.size() - 1; i++ ) for( size_t i = 0; i < sorted.size() - 1; i++ )
{ {
@ -489,8 +484,7 @@ bool EDIT_TOOL::doMoveSelection( const TOOL_EVENT& aEvent, BOARD_COMMIT* aCommit
VECTOR2I mousePos( controls->GetMousePosition() ); VECTOR2I mousePos( controls->GetMousePosition() );
m_cursor = grid.BestSnapAnchor( mousePos, layers, m_cursor = grid.BestSnapAnchor( mousePos, layers, grid.GetSelectionGrid( selection ), sel_items );
grid.GetSelectionGrid( selection ), sel_items );
if( controls->GetSettings().m_lastKeyboardCursorPositionValid ) if( controls->GetSettings().m_lastKeyboardCursorPositionValid )
{ {
@ -498,8 +492,7 @@ bool EDIT_TOOL::doMoveSelection( const TOOL_EVENT& aEvent, BOARD_COMMIT* aCommit
grid.SetUseGrid( false ); grid.SetUseGrid( false );
} }
m_cursor = grid.BestSnapAnchor( mousePos, layers, m_cursor = grid.BestSnapAnchor( mousePos, layers, grid.GetSelectionGrid( selection ), sel_items );
grid.GetSelectionGrid( selection ), sel_items );
if( !selection.HasReferencePoint() ) if( !selection.HasReferencePoint() )
originalPos = m_cursor; originalPos = m_cursor;
@ -657,8 +650,7 @@ bool EDIT_TOOL::doMoveSelection( const TOOL_EVENT& aEvent, BOARD_COMMIT* aCommit
// Use the mouse position over cursor, as otherwise large grids will allow only // Use the mouse position over cursor, as otherwise large grids will allow only
// snapping to items that are closest to grid points // snapping to items that are closest to grid points
m_cursor = grid.BestDragOrigin( originalMousePos, sel_items, m_cursor = grid.BestDragOrigin( originalMousePos, sel_items, grid.GetSelectionGrid( selection ),
grid.GetSelectionGrid( selection ),
&m_selectionTool->GetFilter() ); &m_selectionTool->GetFilter() );
// Set the current cursor position to the first dragged item origin, so the // Set the current cursor position to the first dragged item origin, so the
@ -710,11 +702,17 @@ bool EDIT_TOOL::doMoveSelection( const TOOL_EVENT& aEvent, BOARD_COMMIT* aCommit
{ {
m_selectionTool->GetToolMenu().ShowContextMenu( selection ); m_selectionTool->GetToolMenu().ShowContextMenu( selection );
} }
else if( evt->IsAction( &ACTIONS::undo ) || evt->IsAction( &ACTIONS::doDelete ) ) else if( evt->IsAction( &ACTIONS::undo ) )
{ {
restore_state = true; // Perform undo locally restore_state = true; // Perform undo locally
break; // Finish break; // Finish
} }
else if( evt->IsAction( &ACTIONS::doDelete ) )
{
evt->SetPassEvent();
// Exit on a delete; there will no longer be anything to drag.
break;
}
else if( evt->IsAction( &ACTIONS::duplicate ) || evt->IsAction( &ACTIONS::cut ) ) else if( evt->IsAction( &ACTIONS::duplicate ) || evt->IsAction( &ACTIONS::cut ) )
{ {
wxBell(); wxBell();
@ -786,8 +784,10 @@ bool EDIT_TOOL::doMoveSelection( const TOOL_EVENT& aEvent, BOARD_COMMIT* aCommit
} }
else if( evt->IsAction( &ACTIONS::increment ) ) else if( evt->IsAction( &ACTIONS::increment ) )
{ {
m_toolMgr->RunSynchronousAction( ACTIONS::increment, aCommit, if( evt->HasParameter() )
evt->Parameter<ACTIONS::INCREMENT>() ); m_toolMgr->RunSynchronousAction( ACTIONS::increment, aCommit, evt->Parameter<ACTIONS::INCREMENT>() );
else
m_toolMgr->RunSynchronousAction( ACTIONS::increment, aCommit, ACTIONS::INCREMENT { 1, 0 } );
} }
else if( ZONE_FILLER_TOOL::IsZoneFillAction( evt ) else if( ZONE_FILLER_TOOL::IsZoneFillAction( evt )
|| evt->IsAction( &PCB_ACTIONS::moveExact ) || evt->IsAction( &PCB_ACTIONS::moveExact )

View File

@ -532,7 +532,7 @@ int MULTICHANNEL_TOOL::RepeatLayout( const TOOL_EVENT& aEvent, ZONE* aRefZone )
{ {
int totalCopied = 0; int totalCopied = 0;
BOARD_COMMIT commit( GetManager(), true ); BOARD_COMMIT commit( GetManager(), true, false );
for( auto& targetArea : m_areas.m_compatMap ) for( auto& targetArea : m_areas.m_compatMap )
{ {
if( !targetArea.second.m_doCopy ) if( !targetArea.second.m_doCopy )
@ -549,17 +549,14 @@ int MULTICHANNEL_TOOL::RepeatLayout( const TOOL_EVENT& aEvent, ZONE* aRefZone )
m_areas.m_options, targetArea.second.m_affectedItems, m_areas.m_options, targetArea.second.m_affectedItems,
targetArea.second.m_groupableItems ) ) targetArea.second.m_groupableItems ) )
{ {
auto errMsg = wxString::Format( auto errMsg = wxString::Format( _( "Copy Rule Area contents failed between rule areas '%s' and '%s'." ),
_( "Copy Rule Area contents failed between rule areas '%s' and '%s'." ),
m_areas.m_refRA->m_area->GetZoneName(), m_areas.m_refRA->m_area->GetZoneName(),
targetArea.first->m_area->GetZoneName() ); targetArea.first->m_area->GetZoneName() );
commit.Revert(); commit.Revert();
if( Pgm().IsGUI() ) if( Pgm().IsGUI() )
{
frame()->ShowInfoBarError( errMsg, true ); frame()->ShowInfoBarError( errMsg, true );
}
return -1; return -1;
} }
@ -1148,7 +1145,7 @@ int MULTICHANNEL_TOOL::AutogenerateRuleAreas( const TOOL_EVENT& aEvent )
wxLogTrace( traceMultichannelTool, wxT( "%d placement areas found\n" ), (int) m_areas.m_areas.size() ); wxLogTrace( traceMultichannelTool, wxT( "%d placement areas found\n" ), (int) m_areas.m_areas.size() );
BOARD_COMMIT commit( GetManager(), true ); BOARD_COMMIT commit( GetManager(), true, false );
for( RULE_AREA& ra : m_areas.m_areas ) for( RULE_AREA& ra : m_areas.m_areas )
{ {

View File

@ -20,6 +20,7 @@
* or you may write to the Free Software Foundation, Inc., * or you may write to the Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
*/ */
#include <kiplatform/ui.h> #include <kiplatform/ui.h>
#include <tool/tool_manager.h> #include <tool/tool_manager.h>
#include <tools/pcb_group_tool.h> #include <tools/pcb_group_tool.h>
@ -33,6 +34,13 @@
#include <footprint.h> #include <footprint.h>
std::shared_ptr<COMMIT> PCB_GROUP_TOOL::createCommit()
{
return std::make_shared<BOARD_COMMIT>( m_toolMgr, m_frame->IsType( FRAME_PCB_EDITOR ),
m_frame->IsType( FRAME_FOOTPRINT_EDITOR ) );
}
int PCB_GROUP_TOOL::PickNewMember( const TOOL_EVENT& aEvent ) int PCB_GROUP_TOOL::PickNewMember( const TOOL_EVENT& aEvent )
{ {
bool isFootprintEditor = m_frame->GetFrameType() == FRAME_FOOTPRINT_EDITOR; bool isFootprintEditor = m_frame->GetFrameType() == FRAME_FOOTPRINT_EDITOR;

View File

@ -1,3 +1,26 @@
/*
* 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 <tool/group_tool.h> #include <tool/group_tool.h>
#include <board_commit.h> #include <board_commit.h>
#include <pcb_group.h> #include <pcb_group.h>
@ -14,7 +37,7 @@ public:
int Group( const TOOL_EVENT& aEvent ) override; int Group( const TOOL_EVENT& aEvent ) override;
protected: protected:
std::shared_ptr<COMMIT> createCommit() override { return std::make_shared<BOARD_COMMIT>( this ); } std::shared_ptr<COMMIT> createCommit() override;
EDA_GROUP* getGroupFromItem( EDA_ITEM* aItem ) override EDA_GROUP* getGroupFromItem( EDA_ITEM* aItem ) override
{ {

View File

@ -32,18 +32,8 @@ using namespace std::placeholders;
#include <advanced_config.h> #include <advanced_config.h>
#include <macros.h> #include <macros.h>
#include <core/kicad_algo.h>
#include <board.h> #include <board.h>
#include <board_design_settings.h> #include <board_design_settings.h>
#include <board_item.h>
#include <pcb_reference_image.h>
#include <pcb_track.h>
#include <footprint.h>
#include <pad.h>
#include <pcb_group.h>
#include <pcb_shape.h>
#include <pcb_text.h>
#include <pcb_textbox.h>
#include <pcb_table.h> #include <pcb_table.h>
#include <pcb_tablecell.h> #include <pcb_tablecell.h>
#include <pcb_marker.h> #include <pcb_marker.h>
@ -51,7 +41,6 @@ using namespace std::placeholders;
#include <zone.h> #include <zone.h>
#include <collectors.h> #include <collectors.h>
#include <dialog_filter_selection.h> #include <dialog_filter_selection.h>
#include <class_draw_panel_gal.h>
#include <view/view_controls.h> #include <view/view_controls.h>
#include <gal/painter.h> #include <gal/painter.h>
#include <router/router_tool.h> #include <router/router_tool.h>
@ -63,9 +52,7 @@ using namespace std::placeholders;
#include <tools/pcb_selection_tool.h> #include <tools/pcb_selection_tool.h>
#include <tools/pcb_actions.h> #include <tools/pcb_actions.h>
#include <tools/board_inspection_tool.h> #include <tools/board_inspection_tool.h>
#include <connectivity/connectivity_data.h>
#include <ratsnest/ratsnest_data.h> #include <ratsnest/ratsnest_data.h>
#include <footprint_viewer_frame.h>
#include <geometry/geometry_utils.h> #include <geometry/geometry_utils.h>
#include <wx/event.h> #include <wx/event.h>
#include <wx/timer.h> #include <wx/timer.h>
@ -266,8 +253,7 @@ void PCB_SELECTION_TOOL::OnIdle( wxIdleEvent& aEvent )
{ {
wxMouseState keyboardState = wxGetMouseState(); wxMouseState keyboardState = wxGetMouseState();
setModifiersState( keyboardState.ShiftDown(), keyboardState.ControlDown(), setModifiersState( keyboardState.ShiftDown(), keyboardState.ControlDown(), keyboardState.AltDown() );
keyboardState.AltDown() );
if( m_additive ) if( m_additive )
m_frame->GetCanvas()->SetCurrentCursor( KICURSOR::ADD ); m_frame->GetCanvas()->SetCurrentCursor( KICURSOR::ADD );
@ -293,8 +279,7 @@ int PCB_SELECTION_TOOL::Main( const TOOL_EVENT& aEvent )
trackDragAction = cfg->m_TrackDragAction; trackDragAction = cfg->m_TrackDragAction;
// on left click, a selection is made, depending on modifiers ALT, SHIFT, CTRL: // on left click, a selection is made, depending on modifiers ALT, SHIFT, CTRL:
setModifiersState( evt->Modifier( MD_SHIFT ), evt->Modifier( MD_CTRL ), setModifiersState( evt->Modifier( MD_SHIFT ), evt->Modifier( MD_CTRL ), evt->Modifier( MD_ALT ) );
evt->Modifier( MD_ALT ) );
PCB_BASE_FRAME* frame = getEditFrame<PCB_BASE_FRAME>(); PCB_BASE_FRAME* frame = getEditFrame<PCB_BASE_FRAME>();
bool brd_editor = frame && frame->IsType( FRAME_PCB_EDITOR ); bool brd_editor = frame && frame->IsType( FRAME_PCB_EDITOR );
@ -403,12 +388,9 @@ int PCB_SELECTION_TOOL::Main( const TOOL_EVENT& aEvent )
if( field >= 0 ) if( field >= 0 )
{ {
const int delta = evt->Parameter<int>(); const int delta = evt->Parameter<int>();
ACTIONS::INCREMENT incParams{ ACTIONS::INCREMENT params { delta > 0 ? 1 : -1, field };
delta > 0 ? 1 : -1,
field
};
m_toolMgr->RunAction( ACTIONS::increment, incParams ); m_toolMgr->RunAction( ACTIONS::increment, params );
} }
} }
else if( evt->IsDrag( BUT_LEFT ) ) else if( evt->IsDrag( BUT_LEFT ) )
@ -453,10 +435,16 @@ int PCB_SELECTION_TOOL::Main( const TOOL_EVENT& aEvent )
else if( ( hasModifier() || dragAction == MOUSE_DRAG_ACTION::SELECT ) else if( ( hasModifier() || dragAction == MOUSE_DRAG_ACTION::SELECT )
|| ( m_selection.Empty() && dragAction != MOUSE_DRAG_ACTION::DRAG_ANY ) ) || ( m_selection.Empty() && dragAction != MOUSE_DRAG_ACTION::DRAG_ANY ) )
{ {
if( m_selectionMode == SELECTION_MODE::INSIDE_RECTANGLE || m_selectionMode == SELECTION_MODE::TOUCHING_RECTANGLE ) if( m_selectionMode == SELECTION_MODE::INSIDE_RECTANGLE
|| m_selectionMode == SELECTION_MODE::TOUCHING_RECTANGLE )
{
SelectRectArea( aEvent ); SelectRectArea( aEvent );
else if( m_selectionMode == SELECTION_MODE::INSIDE_LASSO || m_selectionMode == SELECTION_MODE::TOUCHING_LASSO ) }
else if( m_selectionMode == SELECTION_MODE::INSIDE_LASSO
|| m_selectionMode == SELECTION_MODE::TOUCHING_LASSO )
{
SelectPolyArea( aEvent ); SelectPolyArea( aEvent );
}
else else
{ {
wxASSERT_MSG( false, wxT( "Unknown selection mode" ) ); wxASSERT_MSG( false, wxT( "Unknown selection mode" ) );
@ -771,8 +759,7 @@ bool PCB_SELECTION_TOOL::ctrlClickHighlights()
} }
bool PCB_SELECTION_TOOL::selectPoint( const VECTOR2I& aWhere, bool aOnDrag, bool PCB_SELECTION_TOOL::selectPoint( const VECTOR2I& aWhere, bool aOnDrag, bool* aSelectionCancelledFlag,
bool* aSelectionCancelledFlag,
CLIENT_SELECTION_FILTER aClientFilter ) CLIENT_SELECTION_FILTER aClientFilter )
{ {
GENERAL_COLLECTORS_GUIDE guide = getCollectorsGuide(); GENERAL_COLLECTORS_GUIDE guide = getCollectorsGuide();
@ -1081,8 +1068,7 @@ int PCB_SELECTION_TOOL::SelectRectArea( const TOOL_EVENT& aEvent )
area.SetAdditive( m_drag_additive ); area.SetAdditive( m_drag_additive );
area.SetSubtractive( m_drag_subtractive ); area.SetSubtractive( m_drag_subtractive );
area.SetExclusiveOr( false ); area.SetExclusiveOr( false );
area.SetMode( greedySelection ? SELECTION_MODE::TOUCHING_RECTANGLE area.SetMode( greedySelection ? SELECTION_MODE::TOUCHING_RECTANGLE : SELECTION_MODE::INSIDE_RECTANGLE );
: SELECTION_MODE::INSIDE_RECTANGLE );
view->SetVisible( &area, true ); view->SetVisible( &area, true );
view->Update( &area ); view->Update( &area );
@ -1163,8 +1149,7 @@ int PCB_SELECTION_TOOL::SelectPolyArea( const TOOL_EVENT& aEvent )
if( getView()->IsMirroredX() && shapeArea != 0 ) if( getView()->IsMirroredX() && shapeArea != 0 )
isClockwise = !isClockwise; isClockwise = !isClockwise;
selectionMode = isClockwise ? SELECTION_MODE::INSIDE_LASSO selectionMode = isClockwise ? SELECTION_MODE::INSIDE_LASSO : SELECTION_MODE::TOUCHING_LASSO;
: SELECTION_MODE::TOUCHING_LASSO;
if( evt->IsCancelInteractive() || evt->IsActivate() ) if( evt->IsCancelInteractive() || evt->IsActivate() )
{ {
@ -1172,12 +1157,14 @@ int PCB_SELECTION_TOOL::SelectPolyArea( const TOOL_EVENT& aEvent )
evt->SetPassEvent( false ); evt->SetPassEvent( false );
break; break;
} }
else if( evt->IsDrag( BUT_LEFT ) || evt->IsClick( BUT_LEFT ) else if( evt->IsDrag( BUT_LEFT )
|| evt->IsClick( BUT_LEFT )
|| evt->IsAction( &ACTIONS::cursorClick ) ) || evt->IsAction( &ACTIONS::cursorClick ) )
{ {
points.Append( evt->Position() ); points.Append( evt->Position() );
} }
else if( evt->IsDblClick( BUT_LEFT ) || evt->IsAction( &ACTIONS::cursorDblClick ) else if( evt->IsDblClick( BUT_LEFT )
|| evt->IsAction( &ACTIONS::cursorDblClick )
|| evt->IsAction( &ACTIONS::finishInteractive ) ) || evt->IsAction( &ACTIONS::finishInteractive ) )
{ {
area.GetPoly().GenerateBBoxCache(); area.GetPoly().GenerateBBoxCache();
@ -1466,8 +1453,7 @@ int PCB_SELECTION_TOOL::UnselectAll( const TOOL_EVENT& aEvent )
} }
void connectedItemFilter( const VECTOR2I&, GENERAL_COLLECTOR& aCollector, void connectedItemFilter( const VECTOR2I&, GENERAL_COLLECTOR& aCollector, PCB_SELECTION_TOOL* sTool )
PCB_SELECTION_TOOL* sTool )
{ {
// Narrow the collection down to a single BOARD_CONNECTED_ITEM for each represented net. // Narrow the collection down to a single BOARD_CONNECTED_ITEM for each represented net.
// All other items types are removed. // All other items types are removed.
@ -1793,12 +1779,9 @@ void PCB_SELECTION_TOOL::selectAllConnectedTracks( const std::vector<BOARD_CONNE
for( PCB_TRACK* track : trackMap[pt] ) for( PCB_TRACK* track : trackMap[pt] )
{ {
if( track->GetStart() != track->GetEnd() if( track->GetStart() != track->GetEnd() && layerSetCu.Contains( track->GetLayer() ) )
&& layerSetCu.Contains( track->GetLayer() ) )
{
pt_count++; pt_count++;
} }
}
if( pt_count > 2 || gotVia || gotNonStartPad ) if( pt_count > 2 || gotVia || gotNonStartPad )
{ {
@ -2632,10 +2615,8 @@ void PCB_SELECTION_TOOL::FindItem( BOARD_ITEM* aItem )
if( !screenRect.Contains( aItem->GetBoundingBox() ) ) if( !screenRect.Contains( aItem->GetBoundingBox() ) )
{ {
double scaleX = screenSize.x / double scaleX = screenSize.x / static_cast<double>( aItem->GetBoundingBox().GetWidth() );
static_cast<double>( aItem->GetBoundingBox().GetWidth() ); double scaleY = screenSize.y / static_cast<double>( aItem->GetBoundingBox().GetHeight() );
double scaleY = screenSize.y /
static_cast<double>( aItem->GetBoundingBox().GetHeight() );
scaleX /= marginFactor; scaleX /= marginFactor;
scaleY /= marginFactor; scaleY /= marginFactor;
@ -2677,8 +2658,8 @@ static bool itemIsIncludedByFilter( const BOARD_ITEM& aItem, const BOARD& aBoard
{ {
const FOOTPRINT& footprint = static_cast<const FOOTPRINT&>( aItem ); const FOOTPRINT& footprint = static_cast<const FOOTPRINT&>( aItem );
return aFilterOptions.includeModules return aFilterOptions.includeModules && ( aFilterOptions.includeLockedModules
&& ( aFilterOptions.includeLockedModules || !footprint.IsLocked() ); || !footprint.IsLocked() );
} }
case PCB_TRACE_T: case PCB_TRACE_T:
@ -3097,6 +3078,7 @@ bool PCB_SELECTION_TOOL::Selectable( const BOARD_ITEM* aItem, bool checkVisibili
const PCB_TEXT* text = nullptr; const PCB_TEXT* text = nullptr;
const PCB_FIELD* field = nullptr; const PCB_FIELD* field = nullptr;
const PCB_MARKER* marker = nullptr; const PCB_MARKER* marker = nullptr;
const PCB_TABLECELL* cell = nullptr;
// Most footprint children can only be selected in the footprint editor. // Most footprint children can only be selected in the footprint editor.
if( aItem->GetParentFootprint() && !m_isFootprintEditor && !checkVisibilityOnly ) if( aItem->GetParentFootprint() && !m_isFootprintEditor && !checkVisibilityOnly )
@ -3193,27 +3175,35 @@ bool PCB_SELECTION_TOOL::Selectable( const BOARD_ITEM* aItem, bool checkVisibili
if( !view()->IsLayerVisible( LAYER_DRAW_BITMAPS ) ) if( !view()->IsLayerVisible( LAYER_DRAW_BITMAPS ) )
return false; return false;
KI_FALLTHROUGH; if( !layerVisible( aItem->GetLayer() ) )
return false;
break;
case PCB_SHAPE_T: case PCB_SHAPE_T:
if( options.m_FilledShapeOpacity == 0.0 && static_cast<const PCB_SHAPE*>( aItem )->IsAnyFill() ) if( options.m_FilledShapeOpacity == 0.0 && static_cast<const PCB_SHAPE*>( aItem )->IsAnyFill() )
return false; return false;
KI_FALLTHROUGH;
case PCB_TEXTBOX_T:
case PCB_TABLE_T:
case PCB_TABLECELL_T:
if( !layerVisible( aItem->GetLayer() ) ) if( !layerVisible( aItem->GetLayer() ) )
return false; return false;
if( aItem->Type() == PCB_TABLECELL_T ) break;
{
const PCB_TABLECELL* cell = static_cast<const PCB_TABLECELL*>( aItem ); case PCB_TEXTBOX_T:
case PCB_TABLE_T:
if( !layerVisible( aItem->GetLayer() ) )
return false;
break;
case PCB_TABLECELL_T:
cell = static_cast<const PCB_TABLECELL*>( aItem );
if( !layerVisible( aItem->GetLayer() ) )
return false;
if( cell->GetRowSpan() == 0 || cell->GetColSpan() == 0 ) if( cell->GetRowSpan() == 0 || cell->GetColSpan() == 0 )
return false; return false;
}
break; break;
@ -3892,8 +3882,7 @@ void PCB_SELECTION_TOOL::GuessSelectionCandidates( GENERAL_COLLECTOR& aCollector
} }
void PCB_SELECTION_TOOL::FilterCollectorForHierarchy( GENERAL_COLLECTOR& aCollector, void PCB_SELECTION_TOOL::FilterCollectorForHierarchy( GENERAL_COLLECTOR& aCollector, bool aMultiselect ) const
bool aMultiselect ) const
{ {
std::unordered_set<EDA_ITEM*> toAdd; std::unordered_set<EDA_ITEM*> toAdd;

View File

@ -41,7 +41,7 @@ public:
void Revert() override {} void Revert() override {}
private: private:
EDA_ITEM* parentObject( EDA_ITEM* aItem ) const override { return aItem; } EDA_ITEM* undoLevelItem( EDA_ITEM* aItem ) const override { return aItem; }
EDA_ITEM* makeImage( EDA_ITEM* aItem ) const override { return aItem->Clone(); } EDA_ITEM* makeImage( EDA_ITEM* aItem ) const override { return aItem->Clone(); }
}; };