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()
{
for( COMMIT_LINE& ent : m_changes )
for( COMMIT_LINE& ent : m_entries )
delete ent.m_copy;
}
COMMIT& COMMIT::Stage( EDA_ITEM* aItem, CHANGE_TYPE aChangeType, BASE_SCREEN* aScreen,
RECURSE_MODE aRecurse )
COMMIT& COMMIT::Stage( EDA_ITEM* aItem, CHANGE_TYPE aChangeType, BASE_SCREEN* aScreen, 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
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( aChangeType & CHT_TYPE )
switch( changeType )
{
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;
case CHT_REMOVE:
if( m_deletedItems.insert( aItem ).second )
{
makeEntry( aItem, CHT_REMOVE | flag, makeImage( aItem ), aScreen );
if( m_deletedItems.find( { aItem, aScreen } ) != m_deletedItems.end() )
break;
if( EDA_GROUP* parentGroup = aItem->GetParentGroup() )
Modify( parentGroup->AsEdaItem(), aScreen, RECURSE_MODE::NO_RECURSE );
}
makeEntry( aItem, CHT_REMOVE | flags, makeImage( aItem ), aScreen );
if( EDA_GROUP* parentGroup = aItem->GetParentGroup() )
Modify( parentGroup->AsEdaItem(), aScreen, RECURSE_MODE::NO_RECURSE );
break;
case CHT_MODIFY:
if( EDA_ITEM* parent = parentObject( aItem ) )
createModified( parent, makeImage( parent ), flag, aScreen );
if( m_addedItems.find( { aItem, aScreen } ) != m_addedItems.end() )
break;
if( m_changedItems.find( { undoItem, aScreen } ) != m_changedItems.end() )
break;
makeEntry( undoItem, CHT_MODIFY | flags, makeImage( undoItem ), aScreen );
break;
default:
wxFAIL;
UNIMPLEMENTED_FOR( undoItem->GetClass() );
}
return *this;
}
COMMIT& COMMIT::Stage( std::vector<EDA_ITEM*> &container, CHANGE_TYPE aChangeType,
BASE_SCREEN *aScreen )
COMMIT& COMMIT::Stage( std::vector<EDA_ITEM*> &container, CHANGE_TYPE aChangeType, BASE_SCREEN *aScreen )
{
for( EDA_ITEM* item : container )
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 )
{
std::erase_if( m_changes,
std::erase_if( m_entries,
[&]( COMMIT_LINE& line )
{
if( line.m_item == aItem && line.m_screen == aScreen )
@ -139,28 +150,22 @@ 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" );
else
makeEntry( aItem, CHT_MODIFY, aCopy, aScreen );
return entry ? entry->m_type : 0;
return *this;
}
COMMIT& COMMIT::createModified( EDA_ITEM* aItem, EDA_ITEM* aCopy, int aExtraFlags,
BASE_SCREEN* aScreen )
int COMMIT::GetStatus( EDA_ITEM* aItem, BASE_SCREEN *aScreen )
{
EDA_ITEM* parent = parentObject( aItem );
COMMIT_LINE* entry = findEntry( undoLevelItem( aItem ), aScreen );
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 entry ? entry->m_type : 0;
}
@ -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
// multiple times in a single commit such as when importing graphics and grouping them.
m_changedItems.insert( aItem );
m_changes.push_back( ent );
switch( aType )
{
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 )
{
for( COMMIT_LINE& change : m_changes )
for( COMMIT_LINE& entry : m_entries )
{
if( change.m_item == aItem && change.m_screen == aScreen )
return &change;
if( entry.m_item == aItem && entry.m_screen == aScreen )
return &entry;
}
return nullptr;
@ -197,10 +209,10 @@ CHANGE_TYPE COMMIT::convert( UNDO_REDO aType ) const
{
switch( aType )
{
case UNDO_REDO::NEWITEM: return CHT_ADD;
case UNDO_REDO::DELETED: return CHT_REMOVE;
case UNDO_REDO::CHANGED: return CHT_MODIFY;
default: wxASSERT( false ); return CHT_MODIFY;
case UNDO_REDO::NEWITEM: return CHT_ADD;
case UNDO_REDO::DELETED: return CHT_REMOVE;
case UNDO_REDO::CHANGED: return CHT_MODIFY;
default: wxFAIL; return CHT_MODIFY;
}
}
@ -209,10 +221,10 @@ UNDO_REDO COMMIT::convert( CHANGE_TYPE aType ) const
{
switch( aType )
{
case CHT_ADD: return UNDO_REDO::NEWITEM;
case CHT_REMOVE: return UNDO_REDO::DELETED;
case CHT_MODIFY: return UNDO_REDO::CHANGED;
default: wxASSERT( false ); return UNDO_REDO::CHANGED;
case CHT_ADD: return UNDO_REDO::NEWITEM;
case CHT_REMOVE: return UNDO_REDO::DELETED;
case CHT_MODIFY: return UNDO_REDO::CHANGED;
default: wxFAIL; return UNDO_REDO::CHANGED;
}
}

View File

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

View File

@ -73,17 +73,6 @@ COMMIT& SCH_COMMIT::Stage( EDA_ITEM *aItem, CHANGE_TYPE aChangeType, BASE_SCREEN
{
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( 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
// a drag operation.
// IS_SELECTED flag should not be set on undo items which were added for a drag operation.
if( aItem->IsSelected() && aItem->HasFlag( SELECTED_BY_DRAG ) )
{
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 )
{
// 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* copy = dynamic_cast<LIB_SYMBOL*>( m_changes.front().m_copy );
LIB_SYMBOL* symbol = dynamic_cast<LIB_SYMBOL*>( m_entries.front().m_item );
LIB_SYMBOL* copy = dynamic_cast<LIB_SYMBOL*>( m_entries.front().m_copy );
if( symbol )
{
@ -220,10 +201,10 @@ void SCH_COMMIT::pushSchEdit( const wxString& aMessage, int aCommitFlags )
Modify( enteredGroup );
// 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* schItem = dynamic_cast<SCH_ITEM*>( ent.m_item );
SCH_ITEM* schCopyItem = dynamic_cast<SCH_ITEM*>( entry.m_copy );
SCH_ITEM* schItem = dynamic_cast<SCH_ITEM*>( entry.m_item );
if( schCopyItem && schCopyItem->Type() == SCH_LINE_T )
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 );
int changeType = ent.m_type & CHT_TYPE;
SCH_ITEM* schItem = dynamic_cast<SCH_ITEM*>( entry.m_item );
int changeType = entry.m_type & CHT_TYPE;
wxCHECK2( schItem, continue );
@ -244,12 +225,12 @@ void SCH_COMMIT::pushSchEdit( const wxString& aMessage, int aCommitFlags )
Modify( schItem->GetParentGroup()->AsEdaItem() );
}
for( COMMIT_LINE& ent : m_changes )
for( COMMIT_LINE& entry : m_entries )
{
int changeType = ent.m_type & CHT_TYPE;
int changeFlags = ent.m_type & CHT_FLAGS;
SCH_ITEM* schItem = dynamic_cast<SCH_ITEM*>( ent.m_item );
SCH_SCREEN* screen = dynamic_cast<SCH_SCREEN*>( ent.m_screen );
int changeType = entry.m_type & CHT_TYPE;
int changeFlags = entry.m_type & CHT_FLAGS;
SCH_ITEM* schItem = dynamic_cast<SCH_ITEM*>( entry.m_item );
SCH_SCREEN* screen = dynamic_cast<SCH_SCREEN*>( entry.m_screen );
wxCHECK2( schItem, continue );
wxCHECK2( screen, continue );
@ -311,8 +292,8 @@ void SCH_COMMIT::pushSchEdit( const wxString& aMessage, int aCommitFlags )
if( !( aCommitFlags & SKIP_UNDO ) )
{
ITEM_PICKER itemWrapper( screen, schItem, UNDO_REDO::DELETED );
itemWrapper.SetLink( ent.m_copy );
ent.m_copy = nullptr; // We've transferred ownership to the undo list
itemWrapper.SetLink( entry.m_copy );
entry.m_copy = nullptr; // We've transferred ownership to the undo list
undoList.PushItem( itemWrapper );
}
@ -353,7 +334,7 @@ void SCH_COMMIT::pushSchEdit( const wxString& aMessage, int aCommitFlags )
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;
if( frame )
@ -368,8 +349,8 @@ void SCH_COMMIT::pushSchEdit( const wxString& aMessage, int aCommitFlags )
if( !( aCommitFlags & SKIP_UNDO ) )
{
ITEM_PICKER itemWrapper( screen, schItem, UNDO_REDO::CHANGED );
itemWrapper.SetLink( ent.m_copy );
ent.m_copy = nullptr; // We've transferred ownership to the undo list
itemWrapper.SetLink( entry.m_copy );
entry.m_copy = nullptr; // We've transferred ownership to the undo list
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 ent.m_copy;
ent.m_copy = nullptr;
delete entry.m_copy;
entry.m_copy = nullptr;
// Clear all flags but SELECTED and others used to move and rotate commands,
// 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();
if( parent && ( parent->Type() == SCH_SYMBOL_T || parent->Type() == LIB_SYMBOL_T ) )
return parent;
if( m_isLibEditor )
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;
}
@ -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_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>();
if( frame && copy )
@ -545,9 +526,6 @@ void SCH_COMMIT::revertLibEdit()
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 )
selTool->RebuildSelection();
@ -562,7 +540,7 @@ void SCH_COMMIT::Revert()
SCH_SELECTION_TOOL* selTool = m_toolMgr->GetTool<SCH_SELECTION_TOOL>();
SCH_SHEET_LIST sheets;
if( m_changes.empty() )
if( m_entries.empty() )
return;
if( m_isLibEditor )
@ -576,7 +554,7 @@ void SCH_COMMIT::Revert()
std::vector<SCH_ITEM*> bulkRemovedItems;
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 changeFlags = ent.m_type & CHT_FLAGS;
@ -703,9 +681,7 @@ void SCH_COMMIT::Revert()
selTool->RebuildSelection();
if( frame )
{
frame->RecalculateConnections( nullptr, NO_CLEANUP );
}
clear();
}

View File

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

View File

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

View File

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

View File

@ -1632,6 +1632,7 @@ int SCH_EDIT_TOOL::RepeatDrawItem( const TOOL_EVENT& aEvent )
static std::vector<KICAD_T> deletableItems =
{
LIB_SYMBOL_T,
SCH_MARKER_T,
SCH_JUNCTION_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 )
{
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() );
if( item->IsNew() )
if( commit->GetStatus( item, m_frame->GetScreen() ) == CHT_ADD )
{
commit->Unstage( item, m_frame->GetScreen() );
delete item;
}
else
{
commit->Removed( item, m_frame->GetScreen() );
}
m_frame->AddToScreen( newtext, m_frame->GetScreen() );
commit->Added( newtext, m_frame->GetScreen() );
if( selected )
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 )
{
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
*/
#ifndef KICAD_SCH_EDIT_TOOL_H
#define KICAD_SCH_EDIT_TOOL_H
#pragma once
#include <tools/sch_tool_base.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>
{
public:
SCH_EDIT_TOOL();
~SCH_EDIT_TOOL() override { }
~SCH_EDIT_TOOL() = default;
static const std::vector<KICAD_T> RotatableItems;
@ -57,11 +52,6 @@ public:
int ChangeBodyStyle( 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.
*
@ -84,9 +74,6 @@ public:
///< Delete the selected items, or the item under the cursor.
int DoDelete( const TOOL_EVENT& aEvent );
///< Run the deletion tool.
int InteractiveDelete( const TOOL_EVENT& aEvent );
/// Drag and drop
int DdAppendFile( const TOOL_EVENT& aEvent );
@ -102,9 +89,4 @@ private:
///< Set up handlers for various events.
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 ) )
{
m_toolMgr->RunSynchronousAction( ACTIONS::increment, aCommit, evt->Parameter<ACTIONS::INCREMENT>() );
if( evt->HasParameter() )
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 ) )
{
@ -1461,8 +1464,7 @@ void SCH_MOVE_TOOL::getConnectedDragItems( SCH_COMMIT* aCommit, SCH_ITEM* aSelec
if( aPoint != line->GetStartPoint() && aPoint != line->GetEndPoint() )
{
// Split line in half
if( !line->IsNew() )
aCommit->Modify( line, m_frame->GetScreen() );
aCommit->Modify( line, m_frame->GetScreen() );
VECTOR2I oldEnd = line->GetEndPoint();
line->SetEndPoint( aPoint );

View File

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

View File

@ -24,6 +24,7 @@
#pragma once
#include "increment.h"
#include <math/vector2d.h>
#include <tool/tool_event.h>
#include <tool/tool_interactive.h>
@ -35,6 +36,9 @@
#include <sch_view.h>
#include <symbol_edit_frame.h>
#include <sch_shape.h>
#include <pin_layout_cache.h>
#include <sch_commit.h>
#include <tool/picker_tool.h>
class SCH_SELECTION;
@ -55,7 +59,8 @@ public:
m_frame( nullptr ),
m_view( nullptr ),
m_selectionTool( nullptr ),
m_isSymbolEditor( false )
m_isSymbolEditor( false ),
m_pickerItem( nullptr )
{};
~SCH_TOOL_BASE() override {};
@ -101,6 +106,247 @@ public:
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:
/**
* Similar to getView()->Update(), but also updates the SCH_SCREEN's RTree.
@ -155,4 +401,5 @@ protected:
KIGFX::SCH_VIEW* m_view;
SCH_SELECTION_TOOL* m_selectionTool;
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 ) )
{
m_toolMgr->RunSynchronousAction( ACTIONS::increment, &commit,
evt->Parameter<ACTIONS::INCREMENT>() );
if( evt->HasParameter() )
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() ) )
{

View File

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

View File

@ -52,8 +52,7 @@
#include <io/kicad/kicad_io_utils.h>
SYMBOL_EDITOR_EDIT_TOOL::SYMBOL_EDITOR_EDIT_TOOL() :
SCH_TOOL_BASE( "eeschema.SymbolEditTool" ),
m_pickerItem( nullptr )
SCH_TOOL_BASE( "eeschema.SymbolEditTool" )
{
}
@ -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 )
{
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()
{
// clang-format off

View File

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

View File

@ -153,8 +153,7 @@ bool SYMBOL_EDITOR_MOVE_TOOL::doMoveSelection( const TOOL_EVENT& aEvent, SCH_COM
VECTOR2I prevPos;
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() );

View File

@ -25,8 +25,7 @@
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
*/
#ifndef __COMMIT_H
#define __COMMIT_H
#pragma once
#include <set>
#include <vector>
@ -115,20 +114,7 @@ public:
*
* @note Requires a copy done before the modification.
*/
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;
}
COMMIT& Modified( EDA_ITEM* aItem, EDA_ITEM* aCopy, BASE_SCREEN *aScreen = nullptr );
/// 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,
@ -137,8 +123,7 @@ public:
virtual COMMIT& Stage( std::vector<EDA_ITEM*>& container, CHANGE_TYPE aChangeType,
BASE_SCREEN *aScreen = nullptr );
virtual COMMIT& Stage( const PICKED_ITEMS_LIST& aItems,
UNDO_REDO aModFlag = UNDO_REDO::UNSPECIFIED,
virtual COMMIT& Stage( const PICKED_ITEMS_LIST& aItems, UNDO_REDO aModFlag = UNDO_REDO::UNSPECIFIED,
BASE_SCREEN *aScreen = nullptr );
void Unstage( EDA_ITEM* aItem, BASE_SCREEN* aScreen );
@ -151,13 +136,13 @@ public:
bool Empty() const
{
return m_changes.empty();
return m_entries.empty();
}
/// Returns status of an item.
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:
struct COMMIT_LINE
@ -165,7 +150,6 @@ protected:
EDA_ITEM* m_item; ///< Main item that is added/deleted/modified
EDA_ITEM* m_copy; ///< Optional copy of the item
CHANGE_TYPE m_type; ///< Modification type
KIID m_parent = NilUuid(); ///< Parent item (primarily for undo of deleted items)
BASE_SCREEN* m_screen;
};
@ -174,12 +158,9 @@ protected:
{
m_changedItems.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,
BASE_SCREEN *aScreen = nullptr );
@ -190,7 +171,7 @@ protected:
*/
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;
@ -198,9 +179,9 @@ protected:
UNDO_REDO convert( CHANGE_TYPE aType ) const;
protected:
std::set<EDA_ITEM*> m_changedItems;
std::set<EDA_ITEM*> m_deletedItems;
std::vector<COMMIT_LINE> m_changes;
std::set<std::pair<EDA_ITEM*, BASE_SCREEN*>> m_addedItems;
std::set<std::pair<EDA_ITEM*, BASE_SCREEN*>> m_changedItems;
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 HasParameter() const
{
return m_param.has_value();
}
/**
* 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 ) :
COMMIT(),
m_toolMgr( aTool->GetManager() ),
m_isBoardEditor( false ),
m_isFootprintEditor( false )
@ -63,6 +64,7 @@ BOARD_COMMIT::BOARD_COMMIT( TOOL_BASE* aTool ) :
BOARD_COMMIT::BOARD_COMMIT( EDA_DRAW_FRAME* aFrame ) :
COMMIT(),
m_toolMgr( aFrame->GetToolManager() ),
m_isBoardEditor( aFrame->IsType( FRAME_PCB_EDITOR ) ),
m_isFootprintEditor( aFrame->IsType( FRAME_FOOTPRINT_EDITOR ) )
@ -71,7 +73,8 @@ BOARD_COMMIT::BOARD_COMMIT( EDA_DRAW_FRAME* aFrame ) :
BOARD_COMMIT::BOARD_COMMIT( TOOL_MANAGER* aMgr ) :
m_toolMgr( aMgr ),
COMMIT(),
m_toolMgr( aMgr ),
m_isBoardEditor( false ),
m_isFootprintEditor( false )
{
@ -83,10 +86,12 @@ BOARD_COMMIT::BOARD_COMMIT( TOOL_MANAGER* aMgr ) :
m_isFootprintEditor = true;
}
BOARD_COMMIT::BOARD_COMMIT( TOOL_MANAGER* aMgr, bool aIsBoardEditor ) :
m_toolMgr( aMgr ),
m_isBoardEditor( aIsBoardEditor ),
m_isFootprintEditor( false )
BOARD_COMMIT::BOARD_COMMIT( TOOL_MANAGER* aMgr, bool aIsBoardEditor, bool aIsFootprintEditor ) :
COMMIT(),
m_toolMgr( aMgr ),
m_isBoardEditor( aIsBoardEditor ),
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,
RECURSE_MODE aRecurse )
COMMIT& BOARD_COMMIT::Stage( EDA_ITEM* aItem, CHANGE_TYPE aChangeType, BASE_SCREEN* aScreen, RECURSE_MODE aRecurse )
{
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,
BASE_SCREEN* aScreen )
COMMIT& BOARD_COMMIT::Stage( std::vector<EDA_ITEM*>& container, CHANGE_TYPE aChangeType, BASE_SCREEN* aScreen )
{
return COMMIT::Stage( container, aChangeType, aScreen );
}
COMMIT& BOARD_COMMIT::Stage( const PICKED_ITEMS_LIST& aItems, UNDO_REDO aModFlag,
BASE_SCREEN* aScreen )
COMMIT& BOARD_COMMIT::Stage( const PICKED_ITEMS_LIST& aItems, UNDO_REDO aModFlag, BASE_SCREEN* aScreen )
{
return COMMIT::Stage( aItems, aModFlag, aScreen );
}
@ -136,7 +138,7 @@ void BOARD_COMMIT::propagateDamage( BOARD_ITEM* aChangedItem, std::vector<ZONE*>
aStaleZones->push_back( static_cast<ZONE*>( aChangedItem ) );
aChangedItem->RunOnChildren( std::bind( &BOARD_COMMIT::propagateDamage, this, _1, aStaleZones, aStaleRuleAreas ),
RECURSE_MODE::NO_RECURSE );
RECURSE_MODE::NO_RECURSE );
BOARD* board = static_cast<BOARD*>( m_toolMgr->GetModel() );
BOX2I damageBBox = aChangedItem->GetBoundingBox();
@ -163,11 +165,8 @@ void BOARD_COMMIT::propagateDamage( BOARD_ITEM* aChangedItem, std::vector<ZONE*>
if( zone->GetIsRuleArea() )
continue;
if( ( zone->GetLayerSet() & damageLayers ).any()
&& zone->GetBoundingBox().Intersects( damageBBox ) )
{
if( ( zone->GetLayerSet() & damageLayers ).any() && zone->GetBoundingBox().Intersects( damageBBox ) )
aStaleZones->push_back( zone );
}
}
}
}
@ -211,9 +210,8 @@ void BOARD_COMMIT::Push( const wxString& aMessage, int aCommitFlags )
std::vector<BOARD_ITEM*> bulkRemovedItems;
std::vector<BOARD_ITEM*> itemsChanged;
if( m_isBoardEditor
&& !( aCommitFlags & ZONE_FILL_OP )
&& ( frame && frame->GetPcbNewSettings()->m_AutoRefillZones ) )
if( m_isBoardEditor && !( aCommitFlags & ZONE_FILL_OP )
&& ( frame && frame->GetPcbNewSettings()->m_AutoRefillZones ) )
{
autofillZones = true;
staleZones = &staleZonesStorage;
@ -222,12 +220,12 @@ void BOARD_COMMIT::Push( const wxString& aMessage, int aCommitFlags )
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;
BOARD_ITEM* boardItem = static_cast<BOARD_ITEM*>( ent.m_item );
BOARD_ITEM* boardItem = static_cast<BOARD_ITEM*>( entry.m_item );
if( m_isBoardEditor )
{
@ -297,14 +295,14 @@ void BOARD_COMMIT::Push( const wxString& aMessage, int aCommitFlags )
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;
BOARD_ITEM* boardItem = static_cast<BOARD_ITEM*>( ent.m_item );
int changeType = ent.m_type & CHT_TYPE;
int changeFlags = ent.m_type & CHT_FLAGS;
BOARD_ITEM* boardItem = static_cast<BOARD_ITEM*>( entry.m_item );
int changeType = entry.m_type & CHT_TYPE;
int changeFlags = entry.m_type & CHT_FLAGS;
switch( changeType )
{
@ -319,14 +317,8 @@ void BOARD_COMMIT::Push( const wxString& aMessage, int aCommitFlags )
{
if( m_isFootprintEditor )
{
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 );
if( FOOTPRINT* parentFP = board->GetFirstFootprint() )
parentFP->Add( boardItem );
}
else
{
@ -347,14 +339,13 @@ void BOARD_COMMIT::Push( const wxString& aMessage, int aCommitFlags )
case CHT_REMOVE:
{
FOOTPRINT* parentFP = boardItem->GetParentFootprint();
EDA_GROUP* parentGroup = boardItem->GetParentGroup();
if( !( aCommitFlags & SKIP_UNDO ) )
{
ITEM_PICKER itemWrapper( nullptr, boardItem, UNDO_REDO::DELETED );
itemWrapper.SetLink( ent.m_copy );
ent.m_copy = nullptr; // We've transferred ownership to the undo list
itemWrapper.SetLink( entry.m_copy );
entry.m_copy = nullptr; // We've transferred ownership to the undo list
undoList.PushItem( itemWrapper );
}
@ -369,9 +360,6 @@ void BOARD_COMMIT::Push( const wxString& aMessage, int aCommitFlags )
if( parentGroup && !( parentGroup->AsEdaItem()->GetFlags() & STRUCT_DELETED ) )
parentGroup->RemoveItem( boardItem );
if( parentFP && !( parentFP->GetFlags() & STRUCT_DELETED ) )
ent.m_parent = parentFP->m_Uuid;
if( boardItem->Type() != PCB_MARKER_T )
propagateDamage( boardItem, staleZones, staleRuleAreas );
@ -383,21 +371,21 @@ void BOARD_COMMIT::Push( const wxString& aMessage, int aCommitFlags )
case PCB_TEXT_T:
case PCB_PAD_T:
case PCB_SHAPE_T: // a shape (normally not on copper layers)
case PCB_REFERENCE_IMAGE_T: // a bitmap on an associated layer
case PCB_GENERATOR_T: // a generator on a layer
case PCB_TEXTBOX_T: // a line-wrapped (and optionally bordered) text item
case PCB_TABLE_T: // rows and columns of tablecells
case PCB_TRACE_T: // a track segment (segment on a copper layer)
case PCB_ARC_T: // an arced track segment (segment on a copper layer)
case PCB_VIA_T: // a via (like track segment on a copper layer)
case PCB_DIM_ALIGNED_T: // a dimension (graphic item)
case PCB_SHAPE_T:
case PCB_REFERENCE_IMAGE_T:
case PCB_GENERATOR_T:
case PCB_TEXTBOX_T:
case PCB_TABLE_T:
case PCB_TRACE_T:
case PCB_ARC_T:
case PCB_VIA_T:
case PCB_DIM_ALIGNED_T:
case PCB_DIM_CENTER_T:
case PCB_DIM_RADIAL_T:
case PCB_DIM_ORTHOGONAL_T:
case PCB_DIM_LEADER_T: // a leader dimension
case PCB_TARGET_T: // a target (graphic item)
case PCB_MARKER_T: // a marker used to show something
case PCB_DIM_LEADER_T:
case PCB_TARGET_T:
case PCB_MARKER_T:
case PCB_ZONE_T:
case PCB_FOOTPRINT_T:
case PCB_GROUP_T:
@ -406,9 +394,10 @@ void BOARD_COMMIT::Push( const wxString& aMessage, int aCommitFlags )
if( !( changeFlags & CHT_DONE ) )
{
if( parentFP )
if( m_isFootprintEditor )
{
parentFP->Remove( boardItem );
if( FOOTPRINT* parentFP = board->GetFirstFootprint() )
parentFP->Remove( boardItem );
}
else
{
@ -437,13 +426,13 @@ void BOARD_COMMIT::Push( const wxString& aMessage, int aCommitFlags )
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 ) )
{
ITEM_PICKER itemWrapper( nullptr, boardItem, UNDO_REDO::CHANGED );
itemWrapper.SetLink( ent.m_copy );
ent.m_copy = nullptr; // We've transferred ownership to the undo list
itemWrapper.SetLink( entry.m_copy );
entry.m_copy = nullptr; // We've transferred ownership to the undo list
undoList.PushItem( itemWrapper );
}
@ -461,7 +450,7 @@ void BOARD_COMMIT::Push( const wxString& aMessage, int aCommitFlags )
updateComponentClasses( boardItem );
if( view )
if( view && boardItem->Type() != PCB_NETINFO_T )
view->Update( 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 ent.m_copy;
ent.m_copy = nullptr;
delete entry.m_copy;
entry.m_copy = nullptr;
boardItem->ClearEditFlags();
boardItem->RunOnChildren(
@ -491,7 +480,7 @@ void BOARD_COMMIT::Push( const wxString& aMessage, int aCommitFlags )
if( m_isBoardEditor )
{
size_t num_changes = m_changes.size();
size_t originalCount = m_entries.size();
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
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* boardItemCopy = nullptr;
if( ent.m_item && ent.m_item->IsBOARD_ITEM() )
boardItem = static_cast<BOARD_ITEM*>( ent.m_item );
if( entry.m_item && entry.m_item->IsBOARD_ITEM() )
boardItem = static_cast<BOARD_ITEM*>( entry.m_item );
if( ent.m_copy && ent.m_copy->IsBOARD_ITEM() )
boardItemCopy = static_cast<BOARD_ITEM*>( ent.m_copy );
if( entry.m_copy && entry.m_copy->IsBOARD_ITEM() )
boardItemCopy = static_cast<BOARD_ITEM*>( entry.m_copy );
wxCHECK2( boardItem, continue );
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 );
undoList.PushItem( itemWrapper );
}
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 );
else if( ( ent.m_type & CHT_TYPE ) == CHT_REMOVE )
else if( ( entry.m_type & CHT_TYPE ) == CHT_REMOVE )
view->Remove( boardItem );
else
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;
}
@ -670,20 +672,21 @@ void BOARD_COMMIT::Revert()
board->IncrementTimeStamp(); // clear caches
auto updateComponentClasses = [this]( BOARD_ITEM* boardItem )
{
if( boardItem->Type() != PCB_FOOTPRINT_T )
return;
auto updateComponentClasses =
[this]( BOARD_ITEM* boardItem )
{
if( boardItem->Type() != PCB_FOOTPRINT_T )
return;
FOOTPRINT* footprint = static_cast<FOOTPRINT*>( boardItem );
GetBoard()->GetComponentClassManager().RebuildRequiredCaches( footprint );
};
FOOTPRINT* footprint = static_cast<FOOTPRINT*>( boardItem );
GetBoard()->GetComponentClassManager().RebuildRequiredCaches( footprint );
};
std::vector<BOARD_ITEM*> bulkAddedItems;
std::vector<BOARD_ITEM*> bulkRemovedItems;
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() )
continue;
@ -698,11 +701,13 @@ void BOARD_COMMIT::Revert()
if( !( changeFlags & CHT_DONE ) )
break;
view->Remove( boardItem );
if( boardItem->Type() != PCB_NETINFO_T )
view->Remove( boardItem );
if( FOOTPRINT* parentFP = boardItem->GetParentFootprint() )
if( m_isFootprintEditor )
{
parentFP->Remove( boardItem );
if( FOOTPRINT* parentFP = board->GetFirstFootprint() )
parentFP->Remove( boardItem );
}
else
{
@ -717,36 +722,38 @@ void BOARD_COMMIT::Revert()
if( !( changeFlags & CHT_DONE ) )
break;
view->Add( boardItem );
if( boardItem->Type() != PCB_NETINFO_T )
view->Add( boardItem );
if( BOARD_ITEM* parent = board->ResolveItem( entry.m_parent, true ) )
if( m_isFootprintEditor )
{
if( parent->Type() == PCB_FOOTPRINT_T )
{
static_cast<FOOTPRINT*>( parent )->Add( boardItem, ADD_MODE::INSERT );
}
else
{
board->Add( boardItem, ADD_MODE::INSERT );
bulkAddedItems.push_back( boardItem );
}
if( FOOTPRINT* parentFP = board->GetFirstFootprint() )
parentFP->Add( boardItem, ADD_MODE::INSERT );
}
else
{
board->Add( boardItem, ADD_MODE::INSERT );
bulkAddedItems.push_back( boardItem );
}
updateComponentClasses( boardItem );
break;
}
case CHT_MODIFY:
{
view->Remove( boardItem );
if( boardItem->Type() != PCB_NETINFO_T )
view->Remove( boardItem );
connectivity->Remove( boardItem );
wxASSERT( entry.m_copy && entry.m_copy->IsBOARD_ITEM() );
BOARD_ITEM* boardItemCopy = static_cast<BOARD_ITEM*>( entry.m_copy );
boardItem->SwapItemData( boardItemCopy );
view->Add( boardItem );
if( boardItem->Type() != PCB_NETINFO_T )
view->Add( boardItem );
connectivity->Add( boardItem );
itemsChanged.push_back( boardItem );

View File

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

View File

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

View File

@ -2182,8 +2182,7 @@ int EDIT_TOOL::Rotate( const TOOL_EVENT& aEvent )
{
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() )
{
@ -2262,6 +2261,7 @@ const std::vector<KICAD_T> EDIT_TOOL::MirrorableItems = {
PCB_GENERATOR_T,
};
int EDIT_TOOL::Mirror( const TOOL_EVENT& aEvent )
{
if( isRouterActive() )
@ -2318,8 +2318,7 @@ int EDIT_TOOL::Mirror( const TOOL_EVENT& aEvent )
if( !item->IsType( MirrorableItems ) )
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
switch( item->Type() )
@ -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->IsNew() && !item->IsMoving() )
commit->Modify( item );
commit->Modify( item );
setJustify( static_cast<PCB_TEXT*>( item ) );
}
else if( item->Type() == PCB_TEXTBOX_T )
{
if( !item->IsNew() && !item->IsMoving() )
commit->Modify( item );
commit->Modify( item );
setJustify( static_cast<PCB_TEXTBOX*>( item ) );
}
}
@ -2524,8 +2519,7 @@ int EDIT_TOOL::Flip( const TOOL_EVENT& aEvent )
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->Normalize();
@ -2862,8 +2856,7 @@ int EDIT_TOOL::MoveExact( const TOOL_EVENT& aEvent )
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() )
boardItem->Move( translation );
@ -3080,20 +3073,20 @@ int EDIT_TOOL::Increment( const TOOL_EVENT& aEvent )
{
const auto incrementableFilter =
[]( const VECTOR2I& aPt, GENERAL_COLLECTOR& aCollector, PCB_SELECTION_TOOL* sTool )
{
for( int i = aCollector.GetCount() - 1; i >= 0; i-- )
{
switch( aCollector[i]->Type() )
{
case PCB_PAD_T:
case PCB_TEXT_T:
break;
default:
aCollector.Remove( i );
break;
}
}
};
for( int i = aCollector.GetCount() - 1; i >= 0; i-- )
{
switch( aCollector[i]->Type() )
{
case PCB_PAD_T:
case PCB_TEXT_T:
break;
default:
aCollector.Remove( i );
break;
}
}
};
PCB_SELECTION& selection = m_selectionTool->RequestSelection( incrementableFilter,
true /* prompt user regarding locked items */ );
@ -3101,7 +3094,10 @@ int EDIT_TOOL::Increment( const TOOL_EVENT& aEvent )
if( selection.Empty() )
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;
incrementer.SetSkipIOSQXZ( true );
@ -3129,14 +3125,11 @@ int EDIT_TOOL::Increment( const TOOL_EVENT& aEvent )
continue;
// Increment on the pad numbers
std::optional<wxString> newNumber = incrementer.Increment( pad.GetNumber(), incParam.Delta,
incParam.Index );
std::optional<wxString> newNumber = incrementer.Increment( pad.GetNumber(), param.Delta, param.Index );
if( newNumber )
{
if( !pad.IsNew() )
commit->Modify( &pad );
commit->Modify( &pad );
pad.SetNumber( *newNumber );
}
@ -3146,14 +3139,11 @@ int EDIT_TOOL::Increment( const TOOL_EVENT& aEvent )
{
PCB_TEXT& text = static_cast<PCB_TEXT&>( *item );
std::optional<wxString> newText = incrementer.Increment( text.GetText(), incParam.Delta,
incParam.Index );
std::optional<wxString> newText = incrementer.Increment( text.GetText(), param.Delta, param.Index );
if( newText )
{
if( !text.IsNew() )
commit->Modify( &text );
commit->Modify( &text );
text.SetText( *newText );
}

View File

@ -47,8 +47,6 @@
#include <dialogs/dialog_move_exact.h>
#include <zone_filler.h>
#include <drc/drc_engine.h>
#include <drc/drc_item.h>
#include <drc/drc_rule.h>
#include <drc/drc_interactive_courtyard_clearance.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
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++ )
{
@ -474,23 +469,22 @@ bool EDIT_TOOL::doMoveSelection( const TOOL_EVENT& aEvent, BOARD_COMMIT* aCommit
if( evt->IsMotion() || evt->IsDrag( BUT_LEFT ) )
eatFirstMouseUp = false;
if( evt->IsAction( &PCB_ACTIONS::move )
|| evt->IsMotion()
|| evt->IsDrag( BUT_LEFT )
|| evt->IsAction( &ACTIONS::refreshPreview )
|| evt->IsAction( &PCB_ACTIONS::moveWithReference )
|| evt->IsAction( &PCB_ACTIONS::moveIndividually ) )
if( evt->IsAction( &PCB_ACTIONS::move )
|| evt->IsMotion()
|| evt->IsDrag( BUT_LEFT )
|| evt->IsAction( &ACTIONS::refreshPreview )
|| evt->IsAction( &PCB_ACTIONS::moveWithReference )
|| evt->IsAction( &PCB_ACTIONS::moveIndividually ) )
{
if( m_dragging && ( evt->IsMotion()
|| evt->IsDrag( BUT_LEFT )
|| evt->IsAction( &ACTIONS::refreshPreview ) ) )
if( m_dragging && ( evt->IsMotion()
|| evt->IsDrag( BUT_LEFT )
|| evt->IsAction( &ACTIONS::refreshPreview ) ) )
{
bool redraw3D = false;
VECTOR2I mousePos( controls->GetMousePosition() );
m_cursor = grid.BestSnapAnchor( mousePos, layers,
grid.GetSelectionGrid( selection ), sel_items );
m_cursor = grid.BestSnapAnchor( mousePos, layers, grid.GetSelectionGrid( selection ), sel_items );
if( controls->GetSettings().m_lastKeyboardCursorPositionValid )
{
@ -498,8 +492,7 @@ bool EDIT_TOOL::doMoveSelection( const TOOL_EVENT& aEvent, BOARD_COMMIT* aCommit
grid.SetUseGrid( false );
}
m_cursor = grid.BestSnapAnchor( mousePos, layers,
grid.GetSelectionGrid( selection ), sel_items );
m_cursor = grid.BestSnapAnchor( mousePos, layers, grid.GetSelectionGrid( selection ), sel_items );
if( !selection.HasReferencePoint() )
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
// snapping to items that are closest to grid points
m_cursor = grid.BestDragOrigin( originalMousePos, sel_items,
grid.GetSelectionGrid( selection ),
m_cursor = grid.BestDragOrigin( originalMousePos, sel_items, grid.GetSelectionGrid( selection ),
&m_selectionTool->GetFilter() );
// Set the current cursor position to the first dragged item origin, so the
@ -710,16 +702,22 @@ bool EDIT_TOOL::doMoveSelection( const TOOL_EVENT& aEvent, BOARD_COMMIT* aCommit
{
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
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 ) )
{
wxBell();
}
else if( evt->IsAction( &PCB_ACTIONS::rotateCw )
else if( evt->IsAction( &PCB_ACTIONS::rotateCw )
|| evt->IsAction( &PCB_ACTIONS::rotateCcw )
|| evt->IsAction( &PCB_ACTIONS::flip )
|| evt->IsAction( &PCB_ACTIONS::mirrorH )
@ -786,8 +784,10 @@ bool EDIT_TOOL::doMoveSelection( const TOOL_EVENT& aEvent, BOARD_COMMIT* aCommit
}
else if( evt->IsAction( &ACTIONS::increment ) )
{
m_toolMgr->RunSynchronousAction( ACTIONS::increment, aCommit,
evt->Parameter<ACTIONS::INCREMENT>() );
if( evt->HasParameter() )
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 )
|| evt->IsAction( &PCB_ACTIONS::moveExact )

View File

@ -532,13 +532,13 @@ int MULTICHANNEL_TOOL::RepeatLayout( const TOOL_EVENT& aEvent, ZONE* aRefZone )
{
int totalCopied = 0;
BOARD_COMMIT commit( GetManager(), true );
BOARD_COMMIT commit( GetManager(), true, false );
for( auto& targetArea : m_areas.m_compatMap )
{
if( !targetArea.second.m_doCopy )
{
wxLogTrace( traceMultichannelTool, wxT("skipping copy to RA '%s' (disabled in dialog)\n"),
targetArea.first->m_ruleName );
targetArea.first->m_ruleName );
continue;
}
@ -549,17 +549,14 @@ int MULTICHANNEL_TOOL::RepeatLayout( const TOOL_EVENT& aEvent, ZONE* aRefZone )
m_areas.m_options, targetArea.second.m_affectedItems,
targetArea.second.m_groupableItems ) )
{
auto errMsg = wxString::Format(
_( "Copy Rule Area contents failed between rule areas '%s' and '%s'." ),
m_areas.m_refRA->m_area->GetZoneName(),
targetArea.first->m_area->GetZoneName() );
auto errMsg = wxString::Format( _( "Copy Rule Area contents failed between rule areas '%s' and '%s'." ),
m_areas.m_refRA->m_area->GetZoneName(),
targetArea.first->m_area->GetZoneName() );
commit.Revert();
if( Pgm().IsGUI() )
{
frame()->ShowInfoBarError( errMsg, true );
}
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() );
BOARD_COMMIT commit( GetManager(), true );
BOARD_COMMIT commit( GetManager(), true, false );
for( RULE_AREA& ra : m_areas.m_areas )
{

View File

@ -20,6 +20,7 @@
* or you may write to the Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
*/
#include <kiplatform/ui.h>
#include <tool/tool_manager.h>
#include <tools/pcb_group_tool.h>
@ -33,6 +34,13 @@
#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 )
{
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 <board_commit.h>
#include <pcb_group.h>
@ -14,7 +37,7 @@ public:
int Group( const TOOL_EVENT& aEvent ) override;
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
{

View File

@ -32,18 +32,8 @@ using namespace std::placeholders;
#include <advanced_config.h>
#include <macros.h>
#include <core/kicad_algo.h>
#include <board.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_tablecell.h>
#include <pcb_marker.h>
@ -51,7 +41,6 @@ using namespace std::placeholders;
#include <zone.h>
#include <collectors.h>
#include <dialog_filter_selection.h>
#include <class_draw_panel_gal.h>
#include <view/view_controls.h>
#include <gal/painter.h>
#include <router/router_tool.h>
@ -63,9 +52,7 @@ using namespace std::placeholders;
#include <tools/pcb_selection_tool.h>
#include <tools/pcb_actions.h>
#include <tools/board_inspection_tool.h>
#include <connectivity/connectivity_data.h>
#include <ratsnest/ratsnest_data.h>
#include <footprint_viewer_frame.h>
#include <geometry/geometry_utils.h>
#include <wx/event.h>
#include <wx/timer.h>
@ -208,17 +195,17 @@ bool PCB_SELECTION_TOOL::Init()
}
// "Cancel" goes at the top of the context menu when a tool is active
menu.AddItem( ACTIONS::cancelInteractive, activeToolCondition, 1 );
menu.AddItem( ACTIONS::groupEnter, groupEnterCondition, 1 );
menu.AddItem( ACTIONS::groupLeave, inGroupCondition, 1 );
menu.AddItem( PCB_ACTIONS::placeLinkedDesignBlock, groupEnterCondition, 1 );
menu.AddItem( ACTIONS::cancelInteractive, activeToolCondition, 1 );
menu.AddItem( ACTIONS::groupEnter, groupEnterCondition, 1 );
menu.AddItem( ACTIONS::groupLeave, inGroupCondition, 1 );
menu.AddItem( PCB_ACTIONS::placeLinkedDesignBlock, groupEnterCondition, 1 );
menu.AddItem( PCB_ACTIONS::saveToLinkedDesignBlock, groupEnterCondition, 1 );
menu.AddItem( PCB_ACTIONS::clearHighlight, haveHighlight, 1 );
menu.AddSeparator( haveHighlight, 1 );
menu.AddItem( PCB_ACTIONS::clearHighlight, haveHighlight, 1 );
menu.AddSeparator( haveHighlight, 1 );
menu.AddItem( ACTIONS::selectColumns, tableCellSelection, 2 );
menu.AddItem( ACTIONS::selectRows, tableCellSelection, 2 );
menu.AddItem( ACTIONS::selectTable, tableCellSelection, 2 );
menu.AddItem( ACTIONS::selectColumns, tableCellSelection, 2 );
menu.AddItem( ACTIONS::selectRows, tableCellSelection, 2 );
menu.AddItem( ACTIONS::selectTable, tableCellSelection, 2 );
menu.AddSeparator( 1 );
@ -266,8 +253,7 @@ void PCB_SELECTION_TOOL::OnIdle( wxIdleEvent& aEvent )
{
wxMouseState keyboardState = wxGetMouseState();
setModifiersState( keyboardState.ShiftDown(), keyboardState.ControlDown(),
keyboardState.AltDown() );
setModifiersState( keyboardState.ShiftDown(), keyboardState.ControlDown(), keyboardState.AltDown() );
if( m_additive )
m_frame->GetCanvas()->SetCurrentCursor( KICURSOR::ADD );
@ -293,8 +279,7 @@ int PCB_SELECTION_TOOL::Main( const TOOL_EVENT& aEvent )
trackDragAction = cfg->m_TrackDragAction;
// on left click, a selection is made, depending on modifiers ALT, SHIFT, CTRL:
setModifiersState( evt->Modifier( MD_SHIFT ), evt->Modifier( MD_CTRL ),
evt->Modifier( MD_ALT ) );
setModifiersState( evt->Modifier( MD_SHIFT ), evt->Modifier( MD_CTRL ), evt->Modifier( MD_ALT ) );
PCB_BASE_FRAME* frame = getEditFrame<PCB_BASE_FRAME>();
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 )
{
const int delta = evt->Parameter<int>();
ACTIONS::INCREMENT incParams{
delta > 0 ? 1 : -1,
field
};
ACTIONS::INCREMENT params { delta > 0 ? 1 : -1, field };
m_toolMgr->RunAction( ACTIONS::increment, incParams );
m_toolMgr->RunAction( ACTIONS::increment, params );
}
}
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 )
|| ( 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 );
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 );
}
else
{
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* aSelectionCancelledFlag,
bool PCB_SELECTION_TOOL::selectPoint( const VECTOR2I& aWhere, bool aOnDrag, bool* aSelectionCancelledFlag,
CLIENT_SELECTION_FILTER aClientFilter )
{
GENERAL_COLLECTORS_GUIDE guide = getCollectorsGuide();
@ -1081,8 +1068,7 @@ int PCB_SELECTION_TOOL::SelectRectArea( const TOOL_EVENT& aEvent )
area.SetAdditive( m_drag_additive );
area.SetSubtractive( m_drag_subtractive );
area.SetExclusiveOr( false );
area.SetMode( greedySelection ? SELECTION_MODE::TOUCHING_RECTANGLE
: SELECTION_MODE::INSIDE_RECTANGLE );
area.SetMode( greedySelection ? SELECTION_MODE::TOUCHING_RECTANGLE : SELECTION_MODE::INSIDE_RECTANGLE );
view->SetVisible( &area, true );
view->Update( &area );
@ -1163,8 +1149,7 @@ int PCB_SELECTION_TOOL::SelectPolyArea( const TOOL_EVENT& aEvent )
if( getView()->IsMirroredX() && shapeArea != 0 )
isClockwise = !isClockwise;
selectionMode = isClockwise ? SELECTION_MODE::INSIDE_LASSO
: SELECTION_MODE::TOUCHING_LASSO;
selectionMode = isClockwise ? SELECTION_MODE::INSIDE_LASSO : SELECTION_MODE::TOUCHING_LASSO;
if( evt->IsCancelInteractive() || evt->IsActivate() )
{
@ -1172,22 +1157,24 @@ int PCB_SELECTION_TOOL::SelectPolyArea( const TOOL_EVENT& aEvent )
evt->SetPassEvent( false );
break;
}
else if( evt->IsDrag( BUT_LEFT ) || evt->IsClick( BUT_LEFT )
|| evt->IsAction( &ACTIONS::cursorClick ) )
else if( evt->IsDrag( BUT_LEFT )
|| evt->IsClick( BUT_LEFT )
|| evt->IsAction( &ACTIONS::cursorClick ) )
{
points.Append( evt->Position() );
}
else if( evt->IsDblClick( BUT_LEFT ) || evt->IsAction( &ACTIONS::cursorDblClick )
|| evt->IsAction( &ACTIONS::finishInteractive ) )
else if( evt->IsDblClick( BUT_LEFT )
|| evt->IsAction( &ACTIONS::cursorDblClick )
|| evt->IsAction( &ACTIONS::finishInteractive ) )
{
area.GetPoly().GenerateBBoxCache();
SelectMultiple( area, m_subtractive, m_exclusive_or );
evt->SetPassEvent( false );
break;
}
else if( evt->IsAction( &PCB_ACTIONS::deleteLastPoint )
|| evt->IsAction( &ACTIONS::doDelete )
|| evt->IsAction( &ACTIONS::undo ) )
else if( evt->IsAction( &PCB_ACTIONS::deleteLastPoint )
|| evt->IsAction( &ACTIONS::doDelete )
|| evt->IsAction( &ACTIONS::undo ) )
{
if( points.GetPointCount() > 0 )
{
@ -1466,8 +1453,7 @@ int PCB_SELECTION_TOOL::UnselectAll( const TOOL_EVENT& aEvent )
}
void connectedItemFilter( const VECTOR2I&, GENERAL_COLLECTOR& aCollector,
PCB_SELECTION_TOOL* sTool )
void connectedItemFilter( const VECTOR2I&, GENERAL_COLLECTOR& aCollector, PCB_SELECTION_TOOL* sTool )
{
// Narrow the collection down to a single BOARD_CONNECTED_ITEM for each represented net.
// All other items types are removed.
@ -1578,9 +1564,9 @@ int PCB_SELECTION_TOOL::expandConnection( const TOOL_EVENT& aEvent )
for( const EDA_ITEM* item : m_selection.GetItems() )
{
if( item->Type() == PCB_FOOTPRINT_T
|| item->Type() == PCB_GENERATOR_T
|| ( static_cast<const BOARD_ITEM*>( item )->IsConnected() ) )
if( item->Type() == PCB_FOOTPRINT_T
|| item->Type() == PCB_GENERATOR_T
|| ( static_cast<const BOARD_ITEM*>( item )->IsConnected() ) )
{
initialCount++;
}
@ -1793,11 +1779,8 @@ void PCB_SELECTION_TOOL::selectAllConnectedTracks( const std::vector<BOARD_CONNE
for( PCB_TRACK* track : trackMap[pt] )
{
if( track->GetStart() != track->GetEnd()
&& layerSetCu.Contains( track->GetLayer() ) )
{
if( track->GetStart() != track->GetEnd() && layerSetCu.Contains( track->GetLayer() ) )
pt_count++;
}
}
if( pt_count > 2 || gotVia || gotNonStartPad )
@ -2632,10 +2615,8 @@ void PCB_SELECTION_TOOL::FindItem( BOARD_ITEM* aItem )
if( !screenRect.Contains( aItem->GetBoundingBox() ) )
{
double scaleX = screenSize.x /
static_cast<double>( aItem->GetBoundingBox().GetWidth() );
double scaleY = screenSize.y /
static_cast<double>( aItem->GetBoundingBox().GetHeight() );
double scaleX = screenSize.x / static_cast<double>( aItem->GetBoundingBox().GetWidth() );
double scaleY = screenSize.y / static_cast<double>( aItem->GetBoundingBox().GetHeight() );
scaleX /= 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 );
return aFilterOptions.includeModules
&& ( aFilterOptions.includeLockedModules || !footprint.IsLocked() );
return aFilterOptions.includeModules && ( aFilterOptions.includeLockedModules
|| !footprint.IsLocked() );
}
case PCB_TRACE_T:
@ -3091,12 +3072,13 @@ bool PCB_SELECTION_TOOL::Selectable( const BOARD_ITEM* aItem, bool checkVisibili
if( aItem->GetParentGroup() && aItem->GetParentGroup()->AsEdaItem()->Type() == PCB_GENERATOR_T )
return false;
const ZONE* zone = nullptr;
const PCB_VIA* via = nullptr;
const PAD* pad = nullptr;
const PCB_TEXT* text = nullptr;
const PCB_FIELD* field = nullptr;
const PCB_MARKER* marker = nullptr;
const ZONE* zone = nullptr;
const PCB_VIA* via = nullptr;
const PAD* pad = nullptr;
const PCB_TEXT* text = nullptr;
const PCB_FIELD* field = nullptr;
const PCB_MARKER* marker = nullptr;
const PCB_TABLECELL* cell = nullptr;
// Most footprint children can only be selected in the footprint editor.
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 ) )
return false;
KI_FALLTHROUGH;
if( !layerVisible( aItem->GetLayer() ) )
return false;
break;
case PCB_SHAPE_T:
if( options.m_FilledShapeOpacity == 0.0 && static_cast<const PCB_SHAPE*>( aItem )->IsAnyFill() )
return false;
KI_FALLTHROUGH;
case PCB_TEXTBOX_T:
case PCB_TABLE_T:
case PCB_TABLECELL_T:
if( !layerVisible( aItem->GetLayer() ) )
return false;
if( aItem->Type() == PCB_TABLECELL_T )
{
const PCB_TABLECELL* cell = static_cast<const PCB_TABLECELL*>( aItem );
break;
if( cell->GetRowSpan() == 0 || cell->GetColSpan() == 0 )
return false;
}
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 )
return false;
break;
@ -3892,8 +3882,7 @@ void PCB_SELECTION_TOOL::GuessSelectionCandidates( GENERAL_COLLECTOR& aCollector
}
void PCB_SELECTION_TOOL::FilterCollectorForHierarchy( GENERAL_COLLECTOR& aCollector,
bool aMultiselect ) const
void PCB_SELECTION_TOOL::FilterCollectorForHierarchy( GENERAL_COLLECTOR& aCollector, bool aMultiselect ) const
{
std::unordered_set<EDA_ITEM*> toAdd;

View File

@ -41,7 +41,7 @@ public:
void Revert() override {}
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(); }
};