diff --git a/common/CMakeLists.txt b/common/CMakeLists.txt index 612c817bed..2791ae821d 100644 --- a/common/CMakeLists.txt +++ b/common/CMakeLists.txt @@ -203,6 +203,7 @@ set( COMMON_SRCS class_plotter.cpp class_undoredo_container.cpp colors.cpp + commit.cpp common.cpp common_plot_functions.cpp common_plotHPGL_functions.cpp diff --git a/common/base_struct.cpp b/common/base_struct.cpp index ecb6c13d71..793864ce25 100644 --- a/common/base_struct.cpp +++ b/common/base_struct.cpp @@ -65,13 +65,7 @@ EDA_ITEM::EDA_ITEM( KICAD_T idType ) EDA_ITEM::EDA_ITEM( const EDA_ITEM& base ) { initVars(); - m_StructType = base.m_StructType; - m_Parent = base.m_Parent; - m_Flags = base.m_Flags; - - // A copy of an item cannot have the same time stamp as the original item. - SetTimeStamp( GetNewTimeStamp() ); - m_Status = base.m_Status; + *this = base; } @@ -82,7 +76,6 @@ void EDA_ITEM::initVars() Pback = NULL; // Linked list: Link (previous struct) m_Parent = NULL; // Linked list: Link (parent struct) m_List = NULL; // I am not on any list yet - m_Image = NULL; // Link to an image copy for undelete or abort command m_Flags = 0; // flags for editions and other SetTimeStamp( 0 ); // Time stamp used for logical links m_Status = 0; @@ -224,23 +217,23 @@ bool EDA_ITEM::operator<( const EDA_ITEM& aItem ) const return false; } -#ifdef USE_EDA_ITEM_OP_EQ // see base_struct.h for explanations EDA_ITEM& EDA_ITEM::operator=( const EDA_ITEM& aItem ) { - if( &aItem != this ) - { - m_Image = aItem.m_Image; - m_StructType = aItem.m_StructType; - m_Parent = aItem.m_Parent; - m_Flags = aItem.m_Flags; - m_TimeStamp = aItem.m_TimeStamp; - m_Status = aItem.m_Status; - m_forceVisible = aItem.m_forceVisible; - } + // do not call initVars() + + m_StructType = aItem.m_StructType; + m_Flags = aItem.m_Flags; + m_Status = aItem.m_Status; + m_Parent = aItem.m_Parent; + m_forceVisible = aItem.m_forceVisible; + + // A copy of an item cannot have the same time stamp as the original item. + SetTimeStamp( GetNewTimeStamp() ); + + // do not copy list related fields (Pnext, Pback, m_List) return *this; } -#endif const BOX2I EDA_ITEM::ViewBBox() const { diff --git a/common/class_undoredo_container.cpp b/common/class_undoredo_container.cpp index 9c71d1ad2d..ada087480e 100644 --- a/common/class_undoredo_container.cpp +++ b/common/class_undoredo_container.cpp @@ -153,10 +153,6 @@ void PICKED_ITEMS_LIST::ClearListAndDeleteItems() case UR_LIBEDIT: /* Libedit save always a copy of the current item * So, the picker is always owner of the picked item */ - case UR_MODEDIT: /* Specific to the module editor (modedit creates a full - * copy of the current module when changed), - * and the picker is owner of this item - */ delete wrapper.GetItem(); break; diff --git a/common/commit.cpp b/common/commit.cpp new file mode 100644 index 0000000000..54b1278436 --- /dev/null +++ b/common/commit.cpp @@ -0,0 +1,176 @@ +/* + * This program source code file is part of KiCad, a free EDA CAD application. + * + * Copyright (C) 2016 CERN + * @author Tomasz Wlostowski + * @author Maciej Suminski + * + * 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 +#include + +COMMIT::COMMIT() +{ +} + + +COMMIT::~COMMIT() +{ + for( COMMIT_LINE& ent : m_changes ) + { + if( ent.m_copy ) + delete ent.m_copy; + } +} + + +COMMIT& COMMIT::Stage( EDA_ITEM* aItem, CHANGE_TYPE aChangeType ) +{ + assert( aChangeType != ( CHT_MODIFY | CHT_DONE ) ); // CHT_MODIFY and CHT_DONE are not compatible + + int flag = aChangeType & CHT_FLAGS; + + switch( aChangeType & CHT_TYPE ) + { + case CHT_ADD: + assert( m_changedItems.find( aItem ) == m_changedItems.end() ); + makeEntry( aItem, CHT_ADD | flag ); + return *this; + + case CHT_REMOVE: + makeEntry( aItem, CHT_REMOVE | flag ); + return *this; + + case CHT_MODIFY: + { + EDA_ITEM* parent = parentObject( aItem ); + + if( m_changedItems.find( parent ) != m_changedItems.end() ) + return *this; // item has been already modified once + + makeEntry( parent, CHT_MODIFY | flag, parent->Clone() ); + + return *this; + } + + default: + assert( false ); + } + + return *this; +} + + +COMMIT& COMMIT::Modified( EDA_ITEM* aItem, EDA_ITEM* aCopy ) +{ + EDA_ITEM* parent = parentObject( aItem ); + + if( m_changedItems.find( parent ) != m_changedItems.end() ) + return *this; // item has been already modified once + + makeEntry( parent, CHT_MODIFY, aCopy ); + + return *this; +} + + +COMMIT& COMMIT::Stage( std::vector& container, CHANGE_TYPE aChangeType ) +{ + for( EDA_ITEM* item : container ) + { + Stage( item, aChangeType ); + } + + return *this; +} + + +COMMIT& COMMIT::Stage( const PICKED_ITEMS_LIST& aItems, UNDO_REDO_T aModFlag ) +{ + for( unsigned int i = 0; i < aItems.GetCount(); i++ ) + { + UNDO_REDO_T change_type = aItems.GetPickedItemStatus( i ); + EDA_ITEM* item = aItems.GetPickedItem( i ); + EDA_ITEM* copy = NULL; + + if( change_type == UR_UNSPECIFIED ) + change_type = aItems.m_Status; + + if( change_type == UR_UNSPECIFIED ) + change_type = aModFlag; + + if( ( copy = aItems.GetPickedItemLink( i ) ) ) + { + assert( change_type == UR_CHANGED ); + + // There was already a copy created, so use it + Modified( item, copy ); + } + else + { + Stage( item, convert( change_type ) ); + } + } + + return *this; +} + + +void COMMIT::makeEntry( EDA_ITEM* aItem, CHANGE_TYPE aType, EDA_ITEM* aCopy ) +{ + // Expect an item copy if it is going to be modified + assert( !!aCopy == ( ( aType & CHT_TYPE ) == CHT_MODIFY ) ); + + COMMIT_LINE ent; + + ent.m_item = aItem; + ent.m_type = aType; + ent.m_copy = aCopy; + + m_changedItems.insert( aItem ); + m_changes.push_back( ent ); +} + + +CHANGE_TYPE COMMIT::convert( UNDO_REDO_T aType ) const +{ + switch( aType ) + { + case UR_NEW: + return CHT_ADD; + + case UR_DELETED: + return CHT_REMOVE; + + default: + assert( false ); + // fall through + + case UR_CHANGED: + case UR_MOVED: + case UR_MIRRORED_X: + case UR_MIRRORED_Y: + case UR_ROTATED: + case UR_ROTATED_CLOCKWISE: + case UR_FLIPPED: + return CHT_MODIFY; + } +} + diff --git a/common/eda_text.cpp b/common/eda_text.cpp index adf5c78ea7..6500c6eec1 100644 --- a/common/eda_text.cpp +++ b/common/eda_text.cpp @@ -66,23 +66,6 @@ EDA_TEXT::EDA_TEXT( const wxString& text ) } -EDA_TEXT::EDA_TEXT( const EDA_TEXT& aText ) -{ - m_Pos = aText.m_Pos; - m_Size = aText.m_Size; - m_Orient = aText.m_Orient; - m_Attributs = aText.m_Attributs; - m_Mirror = aText.m_Mirror; - m_HJustify = aText.m_HJustify; - m_VJustify = aText.m_VJustify; - m_Thickness = aText.m_Thickness; - m_Italic = aText.m_Italic; - m_Bold = aText.m_Bold; - m_MultilineAllowed = aText.m_MultilineAllowed; - m_Text = aText.m_Text; -} - - EDA_TEXT::~EDA_TEXT() { } diff --git a/common/view/view_group.cpp b/common/view/view_group.cpp index afcd7af04a..94123f1b28 100644 --- a/common/view/view_group.cpp +++ b/common/view/view_group.cpp @@ -55,18 +55,21 @@ VIEW_GROUP::~VIEW_GROUP() void VIEW_GROUP::Add( VIEW_ITEM* aItem ) { m_items.insert( aItem ); + ViewUpdate(); } void VIEW_GROUP::Remove( VIEW_ITEM* aItem ) { m_items.erase( aItem ); + ViewUpdate(); } void VIEW_GROUP::Clear() { m_items.clear(); + ViewUpdate(); } @@ -128,7 +131,8 @@ void VIEW_GROUP::FreeItems() { delete item; } - m_items.clear(); + + Clear(); } diff --git a/eeschema/operations_on_items_lists.cpp b/eeschema/operations_on_items_lists.cpp index 89346b1958..6f0b790c27 100644 --- a/eeschema/operations_on_items_lists.cpp +++ b/eeschema/operations_on_items_lists.cpp @@ -258,7 +258,5 @@ SCH_ITEM* DuplicateStruct( SCH_ITEM* aDrawStruct, bool aClone ) if( aClone ) NewDrawStruct->SetTimeStamp( aDrawStruct->GetTimeStamp() ); - NewDrawStruct->SetImage( aDrawStruct ); - return NewDrawStruct; } diff --git a/eeschema/schematic_undo_redo.cpp b/eeschema/schematic_undo_redo.cpp index 7c539d0377..1f7da2e205 100644 --- a/eeschema/schematic_undo_redo.cpp +++ b/eeschema/schematic_undo_redo.cpp @@ -102,7 +102,7 @@ /* Used if undo / redo command: - * swap data between Item and its copy, pointed by its .m_Image member + * swap data between Item and its copy, pointed by its picked item link member * swapped data is data modified by edition, so not all values are swapped */ diff --git a/include/base_struct.h b/include/base_struct.h index 3d11391de9..2990b14f8f 100644 --- a/include/base_struct.h +++ b/include/base_struct.h @@ -179,9 +179,6 @@ protected: /// Flag bits for editing and other uses. STATUS_FLAGS m_Flags; - // Link to an copy of the item use to save the item's state for undo/redo feature. - EDA_ITEM* m_Image; - private: void initVars(); @@ -262,8 +259,6 @@ public: void ClearFlags( STATUS_FLAGS aMask = EDA_ITEM_ALL_FLAGS ) { m_Flags &= ~aMask; } STATUS_FLAGS GetFlags() const { return m_Flags; } - void SetImage( EDA_ITEM* aItem ) { m_Image = aItem; } - /** * Function SetForceVisible * is used to set and cleag force visible flag used to force the item to be drawn @@ -482,17 +477,11 @@ public: */ static bool Sort( const EDA_ITEM* aLeft, const EDA_ITEM* aRight ) { return *aLeft < *aRight; } -#if 0 /** * Operator assignment * is used to assign the members of \a aItem to another object. - * - * @warning This is still a work in progress and not ready for prime time. Do not use - * as there is a known issue with wxString buffers. */ - virtual EDA_ITEM& operator=( const EDA_ITEM& aItem ); - #define USE_EDA_ITEM_OP_EQ -#endif + EDA_ITEM& operator=( const EDA_ITEM& aItem ); /// @copydoc VIEW_ITEM::ViewBBox() virtual const BOX2I ViewBBox() const; diff --git a/include/class_board_item.h b/include/class_board_item.h index 6d9a2f928a..af8491ce26 100644 --- a/include/class_board_item.h +++ b/include/class_board_item.h @@ -79,7 +79,7 @@ protected: LAYER_ID m_Layer; static int getTrailingInt( wxString aStr ); - static int getNextNumberInSequence( std::set aSeq, bool aFillSequenceGaps ); + static int getNextNumberInSequence( const std::set& aSeq, bool aFillSequenceGaps ); public: @@ -88,7 +88,8 @@ public: { } - // Do not create a copy constructor. The one generated by the compiler is adequate. + // Do not create a copy constructor & operator=. + // The ones generated by the compiler are adequate. virtual const wxPoint& GetPosition() const = 0; diff --git a/include/class_undoredo_container.h b/include/class_undoredo_container.h index 13c9e85b23..ce54b45a8b 100644 --- a/include/class_undoredo_container.h +++ b/include/class_undoredo_container.h @@ -69,8 +69,6 @@ enum UNDO_REDO_T { UR_ROTATED_CLOCKWISE, // Rotated item (clockwise), undo by rotating it UR_FLIPPED, // flipped (board items only), undo by flipping it UR_WIRE_IMAGE, // Specific to Eeschema for handling wires changes. - UR_MODEDIT, // Specific to the module editor (modedit creates a full copy of - // the current module when changed) UR_LIBEDIT, // Specific to the component editor (libedit creates a full copy // of the current component when changed) UR_EXCHANGE_T ///< Use for changing the schematic text type where swapping diff --git a/include/commit.h b/include/commit.h new file mode 100644 index 0000000000..646e991a4b --- /dev/null +++ b/include/commit.h @@ -0,0 +1,160 @@ +/* + * This program source code file is part of KiCad, a free EDA CAD application. + * + * Copyright (C) 2016 CERN + * @author Tomasz Wlostowski + * @author Maciej Suminski + * + * 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 + */ + +#ifndef __COMMIT_H +#define __COMMIT_H + +#include +#include + +#include + +class EDA_ITEM; + +///> Types of changes +enum CHANGE_TYPE { + CHT_ADD = 1, + CHT_REMOVE = 2, + CHT_MODIFY = 4, + CHT_TYPE = CHT_ADD | CHT_REMOVE | CHT_MODIFY, + + ///> Flag to indicate the change is already applied, + ///> just notify observers (not compatible with CHT_MODIFY) + CHT_DONE = 8, + CHT_FLAGS = CHT_DONE +}; + +template +CHANGE_TYPE operator|( CHANGE_TYPE aTypeA, T aTypeB ) +{ + return CHANGE_TYPE( (int) aTypeA | (int) aTypeB ); +} + +template +CHANGE_TYPE operator&( CHANGE_TYPE aTypeA, T aTypeB ) +{ + return CHANGE_TYPE( (int) aTypeA & (int) aTypeB ); +} + + +/** + * Class COMMIT + * + * Represents a set of changes (additions, deletions or modifications) + * of a data model (e.g. the BOARD) class. + * + * The class can be used to propagate changes to subscribed objects (e.g. views, ratsnest), + * and automatically create undo/redo points. + */ +class COMMIT +{ +public: + COMMIT(); + virtual ~COMMIT(); + + ///> Adds a new item to the model + COMMIT& Add( EDA_ITEM* aItem ) + { + return Stage( aItem, CHT_ADD ); + } + + ///> Notifies observers that aItem has been added + COMMIT& Added( EDA_ITEM* aItem ) + { + return Stage( aItem, CHT_ADD | CHT_DONE ); + } + + ///> Removes a new item from the model + COMMIT& Remove( EDA_ITEM* aItem ) + { + return Stage( aItem, CHT_REMOVE ); + } + + ///> Notifies observers that aItem has been removed + COMMIT& Removed( EDA_ITEM* aItem ) + { + return Stage( aItem, CHT_REMOVE | CHT_DONE ); + } + + ///> Modifies a given item in the model. + ///> Must be called before modification is performed. + COMMIT& Modify( EDA_ITEM* aItem ) + { + return Stage( aItem, CHT_MODIFY ); + } + + ///> Creates an undo entry for an item that has been already modified. Requires a copy done + ///> before the modification. + COMMIT& Modified( EDA_ITEM* aItem, EDA_ITEM* aCopy ); + + ///> Adds a change of the item aItem of type aChangeType to the change list. + COMMIT& Stage( EDA_ITEM* aItem, CHANGE_TYPE aChangeType ); + + COMMIT& Stage( std::vector& container, CHANGE_TYPE aChangeType ); + + COMMIT& Stage( const PICKED_ITEMS_LIST& aItems, UNDO_REDO_T aModFlag = UR_UNSPECIFIED ); + + ///> Executes the changes. + virtual void Push( const wxString& aMessage ) = 0; + + ///> Revertes the commit by restoring the modifed items state. + virtual void Revert() = 0; + + bool Empty() const + { + return m_changes.empty(); + } + +protected: + struct COMMIT_LINE + { + ///> Main item that is added/deleted/modified + EDA_ITEM* m_item; + + ///> Optional copy of the item + EDA_ITEM* m_copy; + + ///> Modification type + CHANGE_TYPE m_type; + }; + + // Should be called in Push() & Revert() methods + void clear() + { + m_changedItems.clear(); + m_changes.clear(); + } + + virtual void makeEntry( EDA_ITEM* aItem, CHANGE_TYPE aType, EDA_ITEM* aCopy = NULL ); + + virtual EDA_ITEM* parentObject( EDA_ITEM* aItem ) const = 0; + + CHANGE_TYPE convert( UNDO_REDO_T aType ) const; + + std::set m_changedItems; + std::vector m_changes; +}; + +#endif diff --git a/include/eda_text.h b/include/eda_text.h index f82609da5c..aa2b6d4c1a 100644 --- a/include/eda_text.h +++ b/include/eda_text.h @@ -97,7 +97,10 @@ protected: public: EDA_TEXT( const wxString& text = wxEmptyString ); - EDA_TEXT( const EDA_TEXT& aText ); + + // Do not create a copy constructor & operator=. + // The ones generated by the compiler are adequate. + virtual ~EDA_TEXT(); /** diff --git a/include/ttl/halfedge/hetriang.h b/include/ttl/halfedge/hetriang.h index e10af65aad..91a6354ce0 100644 --- a/include/ttl/halfedge/hetriang.h +++ b/include/ttl/halfedge/hetriang.h @@ -43,7 +43,7 @@ #define _HE_TRIANG_H_ //#define TTL_USE_NODE_ID // Each node gets it's own unique id -#define TTL_USE_NODE_FLAG // Each node gets a flag (can be set to true or false) +//#define TTL_USE_NODE_FLAG // Each node gets a flag (can be set to true or false) #include #include @@ -106,6 +106,9 @@ protected: /// Tag for quick connection resolution int m_tag; + /// Whether it the node can be a target for ratsnest lines + bool m_noline; + /// List of board items that share this node std::unordered_set m_parents; @@ -124,7 +127,7 @@ public: #ifdef TTL_USE_NODE_ID m_id( id_count++ ), #endif - m_x( aX ), m_y( aY ), m_tag( -1 ) + m_x( aX ), m_y( aY ), m_tag( -1 ), m_noline( false ) { m_layers.reset(); } @@ -156,6 +159,18 @@ public: m_tag = aTag; } + /// Decides whether this node can be a ratsnest line target + inline void SetNoLine( bool aEnable ) + { + m_noline = aEnable; + } + + /// Returns true if this node can be a target for ratsnest lines + inline const bool& GetNoLine() const + { + return m_noline; + } + #ifdef TTL_USE_NODE_ID /// Returns the id (TTL_USE_NODE_ID must be defined) inline int Id() const diff --git a/include/view/view_group.h b/include/view/view_group.h index 2a1ad62756..056a812f79 100644 --- a/include/view/view_group.h +++ b/include/view/view_group.h @@ -131,6 +131,7 @@ public: inline virtual void SetLayer( int aLayer ) { m_layer = aLayer; + ViewUpdate(); } /** diff --git a/include/wxPcbStruct.h b/include/wxPcbStruct.h index 887e7f3075..356495f925 100644 --- a/include/wxPcbStruct.h +++ b/include/wxPcbStruct.h @@ -39,6 +39,8 @@ /* Forward declarations of classes. */ class PCB_SCREEN; class BOARD; +class BOARD_COMMIT; +class BOARD_ITEM_CONTAINER; class TEXTE_PCB; class MODULE; class TRACK; @@ -637,64 +639,6 @@ public: void OnSelectOptionToolbar( wxCommandEvent& event ); void ToolOnRightClick( wxCommandEvent& event ); - /** - * Function SaveCopyInUndoList. - * Creates a new entry in undo list of commands. - * add a picker to handle aItemToCopy - * @param aItemToCopy = the board item modified by the command to undo - * @param aTypeCommand = command type (see enum UNDO_REDO_T) - * @param aTransformPoint = the reference point of the transformation, for - * commands like move - */ - virtual void SaveCopyInUndoList( BOARD_ITEM* aItemToCopy, - UNDO_REDO_T aTypeCommand, - const wxPoint& aTransformPoint = wxPoint( 0, 0 ) ); - - /** - * Function SaveCopyInUndoList (overloaded). - * Creates a new entry in undo list of commands. - * add a list of pickers to handle a list of items - * @param aItemsList = the list of items modified by the command to undo - * @param aTypeCommand = command type (see enum UNDO_REDO_T) - * @param aTransformPoint = the reference point of the transformation, for - * commands like move - */ - virtual void SaveCopyInUndoList( const PICKED_ITEMS_LIST& aItemsList, - UNDO_REDO_T aTypeCommand, - const wxPoint& aTransformPoint = wxPoint( 0, 0 ) ); - - /** - * Function PutDataInPreviousState - * Used in undo or redo command. - * Put data pointed by List in the previous state, i.e. the state memorized by List - * @param aList = a PICKED_ITEMS_LIST pointer to the list of items to undo/redo - * @param aRedoCommand = a bool: true for redo, false for undo - * @param aRebuildRatsnet = a bool: true to rebuild ratsnest (normal use), false - * to just retrieve last state (used in abort commands that do not need to - * rebuild ratsnest) - */ - void PutDataInPreviousState( PICKED_ITEMS_LIST* aList, - bool aRedoCommand, - bool aRebuildRatsnet = true ); - - /** - * Function RestoreCopyFromRedoList - * Redo the last edition: - * - Save the current board in Undo list - * - Get an old version of the board from Redo list - * @return none - */ - void RestoreCopyFromRedoList( wxCommandEvent& aEvent ); - - /** - * Function RestoreCopyFromUndoList - * Undo the last edition: - * - Save the current board in Redo list - * - Get an old version of the board from Undo list - * @return none - */ - void RestoreCopyFromUndoList( wxCommandEvent& aEvent ); - /* Block operations: */ /** @@ -916,6 +860,9 @@ public: ///> @copydoc PCB_BASE_FRAME::SetBoard() void SetBoard( BOARD* aBoard ); + ///> @copydoc PCB_BASE_EDIT_FRAME::GetModel() + BOARD_ITEM_CONTAINER* GetModel() const override; + ///> @copydoc PCB_BASE_FRAME::SetPageSettings() void SetPageSettings( const PAGE_INFO& aPageSettings ); // overload @@ -1142,11 +1089,9 @@ public: * OldModule is deleted or put in undo list. * @param aOldModule = footprint to replace * @param aNewModule = footprint to put - * @param aUndoPickList = the undo list used to save OldModule. If null, - * OldModule is deleted + * @param aCommit = commit that should store the changes */ - void Exchange_Module( MODULE* aOldModule, MODULE* aNewModule, - PICKED_ITEMS_LIST* aUndoPickList ); + void Exchange_Module( MODULE* aOldModule, MODULE* aNewModule, BOARD_COMMIT& aCommit ); // loading modules: see PCB_BASE_FRAME diff --git a/pcbnew/CMakeLists.txt b/pcbnew/CMakeLists.txt index c4aff5177a..a2e094b487 100644 --- a/pcbnew/CMakeLists.txt +++ b/pcbnew/CMakeLists.txt @@ -182,6 +182,7 @@ set( PCBNEW_AUTOROUTER_SRCS ) set( PCBNEW_CLASS_SRCS + board_commit.cpp tool_modview.cpp modview_frame.cpp pcbframe.cpp @@ -190,7 +191,6 @@ set( PCBNEW_CLASS_SRCS array_creator.cpp attribut.cpp board_items_to_polygon_shape_transform.cpp - board_undo_redo.cpp board_netlist_updater.cpp block.cpp block_module_editor.cpp @@ -237,7 +237,6 @@ set( PCBNEW_CLASS_SRCS modedit.cpp modedit_onclick.cpp modeditoptions.cpp - modedit_undo_redo.cpp moduleframe.cpp modules.cpp move-drag_pads.cpp @@ -266,6 +265,7 @@ set( PCBNEW_CLASS_SRCS toolbars_update_user_interface.cpp tracepcb.cpp tr_modif.cpp + undo_redo.cpp xchgmod.cpp zones_convert_brd_items_to_polygons_with_Boost.cpp zones_convert_to_polygons_aux_functions.cpp diff --git a/pcbnew/array_creator.cpp b/pcbnew/array_creator.cpp index 537abea823..5787e35dee 100644 --- a/pcbnew/array_creator.cpp +++ b/pcbnew/array_creator.cpp @@ -28,7 +28,7 @@ #include "array_creator.h" -#include +#include #include @@ -41,6 +41,7 @@ void ARRAY_CREATOR::Invoke() if( numItems == 0 ) return; + BOARD_COMMIT commit( &m_parent ); MODULE* const module = getModule(); const bool isModuleEditor = module != NULL; @@ -52,77 +53,63 @@ void ARRAY_CREATOR::Invoke() DIALOG_CREATE_ARRAY::ARRAY_OPTIONS* const array_opts = dialog.GetArrayOptions(); - if( ret == wxID_OK && array_opts != NULL ) + if( ret != wxID_OK || array_opts == NULL ) + return; + + for ( int i = 0; i < numItems; ++i ) { - PICKED_ITEMS_LIST newItemsList; + BOARD_ITEM* item = getNthItemToArray( i ); - if( isModuleEditor ) + if( item->Type() == PCB_PAD_T && !isModuleEditor ) { - // modedit saves everything upfront - m_parent.SaveCopyInUndoList( getBoard()->m_Modules, UR_MODEDIT ); + // If it is not the module editor, then duplicate the parent module instead + item = static_cast( item )->GetParent(); } - for ( int i = 0; i < numItems; ++i ) + // The first item in list is the original item. We do not modify it + for( int ptN = 1; ptN < array_opts->GetArraySize(); ptN++ ) { - BOARD_ITEM* item = getNthItemToArray( i ); + BOARD_ITEM* new_item; - if( item->Type() == PCB_PAD_T && !isModuleEditor ) + if( isModuleEditor ) { - // If it is not the module editor, then duplicate the parent module instead - item = static_cast( item )->GetParent(); + // increment pad numbers if do any renumbering + // (we will number again later according to the numbering scheme if set) + new_item = module->Duplicate( item, array_opts->ShouldNumberItems() ); + } + else + { + // PCB items keep the same numbering + new_item = getBoard()->Duplicate( item ); + + // @TODO: we should merge zones. This is a bit tricky, because + // the undo command needs saving old area, if it is merged. } - // The first item in list is the original item. We do not modify it - for( int ptN = 1; ptN < array_opts->GetArraySize(); ptN++ ) + if( new_item ) { - BOARD_ITEM* new_item; + array_opts->TransformItem( ptN, new_item, rotPoint ); + prePushAction( new_item ); + commit.Add( new_item ); + postPushAction( new_item ); + } - if( isModuleEditor ) + // attempt to renumber items if the array parameters define + // a complete numbering scheme to number by (as opposed to + // implicit numbering by incrementing the items during creation + if( new_item && array_opts->NumberingStartIsSpecified() ) + { + // Renumber pads. Only new pad number renumbering has meaning, + // in the footprint editor. + if( new_item->Type() == PCB_PAD_T ) { - // increment pad numbers if do any renumbering - // (we will number again later according to the numbering scheme if set) - new_item = module->DuplicateAndAddItem( - item, array_opts->ShouldNumberItems() ); - } - else - { - // PCB items keep the same numbering - new_item = getBoard()->DuplicateAndAddItem( item ); - - // @TODO: we should merge zones. This is a bit tricky, because - // the undo command needs saving old area, if it is merged. - } - - if( new_item ) - { - array_opts->TransformItem( ptN, new_item, rotPoint ); - prePushAction( new_item ); - newItemsList.PushItem( new_item ); // For undo list - postPushAction( new_item ); - } - - // attempt to renumber items if the array parameters define - // a complete numbering scheme to number by (as opposed to - // implicit numbering by incrementing the items during creation - if( new_item && array_opts->NumberingStartIsSpecified() ) - { - // Renumber pads. Only new pad number renumbering has meaning, - // in the footprint editor. - if( new_item->Type() == PCB_PAD_T ) - { - const wxString padName = array_opts->GetItemNumber( ptN ); - static_cast( new_item )->SetPadName( padName ); - } + const wxString padName = array_opts->GetItemNumber( ptN ); + static_cast( new_item )->SetPadName( padName ); } } } - - if( !isModuleEditor ) - { - // Add all items as a single undo point for PCB editors - m_parent.SaveCopyInUndoList( newItemsList, UR_NEW ); - } - - finalise(); } + + commit.Push( _( "Create an array" ) ); + finalise(); } diff --git a/pcbnew/block_module_editor.cpp b/pcbnew/block_module_editor.cpp index 1a635e972f..d1ff77b44f 100644 --- a/pcbnew/block_module_editor.cpp +++ b/pcbnew/block_module_editor.cpp @@ -196,7 +196,7 @@ bool FOOTPRINT_EDIT_FRAME::HandleBlockEnd( wxDC* DC ) if( ret == wxID_OK ) { - SaveCopyInUndoList( currentModule, UR_MODEDIT ); + SaveCopyInUndoList( currentModule, UR_CHANGED ); const wxPoint blockCentre = GetScreen()->m_BlockLocate.Centre(); MoveMarkedItemsExactly( currentModule, blockCentre, translation, rotation ); } @@ -213,7 +213,7 @@ bool FOOTPRINT_EDIT_FRAME::HandleBlockEnd( wxDC* DC ) itemsCount = MarkItemsInBloc( currentModule, GetScreen()->m_BlockLocate ); if( itemsCount ) - SaveCopyInUndoList( currentModule, UR_MODEDIT ); + SaveCopyInUndoList( currentModule, UR_CHANGED ); DeleteMarkedItems( currentModule ); break; @@ -226,7 +226,7 @@ bool FOOTPRINT_EDIT_FRAME::HandleBlockEnd( wxDC* DC ) itemsCount = MarkItemsInBloc( currentModule, GetScreen()->m_BlockLocate ); if( itemsCount ) - SaveCopyInUndoList( currentModule, UR_MODEDIT ); + SaveCopyInUndoList( currentModule, UR_CHANGED ); RotateMarkedItems( currentModule, GetScreen()->m_BlockLocate.Centre() ); break; @@ -237,7 +237,7 @@ bool FOOTPRINT_EDIT_FRAME::HandleBlockEnd( wxDC* DC ) itemsCount = MarkItemsInBloc( currentModule, GetScreen()->m_BlockLocate ); if( itemsCount ) - SaveCopyInUndoList( currentModule, UR_MODEDIT ); + SaveCopyInUndoList( currentModule, UR_CHANGED ); MirrorMarkedItems( currentModule, GetScreen()->m_BlockLocate.Centre() ); break; @@ -293,7 +293,7 @@ void FOOTPRINT_EDIT_FRAME::HandleBlockPlace( wxDC* DC ) case BLOCK_MOVE: // Move case BLOCK_PRESELECT_MOVE: // Move with preselection list GetScreen()->m_BlockLocate.ClearItemsList(); - SaveCopyInUndoList( currentModule, UR_MODEDIT ); + SaveCopyInUndoList( currentModule, UR_CHANGED ); MoveMarkedItems( currentModule, GetScreen()->m_BlockLocate.GetMoveVector() ); m_canvas->Refresh( true ); break; @@ -301,7 +301,7 @@ void FOOTPRINT_EDIT_FRAME::HandleBlockPlace( wxDC* DC ) case BLOCK_COPY: // Copy case BLOCK_COPY_AND_INCREMENT: // Copy and increment pad names GetScreen()->m_BlockLocate.ClearItemsList(); - SaveCopyInUndoList( currentModule, UR_MODEDIT ); + SaveCopyInUndoList( currentModule, UR_CHANGED ); CopyMarkedItems( currentModule, GetScreen()->m_BlockLocate.GetMoveVector(), command == BLOCK_COPY_AND_INCREMENT ); break; @@ -313,12 +313,12 @@ void FOOTPRINT_EDIT_FRAME::HandleBlockPlace( wxDC* DC ) case BLOCK_MIRROR_X: case BLOCK_MIRROR_Y: case BLOCK_FLIP: // Mirror by popup menu, from block move - SaveCopyInUndoList( currentModule, UR_MODEDIT ); + SaveCopyInUndoList( currentModule, UR_CHANGED ); MirrorMarkedItems( currentModule, GetScreen()->m_BlockLocate.Centre() ); break; case BLOCK_ROTATE: - SaveCopyInUndoList( currentModule, UR_MODEDIT ); + SaveCopyInUndoList( currentModule, UR_CHANGED ); RotateMarkedItems( currentModule, GetScreen()->m_BlockLocate.Centre() ); break; diff --git a/pcbnew/board_commit.cpp b/pcbnew/board_commit.cpp new file mode 100644 index 0000000000..62139f711e --- /dev/null +++ b/pcbnew/board_commit.cpp @@ -0,0 +1,366 @@ +/* + * This program source code file is part of KiCad, a free EDA CAD application. + * + * Copyright (C) 2016 CERN + * @author Tomasz Wlostowski + * + * 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 +#include +#include +#include +#include +#include +#include + +#include + +#include + +BOARD_COMMIT::BOARD_COMMIT( PCB_TOOL* aTool ) +{ + m_toolMgr = aTool->GetManager(); + m_editModules = aTool->EditingModules(); +} + + +BOARD_COMMIT::BOARD_COMMIT( PCB_BASE_FRAME* aFrame ) +{ + m_toolMgr = aFrame->GetToolManager(); + m_editModules = aFrame->IsType( FRAME_PCB_MODULE_EDITOR ); +} + + +BOARD_COMMIT::~BOARD_COMMIT() +{ +} + + +void BOARD_COMMIT::Push( const wxString& aMessage ) +{ + // Objects potentially interested in changes: + PICKED_ITEMS_LIST undoList; + KIGFX::VIEW* view = m_toolMgr->GetView(); + BOARD* board = (BOARD*) m_toolMgr->GetModel(); + PCB_BASE_FRAME* frame = (PCB_BASE_FRAME*) m_toolMgr->GetEditFrame(); + RN_DATA* ratsnest = board->GetRatsnest(); + std::set savedModules; + + if( Empty() ) + return; + + for( COMMIT_LINE& ent : m_changes ) + { + int changeType = ent.m_type & CHT_TYPE; + int changeFlags = ent.m_type & CHT_FLAGS; + BOARD_ITEM* boardItem = static_cast( ent.m_item ); + + // Module items need to be saved in the undo buffer before modification + if( m_editModules ) + { + // Be sure that we are storing a module + if( ent.m_item->Type() != PCB_MODULE_T ) + ent.m_item = ent.m_item->GetParent(); + + // We have not saved the module yet, so let's create an entry + if( savedModules.count( ent.m_item ) == 0 ) + { + if( !ent.m_copy ) + { + assert( changeType != CHT_MODIFY ); // too late to make a copy.. + ent.m_copy = ent.m_item->Clone(); + } + + assert( ent.m_item->Type() == PCB_MODULE_T ); + assert( ent.m_copy->Type() == PCB_MODULE_T ); + + ITEM_PICKER itemWrapper( ent.m_item, UR_CHANGED ); + itemWrapper.SetLink( ent.m_copy ); + undoList.PushItem( itemWrapper ); + frame->SaveCopyInUndoList( undoList, UR_CHANGED ); + + savedModules.insert( ent.m_item ); + static_cast( ent.m_item )->SetLastEditTime(); + } + } + + switch( changeType ) + { + case CHT_ADD: + { + if( !m_editModules ) + { + undoList.PushItem( ITEM_PICKER( boardItem, UR_NEW ) ); + + if( !( changeFlags & CHT_DONE ) ) + board->Add( boardItem ); + + //ratsnest->Add( boardItem ); // TODO currently done by BOARD::Add() + + if( boardItem->Type() == PCB_MODULE_T ) + { + MODULE* mod = static_cast( boardItem ); + mod->RunOnChildren( boost::bind( &KIGFX::VIEW::Add, view, _1 ) ); + } + } + else + { + // modules inside modules are not supported yet + assert( boardItem->Type() != PCB_MODULE_T ); + + if( !( changeFlags & CHT_DONE ) ) + board->m_Modules->Add( boardItem ); + } + + view->Add( boardItem ); + break; + } + + case CHT_REMOVE: + { + if( !m_editModules ) + { + undoList.PushItem( ITEM_PICKER( boardItem, UR_DELETED ) ); + } + + switch( boardItem->Type() ) + { + // Module items + case PCB_PAD_T: + case PCB_MODULE_EDGE_T: + case PCB_MODULE_TEXT_T: + { + // Do not allow footprint text removal when not editing a module + if( !m_editModules ) + break; + + bool remove = true; + + if( boardItem->Type() == PCB_MODULE_TEXT_T ) + { + TEXTE_MODULE* text = static_cast( boardItem ); + + switch( text->GetType() ) + { + case TEXTE_MODULE::TEXT_is_REFERENCE: + //DisplayError( frame, _( "Cannot delete component reference." ) ); + remove = false; + break; + + case TEXTE_MODULE::TEXT_is_VALUE: + //DisplayError( frame, _( "Cannot delete component value." ) ); + remove = false; + break; + + case TEXTE_MODULE::TEXT_is_DIVERS: // suppress warnings + break; + + default: + assert( false ); + break; + } + } + + if( remove ) + { + view->Remove( boardItem ); + + if( !( changeFlags & CHT_DONE ) ) + { + MODULE* module = static_cast( boardItem->GetParent() ); + assert( module && module->Type() == PCB_MODULE_T ); + module->Delete( boardItem ); + } + + board->m_Status_Pcb = 0; // it is done in the legacy view (ratsnest perhaps?) + } + + break; + } + + // Board items + case PCB_LINE_T: // a segment not on copper layers + case PCB_TEXT_T: // a text on a layer + case PCB_TRACE_T: // a track segment (segment on a copper layer) + case PCB_VIA_T: // a via (like track segment on a copper layer) + case PCB_DIMENSION_T: // a dimension (graphic item) + case PCB_TARGET_T: // a target (graphic item) + case PCB_MARKER_T: // a marker used to show something + case PCB_ZONE_T: // SEG_ZONE items are now deprecated + case PCB_ZONE_AREA_T: + view->Remove( boardItem ); + + if( !( changeFlags & CHT_DONE ) ) + board->Remove( boardItem ); + + //ratsnest->Remove( boardItem ); // currently done by BOARD::Remove() + break; + + case PCB_MODULE_T: + { + // There are no modules inside a module yet + assert( !m_editModules ); + + MODULE* module = static_cast( boardItem ); + module->ClearFlags(); + module->RunOnChildren( boost::bind( &KIGFX::VIEW::Remove, view, _1 ) ); + + view->Remove( module ); + + if( !( changeFlags & CHT_DONE ) ) + board->Remove( module ); + + // Clear flags to indicate, that the ratsnest, list of nets & pads are not valid anymore + board->m_Status_Pcb = 0; + } + break; + + default: // other types do not need to (or should not) be handled + assert( false ); + break; + } + break; + } + + case CHT_MODIFY: + { + if( !m_editModules ) + { + ITEM_PICKER itemWrapper( boardItem, UR_CHANGED ); + assert( ent.m_copy ); + itemWrapper.SetLink( ent.m_copy ); + undoList.PushItem( itemWrapper ); + } + + boardItem->ViewUpdate( KIGFX::VIEW_ITEM::ALL ); + ratsnest->Update( boardItem ); + break; + } + + default: + assert( false ); + break; + } + } + + if( !m_editModules ) + frame->SaveCopyInUndoList( undoList, UR_UNSPECIFIED ); + + frame->OnModify(); + ratsnest->Recalculate(); + + clear(); +} + + +EDA_ITEM* BOARD_COMMIT::parentObject( EDA_ITEM* aItem ) const +{ + switch( aItem->Type() ) + { + case PCB_PAD_T: + case PCB_MODULE_EDGE_T: + case PCB_MODULE_TEXT_T: + return aItem->GetParent(); + default: + return aItem; + } + + return aItem; +} + + +void BOARD_COMMIT::Revert() +{ + PICKED_ITEMS_LIST undoList; + KIGFX::VIEW* view = m_toolMgr->GetView(); + BOARD* board = (BOARD*) m_toolMgr->GetModel(); + RN_DATA* ratsnest = board->GetRatsnest(); + + for( auto it = m_changes.rbegin(); it != m_changes.rend(); ++it ) + { + COMMIT_LINE& ent = *it; + BOARD_ITEM* item = static_cast( ent.m_item ); + BOARD_ITEM* copy = static_cast( ent.m_copy ); + + switch( ent.m_type ) + { + case CHT_ADD: + if( item->Type() == PCB_MODULE_T ) + { + MODULE* oldModule = static_cast( item ); + oldModule->RunOnChildren( boost::bind( &KIGFX::VIEW::Remove, view, _1 ) ); + } + + view->Remove( item ); + ratsnest->Remove( item ); + break; + + case CHT_REMOVE: + if( item->Type() == PCB_MODULE_T ) + { + MODULE* newModule = static_cast( item ); + newModule->RunOnChildren( boost::bind( &EDA_ITEM::ClearFlags, _1, SELECTED ) ); + newModule->RunOnChildren( boost::bind( &KIGFX::VIEW::Add, view, _1 ) ); + } + + view->Add( item ); + ratsnest->Add( item ); + break; + + case CHT_MODIFY: + { + if( item->Type() == PCB_MODULE_T ) + { + MODULE* oldModule = static_cast( item ); + oldModule->RunOnChildren( boost::bind( &KIGFX::VIEW::Remove, view, _1 ) ); + } + + view->Remove( item ); + ratsnest->Remove( item ); + + item->SwapData( copy ); + + item->ClearFlags( SELECTED ); + + // Update all pads/drawings/texts, as they become invalid + // for the VIEW after SwapData() called for modules + if( item->Type() == PCB_MODULE_T ) + { + MODULE* newModule = static_cast( item ); + newModule->RunOnChildren( boost::bind( &EDA_ITEM::ClearFlags, _1, SELECTED ) ); + newModule->RunOnChildren( boost::bind( &KIGFX::VIEW::Add, view, _1 ) ); + } + + view->Add( item ); + ratsnest->Add( item ); + delete copy; + break; + } + + default: + assert( false ); + break; + } + } + + ratsnest->Recalculate(); + + clear(); +} diff --git a/pcbnew/board_commit.h b/pcbnew/board_commit.h new file mode 100644 index 0000000000..7f4d09db15 --- /dev/null +++ b/pcbnew/board_commit.h @@ -0,0 +1,52 @@ +/* + * This program source code file is part of KiCad, a free EDA CAD application. + * + * Copyright (C) 2016 CERN + * @author Tomasz Wlostowski + * + * 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 + */ + +#ifndef __BOARD_COMMIT_H +#define __BOARD_COMMIT_H + +#include + +class BOARD_ITEM; +class PICKED_ITEMS_LIST; +class PCB_TOOL; +class PCB_BASE_FRAME; +class TOOL_MANAGER; + +class BOARD_COMMIT : public COMMIT +{ +public: + BOARD_COMMIT( PCB_TOOL* aTool ); + BOARD_COMMIT( PCB_BASE_FRAME* aFrame ); + virtual ~BOARD_COMMIT(); + + virtual void Push( const wxString& aMessage ); + virtual void Revert(); + +private: + TOOL_MANAGER* m_toolMgr; + bool m_editModules; + virtual EDA_ITEM* parentObject( EDA_ITEM* aItem ) const; +}; + +#endif diff --git a/pcbnew/board_item_container.h b/pcbnew/board_item_container.h new file mode 100644 index 0000000000..9e100bd1fa --- /dev/null +++ b/pcbnew/board_item_container.h @@ -0,0 +1,73 @@ +/* + * This program source code file is part of KICAD, a free EDA CAD application. + * + * Copyright (C) 2016 CERN + * @author Maciej Suminski + * + * 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 + */ + +#ifndef BOARD_ITEM_CONTAINER_H +#define BOARD_ITEM_CONTAINER_H + +#include + +enum ADD_MODE { ADD_INSERT, ADD_APPEND }; + +/** + * @brief Abstract interface for BOARD_ITEMs capable of storing other items inside. + * @see MODULE + * @see BOARD + */ +class BOARD_ITEM_CONTAINER : public BOARD_ITEM +{ +public: + BOARD_ITEM_CONTAINER( BOARD_ITEM* aParent, KICAD_T aType ) + : BOARD_ITEM( aParent, aType ) + { + } + + virtual ~BOARD_ITEM_CONTAINER() + { + } + + /** + * @brief Adds an item to the container. + * @param aItem is an item to be added. + * @param aMode decides whether the item is added in the beginning or at the end of the list. + */ + virtual void Add( BOARD_ITEM* aItem, ADD_MODE aMode = ADD_INSERT ) = 0; + + /** + * @brief Removes an item from the container. + * @param aItem is an item to be removed. + */ + virtual void Remove( BOARD_ITEM* aItem ) = 0; + + /** + * @brief Removes an item from the containter and deletes it. + * @param aItem is an item to be deleted. + */ + virtual void Delete( BOARD_ITEM* aItem ) + { + Remove( aItem ); + delete aItem; + } +}; + +#endif /* BOARD_ITEM_CONTAINER_H */ diff --git a/pcbnew/board_netlist_updater.cpp b/pcbnew/board_netlist_updater.cpp index f0a628b0ba..ffe5cac447 100644 --- a/pcbnew/board_netlist_updater.cpp +++ b/pcbnew/board_netlist_updater.cpp @@ -49,42 +49,28 @@ #include -BOARD_NETLIST_UPDATER::BOARD_NETLIST_UPDATER ( PCB_EDIT_FRAME *aFrame, BOARD *aBoard ) : - m_frame ( aFrame ), +BOARD_NETLIST_UPDATER::BOARD_NETLIST_UPDATER( PCB_EDIT_FRAME* aFrame, BOARD* aBoard ) : + m_commit( aFrame ), + m_frame( aFrame ), m_board( aBoard ) { m_reporter = &NULL_REPORTER::GetInstance(); - m_undoList = new PICKED_ITEMS_LIST; - m_deleteSinglePadNets = true; - m_deleteUnusedComponents = false; - m_isDryRun = false; - m_replaceFootprints = true; - m_lookupByTimestamp = false; + m_deleteSinglePadNets = true; + m_deleteUnusedComponents = false; + m_isDryRun = false; + m_replaceFootprints = true; + m_lookupByTimestamp = false; - m_warningCount = 0; - m_errorCount = 0; + m_warningCount = 0; + m_errorCount = 0; } -BOARD_NETLIST_UPDATER::~BOARD_NETLIST_UPDATER () + +BOARD_NETLIST_UPDATER::~BOARD_NETLIST_UPDATER() { - delete m_undoList; } -void BOARD_NETLIST_UPDATER::pushUndo( BOARD_ITEM* aItem, UNDO_REDO_T aCommandType, BOARD_ITEM* aCopy ) -{ - ITEM_PICKER picker( aItem, aCommandType ); - - if( aCommandType == UR_CHANGED ) - { - if( m_undoList->FindItem ( aItem ) >= 0 ) // add only once - return; - - picker.SetLink( aCopy ? aCopy : aItem->Clone() ); - } - - m_undoList->PushItem( picker ); -} wxPoint BOARD_NETLIST_UPDATER::estimateComponentInsertionPosition() { @@ -124,28 +110,24 @@ MODULE* BOARD_NETLIST_UPDATER::addNewComponent( COMPONENT* aComponent ) GetChars( aComponent->GetReference() ), GetChars( aComponent->GetTimeStamp() ), GetChars( aComponent->GetFPID().Format() ) ); - m_reporter->Report( msg, REPORTER::RPT_INFO ); msg.Printf( _( "Add component %s, footprint: %s.\n" ), GetChars( aComponent->GetReference() ), GetChars( aComponent->GetFPID().Format() ) ); - m_reporter->Report( msg, REPORTER::RPT_ACTION ); if( !m_isDryRun ) { // Owned by NETLIST, can only copy it. - MODULE *footprint = new MODULE( *aComponent->GetModule() ); + MODULE* footprint = new MODULE( *aComponent->GetModule() ); footprint->SetParent( m_board ); footprint->SetPosition( estimateComponentInsertionPosition( ) ); footprint->SetTimeStamp( GetNewTimeStamp() ); - m_board->Add( footprint, ADD_APPEND ); m_addedComponents.push_back( footprint ); - - pushUndo( footprint, UR_NEW ); + m_commit.Add( footprint ); return footprint; } @@ -165,23 +147,22 @@ MODULE* BOARD_NETLIST_UPDATER::addNewComponent( COMPONENT* aComponent ) GetChars( aComponent->GetFPID().Format() ) ); m_reporter->Report( msg, REPORTER::RPT_INFO ); - - m_errorCount ++; + ++m_errorCount; } return NULL; } -MODULE* BOARD_NETLIST_UPDATER::replaceComponent( NETLIST& aNetlist, MODULE *aPcbComponent, COMPONENT* aNewComponent ) + +MODULE* BOARD_NETLIST_UPDATER::replaceComponent( NETLIST& aNetlist, MODULE* aPcbComponent, COMPONENT* aNewComponent ) { wxString msg; if( !m_replaceFootprints ) return NULL; -// Test if the footprint has not changed - if( aNewComponent->GetFPID().empty() || - aPcbComponent->GetFPID() == aNewComponent->GetFPID() ) + // Test if the footprint has not changed + if( aNewComponent->GetFPID().empty() || aPcbComponent->GetFPID() == aNewComponent->GetFPID() ) return NULL; if( aNewComponent->GetModule() != NULL ) @@ -205,7 +186,9 @@ MODULE* BOARD_NETLIST_UPDATER::replaceComponent( NETLIST& aNetlist, MODULE *aPcb if( !m_isDryRun ) { wxASSERT( aPcbComponent != NULL ); + MODULE* newFootprint = new MODULE( *aNewComponent->GetModule() ); + newFootprint->SetParent( m_board ); if( aNetlist.IsFindByTimeStamp() ) newFootprint->SetReference( aPcbComponent->GetReference() ); @@ -213,16 +196,14 @@ MODULE* BOARD_NETLIST_UPDATER::replaceComponent( NETLIST& aNetlist, MODULE *aPcb newFootprint->SetPath( aPcbComponent->GetPath() ); aPcbComponent->CopyNetlistSettings( newFootprint, false ); - m_board->Remove( aPcbComponent ); - m_board->Add( newFootprint, ADD_APPEND ); - - pushUndo( aPcbComponent, UR_DELETED ); - pushUndo( newFootprint, UR_NEW ); + m_commit.Remove( aPcbComponent ); + m_commit.Add( newFootprint ); return newFootprint; } - } else { - + } + else + { msg.Printf( _( "Cannot change component %s footprint due to missing " "footprint %s.\n" ), GetChars( aPcbComponent->GetReference() ), @@ -238,13 +219,14 @@ MODULE* BOARD_NETLIST_UPDATER::replaceComponent( NETLIST& aNetlist, MODULE *aPcb m_reporter->Report( msg, REPORTER::RPT_INFO ); - m_errorCount ++; + ++m_errorCount; } return NULL; } -bool BOARD_NETLIST_UPDATER::updateComponentParameters( MODULE *aPcbComponent, COMPONENT* aNewComponent ) + +bool BOARD_NETLIST_UPDATER::updateComponentParameters( MODULE* aPcbComponent, COMPONENT* aNewComponent ) { wxString msg; @@ -292,9 +274,10 @@ bool BOARD_NETLIST_UPDATER::updateComponentParameters( MODULE *aPcbComponent, CO GetChars( aPcbComponent->GetPath() ), GetChars( aPcbComponent->GetValue() ), GetChars( aNewComponent->GetValue() ) ); + m_reporter->Report( msg, REPORTER::RPT_ACTION ); - if ( !m_isDryRun ) + if( !m_isDryRun ) { changed = true; aPcbComponent->SetValue( aNewComponent->GetValue() ); @@ -308,9 +291,10 @@ bool BOARD_NETLIST_UPDATER::updateComponentParameters( MODULE *aPcbComponent, CO GetChars( aPcbComponent->GetReference() ), GetChars( aPcbComponent->GetPath() ), GetChars( aNewComponent->GetTimeStamp() ) ); + m_reporter->Report( msg, REPORTER::RPT_INFO ); - if ( !m_isDryRun ) + if( !m_isDryRun ) { changed = true; aPcbComponent->SetPath( aNewComponent->GetTimeStamp() ); @@ -318,14 +302,15 @@ bool BOARD_NETLIST_UPDATER::updateComponentParameters( MODULE *aPcbComponent, CO } if( changed ) - pushUndo( aPcbComponent, UR_CHANGED, copy ); + m_commit.Modified( aPcbComponent, copy ); else delete copy; return true; } -bool BOARD_NETLIST_UPDATER::updateComponentPadConnections( MODULE *aPcbComponent, COMPONENT* aNewComponent ) + +bool BOARD_NETLIST_UPDATER::updateComponentPadConnections( MODULE* aPcbComponent, COMPONENT* aNewComponent ) { wxString msg; @@ -333,7 +318,7 @@ bool BOARD_NETLIST_UPDATER::updateComponentPadConnections( MODULE *aPcbComponent MODULE* copy = (MODULE*) aPcbComponent->Clone(); // At this point, the component footprint is updated. Now update the nets. - for( D_PAD *pad = aPcbComponent->Pads(); pad; pad = pad->Next() ) + for( D_PAD* pad = aPcbComponent->Pads(); pad; pad = pad->Next() ) { COMPONENT_NET net = aNewComponent->GetNet( pad->GetPadName() ); @@ -351,7 +336,6 @@ bool BOARD_NETLIST_UPDATER::updateComponentPadConnections( MODULE *aPcbComponent GetChars( aPcbComponent->GetPath() ), GetChars( pad->GetPadName() ) ); m_reporter->Report( msg, REPORTER::RPT_INFO ); - } if( !m_isDryRun ) @@ -364,38 +348,46 @@ bool BOARD_NETLIST_UPDATER::updateComponentPadConnections( MODULE *aPcbComponent { if( net.GetNetName() != pad->GetNetname() ) { - NETINFO_ITEM* netinfo = m_board->FindNet( net.GetNetName() ); + const wxString& netName = net.GetNetName(); + NETINFO_ITEM* netinfo = m_board->FindNet( netName ); - if( netinfo == NULL ) + if( netinfo == nullptr ) + { + // It might be a new net that has not been added to the board yet + auto netIt = m_addedNets.find( netName ); + + if( netIt != m_addedNets.end() ) + netinfo = netIt->second; + } + + if( netinfo == nullptr ) { // It is a new net, we have to add it if( !m_isDryRun ) { changed = true; - netinfo = new NETINFO_ITEM( m_board, net.GetNetName() ); - m_board->AppendNet( netinfo ); - pushUndo( netinfo, UR_NEW ); + netinfo = new NETINFO_ITEM( m_board, netName ); + m_commit.Add( netinfo ); + m_addedNets[netName] = netinfo; } - msg.Printf( _( "Add net %s.\n" ), - GetChars( net.GetNetName() ) ); - + msg.Printf( _( "Add net %s.\n" ), GetChars( netName ) ); m_reporter->Report( msg, REPORTER::RPT_ACTION ); } - if( pad->GetNetname() != wxString("") ) + if( !pad->GetNetname().IsEmpty() ) { msg.Printf( _( "Reconnect component %s pin %s from net %s to net %s.\n"), GetChars( aPcbComponent->GetReference() ), GetChars( pad->GetPadName() ), GetChars( pad->GetNetname() ), - GetChars( net.GetNetName() ) ); + GetChars( netName ) ); } else { msg.Printf( _( "Connect component %s pin %s to net %s.\n"), GetChars( aPcbComponent->GetReference() ), GetChars( pad->GetPadName() ), - GetChars( net.GetNetName() ) ); + GetChars( netName ) ); } m_reporter->Report( msg, REPORTER::RPT_ACTION ); @@ -406,27 +398,27 @@ bool BOARD_NETLIST_UPDATER::updateComponentPadConnections( MODULE *aPcbComponent GetChars( aPcbComponent->GetPath() ), GetChars( pad->GetPadName() ), GetChars( pad->GetNetname() ), - GetChars( net.GetNetName() ) ); - + GetChars( netName ) ); m_reporter->Report( msg, REPORTER::RPT_INFO ); - if ( !m_isDryRun ) + if( !m_isDryRun ) { changed = true; - pad->SetNetCode( netinfo->GetNet() ); + pad->SetNet( netinfo ); } } } } if( changed ) - pushUndo( aPcbComponent, UR_CHANGED, copy ); + m_commit.Modified( aPcbComponent, copy ); else delete copy; return true; } + bool BOARD_NETLIST_UPDATER::deleteUnusedComponents( NETLIST& aNetlist ) { wxString msg; @@ -437,9 +429,6 @@ bool BOARD_NETLIST_UPDATER::deleteUnusedComponents( NETLIST& aNetlist ) { nextModule = module->Next(); - if( module->IsLocked() ) - continue; - if( m_lookupByTimestamp ) component = aNetlist.GetComponentByTimeStamp( module->GetPath() ); else @@ -447,6 +436,14 @@ bool BOARD_NETLIST_UPDATER::deleteUnusedComponents( NETLIST& aNetlist ) if( component == NULL ) { + if( module->IsLocked() ) + { + msg.Printf( _( "Component %s is locked, skipping removal.\n" ), + GetChars( module->GetReference() ) ); + m_reporter->Report( msg, REPORTER::RPT_INFO ); + continue; + } + msg.Printf( _( "Remove component %s." ), GetChars( module->GetReference() ) ); m_reporter->Report( msg, REPORTER::RPT_ACTION ); @@ -457,16 +454,14 @@ bool BOARD_NETLIST_UPDATER::deleteUnusedComponents( NETLIST& aNetlist ) m_reporter->Report( msg, REPORTER::RPT_INFO ); if( !m_isDryRun ) - { - pushUndo( module, UR_DELETED ); - m_board->Remove( module ); - } + m_commit.Remove( module ); } } return true; } + bool BOARD_NETLIST_UPDATER::deleteSinglePadNets() { int count = 0; @@ -520,7 +515,6 @@ bool BOARD_NETLIST_UPDATER::deleteSinglePadNets() { msg.Printf( _( "Remove single pad net %s." ), GetChars( previouspad->GetNetname() ) ); - m_reporter->Report( msg, REPORTER::RPT_ACTION ); msg.Printf( _( "Remove single pad net \"%s\" on \"%s\" pad '%s'\n" ), @@ -529,7 +523,6 @@ bool BOARD_NETLIST_UPDATER::deleteSinglePadNets() GetChars( previouspad->GetPadName() ) ); m_reporter->Report( msg, REPORTER::RPT_ACTION ); - //pushUndo( previouspad, UR_CHANGED ); previouspad->SetNetCode( NETINFO_LIST::UNCONNECTED ); } } @@ -547,13 +540,12 @@ bool BOARD_NETLIST_UPDATER::deleteSinglePadNets() // Examine last pad if( pad && count == 1 ) - { - //pushUndo( pad, UR_CHANGED ); pad->SetNetCode( NETINFO_LIST::UNCONNECTED ); - } + return true; } + bool BOARD_NETLIST_UPDATER::testConnectivity( NETLIST& aNetlist ) { // Last step: Some tests: @@ -592,7 +584,7 @@ bool BOARD_NETLIST_UPDATER::testConnectivity( NETLIST& aNetlist ) GetChars( padname ), GetChars( footprint->GetFPID().Format() ) ); m_reporter->Report( msg, REPORTER::RPT_ERROR ); - m_errorCount ++; + ++m_errorCount; } } @@ -611,13 +603,14 @@ bool BOARD_NETLIST_UPDATER::testConnectivity( NETLIST& aNetlist ) msg.Printf( _( "Copper zone (net name %s): net has no pads connected." ), GetChars( zone->GetNet()->GetNetname() ) ); m_reporter->Report( msg, REPORTER::RPT_WARNING ); - m_warningCount ++; + ++m_warningCount; } } return true; } + bool BOARD_NETLIST_UPDATER::UpdateNetlist( NETLIST& aNetlist ) { wxString msg; @@ -630,17 +623,15 @@ bool BOARD_NETLIST_UPDATER::UpdateNetlist( NETLIST& aNetlist ) m_board->SetStatus( 0 ); } - for( int i = 0; i < (int) aNetlist.GetCount(); i++ ) { COMPONENT* component = aNetlist.GetComponent( i ); - MODULE *footprint = NULL; + MODULE* footprint = NULL; msg.Printf( _( "Processing component \"%s:%s:%s\".\n" ), GetChars( component->GetReference() ), GetChars( component->GetTimeStamp() ), GetChars( component->GetFPID().Format() ) ); - m_reporter->Report( msg, REPORTER::RPT_INFO ); if( aNetlist.IsFindByTimeStamp() ) @@ -650,8 +641,9 @@ bool BOARD_NETLIST_UPDATER::UpdateNetlist( NETLIST& aNetlist ) if( footprint ) // An existing footprint. { - MODULE *newFootprint = replaceComponent ( aNetlist, footprint, component ); - if ( newFootprint ) + MODULE* newFootprint = replaceComponent( aNetlist, footprint, component ); + + if( newFootprint ) footprint = newFootprint; } else @@ -666,9 +658,6 @@ bool BOARD_NETLIST_UPDATER::UpdateNetlist( NETLIST& aNetlist ) } } - - - //aNetlist.GetDeleteExtraFootprints() if( m_deleteUnusedComponents ) @@ -677,47 +666,40 @@ bool BOARD_NETLIST_UPDATER::UpdateNetlist( NETLIST& aNetlist ) if( m_deleteSinglePadNets ) deleteSinglePadNets(); - if ( !m_isDryRun ) + if( !m_isDryRun ) { - m_frame->SaveCopyInUndoList( *m_undoList, UR_UNSPECIFIED, wxPoint(0, 0) ); - m_frame->OnModify(); - - m_frame->Compile_Ratsnest( NULL, true ); + m_commit.Push( _( "Update netlist" ) ); + m_frame->Compile_Ratsnest( NULL, false ); m_board->GetRatsnest()->ProcessBoard(); - testConnectivity( aNetlist ); } // Update the ratsnest + m_reporter->Report( wxT( "" ), REPORTER::RPT_ACTION ); + m_reporter->Report( wxT( "" ), REPORTER::RPT_ACTION ); - m_reporter->Report( wxT(""), REPORTER::RPT_ACTION ); - m_reporter->Report( wxT(""), REPORTER::RPT_ACTION ); - - msg.Printf( _( "Total warnings: %d, errors: %d." ), - m_warningCount, m_errorCount ); - + msg.Printf( _( "Total warnings: %d, errors: %d." ), m_warningCount, m_errorCount ); m_reporter->Report( msg, REPORTER::RPT_ACTION ); - - if ( m_errorCount ) + if( m_errorCount ) { - - m_reporter->Report( _("Errors occured during the netlist update. Unless you " - "fix them, your board will not be consistent with the schematics." ), + m_reporter->Report( _( "Errors occured during the netlist update. Unless you " + "fix them, your board will not be consistent with the schematics." ), REPORTER::RPT_ERROR ); return false; - } else { - m_reporter->Report( _("Netlist update successful!" ), - REPORTER::RPT_ACTION ); - + } + else + { + m_reporter->Report( _( "Netlist update successful!" ), REPORTER::RPT_ACTION ); } return true; } + bool BOARD_NETLIST_UPDATER::UpdateNetlist( const wxString& aNetlistFileName, - const wxString& aCmpFileName ) + const wxString& aCmpFileName ) { return false; } diff --git a/pcbnew/board_netlist_updater.h b/pcbnew/board_netlist_updater.h index efe50894b9..256722ddc6 100644 --- a/pcbnew/board_netlist_updater.h +++ b/pcbnew/board_netlist_updater.h @@ -39,10 +39,9 @@ class REPORTER; class NETLIST; class COMPONENT; class MODULE; -class PICKED_ITEMS_LIST; class PCB_EDIT_FRAME; -#include +#include /** * Class BOARD_NETLIST_UPDATER @@ -72,94 +71,89 @@ class PCB_EDIT_FRAME; class BOARD_NETLIST_UPDATER { public: + BOARD_NETLIST_UPDATER( PCB_EDIT_FRAME* aFrame, BOARD* aBoard ); + ~BOARD_NETLIST_UPDATER(); - BOARD_NETLIST_UPDATER( PCB_EDIT_FRAME *aFrame, BOARD *aBoard ); - ~BOARD_NETLIST_UPDATER(); + /** + * Function UpdateNetlist() + * + * Updates the board's components according to the new netlist. + * See BOARD_NETLIST_UPDATER class description for the details of the process. + * @param aNetlist the new netlist + * @return true if process was completed successfully + */ + bool UpdateNetlist( NETLIST& aNetlist ); - /** - * Function UpdateNetlist() - * - * Updates the board's components according to the new netlist. - * See BOARD_NETLIST_UPDATER class description for the details of the process. - * @param aNetlist the new netlist - * @return true if process was completed successfully - */ - bool UpdateNetlist( NETLIST& aNetlist ); + // @todo: implement and move NETLIST::ReadPcbNetlist here + bool UpdateNetlist( const wxString& aNetlistFileName, const wxString& aCmpFileName ); - // @todo: implement and move NETLIST::ReadPcbNetlist here - bool UpdateNetlist( const wxString& aNetlistFileName, - const wxString& aCmpFileName ); + ///> Sets the reporter object + void SetReporter( REPORTER* aReporter ) + { + m_reporter = aReporter; + } + ///> Enables "delete single pad nets" option + void SetDeleteSinglePadNets( bool aEnabled ) + { + m_deleteSinglePadNets = aEnabled; + } - ///> Sets the reporter object - void SetReporter ( REPORTER *aReporter ) - { - m_reporter = aReporter; - } + ///> Enables dry run mode (just report, no changes to PCB) + void SetIsDryRun( bool aEnabled ) + { + m_isDryRun = aEnabled; + } - ///> Enables "delete single pad nets" option - void SetDeleteSinglePadNets( bool aEnabled ) - { - m_deleteSinglePadNets = aEnabled; - } + ///> Enables replacing footprints with new ones + void SetReplaceFootprints( bool aEnabled ) + { + m_replaceFootprints = aEnabled; + } - ///> Enables dry run mode (just report, no changes to PCB) - void SetIsDryRun ( bool aEnabled ) - { - m_isDryRun = aEnabled; - } + ///> Enables removing unused components + void SetDeleteUnusedComponents( bool aEnabled ) + { + m_deleteUnusedComponents = aEnabled; + } - ///> Enables replacing footprints with new ones - void SetReplaceFootprints ( bool aEnabled ) - { - m_replaceFootprints = aEnabled; - } + ///> Enables component lookup by timestamp instead of reference + void SetLookupByTimestamp( bool aEnabled ) + { + m_lookupByTimestamp = aEnabled; + } - ///> Enables removing unused components - void SetDeleteUnusedComponents ( bool aEnabled ) - { - m_deleteUnusedComponents = aEnabled; - } - - ///> Enables component lookup by timestamp instead of reference - void SetLookupByTimestamp ( bool aEnabled ) - { - m_lookupByTimestamp = aEnabled; - } - - std::vector GetAddedComponents() const - { - return m_addedComponents; - } + std::vector GetAddedComponents() const + { + return m_addedComponents; + } private: + wxPoint estimateComponentInsertionPosition(); + MODULE* addNewComponent( COMPONENT* aComponent ); + MODULE* replaceComponent( NETLIST& aNetlist, MODULE* aPcbComponent, COMPONENT* aNewComponent ); + bool updateComponentParameters( MODULE* aPcbComponent, COMPONENT* aNewComponent ); + bool updateComponentPadConnections( MODULE* aPcbComponent, COMPONENT* aNewComponent ); + bool deleteUnusedComponents( NETLIST& aNetlist ); + bool deleteSinglePadNets(); + bool testConnectivity( NETLIST& aNetlist ); - void pushUndo( BOARD_ITEM* aItem, UNDO_REDO_T aCommandType, BOARD_ITEM* aCopy = NULL ); + BOARD_COMMIT m_commit; + PCB_EDIT_FRAME* m_frame; + BOARD* m_board; + REPORTER* m_reporter; - wxPoint estimateComponentInsertionPosition(); - MODULE* addNewComponent( COMPONENT* aComponent ); - MODULE* replaceComponent( NETLIST& aNetlist, MODULE *aPcbComponent, COMPONENT* aNewComponent ); - bool updateComponentParameters( MODULE *aPcbComponent, COMPONENT* aNewComponent ); - bool updateComponentPadConnections( MODULE *aPcbComponent, COMPONENT* aNewComponent ); - bool deleteUnusedComponents( NETLIST& aNetlist ); - bool deleteSinglePadNets(); - bool testConnectivity( NETLIST& aNetlist ); + std::vector m_addedComponents; + std::map m_addedNets; - PICKED_ITEMS_LIST *m_undoList; - PCB_EDIT_FRAME *m_frame; - BOARD *m_board; - REPORTER *m_reporter; + bool m_deleteSinglePadNets; + bool m_deleteUnusedComponents; + bool m_isDryRun; + bool m_replaceFootprints; + bool m_lookupByTimestamp; - std::vector m_addedComponents; - - bool m_deleteSinglePadNets; - bool m_deleteUnusedComponents; - bool m_isDryRun; - bool m_replaceFootprints; - bool m_lookupByTimestamp; - - int m_warningCount; - int m_errorCount; + int m_warningCount; + int m_errorCount; }; #endif diff --git a/pcbnew/class_board.cpp b/pcbnew/class_board.cpp index 6bd301ef66..fd82c2b7d9 100644 --- a/pcbnew/class_board.cpp +++ b/pcbnew/class_board.cpp @@ -67,7 +67,7 @@ wxPoint BOARD_ITEM::ZeroOffset( 0, 0 ); BOARD::BOARD() : - BOARD_ITEM( (BOARD_ITEM*) NULL, PCB_T ), + BOARD_ITEM_CONTAINER( (BOARD_ITEM*) NULL, PCB_T ), m_NetInfo( this ), m_paper( PAGE_INFO::A4 ) { @@ -858,7 +858,7 @@ bool BOARD::IsModuleLayerVisible( LAYER_ID layer ) } -void BOARD::Add( BOARD_ITEM* aBoardItem, int aControl ) +void BOARD::Add( BOARD_ITEM* aBoardItem, ADD_MODE aMode ) { if( aBoardItem == NULL ) { @@ -869,24 +869,22 @@ void BOARD::Add( BOARD_ITEM* aBoardItem, int aControl ) switch( aBoardItem->Type() ) { case PCB_NETINFO_T: - aBoardItem->SetParent( this ); m_NetInfo.AppendNet( (NETINFO_ITEM*) aBoardItem ); + break; // this one uses a vector case PCB_MARKER_T: - aBoardItem->SetParent( this ); m_markers.push_back( (MARKER_PCB*) aBoardItem ); break; // this one uses a vector case PCB_ZONE_AREA_T: - aBoardItem->SetParent( this ); m_ZoneDescriptorList.push_back( (ZONE_CONTAINER*) aBoardItem ); break; case PCB_TRACE_T: case PCB_VIA_T: - if( aControl & ADD_APPEND ) + if( aMode == ADD_APPEND ) { m_Track.PushBack( (TRACK*) aBoardItem ); } @@ -897,44 +895,36 @@ void BOARD::Add( BOARD_ITEM* aBoardItem, int aControl ) m_Track.Insert( (TRACK*) aBoardItem, insertAid ); } - aBoardItem->SetParent( this ); break; case PCB_ZONE_T: - if( aControl & ADD_APPEND ) + if( aMode == ADD_APPEND ) m_Zone.PushBack( (SEGZONE*) aBoardItem ); else m_Zone.PushFront( (SEGZONE*) aBoardItem ); - aBoardItem->SetParent( this ); break; case PCB_MODULE_T: - if( aControl & ADD_APPEND ) + if( aMode == ADD_APPEND ) m_Modules.PushBack( (MODULE*) aBoardItem ); else m_Modules.PushFront( (MODULE*) aBoardItem ); - aBoardItem->SetParent( this ); - // Because the list of pads has changed, reset the status // This indicate the list of pad and nets must be recalculated before use m_Status_Pcb = 0; break; - case PCB_MODULE_EDGE_T: - assert( false ); // TODO Orson: I am just checking if it is supposed to be here - case PCB_DIMENSION_T: case PCB_LINE_T: case PCB_TEXT_T: case PCB_TARGET_T: - if( aControl & ADD_APPEND ) + if( aMode == ADD_APPEND ) m_Drawings.PushBack( aBoardItem ); else m_Drawings.PushFront( aBoardItem ); - aBoardItem->SetParent( this ); break; // other types may use linked list @@ -944,15 +934,17 @@ void BOARD::Add( BOARD_ITEM* aBoardItem, int aControl ) msg.Printf( wxT( "BOARD::Add() needs work: BOARD_ITEM type (%d) not handled" ), aBoardItem->Type() ); wxFAIL_MSG( msg ); + return; } break; } + aBoardItem->SetParent( this ); m_ratsnest->Add( aBoardItem ); } -BOARD_ITEM* BOARD::Remove( BOARD_ITEM* aBoardItem ) +void BOARD::Remove( BOARD_ITEM* aBoardItem ) { // find these calls and fix them! Don't send me no stinking' NULL. wxASSERT( aBoardItem ); @@ -965,6 +957,7 @@ BOARD_ITEM* BOARD::Remove( BOARD_ITEM* aBoardItem ) m_NetInfo.RemoveNet( item ); break; } + case PCB_MARKER_T: // find the item in the vector, then remove it @@ -1007,7 +1000,6 @@ BOARD_ITEM* BOARD::Remove( BOARD_ITEM* aBoardItem ) case PCB_DIMENSION_T: case PCB_LINE_T: case PCB_TEXT_T: - case PCB_MODULE_EDGE_T: case PCB_TARGET_T: m_Drawings.Remove( aBoardItem ); break; @@ -1018,8 +1010,6 @@ BOARD_ITEM* BOARD::Remove( BOARD_ITEM* aBoardItem ) } m_ratsnest->Remove( aBoardItem ); - - return aBoardItem; } @@ -2605,7 +2595,7 @@ void BOARD::ReplaceNetlist( NETLIST& aNetlist, bool aDeleteSinglePadNets, { // It is a new net, we have to add it netinfo = new NETINFO_ITEM( this, net.GetNetName() ); - m_NetInfo.AppendNet( netinfo ); + Add( netinfo ); } pad->SetNetCode( netinfo->GetNet() ); @@ -2781,18 +2771,14 @@ void BOARD::ReplaceNetlist( NETLIST& aNetlist, bool aDeleteSinglePadNets, } -BOARD_ITEM* BOARD::DuplicateAndAddItem( const BOARD_ITEM* aItem ) +BOARD_ITEM* BOARD::Duplicate( const BOARD_ITEM* aItem, + bool aAddToBoard ) { BOARD_ITEM* new_item = NULL; switch( aItem->Type() ) { case PCB_MODULE_T: - { - MODULE* new_module = new MODULE( *static_cast( aItem ) ); - new_item = new_module; - break; - } case PCB_TEXT_T: case PCB_LINE_T: case PCB_TRACE_T: @@ -2809,7 +2795,7 @@ BOARD_ITEM* BOARD::DuplicateAndAddItem( const BOARD_ITEM* aItem ) break; } - if( new_item ) + if( new_item && aAddToBoard ) Add( new_item ); return new_item; diff --git a/pcbnew/class_board.h b/pcbnew/class_board.h index cc827e46ca..7035e19102 100644 --- a/pcbnew/class_board.h +++ b/pcbnew/class_board.h @@ -42,6 +42,7 @@ #include #include #include +#include class PCB_BASE_FRAME; @@ -162,7 +163,7 @@ DECL_VEC_FOR_SWIG(TRACKS, TRACK*) * Class BOARD * holds information pertinent to a Pcbnew printed circuit board. */ -class BOARD : public BOARD_ITEM +class BOARD : public BOARD_ITEM_CONTAINER { friend class PCB_EDIT_FRAME; @@ -212,6 +213,20 @@ private: */ void chainMarkedSegments( wxPoint aPosition, const LSET& aLayerSet, TRACKS* aList ); + // The default copy constructor & operator= are inadequate, + // either write one or do not use it at all + BOARD( const BOARD& aOther ) : + BOARD_ITEM_CONTAINER( aOther ), m_NetInfo( this ) + { + assert( false ); + } + + BOARD& operator=( const BOARD& aOther ) + { + assert( false ); + return *this; // just to mute warning + } + public: static inline bool ClassOf( const EDA_ITEM* aItem ) { @@ -257,46 +272,13 @@ public: void SetFileFormatVersionAtLoad( int aVersion ) { m_fileFormatVersionAtLoad = aVersion; } int GetFileFormatVersionAtLoad() const { return m_fileFormatVersionAtLoad; } - /** - * Function Add - * adds the given item to this BOARD and takes ownership of its memory. - * @param aBoardItem The item to add to this board. - * @param aControl An int which can vary how the item is added. - */ - void Add( BOARD_ITEM* aBoardItem, int aControl = 0 ); + ///> @copydoc BOARD_ITEM_CONTAINER::Add() + void Add( BOARD_ITEM* aItem, ADD_MODE aMode = ADD_INSERT ) override; -#define ADD_APPEND 1 ///< aControl flag for Add( aControl ), appends not inserts + ///> @copydoc BOARD_ITEM_CONTAINER::Remove() + void Remove( BOARD_ITEM* aBoardItem ) override; - /** - * Function Delete - * removes the given single item from this BOARD and deletes its memory. - * @param aBoardItem The item to remove from this board and delete - */ - void Delete( BOARD_ITEM* aBoardItem ) - { - // developers should run DEBUG versions and fix such calls with NULL - wxASSERT( aBoardItem ); - - if( aBoardItem ) - delete Remove( aBoardItem ); - } - - - /** - * Function Remove - * removes \a aBoardItem from this BOARD and returns it to caller without deleting it. - * @param aBoardItem The item to remove from this board. - * @return BOARD_ITEM* \a aBoardItem which was passed in. - */ - BOARD_ITEM* Remove( BOARD_ITEM* aBoardItem ); - - /** - * Function DuplicateAndAddItem - * duplicates an item, and add it to the board list. - * @param aItem The item to duplicate. - * @return BOARD_ITEM* \a the new item which was added. - */ - BOARD_ITEM* DuplicateAndAddItem( const BOARD_ITEM* aItem ); + BOARD_ITEM* Duplicate( const BOARD_ITEM* aItem, bool aAddToBoard = false ); /** * Function GetRatsnest() @@ -802,16 +784,6 @@ public: */ NETINFO_ITEM* FindNet( const wxString& aNetname ) const; - /** - * Function AppendNet - * adds a new net description item to the current board. - * @param aNewNet is the new description item. - */ - void AppendNet( NETINFO_ITEM* aNewNet ) - { - m_NetInfo.AppendNet( aNewNet ); - } - NETINFO_LIST& GetNetInfo() { return m_NetInfo; diff --git a/pcbnew/class_board_connected_item.cpp b/pcbnew/class_board_connected_item.cpp index 0843728163..b7162e7884 100644 --- a/pcbnew/class_board_connected_item.cpp +++ b/pcbnew/class_board_connected_item.cpp @@ -34,6 +34,8 @@ #include #include +#include + BOARD_CONNECTED_ITEM::BOARD_CONNECTED_ITEM( BOARD_ITEM* aParent, KICAD_T idtype ) : BOARD_ITEM( aParent, idtype ), m_netinfo( &NETINFO_LIST::ORPHANED_ITEM ), m_Subnet( 0 ), m_ZoneSubnet( 0 ) @@ -41,13 +43,6 @@ BOARD_CONNECTED_ITEM::BOARD_CONNECTED_ITEM( BOARD_ITEM* aParent, KICAD_T idtype } -BOARD_CONNECTED_ITEM::BOARD_CONNECTED_ITEM( const BOARD_CONNECTED_ITEM& aItem ) : - BOARD_ITEM( aItem ), m_netinfo( aItem.m_netinfo ), m_Subnet( aItem.m_Subnet ), - m_ZoneSubnet( aItem.m_ZoneSubnet ) -{ -} - - bool BOARD_CONNECTED_ITEM::SetNetCode( int aNetCode, bool aNoAssert ) { // if aNetCode < 0 ( typically NETINFO_LIST::FORCE_ORPHANED ) @@ -55,6 +50,11 @@ bool BOARD_CONNECTED_ITEM::SetNetCode( int aNetCode, bool aNoAssert ) // set the m_netinfo to the dummy NETINFO_LIST::ORPHANED BOARD* board = GetBoard(); + RN_DATA* ratsnest = board ? board->GetRatsnest() : NULL; + bool addRatsnest = false; + + if( ratsnest ) + addRatsnest = ratsnest->Remove( this ); if( ( aNetCode >= 0 ) && board ) m_netinfo = board->FindNet( aNetCode ); @@ -64,6 +64,10 @@ bool BOARD_CONNECTED_ITEM::SetNetCode( int aNetCode, bool aNoAssert ) if( !aNoAssert ) assert( m_netinfo ); + // Add only if it was previously added to the ratsnest + if( addRatsnest ) + ratsnest->Add( this ); + return ( m_netinfo != NULL ); } diff --git a/pcbnew/class_board_connected_item.h b/pcbnew/class_board_connected_item.h index 2fa293d392..6687f0ab3a 100644 --- a/pcbnew/class_board_connected_item.h +++ b/pcbnew/class_board_connected_item.h @@ -56,7 +56,8 @@ public: BOARD_CONNECTED_ITEM( BOARD_ITEM* aParent, KICAD_T idtype ); - BOARD_CONNECTED_ITEM( const BOARD_CONNECTED_ITEM& aItem ); + // Do not create a copy constructor & operator=. + // The ones generated by the compiler are adequate. static inline bool ClassOf( const EDA_ITEM* aItem ) { @@ -91,6 +92,16 @@ public: return m_netinfo; } + /** + * Function SetNet + * Sets a NET_INFO object for the item. + */ + void SetNet( NETINFO_ITEM* aNetInfo ) + { + assert( aNetInfo->GetBoard() == GetBoard() ); + m_netinfo = aNetInfo; + } + /** * Function GetNetCode * @return int - the net code. diff --git a/pcbnew/class_board_item.cpp b/pcbnew/class_board_item.cpp index 1ae6f8a856..c1e60dbbf9 100644 --- a/pcbnew/class_board_item.cpp +++ b/pcbnew/class_board_item.cpp @@ -219,8 +219,12 @@ int BOARD_ITEM::getTrailingInt( wxString aStr ) return number; } -int BOARD_ITEM::getNextNumberInSequence( std::set aSeq, bool aFillSequenceGaps) + +int BOARD_ITEM::getNextNumberInSequence( const std::set& aSeq, bool aFillSequenceGaps) { + if( aSeq.empty() ) + return 1; + // By default go to the end of the sequence int candidate = *aSeq.rbegin(); @@ -230,16 +234,16 @@ int BOARD_ITEM::getNextNumberInSequence( std::set aSeq, bool aFillSequenceG // start at the beginning candidate = *aSeq.begin(); - for( std::set::iterator it = aSeq.begin(), - itEnd = aSeq.end(); it != itEnd; ++it ) + for( auto it : aSeq ) { - if( *it - candidate > 1 ) + if( it - candidate > 1 ) break; - candidate = *it; + candidate = it; } } - candidate++; + ++candidate; + return candidate; } diff --git a/pcbnew/class_dimension.cpp b/pcbnew/class_dimension.cpp index fab0cd2142..bcdb38abf5 100644 --- a/pcbnew/class_dimension.cpp +++ b/pcbnew/class_dimension.cpp @@ -89,30 +89,6 @@ void DIMENSION::SetLayer( LAYER_ID aLayer ) } -void DIMENSION::Copy( DIMENSION* source ) -{ - m_Value = source->m_Value; - SetLayer( source->GetLayer() ); - m_Width = source->m_Width; - m_Shape = source->m_Shape; - m_Height = source->m_Height; - m_Unit = source->m_Unit; - SetTimeStamp( GetNewTimeStamp() ); - m_Text.Copy( &source->m_Text ); - - m_crossBarO = source->m_crossBarO; - m_crossBarF = source->m_crossBarF; - m_featureLineGO = source->m_featureLineGO; - m_featureLineGF = source->m_featureLineGF; - m_featureLineDO = source->m_featureLineDO; - m_featureLineDF = source->m_featureLineDF; - m_arrowD1F = source->m_arrowD1F; - m_arrowD2F = source->m_arrowD2F; - m_arrowG1F = source->m_arrowG1F; - m_arrowG2F = source->m_arrowG2F; -} - - void DIMENSION::Move( const wxPoint& offset ) { m_Text.SetTextPosition( m_Text.GetTextPosition() + offset ); diff --git a/pcbnew/class_dimension.h b/pcbnew/class_dimension.h index 93e5e8b776..bb444a63ce 100644 --- a/pcbnew/class_dimension.h +++ b/pcbnew/class_dimension.h @@ -78,7 +78,8 @@ public: DIMENSION( BOARD_ITEM* aParent ); - // Do not create a copy constructor. The one generated by the compiler is adequate. + // Do not create a copy constructor & operator=. + // The ones generated by the compiler are adequate. ~DIMENSION(); @@ -182,8 +183,6 @@ public: TEXTE_PCB& Text() { return m_Text; } TEXTE_PCB& Text() const { return *(const_cast (&m_Text)); } - void Copy( DIMENSION* source ); - void Draw( EDA_DRAW_PANEL* panel, wxDC* DC, GR_DRAWMODE aColorMode, const wxPoint& offset = ZeroOffset ); diff --git a/pcbnew/class_drawsegment.cpp b/pcbnew/class_drawsegment.cpp index c9ceb6ffa1..8dc8b1865c 100644 --- a/pcbnew/class_drawsegment.cpp +++ b/pcbnew/class_drawsegment.cpp @@ -64,34 +64,6 @@ DRAWSEGMENT::~DRAWSEGMENT() } -const DRAWSEGMENT& DRAWSEGMENT::operator = ( const DRAWSEGMENT& rhs ) -{ - // skip the linked list stuff, and parent - - m_Type = rhs.m_Type; - m_Layer = rhs.m_Layer; - m_Width = rhs.m_Width; - m_Start = rhs.m_Start; - m_End = rhs.m_End; - m_Shape = rhs.m_Shape; - m_Angle = rhs.m_Angle; - m_TimeStamp = rhs.m_TimeStamp; - m_BezierC1 = rhs.m_BezierC1; - m_BezierC2 = rhs.m_BezierC1; - m_BezierPoints = rhs.m_BezierPoints; - - return *this; -} - - -void DRAWSEGMENT::Copy( DRAWSEGMENT* source ) -{ - if( source == NULL ) // who would do this? - return; - - *this = *source; // operator = () -} - void DRAWSEGMENT::Rotate( const wxPoint& aRotCentre, double aAngle ) { switch( m_Shape ) diff --git a/pcbnew/class_drawsegment.h b/pcbnew/class_drawsegment.h index 411a5a2306..db8f3c8b18 100644 --- a/pcbnew/class_drawsegment.h +++ b/pcbnew/class_drawsegment.h @@ -65,13 +65,11 @@ protected: public: DRAWSEGMENT( BOARD_ITEM* aParent = NULL, KICAD_T idtype = PCB_LINE_T ); - // Do not create a copy constructor. The one generated by the compiler is adequate. + // Do not create a copy constructor & operator=. + // The ones generated by the compiler are adequate. ~DRAWSEGMENT(); - /// skip the linked list stuff, and parent - const DRAWSEGMENT& operator = ( const DRAWSEGMENT& rhs ); - static inline bool ClassOf( const EDA_ITEM* aItem ) { return aItem && PCB_LINE_T == aItem->Type(); @@ -181,8 +179,6 @@ public: m_PolyPoints = aPoints; } - void Copy( DRAWSEGMENT* source ); - void Draw( EDA_DRAW_PANEL* panel, wxDC* DC, GR_DRAWMODE aDrawMode, const wxPoint& aOffset = ZeroOffset ); diff --git a/pcbnew/class_edge_mod.cpp b/pcbnew/class_edge_mod.cpp index 04376bbbf8..e49f7d7d15 100644 --- a/pcbnew/class_edge_mod.cpp +++ b/pcbnew/class_edge_mod.cpp @@ -65,30 +65,6 @@ EDGE_MODULE::~EDGE_MODULE() } -const EDGE_MODULE& EDGE_MODULE::operator = ( const EDGE_MODULE& rhs ) -{ - if( &rhs == this ) - return *this; - - DRAWSEGMENT::operator=( rhs ); - - m_Start0 = rhs.m_Start0; - m_End0 = rhs.m_End0; - - m_PolyPoints = rhs.m_PolyPoints; // std::vector copy - return *this; -} - - -void EDGE_MODULE::Copy( EDGE_MODULE* source ) -{ - if( source == NULL ) - return; - - *this = *source; -} - - void EDGE_MODULE::SetLocalCoord() { MODULE* module = (MODULE*) m_Parent; diff --git a/pcbnew/class_edge_mod.h b/pcbnew/class_edge_mod.h index f7ffcaaeb1..c89e1c7452 100644 --- a/pcbnew/class_edge_mod.h +++ b/pcbnew/class_edge_mod.h @@ -46,21 +46,16 @@ class EDGE_MODULE : public DRAWSEGMENT public: EDGE_MODULE( MODULE* parent, STROKE_T aShape = S_SEGMENT ); - // Do not create a copy constructor. The one generated by the compiler is adequate. - // EDGE_MODULE( const EDGE_MODULE& ); + // Do not create a copy constructor & operator=. + // The ones generated by the compiler are adequate. ~EDGE_MODULE(); - /// skip the linked list stuff, and parent - const EDGE_MODULE& operator = ( const EDGE_MODULE& rhs ); - static inline bool ClassOf( const EDA_ITEM* aItem ) { return aItem && PCB_MODULE_EDGE_T == aItem->Type(); } - void Copy( EDGE_MODULE* source ); // copy structure - /** * Move an edge of the footprint. * This is a footprint shape modification. diff --git a/pcbnew/class_mire.cpp b/pcbnew/class_mire.cpp index 63c2dc10a0..e447134b6c 100644 --- a/pcbnew/class_mire.cpp +++ b/pcbnew/class_mire.cpp @@ -69,16 +69,6 @@ PCB_TARGET::~PCB_TARGET() { } -void PCB_TARGET::Copy( PCB_TARGET* source ) -{ - m_Layer = source->m_Layer; - m_Width = source->m_Width; - m_Pos = source->m_Pos; - m_Shape = source->m_Shape; - m_Size = source->m_Size; - SetTimeStamp( GetNewTimeStamp() ); -} - /* Draw PCB_TARGET object: 2 segments + 1 circle * The circle radius is half the radius of the target diff --git a/pcbnew/class_mire.h b/pcbnew/class_mire.h index 03bebba9fc..18523b441d 100644 --- a/pcbnew/class_mire.h +++ b/pcbnew/class_mire.h @@ -54,6 +54,9 @@ public: PCB_TARGET( BOARD_ITEM* aParent, int aShape, LAYER_ID aLayer, const wxPoint& aPos, int aSize, int aWidth ); + // Do not create a copy constructor & operator=. + // The ones generated by the compiler are adequate. + ~PCB_TARGET(); void SetPosition( const wxPoint& aPos ) { m_Pos = aPos; } // override @@ -77,8 +80,6 @@ public: void Flip( const wxPoint& aCentre ); - void Copy( PCB_TARGET* source ); - void Draw( EDA_DRAW_PANEL* panel, wxDC* DC, GR_DRAWMODE aDrawMode, const wxPoint& offset = ZeroOffset ); diff --git a/pcbnew/class_module.cpp b/pcbnew/class_module.cpp index 97cc3b33fa..726cd48cac 100644 --- a/pcbnew/class_module.cpp +++ b/pcbnew/class_module.cpp @@ -50,7 +50,7 @@ MODULE::MODULE( BOARD* parent ) : - BOARD_ITEM( (BOARD_ITEM*) parent, PCB_MODULE_T ), + BOARD_ITEM_CONTAINER( (BOARD_ITEM*) parent, PCB_MODULE_T ), m_initial_comments( 0 ) { m_Attributs = MOD_DEFAULT; @@ -79,11 +79,10 @@ MODULE::MODULE( BOARD* parent ) : MODULE::MODULE( const MODULE& aModule ) : - BOARD_ITEM( aModule ) + BOARD_ITEM_CONTAINER( aModule ) { m_Pos = aModule.m_Pos; m_fpid = aModule.m_fpid; - m_Layer = aModule.m_Layer; m_Attributs = aModule.m_Attributs; m_ModuleStatus = aModule.m_ModuleStatus; m_Orient = aModule.m_Orient; @@ -105,35 +104,27 @@ MODULE::MODULE( const MODULE& aModule ) : // Copy reference and value. m_Reference = new TEXTE_MODULE( *aModule.m_Reference ); m_Reference->SetParent( this ); - m_Value = new TEXTE_MODULE( *aModule.m_Value ); m_Value->SetParent( this ); // Copy auxiliary data: Pads for( D_PAD* pad = aModule.m_Pads; pad; pad = pad->Next() ) { - D_PAD* newpad = new D_PAD( *pad ); - assert( newpad->GetNet() == pad->GetNet() ); - newpad->SetParent( this ); - m_Pads.PushBack( newpad ); + Add( new D_PAD( *pad ) ); } // Copy auxiliary data: Drawings for( BOARD_ITEM* item = aModule.m_Drawings; item; item = item->Next() ) { - BOARD_ITEM* newItem; - switch( item->Type() ) { case PCB_MODULE_TEXT_T: case PCB_MODULE_EDGE_T: - newItem = static_cast( item->Clone() ); - newItem->SetParent( this ); - m_Drawings.PushBack( newItem ); + Add( static_cast( item->Clone() ) ); break; default: - wxLogMessage( wxT( "MODULE::Copy() Internal Err: unknown type" ) ); + wxLogMessage( wxT( "Class MODULE copy constructor internal error: unknown type" ) ); break; } } @@ -161,13 +152,76 @@ MODULE::~MODULE() delete m_initial_comments; } - /** - * Function ClearAllNets - * Clear (i.e. force the ORPHANED dummy net info) the net info which - * depends on a given board for all pads of the footprint. - * This is needed when a footprint is copied between the fp editor and - * the board editor for instance, because net info become fully broken - */ + +MODULE& MODULE::operator=( const MODULE& aOther ) +{ + BOARD_ITEM::operator=( aOther ); + + m_Pos = aOther.m_Pos; + m_fpid = aOther.m_fpid; + m_Attributs = aOther.m_Attributs; + m_ModuleStatus = aOther.m_ModuleStatus; + m_Orient = aOther.m_Orient; + m_BoundaryBox = aOther.m_BoundaryBox; + m_CntRot90 = aOther.m_CntRot90; + m_CntRot180 = aOther.m_CntRot180; + m_LastEditTime = aOther.m_LastEditTime; + m_Link = aOther.m_Link; + m_Path = aOther.m_Path; //is this correct behavior? + + m_LocalClearance = aOther.m_LocalClearance; + m_LocalSolderMaskMargin = aOther.m_LocalSolderMaskMargin; + m_LocalSolderPasteMargin = aOther.m_LocalSolderPasteMargin; + m_LocalSolderPasteMarginRatio = aOther.m_LocalSolderPasteMarginRatio; + m_ZoneConnection = aOther.m_ZoneConnection; + m_ThermalWidth = aOther.m_ThermalWidth; + m_ThermalGap = aOther.m_ThermalGap; + + // Copy reference and value + *m_Reference = *aOther.m_Reference; + m_Reference->SetParent( this ); + *m_Value = *aOther.m_Value; + m_Value->SetParent( this ); + + // Copy auxiliary data: Pads + m_Pads.DeleteAll(); + + for( D_PAD* pad = aOther.m_Pads; pad; pad = pad->Next() ) + { + Add( new D_PAD( *pad ) ); + } + + // Copy auxiliary data: Drawings + m_Drawings.DeleteAll(); + + for( BOARD_ITEM* item = aOther.m_Drawings; item; item = item->Next() ) + { + switch( item->Type() ) + { + case PCB_MODULE_TEXT_T: + case PCB_MODULE_EDGE_T: + Add( static_cast( item->Clone() ) ); + break; + + default: + wxLogMessage( wxT( "MODULE::operator=() internal error: unknown type" ) ); + break; + } + } + + // Copy auxiliary data: 3D_Drawings info + m_3D_Drawings.clear(); + m_3D_Drawings = aOther.m_3D_Drawings; + m_Doc = aOther.m_Doc; + m_KeyWord = aOther.m_KeyWord; + + // Ensure auxiliary data is up to date + CalculateBoundingBox(); + + return *this; +} + + void MODULE::ClearAllNets() { // Force the ORPHANED dummy net info for all pads. @@ -177,10 +231,6 @@ void MODULE::ClearAllNets() } -/* Draw the anchor cross (vertical) - * Must be done after the pads, because drawing the hole will erase overwrite - * every thing already drawn. - */ void MODULE::DrawAncre( EDA_DRAW_PANEL* panel, wxDC* DC, const wxPoint& offset, int dim_ancre, GR_DRAWMODE draw_mode ) { @@ -195,86 +245,7 @@ void MODULE::DrawAncre( EDA_DRAW_PANEL* panel, wxDC* DC, const wxPoint& offset, } -void MODULE::Copy( MODULE* aModule ) -{ - m_Pos = aModule->m_Pos; - m_Layer = aModule->m_Layer; - m_fpid = aModule->m_fpid; - m_Attributs = aModule->m_Attributs; - m_ModuleStatus = aModule->m_ModuleStatus; - m_Orient = aModule->m_Orient; - m_BoundaryBox = aModule->m_BoundaryBox; - m_CntRot90 = aModule->m_CntRot90; - m_CntRot180 = aModule->m_CntRot180; - m_LastEditTime = aModule->m_LastEditTime; - m_Link = aModule->m_Link; - m_Path = aModule->m_Path; //is this correct behavior? - SetTimeStamp( GetNewTimeStamp() ); - - m_LocalClearance = aModule->m_LocalClearance; - m_LocalSolderMaskMargin = aModule->m_LocalSolderMaskMargin; - m_LocalSolderPasteMargin = aModule->m_LocalSolderPasteMargin; - m_LocalSolderPasteMarginRatio = aModule->m_LocalSolderPasteMarginRatio; - m_ZoneConnection = aModule->m_ZoneConnection; - m_ThermalWidth = aModule->m_ThermalWidth; - m_ThermalGap = aModule->m_ThermalGap; - - // Copy reference and value. - m_Reference->Copy( aModule->m_Reference ); - m_Value->Copy( aModule->m_Value ); - - // Copy auxiliary data: Pads - m_Pads.DeleteAll(); - - for( D_PAD* pad = aModule->m_Pads; pad; pad = pad->Next() ) - { - D_PAD* newpad = new D_PAD( this ); - newpad->Copy( pad ); - m_Pads.PushBack( newpad ); - } - - // Copy auxiliary data: Drawings - m_Drawings.DeleteAll(); - - for( BOARD_ITEM* item = aModule->m_Drawings; item; item = item->Next() ) - { - switch( item->Type() ) - { - case PCB_MODULE_TEXT_T: - { - TEXTE_MODULE* textm = new TEXTE_MODULE( this ); - textm->Copy( static_cast( item ) ); - m_Drawings.PushBack( textm ); - break; - } - - case PCB_MODULE_EDGE_T: - { - EDGE_MODULE * edge; - edge = new EDGE_MODULE( this ); - edge->Copy( (EDGE_MODULE*) item ); - m_Drawings.PushBack( edge ); - break; - } - - default: - wxLogMessage( wxT( "MODULE::Copy() Internal Err: unknown type" ) ); - break; - } - } - - // Copy auxiliary data: 3D_Drawings info - m_3D_Drawings.clear(); - m_3D_Drawings = aModule->m_3D_Drawings; - m_Doc = aModule->m_Doc; - m_KeyWord = aModule->m_KeyWord; - - // Ensure auxiliary data is up to date - CalculateBoundingBox(); -} - - -void MODULE::Add( BOARD_ITEM* aBoardItem, bool doAppend ) +void MODULE::Add( BOARD_ITEM* aBoardItem, ADD_MODE aMode ) { switch( aBoardItem->Type() ) { @@ -285,14 +256,14 @@ void MODULE::Add( BOARD_ITEM* aBoardItem, bool doAppend ) // no break case PCB_MODULE_EDGE_T: - if( doAppend ) + if( aMode == ADD_APPEND ) m_Drawings.PushBack( aBoardItem ); else m_Drawings.PushFront( aBoardItem ); break; case PCB_PAD_T: - if( doAppend ) + if( aMode == ADD_APPEND ) m_Pads.PushBack( static_cast( aBoardItem ) ); else m_Pads.PushFront( static_cast( aBoardItem ) ); @@ -310,10 +281,32 @@ void MODULE::Add( BOARD_ITEM* aBoardItem, bool doAppend ) } aBoardItem->SetParent( this ); + SetLastEditTime(); + + // Update relative coordinates, it can be done only after there is a parent object assigned + switch( aBoardItem->Type() ) + { + case PCB_MODULE_TEXT_T: + static_cast( aBoardItem )->SetLocalCoord(); + break; + + case PCB_MODULE_EDGE_T: + static_cast( aBoardItem )->SetLocalCoord(); + break; + + case PCB_PAD_T: + static_cast( aBoardItem )->SetLocalCoord(); + break; + + default: + // Huh? It should have been filtered out by the previous switch + assert(false); + break; + } } -BOARD_ITEM* MODULE::Remove( BOARD_ITEM* aBoardItem ) +void MODULE::Remove( BOARD_ITEM* aBoardItem ) { switch( aBoardItem->Type() ) { @@ -324,10 +317,12 @@ BOARD_ITEM* MODULE::Remove( BOARD_ITEM* aBoardItem ) // no break case PCB_MODULE_EDGE_T: - return m_Drawings.Remove( aBoardItem ); + m_Drawings.Remove( aBoardItem ); + break; case PCB_PAD_T: - return m_Pads.Remove( static_cast( aBoardItem ) ); + m_Pads.Remove( static_cast( aBoardItem ) ); + break; default: { @@ -337,8 +332,6 @@ BOARD_ITEM* MODULE::Remove( BOARD_ITEM* aBoardItem ) wxFAIL_MSG( msg ); } } - - return NULL; } @@ -516,9 +509,6 @@ const EDA_RECT MODULE::GetBoundingBox() const } -/* Virtual function, from EDA_ITEM. - * display module info on MsgPanel - */ void MODULE::GetMsgPanelInfo( std::vector< MSG_PANEL_ITEM >& aList ) { int nbpad; @@ -902,11 +892,6 @@ const BOX2I MODULE::ViewBBox() const } -/* Test for validity of the name in a library of the footprint - * ( no spaces, dir separators ... ) - * return true if the given name is valid - * static function - */ bool MODULE::IsLibNameValid( const wxString & aName ) { const wxChar * invalids = StringLibNameInvalidChars( false ); @@ -918,13 +903,6 @@ bool MODULE::IsLibNameValid( const wxString & aName ) } -/* Test for validity of the name of a footprint to be used in a footprint library - * ( no spaces, dir separators ... ) - * param bool aUserReadable = false to get the list of invalid chars - * true to get a readable form (i.e ' ' = 'space' '\t'= 'tab') - * return a constant string giving the list of invalid chars in lib name - * static function - */ const wxChar* MODULE::StringLibNameInvalidChars( bool aUserReadable ) { static const wxChar invalidChars[] = wxT("%$\t \"\\/"); @@ -1132,8 +1110,9 @@ void MODULE::SetOrientation( double newangle ) CalculateBoundingBox(); } -BOARD_ITEM* MODULE::DuplicateAndAddItem( const BOARD_ITEM* aItem, - bool aIncrementPadNumbers ) +BOARD_ITEM* MODULE::Duplicate( const BOARD_ITEM* aItem, + bool aIncrementPadNumbers, + bool aAddToModule ) { BOARD_ITEM* new_item = NULL; D_PAD* new_pad = NULL; @@ -1144,7 +1123,9 @@ BOARD_ITEM* MODULE::DuplicateAndAddItem( const BOARD_ITEM* aItem, { new_pad = new D_PAD( *static_cast( aItem ) ); - Pads().PushBack( new_pad ); + if( aAddToModule ) + Pads().PushBack( new_pad ); + new_item = new_pad; break; } @@ -1159,7 +1140,9 @@ BOARD_ITEM* MODULE::DuplicateAndAddItem( const BOARD_ITEM* aItem, { TEXTE_MODULE* new_text = new TEXTE_MODULE( *old_text ); - GraphicalItems().PushBack( new_text ); + if( aAddToModule ) + GraphicalItems().PushBack( new_text ); + new_item = new_text; } break; @@ -1170,7 +1153,9 @@ BOARD_ITEM* MODULE::DuplicateAndAddItem( const BOARD_ITEM* aItem, EDGE_MODULE* new_edge = new EDGE_MODULE( *static_cast(aItem) ); - GraphicalItems().PushBack( new_edge ); + if( aAddToModule ) + GraphicalItems().PushBack( new_edge ); + new_item = new_edge; break; } diff --git a/pcbnew/class_module.h b/pcbnew/class_module.h index edbedd6afc..715a8f6c85 100644 --- a/pcbnew/class_module.h +++ b/pcbnew/class_module.h @@ -36,6 +36,7 @@ #include #include // ALL_LAYERS definition. #include +#include #include #include @@ -75,7 +76,7 @@ enum MODULE_ATTR_T }; -class MODULE : public BOARD_ITEM +class MODULE : public BOARD_ITEM_CONTAINER { public: MODULE( BOARD* parent ); @@ -84,6 +85,8 @@ public: ~MODULE(); + MODULE& operator=( const MODULE& aOther ); + static inline bool ClassOf( const EDA_ITEM* aItem ) { return PCB_MODULE_T == aItem->Type(); @@ -92,37 +95,11 @@ public: MODULE* Next() const { return static_cast( Pnext ); } MODULE* Back() const { return static_cast( Pback ); } - void Copy( MODULE* Module ); // Copy structure + ///> @copydoc BOARD_ITEM_CONTAINER::Add() + void Add( BOARD_ITEM* aBoardItem, ADD_MODE aMode = ADD_INSERT ) override; - /** - * Function Add - * adds the given item to this MODULE and takes ownership of its memory. - * @param aBoardItem The item to add to this board. - * @param doAppend If true, then append, else insert. - */ - void Add( BOARD_ITEM* aBoardItem, bool doAppend = true ); - - /** - * Function Delete - * removes the given single item from this MODULE and deletes its memory. - * @param aBoardItem The item to remove from this module and delete - */ - void Delete( BOARD_ITEM* aBoardItem ) - { - // developers should run DEBUG versions and fix such calls with NULL - wxASSERT( aBoardItem ); - - if( aBoardItem ) - delete Remove( aBoardItem ); - } - - /** - * Function Remove - * removes \a aBoardItem from this MODULE and returns it to caller without deleting it. - * @param aBoardItem The item to remove from this module. - * @return BOARD_ITEM* \a aBoardItem which was passed in. - */ - BOARD_ITEM* Remove( BOARD_ITEM* aBoardItem ); + ///> @copydoc BOARD_ITEM_CONTAINER::Remove() + void Remove( BOARD_ITEM* aBoardItem ) override; /** * Function ClearAllNets @@ -404,9 +381,16 @@ public: void DrawEdgesOnly( EDA_DRAW_PANEL* panel, wxDC* DC, const wxPoint& offset, GR_DRAWMODE draw_mode ); + /** + * Function DrawAncre + * Draw the anchor cross (vertical) + * Must be done after the pads, because drawing the hole will erase overwrite + * every thing already drawn. + */ void DrawAncre( EDA_DRAW_PANEL* panel, wxDC* DC, const wxPoint& offset, int dim_ancre, GR_DRAWMODE draw_mode ); + ///> @copydoc EDA_ITEM::GetMsgPanelInfo void GetMsgPanelInfo( std::vector< MSG_PANEL_ITEM >& aList ); bool HitTest( const wxPoint& aPosition ) const; @@ -536,12 +520,13 @@ public: void SetPlacementCost90( int aCost ) { m_CntRot90 = aCost; } /** - * Function DuplicateAndAddItem - * Duplicate a given item within the module + * Function Duplicate + * Duplicate a given item within the module, without adding to the board * @return the new item, or NULL if the item could not be duplicated */ - BOARD_ITEM* DuplicateAndAddItem( const BOARD_ITEM* item, - bool aIncrementPadNumbers ); + BOARD_ITEM* Duplicate( const BOARD_ITEM* aItem, + bool aIncrementPadNumbers, + bool aAddToModule = false ); /** * Function Add3DModel diff --git a/pcbnew/class_pad.cpp b/pcbnew/class_pad.cpp index ad087792e7..67cd26162e 100644 --- a/pcbnew/class_pad.cpp +++ b/pcbnew/class_pad.cpp @@ -423,41 +423,6 @@ bool D_PAD::IncrementPadName( bool aSkipUnconnectable, bool aFillSequenceGaps ) } -void D_PAD::Copy( D_PAD* source ) -{ - if( source == NULL ) - return; - - m_Pos = source->m_Pos; - m_layerMask = source->m_layerMask; - - m_NumPadName = source->m_NumPadName; - m_netinfo = source->m_netinfo; - m_Drill = source->m_Drill; - m_drillShape = source->m_drillShape; - m_Offset = source->m_Offset; - m_Size = source->m_Size; - m_DeltaSize = source->m_DeltaSize; - m_Pos0 = source->m_Pos0; - m_boundingRadius = source->m_boundingRadius; - m_padShape = source->m_padShape; - m_Attribute = source->m_Attribute; - m_Orient = source->m_Orient; - m_LengthPadToDie = source->m_LengthPadToDie; - m_LocalClearance = source->m_LocalClearance; - m_LocalSolderMaskMargin = source->m_LocalSolderMaskMargin; - m_LocalSolderPasteMargin = source->m_LocalSolderPasteMargin; - m_LocalSolderPasteMarginRatio = source->m_LocalSolderPasteMarginRatio; - m_ZoneConnection = source->m_ZoneConnection; - m_ThermalWidth = source->m_ThermalWidth; - m_ThermalGap = source->m_ThermalGap; - m_padRoundRectRadiusScale = source->m_padRoundRectRadiusScale; - - SetSubRatsnest( 0 ); - SetSubNet( 0 ); -} - - void D_PAD::CopyNetlistSettings( D_PAD* aPad, bool aCopyLocalSettings ) { // Don't do anything foolish like trying to copy to yourself. diff --git a/pcbnew/class_pad.h b/pcbnew/class_pad.h index 12223ab040..0c277b97c6 100644 --- a/pcbnew/class_pad.h +++ b/pcbnew/class_pad.h @@ -82,8 +82,8 @@ public: public: D_PAD( MODULE* parent ); - // Do not create a copy constructor. The one generated by the compiler is adequate. - // D_PAD( const D_PAD& o ); + // Do not create a copy constructor & operator=. + // The ones generated by the compiler are adequate. /* Default layers used for pads, according to the pad type. * this is default values only, they can be changed for a given pad @@ -99,8 +99,6 @@ public: return aItem && PCB_PAD_T == aItem->Type(); } - void Copy( D_PAD* source ); - D_PAD* Next() const { return static_cast( Pnext ); } MODULE* GetParent() const { return (MODULE*) m_Parent; } diff --git a/pcbnew/class_pcb_text.cpp b/pcbnew/class_pcb_text.cpp index c2e5ca6447..27164e3b14 100644 --- a/pcbnew/class_pcb_text.cpp +++ b/pcbnew/class_pcb_text.cpp @@ -60,27 +60,6 @@ TEXTE_PCB:: ~TEXTE_PCB() } -void TEXTE_PCB::Copy( TEXTE_PCB* source ) -{ - m_Parent = source->m_Parent; - Pback = Pnext = NULL; - m_Mirror = source->m_Mirror; - m_Size = source->m_Size; - m_Orient = source->m_Orient; - m_Pos = source->m_Pos; - m_Layer = source->m_Layer; - m_Thickness = source->m_Thickness; - m_Attributs = source->m_Attributs; - m_Italic = source->m_Italic; - m_Bold = source->m_Bold; - m_HJustify = source->m_HJustify; - m_VJustify = source->m_VJustify; - m_MultilineAllowed = source->m_MultilineAllowed; - - m_Text = source->m_Text; -} - - void TEXTE_PCB::Draw( EDA_DRAW_PANEL* panel, wxDC* DC, GR_DRAWMODE DrawMode, const wxPoint& offset ) { diff --git a/pcbnew/class_pcb_text.h b/pcbnew/class_pcb_text.h index b1f1d31e7e..d1120e7ea5 100644 --- a/pcbnew/class_pcb_text.h +++ b/pcbnew/class_pcb_text.h @@ -45,7 +45,8 @@ class TEXTE_PCB : public BOARD_ITEM, public EDA_TEXT public: TEXTE_PCB( BOARD_ITEM* parent ); - // Do not create a copy constructor. The one generated by the compiler is adequate. + // Do not create a copy constructor & operator=. + // The ones generated by the compiler are adequate. ~TEXTE_PCB(); @@ -73,9 +74,6 @@ public: void Flip( const wxPoint& aCentre ); - /* duplicate structure */ - void Copy( TEXTE_PCB* source ); - void Draw( EDA_DRAW_PANEL* panel, wxDC* DC, GR_DRAWMODE aDrawMode, const wxPoint& offset = ZeroOffset ); diff --git a/pcbnew/class_text_mod.cpp b/pcbnew/class_text_mod.cpp index adb1f302c3..8f1672143e 100644 --- a/pcbnew/class_text_mod.cpp +++ b/pcbnew/class_text_mod.cpp @@ -124,27 +124,6 @@ void TEXTE_MODULE::Move( const wxPoint& aMoveVector ) } -void TEXTE_MODULE::Copy( TEXTE_MODULE* source ) -{ - if( source == NULL ) - return; - - m_Pos = source->m_Pos; - SetLayer( source->GetLayer() ); - - m_Mirror = source->m_Mirror; - m_NoShow = source->m_NoShow; - m_Type = source->m_Type; - m_Orient = source->m_Orient; - m_Pos0 = source->m_Pos0; - m_Size = source->m_Size; - m_Thickness = source->m_Thickness; - m_Italic = source->m_Italic; - m_Bold = source->m_Bold; - m_Text = source->m_Text; -} - - int TEXTE_MODULE::GetLength() const { return m_Text.Len(); diff --git a/pcbnew/class_text_mod.h b/pcbnew/class_text_mod.h index cb6b0470c1..79edd49c60 100644 --- a/pcbnew/class_text_mod.h +++ b/pcbnew/class_text_mod.h @@ -64,7 +64,8 @@ public: TEXTE_MODULE( MODULE* parent, TEXT_TYPE text_type = TEXT_is_DIVERS ); - // Do not create a copy constructor. The one generated by the compiler is adequate. + // Do not create a copy constructor & operator=. + // The ones generated by the compiler are adequate. ~TEXTE_MODULE(); @@ -112,8 +113,6 @@ public: void SetPos0( const wxPoint& aPos ) { m_Pos0 = aPos; SetDrawCoord(); } const wxPoint& GetPos0() const { return m_Pos0; } - void Copy( TEXTE_MODULE* source ); // copy structure - int GetLength() const; // text length /** diff --git a/pcbnew/class_zone.cpp b/pcbnew/class_zone.cpp index 5a464fa797..a03d431932 100644 --- a/pcbnew/class_zone.cpp +++ b/pcbnew/class_zone.cpp @@ -105,6 +105,32 @@ ZONE_CONTAINER::ZONE_CONTAINER( const ZONE_CONTAINER& aZone ) : } +ZONE_CONTAINER& ZONE_CONTAINER::operator=( const ZONE_CONTAINER& aOther ) +{ + BOARD_CONNECTED_ITEM::operator=( aOther ); + + m_Poly->RemoveAllContours(); + m_Poly->Copy( aOther.m_Poly ); // copy outlines + m_CornerSelection = -1; // for corner moving, corner index to drag or -1 if no selection + m_ZoneClearance = aOther.m_ZoneClearance; // clearance value + m_ZoneMinThickness = aOther.m_ZoneMinThickness; + m_FillMode = aOther.m_FillMode; // filling mode (segments/polygons) + m_ArcToSegmentsCount = aOther.m_ArcToSegmentsCount; + m_PadConnection = aOther.m_PadConnection; + m_ThermalReliefGap = aOther.m_ThermalReliefGap; + m_ThermalReliefCopperBridge = aOther.m_ThermalReliefCopperBridge; + m_Poly->SetHatchStyle( aOther.m_Poly->GetHatchStyle() ); + m_Poly->SetHatchPitch( aOther.m_Poly->GetHatchPitch() ); + m_Poly->m_HatchLines = aOther.m_Poly->m_HatchLines; // copy vector + m_FilledPolysList.RemoveAllContours(); + m_FilledPolysList.Append( aOther.m_FilledPolysList ); + m_FillSegmList.clear(); + m_FillSegmList = aOther.m_FillSegmList; + + return *this; +} + + ZONE_CONTAINER::~ZONE_CONTAINER() { delete m_Poly; @@ -751,33 +777,6 @@ void ZONE_CONTAINER::Mirror( const wxPoint& mirror_ref ) } -void ZONE_CONTAINER::Copy( ZONE_CONTAINER* src ) -{ - m_Parent = src->m_Parent; - m_Layer = src->m_Layer; - SetNetCode( src->GetNetCode() ); - SetTimeStamp( src->m_TimeStamp ); - m_Poly->RemoveAllContours(); - m_Poly->Copy( src->m_Poly ); // copy outlines - m_CornerSelection = -1; // For corner moving, corner index to drag, - // or -1 if no selection - m_ZoneClearance = src->m_ZoneClearance; // clearance value - m_ZoneMinThickness = src->m_ZoneMinThickness; - m_FillMode = src->m_FillMode; // Filling mode (segments/polygons) - m_ArcToSegmentsCount = src->m_ArcToSegmentsCount; - m_PadConnection = src->m_PadConnection; - m_ThermalReliefGap = src->m_ThermalReliefGap; - m_ThermalReliefCopperBridge = src->m_ThermalReliefCopperBridge; - m_Poly->SetHatchStyle( src->m_Poly->GetHatchStyle() ); - m_Poly->SetHatchPitch( src->m_Poly->GetHatchPitch() ); - m_Poly->m_HatchLines = src->m_Poly->m_HatchLines; // Copy vector - m_FilledPolysList.RemoveAllContours(); - m_FilledPolysList.Append( src->m_FilledPolysList ); - m_FillSegmList.clear(); - m_FillSegmList = src->m_FillSegmList; -} - - ZoneConnection ZONE_CONTAINER::GetPadConnection( D_PAD* aPad ) const { if( aPad == NULL || aPad->GetZoneConnection() == PAD_ZONE_CONN_INHERITED ) diff --git a/pcbnew/class_zone.h b/pcbnew/class_zone.h index 798e3f2499..76c5ae8baf 100644 --- a/pcbnew/class_zone.h +++ b/pcbnew/class_zone.h @@ -82,6 +82,7 @@ public: ZONE_CONTAINER( BOARD* parent ); ZONE_CONTAINER( const ZONE_CONTAINER& aZone ); + ZONE_CONTAINER& operator=( const ZONE_CONTAINER &aOther ); ~ZONE_CONTAINER(); @@ -104,13 +105,6 @@ public: */ unsigned GetPriority() const { return m_priority; } - /** - * Function copy - * copy useful data from the source. - * flags and linked list pointers are NOT copied - */ - void Copy( ZONE_CONTAINER* src ); - void GetMsgPanelInfo( std::vector< MSG_PANEL_ITEM >& aList ); /** diff --git a/pcbnew/connect.cpp b/pcbnew/connect.cpp index 848c30b531..50c3805cf9 100644 --- a/pcbnew/connect.cpp +++ b/pcbnew/connect.cpp @@ -942,6 +942,10 @@ void PCB_BASE_FRAME::RecalculateAllTracksNetcode() } } + /// @todo LEGACY tracks might have changed their nets, so we need to refresh labels in GAL + for( TRACK* track = m_Pcb->m_Track; track; track = track->Next() ) + track->ViewUpdate(); + // Sort the track list by net codes: RebuildTrackChain( m_Pcb ); } diff --git a/pcbnew/dialogs/dialog_create_array_base.cpp b/pcbnew/dialogs/dialog_create_array_base.cpp index 67d5e6ef9e..0e1e2ceed4 100644 --- a/pcbnew/dialogs/dialog_create_array_base.cpp +++ b/pcbnew/dialogs/dialog_create_array_base.cpp @@ -1,5 +1,5 @@ /////////////////////////////////////////////////////////////////////////// -// C++ code generated with wxFormBuilder (version Mar 9 2016) +// C++ code generated with wxFormBuilder (version Jun 21 2016) // http://www.wxformbuilder.org/ // // PLEASE DO "NOT" EDIT THIS FILE! @@ -290,19 +290,19 @@ DIALOG_CREATE_ARRAY_BASE::DIALOG_CREATE_ARRAY_BASE( wxWindow* parent, wxWindowID // Connect Events this->Connect( wxEVT_CLOSE_WINDOW, wxCloseEventHandler( DIALOG_CREATE_ARRAY_BASE::OnClose ) ); - m_entryNx->Connect( wxEVT_COMMAND_TEXT_ENTER, wxCommandEventHandler( DIALOG_CREATE_ARRAY_BASE::OnParameterChanged ), NULL, this ); - m_entryNy->Connect( wxEVT_COMMAND_TEXT_ENTER, wxCommandEventHandler( DIALOG_CREATE_ARRAY_BASE::OnParameterChanged ), NULL, this ); - m_entryDx->Connect( wxEVT_COMMAND_TEXT_ENTER, wxCommandEventHandler( DIALOG_CREATE_ARRAY_BASE::OnParameterChanged ), NULL, this ); - m_entryDy->Connect( wxEVT_COMMAND_TEXT_ENTER, wxCommandEventHandler( DIALOG_CREATE_ARRAY_BASE::OnParameterChanged ), NULL, this ); - m_entryOffsetX->Connect( wxEVT_COMMAND_TEXT_ENTER, wxCommandEventHandler( DIALOG_CREATE_ARRAY_BASE::OnParameterChanged ), NULL, this ); - m_entryOffsetY->Connect( wxEVT_COMMAND_TEXT_ENTER, wxCommandEventHandler( DIALOG_CREATE_ARRAY_BASE::OnParameterChanged ), NULL, this ); - m_entryStagger->Connect( wxEVT_COMMAND_TEXT_ENTER, wxCommandEventHandler( DIALOG_CREATE_ARRAY_BASE::OnParameterChanged ), NULL, this ); + m_entryNx->Connect( wxEVT_COMMAND_TEXT_UPDATED, wxCommandEventHandler( DIALOG_CREATE_ARRAY_BASE::OnParameterChanged ), NULL, this ); + m_entryNy->Connect( wxEVT_COMMAND_TEXT_UPDATED, wxCommandEventHandler( DIALOG_CREATE_ARRAY_BASE::OnParameterChanged ), NULL, this ); + m_entryDx->Connect( wxEVT_COMMAND_TEXT_UPDATED, wxCommandEventHandler( DIALOG_CREATE_ARRAY_BASE::OnParameterChanged ), NULL, this ); + m_entryDy->Connect( wxEVT_COMMAND_TEXT_UPDATED, wxCommandEventHandler( DIALOG_CREATE_ARRAY_BASE::OnParameterChanged ), NULL, this ); + m_entryOffsetX->Connect( wxEVT_COMMAND_TEXT_UPDATED, wxCommandEventHandler( DIALOG_CREATE_ARRAY_BASE::OnParameterChanged ), NULL, this ); + m_entryOffsetY->Connect( wxEVT_COMMAND_TEXT_UPDATED, wxCommandEventHandler( DIALOG_CREATE_ARRAY_BASE::OnParameterChanged ), NULL, this ); + m_entryStagger->Connect( wxEVT_COMMAND_TEXT_UPDATED, wxCommandEventHandler( DIALOG_CREATE_ARRAY_BASE::OnParameterChanged ), NULL, this ); m_rbGridStartNumberingOpt->Connect( wxEVT_COMMAND_RADIOBOX_SELECTED, wxCommandEventHandler( DIALOG_CREATE_ARRAY_BASE::OnParameterChanged ), NULL, this ); m_radioBoxGridNumberingScheme->Connect( wxEVT_COMMAND_RADIOBOX_SELECTED, wxCommandEventHandler( DIALOG_CREATE_ARRAY_BASE::OnParameterChanged ), NULL, this ); m_entryCentreX->Connect( wxEVT_COMMAND_TEXT_UPDATED, wxCommandEventHandler( DIALOG_CREATE_ARRAY_BASE::OnParameterChanged ), NULL, this ); m_entryCentreY->Connect( wxEVT_COMMAND_TEXT_UPDATED, wxCommandEventHandler( DIALOG_CREATE_ARRAY_BASE::OnParameterChanged ), NULL, this ); - m_entryCircAngle->Connect( wxEVT_COMMAND_TEXT_ENTER, wxCommandEventHandler( DIALOG_CREATE_ARRAY_BASE::OnParameterChanged ), NULL, this ); - m_entryCircCount->Connect( wxEVT_COMMAND_TEXT_ENTER, wxCommandEventHandler( DIALOG_CREATE_ARRAY_BASE::OnParameterChanged ), NULL, this ); + m_entryCircAngle->Connect( wxEVT_COMMAND_TEXT_UPDATED, wxCommandEventHandler( DIALOG_CREATE_ARRAY_BASE::OnParameterChanged ), NULL, this ); + m_entryCircCount->Connect( wxEVT_COMMAND_TEXT_UPDATED, wxCommandEventHandler( DIALOG_CREATE_ARRAY_BASE::OnParameterChanged ), NULL, this ); m_rbCircStartNumberingOpt->Connect( wxEVT_COMMAND_RADIOBOX_SELECTED, wxCommandEventHandler( DIALOG_CREATE_ARRAY_BASE::OnParameterChanged ), NULL, this ); m_stdButtonsOK->Connect( wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler( DIALOG_CREATE_ARRAY_BASE::OnOkClick ), NULL, this ); } @@ -311,19 +311,19 @@ DIALOG_CREATE_ARRAY_BASE::~DIALOG_CREATE_ARRAY_BASE() { // Disconnect Events this->Disconnect( wxEVT_CLOSE_WINDOW, wxCloseEventHandler( DIALOG_CREATE_ARRAY_BASE::OnClose ) ); - m_entryNx->Disconnect( wxEVT_COMMAND_TEXT_ENTER, wxCommandEventHandler( DIALOG_CREATE_ARRAY_BASE::OnParameterChanged ), NULL, this ); - m_entryNy->Disconnect( wxEVT_COMMAND_TEXT_ENTER, wxCommandEventHandler( DIALOG_CREATE_ARRAY_BASE::OnParameterChanged ), NULL, this ); - m_entryDx->Disconnect( wxEVT_COMMAND_TEXT_ENTER, wxCommandEventHandler( DIALOG_CREATE_ARRAY_BASE::OnParameterChanged ), NULL, this ); - m_entryDy->Disconnect( wxEVT_COMMAND_TEXT_ENTER, wxCommandEventHandler( DIALOG_CREATE_ARRAY_BASE::OnParameterChanged ), NULL, this ); - m_entryOffsetX->Disconnect( wxEVT_COMMAND_TEXT_ENTER, wxCommandEventHandler( DIALOG_CREATE_ARRAY_BASE::OnParameterChanged ), NULL, this ); - m_entryOffsetY->Disconnect( wxEVT_COMMAND_TEXT_ENTER, wxCommandEventHandler( DIALOG_CREATE_ARRAY_BASE::OnParameterChanged ), NULL, this ); - m_entryStagger->Disconnect( wxEVT_COMMAND_TEXT_ENTER, wxCommandEventHandler( DIALOG_CREATE_ARRAY_BASE::OnParameterChanged ), NULL, this ); + m_entryNx->Disconnect( wxEVT_COMMAND_TEXT_UPDATED, wxCommandEventHandler( DIALOG_CREATE_ARRAY_BASE::OnParameterChanged ), NULL, this ); + m_entryNy->Disconnect( wxEVT_COMMAND_TEXT_UPDATED, wxCommandEventHandler( DIALOG_CREATE_ARRAY_BASE::OnParameterChanged ), NULL, this ); + m_entryDx->Disconnect( wxEVT_COMMAND_TEXT_UPDATED, wxCommandEventHandler( DIALOG_CREATE_ARRAY_BASE::OnParameterChanged ), NULL, this ); + m_entryDy->Disconnect( wxEVT_COMMAND_TEXT_UPDATED, wxCommandEventHandler( DIALOG_CREATE_ARRAY_BASE::OnParameterChanged ), NULL, this ); + m_entryOffsetX->Disconnect( wxEVT_COMMAND_TEXT_UPDATED, wxCommandEventHandler( DIALOG_CREATE_ARRAY_BASE::OnParameterChanged ), NULL, this ); + m_entryOffsetY->Disconnect( wxEVT_COMMAND_TEXT_UPDATED, wxCommandEventHandler( DIALOG_CREATE_ARRAY_BASE::OnParameterChanged ), NULL, this ); + m_entryStagger->Disconnect( wxEVT_COMMAND_TEXT_UPDATED, wxCommandEventHandler( DIALOG_CREATE_ARRAY_BASE::OnParameterChanged ), NULL, this ); m_rbGridStartNumberingOpt->Disconnect( wxEVT_COMMAND_RADIOBOX_SELECTED, wxCommandEventHandler( DIALOG_CREATE_ARRAY_BASE::OnParameterChanged ), NULL, this ); m_radioBoxGridNumberingScheme->Disconnect( wxEVT_COMMAND_RADIOBOX_SELECTED, wxCommandEventHandler( DIALOG_CREATE_ARRAY_BASE::OnParameterChanged ), NULL, this ); m_entryCentreX->Disconnect( wxEVT_COMMAND_TEXT_UPDATED, wxCommandEventHandler( DIALOG_CREATE_ARRAY_BASE::OnParameterChanged ), NULL, this ); m_entryCentreY->Disconnect( wxEVT_COMMAND_TEXT_UPDATED, wxCommandEventHandler( DIALOG_CREATE_ARRAY_BASE::OnParameterChanged ), NULL, this ); - m_entryCircAngle->Disconnect( wxEVT_COMMAND_TEXT_ENTER, wxCommandEventHandler( DIALOG_CREATE_ARRAY_BASE::OnParameterChanged ), NULL, this ); - m_entryCircCount->Disconnect( wxEVT_COMMAND_TEXT_ENTER, wxCommandEventHandler( DIALOG_CREATE_ARRAY_BASE::OnParameterChanged ), NULL, this ); + m_entryCircAngle->Disconnect( wxEVT_COMMAND_TEXT_UPDATED, wxCommandEventHandler( DIALOG_CREATE_ARRAY_BASE::OnParameterChanged ), NULL, this ); + m_entryCircCount->Disconnect( wxEVT_COMMAND_TEXT_UPDATED, wxCommandEventHandler( DIALOG_CREATE_ARRAY_BASE::OnParameterChanged ), NULL, this ); m_rbCircStartNumberingOpt->Disconnect( wxEVT_COMMAND_RADIOBOX_SELECTED, wxCommandEventHandler( DIALOG_CREATE_ARRAY_BASE::OnParameterChanged ), NULL, this ); m_stdButtonsOK->Disconnect( wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler( DIALOG_CREATE_ARRAY_BASE::OnOkClick ), NULL, this ); diff --git a/pcbnew/dialogs/dialog_create_array_base.fbp b/pcbnew/dialogs/dialog_create_array_base.fbp index b4af4d44b9..a9d0660856 100644 --- a/pcbnew/dialogs/dialog_create_array_base.fbp +++ b/pcbnew/dialogs/dialog_create_array_base.fbp @@ -446,8 +446,8 @@ - - OnParameterChanged + OnParameterChanged + @@ -626,8 +626,8 @@ - - OnParameterChanged + OnParameterChanged + @@ -806,8 +806,8 @@ - - OnParameterChanged + OnParameterChanged + @@ -1072,8 +1072,8 @@ - - OnParameterChanged + OnParameterChanged + @@ -1338,8 +1338,8 @@ - - OnParameterChanged + OnParameterChanged + @@ -1604,8 +1604,8 @@ - - OnParameterChanged + OnParameterChanged + @@ -1870,8 +1870,8 @@ - - OnParameterChanged + OnParameterChanged + @@ -3937,8 +3937,8 @@ - - OnParameterChanged + OnParameterChanged + @@ -4203,8 +4203,8 @@ - - OnParameterChanged + OnParameterChanged + @@ -4399,6 +4399,7 @@ m_circPadNumberingSizer wxVERTICAL + 1 protected diff --git a/pcbnew/dialogs/dialog_create_array_base.h b/pcbnew/dialogs/dialog_create_array_base.h index 0e11e36291..9419cef108 100644 --- a/pcbnew/dialogs/dialog_create_array_base.h +++ b/pcbnew/dialogs/dialog_create_array_base.h @@ -1,5 +1,5 @@ /////////////////////////////////////////////////////////////////////////// -// C++ code generated with wxFormBuilder (version Mar 9 2016) +// C++ code generated with wxFormBuilder (version Jun 21 2016) // http://www.wxformbuilder.org/ // // PLEASE DO "NOT" EDIT THIS FILE! diff --git a/pcbnew/dialogs/dialog_edit_module_for_BoardEditor.cpp b/pcbnew/dialogs/dialog_edit_module_for_BoardEditor.cpp index e37f4ffb5b..6a1589e20b 100644 --- a/pcbnew/dialogs/dialog_edit_module_for_BoardEditor.cpp +++ b/pcbnew/dialogs/dialog_edit_module_for_BoardEditor.cpp @@ -41,6 +41,7 @@ #include #include #include +#include #include #include @@ -325,10 +326,10 @@ void DIALOG_MODULE_BOARD_EDITOR::InitModeditProperties() } - m_ReferenceCopy = new TEXTE_MODULE( NULL ); - m_ValueCopy = new TEXTE_MODULE( NULL ); - m_ReferenceCopy->Copy( &m_CurrentModule->Reference() ); - m_ValueCopy->Copy( &m_CurrentModule->Value() ); + m_ReferenceCopy = new TEXTE_MODULE( m_CurrentModule->Reference() ); + m_ReferenceCopy->SetParent( m_CurrentModule ); + m_ValueCopy = new TEXTE_MODULE( m_CurrentModule->Value() ); + m_ValueCopy->SetParent( m_CurrentModule ); m_ReferenceCtrl->SetValue( m_ReferenceCopy->GetText() ); m_ValueCtrl->SetValue( m_ValueCopy->GetText() ); @@ -610,6 +611,9 @@ bool DIALOG_MODULE_BOARD_EDITOR::TransferDataFromWindow() wxPoint modpos; wxString msg; + BOARD_COMMIT commit( m_Parent ); + commit.Modify( m_CurrentModule ); + if( !Validate() || !DIALOG_MODULE_BOARD_EDITOR_BASE::TransferDataFromWindow() || !m_PanelProperties->TransferDataFromWindow() ) { @@ -623,10 +627,6 @@ bool DIALOG_MODULE_BOARD_EDITOR::TransferDataFromWindow() return false; } - if( m_CurrentModule->GetFlags() == 0 ) // this is a simple edition, we - // must create an undo entry - m_Parent->SaveCopyInUndoList( m_CurrentModule, UR_CHANGED ); - if( m_DC ) { m_Parent->GetCanvas()->CrossHairOff( m_DC ); @@ -634,8 +634,10 @@ bool DIALOG_MODULE_BOARD_EDITOR::TransferDataFromWindow() } // Init Fields (should be first, because they can be moved or/and flipped later): - m_CurrentModule->Reference().Copy( m_ReferenceCopy ); - m_CurrentModule->Value().Copy( m_ValueCopy ); + TEXTE_MODULE& reference = m_CurrentModule->Reference(); + reference = *m_ReferenceCopy; + TEXTE_MODULE& value = m_CurrentModule->Value(); + value = *m_ValueCopy; // Initialize masks clearances m_CurrentModule->SetLocalClearance( ValueFromTextCtrl( *m_NetClearanceValueCtrl ) ); @@ -739,7 +741,9 @@ bool DIALOG_MODULE_BOARD_EDITOR::TransferDataFromWindow() m_CurrentModule->CalculateBoundingBox(); - m_Parent->OnModify(); + // This is a simple edition, we must create an undo entry + if( m_CurrentModule->GetFlags() == 0 ) + commit.Push( _( "Modify module properties" ) ); SetReturnCode( PRM_EDITOR_EDIT_OK ); diff --git a/pcbnew/dialogs/dialog_edit_module_for_Modedit.cpp b/pcbnew/dialogs/dialog_edit_module_for_Modedit.cpp index 547a846156..7d7ccf3d35 100644 --- a/pcbnew/dialogs/dialog_edit_module_for_Modedit.cpp +++ b/pcbnew/dialogs/dialog_edit_module_for_Modedit.cpp @@ -43,6 +43,7 @@ #include #include #include +#include #include #include @@ -165,10 +166,10 @@ void DIALOG_MODULE_MODULE_EDITOR::initModeditProperties() m_DocCtrl->SetValue( m_currentModule->GetDescription() ); m_KeywordCtrl->SetValue( m_currentModule->GetKeywords() ); - m_referenceCopy = new TEXTE_MODULE( NULL ); - m_valueCopy = new TEXTE_MODULE( NULL ); - m_referenceCopy->Copy( &m_currentModule->Reference() ); - m_valueCopy->Copy( &m_currentModule->Value() ); + m_referenceCopy = new TEXTE_MODULE( m_currentModule->Reference() ); + m_referenceCopy->SetParent( m_currentModule ); + m_valueCopy = new TEXTE_MODULE( m_currentModule->Value() ); + m_valueCopy->SetParent( m_currentModule ); m_ReferenceCtrl->SetValue( m_referenceCopy->GetText() ); m_ValueCtrl->SetValue( m_valueCopy->GetText() ); m_FootprintNameCtrl->SetValue( m_currentModule->GetFPID().Format() ); @@ -440,6 +441,7 @@ void DIALOG_MODULE_MODULE_EDITOR::OnCancelClick( wxCommandEvent& event ) void DIALOG_MODULE_MODULE_EDITOR::OnOkClick( wxCommandEvent& event ) { + BOARD_COMMIT commit( m_parent ); wxString msg; // First, test for invalid chars in module name @@ -465,7 +467,8 @@ void DIALOG_MODULE_MODULE_EDITOR::OnOkClick( wxCommandEvent& event ) return; } - m_parent->SaveCopyInUndoList( m_currentModule, UR_MODEDIT ); + commit.Modify( m_currentModule ); + m_currentModule->SetLocked( m_AutoPlaceCtrl->GetSelection() == 1 ); switch( m_AttributsCtrl->GetSelection() ) @@ -493,8 +496,10 @@ void DIALOG_MODULE_MODULE_EDITOR::OnOkClick( wxCommandEvent& event ) m_currentModule->SetFPID( FPID( footprintName ) ); // Init Fields: - m_currentModule->Reference().Copy( m_referenceCopy ); - m_currentModule->Value().Copy( m_valueCopy ); + TEXTE_MODULE& reference = m_currentModule->Reference(); + reference = *m_referenceCopy; + TEXTE_MODULE& value = m_currentModule->Value(); + value = *m_valueCopy; // Initialize masks clearances m_currentModule->SetLocalClearance( ValueFromTextCtrl( *m_NetClearanceValueCtrl ) ); @@ -520,7 +525,7 @@ void DIALOG_MODULE_MODULE_EDITOR::OnOkClick( wxCommandEvent& event ) m_currentModule->CalculateBoundingBox(); - m_parent->OnModify(); + commit.Push( _( "Modify module properties" ) ); EndModal( 1 ); } diff --git a/pcbnew/dialogs/dialog_edit_module_text.cpp b/pcbnew/dialogs/dialog_edit_module_text.cpp index 9d38affffb..df809cbefa 100644 --- a/pcbnew/dialogs/dialog_edit_module_text.cpp +++ b/pcbnew/dialogs/dialog_edit_module_text.cpp @@ -41,6 +41,7 @@ #include #include #include +#include #include #include @@ -207,11 +208,13 @@ bool DialogEditModuleText::TransferDataToWindow() bool DialogEditModuleText::TransferDataFromWindow() { + BOARD_COMMIT commit( m_parent ); + if( !Validate() || !DialogEditModuleText_base::TransferDataFromWindow() ) return false; if( m_module ) - m_parent->SaveCopyInUndoList( m_module, UR_CHANGED ); + commit.Modify( m_currentText ); #ifndef USE_WX_OVERLAY if( m_dc ) //Erase old text on screen @@ -325,7 +328,7 @@ bool DialogEditModuleText::TransferDataFromWindow() m_parent->Refresh(); #endif - m_parent->OnModify(); + commit.Push( _( "Modify module text" ) ); if( m_module ) m_module->SetLastEditTime(); diff --git a/pcbnew/dialogs/dialog_global_deletion.cpp b/pcbnew/dialogs/dialog_global_deletion.cpp index cbbc61b973..6c36cad2d6 100644 --- a/pcbnew/dialogs/dialog_global_deletion.cpp +++ b/pcbnew/dialogs/dialog_global_deletion.cpp @@ -30,6 +30,7 @@ using namespace std::placeholders; #include #include #include +#include #include #include @@ -108,11 +109,9 @@ void DIALOG_GLOBAL_DELETION::AcceptPcbDelete() return; BOARD* pcb = m_Parent->GetBoard(); - PICKED_ITEMS_LIST pickersList; - ITEM_PICKER itemPicker( NULL, UR_DELETED ); + BOARD_COMMIT commit( m_Parent ); BOARD_ITEM* item; BOARD_ITEM* nextitem; - RN_DATA* ratsnest = pcb->GetRatsnest(); LSET layers_filter = LSET().set(); @@ -128,11 +127,7 @@ void DIALOG_GLOBAL_DELETION::AcceptPcbDelete() { if( delAll || layers_filter[item->GetLayer()] ) { - itemPicker.SetItem( item ); - pickersList.PushItem( itemPicker ); - pcb->Remove( item ); - item->ViewRelease(); - ratsnest->Remove( item ); + commit.Remove( item ); gen_rastnest = true; } else @@ -160,13 +155,9 @@ void DIALOG_GLOBAL_DELETION::AcceptPcbDelete() { nextitem = item->Next(); - if( delAll || - ( item->Type() == PCB_LINE_T && masque_layer[item->GetLayer()] ) ) + if( delAll || ( item->Type() == PCB_LINE_T && masque_layer[item->GetLayer()] ) ) { - itemPicker.SetItem( item ); - pickersList.PushItem( itemPicker ); - item->ViewRelease(); - item->UnLink(); + commit.Remove( item ); } } } @@ -179,13 +170,9 @@ void DIALOG_GLOBAL_DELETION::AcceptPcbDelete() { nextitem = item->Next(); - if( delAll || - ( item->Type() == PCB_TEXT_T && del_text_layers[item->GetLayer()] ) ) + if( delAll || ( item->Type() == PCB_TEXT_T && del_text_layers[item->GetLayer()] ) ) { - itemPicker.SetItem( item ); - pickersList.PushItem( itemPicker ); - item->ViewRelease(); - item->UnLink(); + commit.Remove( item ); } } } @@ -205,13 +192,7 @@ void DIALOG_GLOBAL_DELETION::AcceptPcbDelete() if( del_fp ) { - itemPicker.SetItem( item ); - pickersList.PushItem( itemPicker ); - static_cast( item )->RunOnChildren( - std::bind( &KIGFX::VIEW_ITEM::ViewRelease, _1 ) ); - ratsnest->Remove( item ); - item->ViewRelease(); - item->UnLink(); + commit.Remove( item ); gen_rastnest = true; } } @@ -249,17 +230,12 @@ void DIALOG_GLOBAL_DELETION::AcceptPcbDelete() continue; } - itemPicker.SetItem( track ); - pickersList.PushItem( itemPicker ); - track->ViewRelease(); - ratsnest->Remove( track ); - track->UnLink(); + commit.Remove( track ); gen_rastnest = true; } } - if( pickersList.GetCount() ) - m_Parent->SaveCopyInUndoList( pickersList, UR_DELETED ); + commit.Push( wxT( "Global delete" ) ); if( m_DelMarkers->GetValue() ) pcb->DeleteMARKERs(); @@ -268,9 +244,7 @@ void DIALOG_GLOBAL_DELETION::AcceptPcbDelete() m_Parent->Compile_Ratsnest( NULL, true ); // There is a chance that some of tracks have changed their nets, so rebuild ratsnest from scratch - if( m_Parent->IsGalCanvasActive() ) - pcb->GetRatsnest()->ProcessBoard(); - - m_Parent->GetCanvas()->Refresh(); - m_Parent->OnModify(); + // TODO necessary? if not, remove rn_data.h header as well + //if( m_Parent->IsGalCanvasActive() ) + //pcb->GetRatsnest()->ProcessBoard(); } diff --git a/pcbnew/dialogs/dialog_global_modules_fields_edition.cpp b/pcbnew/dialogs/dialog_global_modules_fields_edition.cpp index 355d8a5ef5..25fdc9280c 100644 --- a/pcbnew/dialogs/dialog_global_modules_fields_edition.cpp +++ b/pcbnew/dialogs/dialog_global_modules_fields_edition.cpp @@ -34,6 +34,7 @@ #include #include #include +#include #include #include @@ -134,35 +135,21 @@ void DIALOG_GLOBAL_MODULES_FIELDS_EDITION::OnOKClick( wxCommandEvent& event ) void PCB_EDIT_FRAME::OnResetModuleTextSizes( wxCommandEvent& event ) { - DIALOG_GLOBAL_MODULES_FIELDS_EDITION dlg(this); + DIALOG_GLOBAL_MODULES_FIELDS_EDITION dlg( this ); dlg.ShowModal(); - - if( IsGalCanvasActive() ) - { - for( MODULE* module = GetBoard()->m_Modules; module; module = module->Next() ) - { - module->Value().ViewUpdate(); - module->Reference().ViewUpdate(); - } - } - - m_canvas->Refresh(); } void PCB_BASE_FRAME::ResetModuleTextSizes( const wxString & aFilter, bool aRef, bool aValue, bool aOthers ) { - MODULE* module; - BOARD_ITEM* boardItem; - ITEM_PICKER itemWrapper( NULL, UR_CHANGED ); - PICKED_ITEMS_LIST undoItemList; - unsigned int ii; + BOARD_COMMIT commit( this ); + + int modTextWidth = GetDesignSettings().m_ModuleTextWidth; + const wxSize& modTextSize = GetDesignSettings().m_ModuleTextSize; // Prepare undo list - for( module = GetBoard()->m_Modules; module; module = module->Next() ) + for( MODULE* module = GetBoard()->m_Modules; module; module = module->Next() ) { - itemWrapper.SetItem( module ); - if( ! aFilter.IsEmpty() ) { if( ! WildCompareString( aFilter, FROM_UTF8( module->GetFPID().Format().c_str() ), @@ -173,81 +160,50 @@ void PCB_BASE_FRAME::ResetModuleTextSizes( const wxString & aFilter, bool aRef, if( aRef ) { - TEXTE_MODULE *item = &module->Reference(); + TEXTE_MODULE* item = &module->Reference(); if( item->GetSize() != GetDesignSettings().m_ModuleTextSize || item->GetThickness() != GetDesignSettings().m_ModuleTextWidth ) { - undoItemList.PushItem( itemWrapper ); + commit.Modify( item ); + item->SetThickness( modTextWidth ); + item->SetSize( modTextSize ); } } if( aValue ) { - TEXTE_MODULE *item = &module->Value(); + TEXTE_MODULE* item = &module->Value(); if( item->GetSize() != GetDesignSettings().m_ModuleTextSize || item->GetThickness() != GetDesignSettings().m_ModuleTextWidth ) { - undoItemList.PushItem( itemWrapper ); + commit.Modify( item ); + item->SetThickness( modTextWidth ); + item->SetSize( modTextSize ); } } if( aOthers ) { // Go through all other module text fields - for( boardItem = module->GraphicalItems(); boardItem; boardItem = boardItem->Next() ) + for( BOARD_ITEM* boardItem = module->GraphicalItems(); boardItem; boardItem = boardItem->Next() ) { if( boardItem->Type() == PCB_MODULE_TEXT_T ) { - TEXTE_MODULE *item = static_cast( boardItem ); + TEXTE_MODULE* item = static_cast( boardItem ); if( item->GetSize() != GetDesignSettings().m_ModuleTextSize || item->GetThickness() != GetDesignSettings().m_ModuleTextWidth ) { - undoItemList.PushItem( itemWrapper ); + commit.Modify( item ); + item->SetThickness( modTextWidth ); + item->SetSize( modTextSize ); } } } } } - // Exit if there's nothing to do - if( !undoItemList.GetCount() ) - return; - - SaveCopyInUndoList( undoItemList, UR_CHANGED ); - - // Apply changes to modules in the undo list - for( ii = 0; ii < undoItemList.GetCount(); ii++ ) - { - module = (MODULE*) undoItemList.GetPickedItem( ii ); - - if( aRef ) - { - module->Reference().SetThickness( GetDesignSettings().m_ModuleTextWidth ); - module->Reference().SetSize( GetDesignSettings().m_ModuleTextSize ); - } - - if( aValue ) - { - module->Value().SetThickness( GetDesignSettings().m_ModuleTextWidth ); - module->Value().SetSize( GetDesignSettings().m_ModuleTextSize ); - } - - if( aOthers ) - { - for( boardItem = module->GraphicalItems(); boardItem; boardItem = boardItem->Next() ) - { - if( boardItem->Type() == PCB_MODULE_TEXT_T ) - { - TEXTE_MODULE *item = static_cast( boardItem ); - item->SetThickness( GetDesignSettings().m_ModuleTextWidth ); - item->SetSize( GetDesignSettings().m_ModuleTextSize ); - } - } - } - } - - OnModify(); + commit.Push( wxT( "Reset module text size" ) ); } diff --git a/pcbnew/dialogs/dialog_graphic_item_properties.cpp b/pcbnew/dialogs/dialog_graphic_item_properties.cpp index d8c2098ae5..7790d36aef 100644 --- a/pcbnew/dialogs/dialog_graphic_item_properties.cpp +++ b/pcbnew/dialogs/dialog_graphic_item_properties.cpp @@ -44,6 +44,7 @@ #include #include #include +#include #include #include @@ -227,7 +228,8 @@ bool DIALOG_GRAPHIC_ITEM_PROPERTIES::TransferDataFromWindow() if( !DIALOG_GRAPHIC_ITEM_PROPERTIES_BASE::TransferDataFromWindow() ) return false; - m_parent->SaveCopyInUndoList( m_item, UR_CHANGED ); + BOARD_COMMIT commit( m_parent ); + commit.Modify( m_item ); wxString msg; @@ -264,7 +266,7 @@ bool DIALOG_GRAPHIC_ITEM_PROPERTIES::TransferDataFromWindow() m_item->SetAngle( m_AngleValue * 10.0 ); } - m_parent->OnModify(); + commit.Push( _( "Modify drawing properties" ) ); if( m_DC ) m_item->Draw( m_parent->GetCanvas(), m_DC, GR_OR ); diff --git a/pcbnew/dialogs/dialog_graphic_item_properties_for_Modedit.cpp b/pcbnew/dialogs/dialog_graphic_item_properties_for_Modedit.cpp index 17106f65ce..81c1f99e93 100644 --- a/pcbnew/dialogs/dialog_graphic_item_properties_for_Modedit.cpp +++ b/pcbnew/dialogs/dialog_graphic_item_properties_for_Modedit.cpp @@ -43,6 +43,7 @@ #include #include #include +#include #include #include @@ -212,6 +213,9 @@ void DIALOG_MODEDIT_FP_BODY_ITEM_PROPERTIES::OnLayerChoice( wxCommandEvent& even bool DIALOG_MODEDIT_FP_BODY_ITEM_PROPERTIES::TransferDataFromWindow() { + BOARD_COMMIT commit( m_parent ); + commit.Modify( m_module ); + if( !DIALOG_GRAPHIC_ITEM_PROPERTIES_BASE::TransferDataFromWindow() ) return false; @@ -223,14 +227,10 @@ bool DIALOG_MODEDIT_FP_BODY_ITEM_PROPERTIES::TransferDataFromWindow() * confirmation is requested */ if( !IsOK( NULL, _( "The graphic item will be on a copper layer. This is very dangerous. Are you sure?" ) ) ) - return false;; + return false; } - m_parent->SaveCopyInUndoList( m_module, UR_MODEDIT ); - m_module->SetLastEditTime(); - wxString msg; - wxPoint coord; msg = m_Center_StartXCtrl->GetValue(); @@ -262,7 +262,8 @@ bool DIALOG_MODEDIT_FP_BODY_ITEM_PROPERTIES::TransferDataFromWindow() m_item->SetAngle( m_AngleValue * 10.0 ); } - m_parent->OnModify(); + commit.Push( _( "Modify module graphic item" ) ); + m_parent->SetMsgPanel( m_item ); return true; diff --git a/pcbnew/dialogs/dialog_pad_properties.cpp b/pcbnew/dialogs/dialog_pad_properties.cpp index 3525a7ee8a..a56522e261 100644 --- a/pcbnew/dialogs/dialog_pad_properties.cpp +++ b/pcbnew/dialogs/dialog_pad_properties.cpp @@ -38,6 +38,7 @@ #include #include #include +#include #include #include @@ -117,9 +118,9 @@ DIALOG_PAD_PROPERTIES::DIALOG_PAD_PROPERTIES( PCB_BASE_FRAME* aParent, D_PAD* aP m_dummyPad = new D_PAD( (MODULE*) NULL ); if( aPad ) - m_dummyPad->Copy( aPad ); + *m_dummyPad = *aPad; else // We are editing a "master" pad, i.e. a template to create new pads - m_dummyPad->Copy( m_padMaster ); + *m_dummyPad = *m_padMaster; // Show the X and Y axis. It is usefull because pad shape can have an offset // or be a complex shape. @@ -921,6 +922,8 @@ bool DIALOG_PAD_PROPERTIES::TransferDataToWindow() bool DIALOG_PAD_PROPERTIES::TransferDataFromWindow() { + BOARD_COMMIT commit( m_parent ); + if( !wxDialog::TransferDataFromWindow() ) return false; @@ -940,114 +943,116 @@ bool DIALOG_PAD_PROPERTIES::TransferDataFromWindow() // m_padMaster is a pattern: ensure there is no net for this pad: m_padMaster->SetNetCode( NETINFO_LIST::UNCONNECTED ); - if( m_currentPad ) // Set current Pad parameters + if( !m_currentPad ) // Set current Pad parameters + return false; + + commit.Modify( m_currentPad ); + + wxSize size; + MODULE* footprint = m_currentPad->GetParent(); + + footprint->SetLastEditTime(); + + // redraw the area where the pad was, without pad (delete pad on screen) + m_currentPad->SetFlags( DO_NOT_DRAW ); + m_parent->GetCanvas()->RefreshDrawingRect( m_currentPad->GetBoundingBox() ); + m_currentPad->ClearFlags( DO_NOT_DRAW ); + + // Update values + m_currentPad->SetShape( m_padMaster->GetShape() ); + m_currentPad->SetAttribute( m_padMaster->GetAttribute() ); + + if( m_currentPad->GetPosition() != m_padMaster->GetPosition() ) { - wxSize size; - MODULE* footprint = m_currentPad->GetParent(); - - m_parent->SaveCopyInUndoList( footprint, UR_CHANGED ); - footprint->SetLastEditTime(); - - // redraw the area where the pad was, without pad (delete pad on screen) - m_currentPad->SetFlags( DO_NOT_DRAW ); - m_parent->GetCanvas()->RefreshDrawingRect( m_currentPad->GetBoundingBox() ); - m_currentPad->ClearFlags( DO_NOT_DRAW ); - - // Update values - m_currentPad->SetShape( m_padMaster->GetShape() ); - m_currentPad->SetAttribute( m_padMaster->GetAttribute() ); - - if( m_currentPad->GetPosition() != m_padMaster->GetPosition() ) - { - m_currentPad->SetPosition( m_padMaster->GetPosition() ); - rastnestIsChanged = true; - } - - // compute the pos 0 value, i.e. pad position for footprint with orientation = 0 - // i.e. relative to footprint origin (footprint position) - wxPoint pt = m_currentPad->GetPosition() - footprint->GetPosition(); - - RotatePoint( &pt, -footprint->GetOrientation() ); - - m_currentPad->SetPos0( pt ); - - m_currentPad->SetOrientation( m_padMaster->GetOrientation() * isign - + footprint->GetOrientation() ); - - m_currentPad->SetSize( m_padMaster->GetSize() ); - - size = m_padMaster->GetDelta(); - size.y *= isign; - m_currentPad->SetDelta( size ); - - m_currentPad->SetDrillSize( m_padMaster->GetDrillSize() ); - m_currentPad->SetDrillShape( m_padMaster->GetDrillShape() ); - - wxPoint offset = m_padMaster->GetOffset(); - offset.y *= isign; - m_currentPad->SetOffset( offset ); - - m_currentPad->SetPadToDieLength( m_padMaster->GetPadToDieLength() ); - - if( m_currentPad->GetLayerSet() != m_padMaster->GetLayerSet() ) - { - rastnestIsChanged = true; - m_currentPad->SetLayerSet( m_padMaster->GetLayerSet() ); - } - - if( m_isFlipped ) - { - m_currentPad->SetLayerSet( FlipLayerMask( m_currentPad->GetLayerSet() ) ); - } - - m_currentPad->SetPadName( m_padMaster->GetPadName() ); - - wxString padNetname; - - // For PAD_ATTRIB_HOLE_NOT_PLATED, ensure there is no net name selected - if( m_padMaster->GetAttribute() != PAD_ATTRIB_HOLE_NOT_PLATED ) - padNetname = m_PadNetNameCtrl->GetValue(); - - if( m_currentPad->GetNetname() != padNetname ) - { - const NETINFO_ITEM* netinfo = m_board->FindNet( padNetname ); - - if( !padNetname.IsEmpty() && netinfo == NULL ) - { - DisplayError( NULL, _( "Unknown netname, netname not changed" ) ); - } - else if( netinfo ) - { - rastnestIsChanged = true; - m_currentPad->SetNetCode( netinfo->GetNet() ); - } - } - - m_currentPad->SetLocalClearance( m_padMaster->GetLocalClearance() ); - m_currentPad->SetLocalSolderMaskMargin( m_padMaster->GetLocalSolderMaskMargin() ); - m_currentPad->SetLocalSolderPasteMargin( m_padMaster->GetLocalSolderPasteMargin() ); - m_currentPad->SetLocalSolderPasteMarginRatio( m_padMaster->GetLocalSolderPasteMarginRatio() ); - m_currentPad->SetZoneConnection( m_padMaster->GetZoneConnection() ); - m_currentPad->SetThermalWidth( m_padMaster->GetThermalWidth() ); - m_currentPad->SetThermalGap( m_padMaster->GetThermalGap() ); - m_currentPad->SetRoundRectRadiusRatio( m_padMaster->GetRoundRectRadiusRatio() ); - - // rounded rect pads with radius ratio = 0 are in fact rect pads. - // So set the right shape (and perhaps issues with a radius = 0) - if( m_currentPad->GetShape() == PAD_SHAPE_ROUNDRECT && - m_currentPad->GetRoundRectRadiusRatio() == 0.0 ) - { - m_currentPad->SetShape( PAD_SHAPE_RECT ); - } - - footprint->CalculateBoundingBox(); - m_parent->SetMsgPanel( m_currentPad ); - - // redraw the area where the pad was - m_parent->GetCanvas()->RefreshDrawingRect( m_currentPad->GetBoundingBox() ); - m_parent->OnModify(); + m_currentPad->SetPosition( m_padMaster->GetPosition() ); + rastnestIsChanged = true; } + // compute the pos 0 value, i.e. pad position for footprint with orientation = 0 + // i.e. relative to footprint origin (footprint position) + wxPoint pt = m_currentPad->GetPosition() - footprint->GetPosition(); + + RotatePoint( &pt, -footprint->GetOrientation() ); + + m_currentPad->SetPos0( pt ); + + m_currentPad->SetOrientation( m_padMaster->GetOrientation() * isign + + footprint->GetOrientation() ); + + m_currentPad->SetSize( m_padMaster->GetSize() ); + + size = m_padMaster->GetDelta(); + size.y *= isign; + m_currentPad->SetDelta( size ); + + m_currentPad->SetDrillSize( m_padMaster->GetDrillSize() ); + m_currentPad->SetDrillShape( m_padMaster->GetDrillShape() ); + + wxPoint offset = m_padMaster->GetOffset(); + offset.y *= isign; + m_currentPad->SetOffset( offset ); + + m_currentPad->SetPadToDieLength( m_padMaster->GetPadToDieLength() ); + + if( m_currentPad->GetLayerSet() != m_padMaster->GetLayerSet() ) + { + rastnestIsChanged = true; + m_currentPad->SetLayerSet( m_padMaster->GetLayerSet() ); + } + + if( m_isFlipped ) + { + m_currentPad->SetLayerSet( FlipLayerMask( m_currentPad->GetLayerSet() ) ); + } + + m_currentPad->SetPadName( m_padMaster->GetPadName() ); + + wxString padNetname; + + // For PAD_ATTRIB_HOLE_NOT_PLATED, ensure there is no net name selected + if( m_padMaster->GetAttribute() != PAD_ATTRIB_HOLE_NOT_PLATED ) + padNetname = m_PadNetNameCtrl->GetValue(); + + if( m_currentPad->GetNetname() != padNetname ) + { + const NETINFO_ITEM* netinfo = m_board->FindNet( padNetname ); + + if( !padNetname.IsEmpty() && netinfo == NULL ) + { + DisplayError( NULL, _( "Unknown netname, netname not changed" ) ); + } + else if( netinfo ) + { + rastnestIsChanged = true; + m_currentPad->SetNetCode( netinfo->GetNet() ); + } + } + + m_currentPad->SetLocalClearance( m_padMaster->GetLocalClearance() ); + m_currentPad->SetLocalSolderMaskMargin( m_padMaster->GetLocalSolderMaskMargin() ); + m_currentPad->SetLocalSolderPasteMargin( m_padMaster->GetLocalSolderPasteMargin() ); + m_currentPad->SetLocalSolderPasteMarginRatio( m_padMaster->GetLocalSolderPasteMarginRatio() ); + m_currentPad->SetZoneConnection( m_padMaster->GetZoneConnection() ); + m_currentPad->SetThermalWidth( m_padMaster->GetThermalWidth() ); + m_currentPad->SetThermalGap( m_padMaster->GetThermalGap() ); + m_currentPad->SetRoundRectRadiusRatio( m_padMaster->GetRoundRectRadiusRatio() ); + + // rounded rect pads with radius ratio = 0 are in fact rect pads. + // So set the right shape (and perhaps issues with a radius = 0) + if( m_currentPad->GetShape() == PAD_SHAPE_ROUNDRECT && + m_currentPad->GetRoundRectRadiusRatio() == 0.0 ) + { + m_currentPad->SetShape( PAD_SHAPE_RECT ); + } + + footprint->CalculateBoundingBox(); + m_parent->SetMsgPanel( m_currentPad ); + + // redraw the area where the pad was + m_parent->GetCanvas()->RefreshDrawingRect( m_currentPad->GetBoundingBox() ); + + commit.Push( _( "Modify pad" ) ); + if( rastnestIsChanged ) // The net ratsnest must be recalculated m_board->m_Status_Pcb = 0; diff --git a/pcbnew/dialogs/dialog_pcb_text_properties.cpp b/pcbnew/dialogs/dialog_pcb_text_properties.cpp index 0e83ad0f71..32f19d2855 100644 --- a/pcbnew/dialogs/dialog_pcb_text_properties.cpp +++ b/pcbnew/dialogs/dialog_pcb_text_properties.cpp @@ -43,6 +43,7 @@ #include #include #include +#include class PCB_EDIT_FRAME; @@ -188,10 +189,12 @@ bool DIALOG_PCB_TEXT_PROPERTIES::TransferDataToWindow() bool DIALOG_PCB_TEXT_PROPERTIES::TransferDataFromWindow() { - if( !DIALOG_PCB_TEXT_PROPERTIES_BASE::TransferDataFromWindow() ) return false; + BOARD_COMMIT commit( m_Parent ); + commit.Modify( m_SelectedPCBText ); + // Test for acceptable layer. // Incorrect layer can happen for old boards, // having texts on edge cut layer for instance @@ -206,8 +209,7 @@ bool DIALOG_PCB_TEXT_PROPERTIES::TransferDataFromWindow() // If no other command in progress, prepare undo command // (for a command in progress, will be made later, at the completion of command) - if( m_SelectedPCBText->GetFlags() == 0 ) - m_Parent->SaveCopyInUndoList( m_SelectedPCBText, UR_CHANGED ); + bool pushCommit = ( m_SelectedPCBText->GetFlags() == 0 ); /* set flag in edit to force undo/redo/abort proper operation, * and avoid new calls to SaveCopyInUndoList for the same text @@ -303,9 +305,11 @@ bool DIALOG_PCB_TEXT_PROPERTIES::TransferDataFromWindow() m_SelectedPCBText->Draw( m_Parent->GetCanvas(), m_DC, GR_OR ); } #else - m_parent->Refresh(); + m_Parent->Refresh(); #endif - m_Parent->OnModify(); + + if( pushCommit ) + commit.Push( _( "Change text properties" ) ); return true; } diff --git a/pcbnew/dialogs/dialog_track_via_properties.cpp b/pcbnew/dialogs/dialog_track_via_properties.cpp index 8bd3918ec8..78ca781e44 100644 --- a/pcbnew/dialogs/dialog_track_via_properties.cpp +++ b/pcbnew/dialogs/dialog_track_via_properties.cpp @@ -29,6 +29,8 @@ #include #include +#include + DIALOG_TRACK_VIA_PROPERTIES::DIALOG_TRACK_VIA_PROPERTIES( PCB_BASE_FRAME* aParent, const SELECTION& aItems ) : DIALOG_TRACK_VIA_PROPERTIES_BASE( aParent ), m_items( aItems ), m_trackStartX( aParent, m_TrackStartXCtrl, m_TrackStartXUnit ), @@ -202,7 +204,7 @@ DIALOG_TRACK_VIA_PROPERTIES::DIALOG_TRACK_VIA_PROPERTIES( PCB_BASE_FRAME* aParen } -bool DIALOG_TRACK_VIA_PROPERTIES::Apply() +bool DIALOG_TRACK_VIA_PROPERTIES::Apply( COMMIT& aCommit ) { if( !check() ) return false; @@ -214,6 +216,7 @@ bool DIALOG_TRACK_VIA_PROPERTIES::Apply() for( int i = 0; i < m_items.Size(); ++i ) { BOARD_ITEM* item = m_items.Item( i ); + aCommit.Modify( item ); switch( item->Type() ) { diff --git a/pcbnew/dialogs/dialog_track_via_properties.h b/pcbnew/dialogs/dialog_track_via_properties.h index 32f739308c..206f08a6c5 100644 --- a/pcbnew/dialogs/dialog_track_via_properties.h +++ b/pcbnew/dialogs/dialog_track_via_properties.h @@ -28,6 +28,8 @@ #include struct SELECTION; +class COMMIT; + class PCB_BASE_FRAME; class DIALOG_TRACK_VIA_PROPERTIES : public DIALOG_TRACK_VIA_PROPERTIES_BASE @@ -36,7 +38,7 @@ public: DIALOG_TRACK_VIA_PROPERTIES( PCB_BASE_FRAME* aParent, const SELECTION& aItems ); ///> Applies values from the dialog to the selected items. - bool Apply(); + bool Apply( COMMIT& aCommit ); private: void onClose( wxCloseEvent& aEvent ); diff --git a/pcbnew/dialogs/dialog_update_pcb.cpp b/pcbnew/dialogs/dialog_update_pcb.cpp index 7efcda67b0..ff35ec52cd 100644 --- a/pcbnew/dialogs/dialog_update_pcb.cpp +++ b/pcbnew/dialogs/dialog_update_pcb.cpp @@ -19,35 +19,29 @@ DIALOG_UPDATE_PCB::DIALOG_UPDATE_PCB( PCB_EDIT_FRAME* aParent, NETLIST *aNetlist m_netlist (aNetlist) { m_messagePanel->SetLabel( _("Changes to be applied:") ); - m_messagePanel->SetLazyUpdate ( true ); + m_messagePanel->SetLazyUpdate( true ); m_netlist->SortByReference(); m_btnPerformUpdate->SetFocus(); m_messagePanel->SetVisibleSeverities( REPORTER::RPT_WARNING | REPORTER::RPT_ERROR | REPORTER::RPT_ACTION ); } + DIALOG_UPDATE_PCB::~DIALOG_UPDATE_PCB() { - } + void DIALOG_UPDATE_PCB::PerformUpdate( bool aDryRun ) { m_messagePanel->Clear(); - REPORTER &reporter = m_messagePanel->Reporter(); - KIGFX::VIEW* view = m_frame->GetGalCanvas()->GetView(); - TOOL_MANAGER *toolManager = m_frame->GetToolManager(); - BOARD *board = m_frame->GetBoard(); + REPORTER& reporter = m_messagePanel->Reporter(); + TOOL_MANAGER* toolManager = m_frame->GetToolManager(); + BOARD* board = m_frame->GetBoard(); if( !aDryRun ) { - // Remove old modules - for( MODULE* module = board->m_Modules; module; module = module->Next() ) - { - module->RunOnChildren( std::bind( &KIGFX::VIEW::Remove, view, _1 ) ); - view->Remove( module ); - } // Clear selection, just in case a selected item has to be removed toolManager->RunAction( COMMON_ACTIONS::selectionClear, true ); @@ -57,7 +51,8 @@ void DIALOG_UPDATE_PCB::PerformUpdate( bool aDryRun ) m_netlist->SetFindByTimeStamp( m_matchByTimestamp->GetValue() ); m_netlist->SetReplaceFootprints( true ); - try { + try + { m_frame->LoadFootprints( *m_netlist, &reporter ); } catch( IO_ERROR &error ) @@ -70,14 +65,12 @@ void DIALOG_UPDATE_PCB::PerformUpdate( bool aDryRun ) } BOARD_NETLIST_UPDATER updater( m_frame, m_frame->GetBoard() ); - updater.SetReporter ( &reporter ); updater.SetIsDryRun( aDryRun); updater.SetLookupByTimestamp( m_matchByTimestamp->GetValue() ); updater.SetDeleteUnusedComponents ( true ); updater.SetReplaceFootprints( true ); - updater.SetDeleteSinglePadNets ( false ); - + updater.SetDeleteSinglePadNets( false ); updater.UpdateNetlist( *m_netlist ); m_messagePanel->Flush(); @@ -85,30 +78,14 @@ void DIALOG_UPDATE_PCB::PerformUpdate( bool aDryRun ) if( aDryRun ) return; - std::vector newFootprints = updater.GetAddedComponents(); - - m_frame->OnModify(); m_frame->SetCurItem( NULL ); - - // Reload modules - for( MODULE* module = board->m_Modules; module; module = module->Next() ) - { - module->RunOnChildren( std::bind( &KIGFX::VIEW::Add, view, _1 ) ); - view->Add( module ); - module->ViewUpdate(); - } - - // Rebuild the board connectivity: - if( m_frame->IsGalCanvasActive() ) - board->GetRatsnest()->ProcessBoard(); - - m_frame->Compile_Ratsnest( NULL, true ); - m_frame->SetMsgPanel( board ); - if( m_frame->IsGalCanvasActive() ) { + std::vector newFootprints = updater.GetAddedComponents(); + + // Place the new modules m_frame->SpreadFootprints( &newFootprints, false, false, m_frame->GetCrossHairPosition() ); if( !newFootprints.empty() ) @@ -117,30 +94,33 @@ void DIALOG_UPDATE_PCB::PerformUpdate( bool aDryRun ) { toolManager->RunAction( COMMON_ACTIONS::selectItem, true, footprint ); } + toolManager->InvokeTool( "pcbnew.InteractiveEdit" ); } } - m_btnPerformUpdate->Enable( false ); m_btnPerformUpdate->SetLabel( _( "Update complete" ) ); - m_btnCancel->SetLabel ( _("Close") ); + m_btnCancel->SetLabel( _( "Close" ) ); m_btnCancel->SetFocus(); } + void DIALOG_UPDATE_PCB::OnMatchChange( wxCommandEvent& event ) { PerformUpdate( true ); } + void DIALOG_UPDATE_PCB::OnCancelClick( wxCommandEvent& event ) { EndModal( wxID_CANCEL ); } + void DIALOG_UPDATE_PCB::OnUpdateClick( wxCommandEvent& event ) { - m_messagePanel->SetLabel( _("Changes applied to the PCB:") ); + m_messagePanel->SetLabel( _( "Changes applied to the PCB:" ) ); PerformUpdate( false ); - m_btnCancel->SetFocus( ); + m_btnCancel->SetFocus(); } diff --git a/pcbnew/dimension.cpp b/pcbnew/dimension.cpp index 1cf4e5c23d..28f3c91480 100644 --- a/pcbnew/dimension.cpp +++ b/pcbnew/dimension.cpp @@ -37,6 +37,7 @@ #include #include #include +#include #include #include @@ -161,6 +162,8 @@ DIALOG_DIMENSION_EDITOR::DIALOG_DIMENSION_EDITOR( PCB_EDIT_FRAME* aParent, void DIALOG_DIMENSION_EDITOR::OnOKClick( wxCommandEvent& event ) { + BOARD_COMMIT commit( m_parent ); + LAYER_ID newlayer = ToLAYER_ID( m_SelLayerBox->GetLayerSelection() ); if( !m_parent->GetBoard()->IsLayerEnabled( newlayer ) ) @@ -177,7 +180,7 @@ void DIALOG_DIMENSION_EDITOR::OnOKClick( wxCommandEvent& event ) } #endif - m_parent->SaveCopyInUndoList(m_currentDimension, UR_CHANGED); + commit.Modify( m_currentDimension ); if( m_Name->GetValue() != wxEmptyString ) { @@ -228,7 +231,7 @@ void DIALOG_DIMENSION_EDITOR::OnOKClick( wxCommandEvent& event ) m_parent->Refresh(); #endif - m_parent->OnModify(); + commit.Push( _( "Modifed dimensions properties" ) ); event.Skip(); // ends returning wxID_OK (default behavior) } diff --git a/pcbnew/eagle_plugin.cpp b/pcbnew/eagle_plugin.cpp index 8e51b5763c..55f6108cba 100644 --- a/pcbnew/eagle_plugin.cpp +++ b/pcbnew/eagle_plugin.cpp @@ -2622,7 +2622,7 @@ void EAGLE_PLUGIN::loadSignals( CPTREE& aSignals ) const string& nname = net->second.get( ".name" ); wxString netName = FROM_UTF8( nname.c_str() ); - m_board->AppendNet( new NETINFO_ITEM( m_board, netName, netCode ) ); + m_board->Add( new NETINFO_ITEM( m_board, netName, netCode ) ); m_xpath->Value( nname.c_str() ); diff --git a/pcbnew/edgemod.cpp b/pcbnew/edgemod.cpp index 5dc01b5581..f24dc07b99 100644 --- a/pcbnew/edgemod.cpp +++ b/pcbnew/edgemod.cpp @@ -163,7 +163,7 @@ void FOOTPRINT_EDIT_FRAME::Edit_Edge_Width( EDGE_MODULE* aEdge ) { MODULE* module = GetBoard()->m_Modules; - SaveCopyInUndoList( module, UR_MODEDIT ); + SaveCopyInUndoList( module, UR_CHANGED ); if( aEdge == NULL ) { @@ -225,7 +225,7 @@ void FOOTPRINT_EDIT_FRAME::Edit_Edge_Layer( EDGE_MODULE* aEdge ) if( aEdge && (aEdge->GetLayer() != new_layer) ) { if( ! modified ) // save only once - SaveCopyInUndoList( module, UR_MODEDIT ); + SaveCopyInUndoList( module, UR_CHANGED ); aEdge->SetLayer( new_layer ); modified = true; } @@ -233,7 +233,7 @@ void FOOTPRINT_EDIT_FRAME::Edit_Edge_Layer( EDGE_MODULE* aEdge ) } else if( aEdge->GetLayer() != new_layer ) { - SaveCopyInUndoList( module, UR_MODEDIT ); + SaveCopyInUndoList( module, UR_CHANGED ); aEdge->SetLayer( new_layer ); modified = true; } @@ -330,7 +330,7 @@ EDGE_MODULE* FOOTPRINT_EDIT_FRAME::Begin_Edge_Module( EDGE_MODULE* aEdge, if( aEdge == NULL ) // Start a new edge item { - SaveCopyInUndoList( module, UR_MODEDIT ); + SaveCopyInUndoList( module, UR_CHANGED ); aEdge = new EDGE_MODULE( module ); MoveVector.x = MoveVector.y = 0; diff --git a/pcbnew/edit_pcb_text.cpp b/pcbnew/edit_pcb_text.cpp index 0115be3a19..c9c11e5e7e 100644 --- a/pcbnew/edit_pcb_text.cpp +++ b/pcbnew/edit_pcb_text.cpp @@ -136,7 +136,7 @@ void PCB_EDIT_FRAME::StartMoveTextePcb( TEXTE_PCB* aTextePcb, wxDC* aDC, bool aE // if it is an existing item: prepare a copy to undo/abort command if( !aTextePcb->IsNew() ) - s_TextCopy.Copy( aTextePcb ); + s_TextCopy = *aTextePcb; aTextePcb->SetFlags( IS_MOVED ); SetMsgPanel( aTextePcb ); @@ -192,7 +192,7 @@ TEXTE_PCB* PCB_EDIT_FRAME::CreateTextePcb( wxDC* aDC, TEXTE_PCB* aText ) if( aText ) { - textePcb->Copy( aText ); + *textePcb = *aText; GetBoard()->Add( textePcb ); textePcb->SetFlags( IS_NEW ); if( aDC ) diff --git a/pcbnew/edtxtmod.cpp b/pcbnew/edtxtmod.cpp index 733183f96d..07372bf50e 100644 --- a/pcbnew/edtxtmod.cpp +++ b/pcbnew/edtxtmod.cpp @@ -243,7 +243,7 @@ void PCB_BASE_FRAME::PlaceTexteModule( TEXTE_MODULE* Text, wxDC* DC ) if( IsType( FRAME_PCB ) ) SaveCopyInUndoList( Module, UR_CHANGED ); else - SaveCopyInUndoList( Module, UR_MODEDIT ); + SaveCopyInUndoList( Module, UR_CHANGED ); Text->SetOrientation( tmp ); diff --git a/pcbnew/import_dxf/dialog_dxf_import.cpp b/pcbnew/import_dxf/dialog_dxf_import.cpp index 76d84c4d83..ff07ed5d86 100644 --- a/pcbnew/import_dxf/dialog_dxf_import.cpp +++ b/pcbnew/import_dxf/dialog_dxf_import.cpp @@ -245,7 +245,7 @@ bool InvokeDXFDialogModuleImport( PCB_BASE_FRAME* aCaller, MODULE* aModule ) { const std::list& list = dlg.GetImportedItems(); - aCaller->SaveCopyInUndoList( aModule, UR_MODEDIT ); + aCaller->SaveCopyInUndoList( aModule, UR_CHANGED ); aCaller->OnModify(); std::list::const_iterator it, itEnd; @@ -264,7 +264,6 @@ bool InvokeDXFDialogModuleImport( PCB_BASE_FRAME* aCaller, MODULE* aModule ) converted = new EDGE_MODULE( aModule ); *static_cast( converted ) = *static_cast( item ); aModule->Add( converted ); - static_cast( converted )->SetLocalCoord(); delete item; break; } @@ -274,7 +273,6 @@ bool InvokeDXFDialogModuleImport( PCB_BASE_FRAME* aCaller, MODULE* aModule ) converted = new TEXTE_MODULE( aModule ); *static_cast( converted ) = *static_cast( item ); aModule->Add( converted ); - static_cast( converted )->SetLocalCoord(); delete item; break; } diff --git a/pcbnew/legacy_plugin.cpp b/pcbnew/legacy_plugin.cpp index d5a0988c21..bc8f23c7ef 100644 --- a/pcbnew/legacy_plugin.cpp +++ b/pcbnew/legacy_plugin.cpp @@ -2080,7 +2080,7 @@ void LEGACY_PLUGIN::loadNETINFO_ITEM() // if it is not the net 0, or if the net 0 does not exists. if( net && ( net->GetNet() > 0 || m_board->FindNet( 0 ) == NULL ) ) { - m_board->AppendNet( net ); + m_board->Add( net ); // Be sure we have room to store the net in m_netCodes if( (int)m_netCodes.size() <= netCode ) diff --git a/pcbnew/modedit.cpp b/pcbnew/modedit.cpp index cf0d77ee25..c4db2911f8 100644 --- a/pcbnew/modedit.cpp +++ b/pcbnew/modedit.cpp @@ -40,6 +40,7 @@ #include #include #include +#include #include #include @@ -436,66 +437,42 @@ void FOOTPRINT_EDIT_FRAME::Process_Special_Functions( wxCommandEvent& event ) } m_toolManager->RunAction( COMMON_ACTIONS::selectionClear, true ); + pcbframe->GetToolManager()->RunAction( COMMON_ACTIONS::selectionClear, true ); + BOARD_COMMIT commit( pcbframe ); // Create the "new" module MODULE* newmodule = new MODULE( *module_in_edit ); newmodule->SetParent( mainpcb ); newmodule->SetLink( 0 ); - // Put the footprint in the main pcb linked list. - mainpcb->Add( newmodule ); - if( source_module ) // this is an update command { // In the main board, // the new module replace the old module (pos, orient, ref, value // and connexions are kept) // and the source_module (old module) is deleted - PICKED_ITEMS_LIST pickList; - - if( pcbframe->IsGalCanvasActive() ) - { - KIGFX::VIEW* view = pcbframe->GetGalCanvas()->GetView(); - source_module->RunOnChildren( std::bind( &KIGFX::VIEW::Remove, view, - std::placeholders::_1 ) ); - view->Remove( source_module ); - } - - pcbframe->Exchange_Module( source_module, newmodule, &pickList ); + pcbframe->Exchange_Module( source_module, newmodule, commit ); newmodule->SetTimeStamp( module_in_edit->GetLink() ); - - if( pickList.GetCount() ) - pcbframe->SaveCopyInUndoList( pickList, UR_UNSPECIFIED ); + commit.Push( wxT( "Update module" ) ); } else // This is an insert command { wxPoint cursor_pos = pcbframe->GetCrossHairPosition(); + commit.Add( newmodule ); pcbframe->SetCrossHairPosition( wxPoint( 0, 0 ) ); pcbframe->PlaceModule( newmodule, NULL ); newmodule->SetPosition( wxPoint( 0, 0 ) ); pcbframe->SetCrossHairPosition( cursor_pos ); newmodule->SetTimeStamp( GetNewTimeStamp() ); - pcbframe->SaveCopyInUndoList( newmodule, UR_NEW ); + commit.Push( wxT( "Insert module" ) ); } newmodule->ClearFlags(); GetScreen()->ClrModify(); pcbframe->SetCurItem( NULL ); + // @todo LEGACY should be unnecessary mainpcb->m_Status_Pcb = 0; - - if( pcbframe->IsGalCanvasActive() ) - { - RN_DATA* ratsnest = pcbframe->GetBoard()->GetRatsnest(); - ratsnest->Update( newmodule ); - ratsnest->Recalculate(); - - KIGFX::VIEW* view = pcbframe->GetGalCanvas()->GetView(); - newmodule->RunOnChildren( std::bind( &KIGFX::VIEW::Add, view, - std::placeholders::_1 ) ); - view->Add( newmodule ); - pcbframe->GetGalCanvas()->ForceRefresh(); - } } break; @@ -651,7 +628,7 @@ void FOOTPRINT_EDIT_FRAME::Process_Special_Functions( wxCommandEvent& event ) break; case ID_POPUP_PCB_DELETE_PAD: - SaveCopyInUndoList( GetBoard()->m_Modules, UR_MODEDIT ); + SaveCopyInUndoList( GetBoard()->m_Modules, UR_CHANGED ); DeletePad( (D_PAD*) GetScreen()->GetCurItem(), false ); SetCurItem( NULL ); m_canvas->MoveCursorToCrossHair(); @@ -674,13 +651,13 @@ void FOOTPRINT_EDIT_FRAME::Process_Special_Functions( wxCommandEvent& event ) break; case ID_POPUP_PCB_IMPORT_PAD_SETTINGS: - SaveCopyInUndoList( GetBoard()->m_Modules, UR_MODEDIT ); + SaveCopyInUndoList( GetBoard()->m_Modules, UR_CHANGED ); m_canvas->MoveCursorToCrossHair(); Import_Pad_Settings( (D_PAD*) GetScreen()->GetCurItem(), true ); break; case ID_POPUP_PCB_GLOBAL_IMPORT_PAD_SETTINGS: - SaveCopyInUndoList( GetBoard()->m_Modules, UR_MODEDIT ); + SaveCopyInUndoList( GetBoard()->m_Modules, UR_CHANGED ); // Calls the global change dialog: DlgGlobalChange_PadSettings( (D_PAD*) GetScreen()->GetCurItem() ); m_canvas->MoveCursorToCrossHair(); @@ -707,7 +684,7 @@ void FOOTPRINT_EDIT_FRAME::Process_Special_Functions( wxCommandEvent& event ) break; case ID_POPUP_PCB_DELETE_TEXTMODULE: - SaveCopyInUndoList( GetBoard()->m_Modules, UR_MODEDIT ); + SaveCopyInUndoList( GetBoard()->m_Modules, UR_CHANGED ); DeleteTextModule( static_cast( GetScreen()->GetCurItem() ) ); SetCurItem( NULL ); m_canvas->MoveCursorToCrossHair(); @@ -765,7 +742,7 @@ void FOOTPRINT_EDIT_FRAME::Process_Special_Functions( wxCommandEvent& event ) break; case ID_POPUP_PCB_DELETE_EDGE: - SaveCopyInUndoList( GetBoard()->m_Modules, UR_MODEDIT ); + SaveCopyInUndoList( GetBoard()->m_Modules, UR_CHANGED ); m_canvas->MoveCursorToCrossHair(); RemoveStruct( GetScreen()->GetCurItem() ); SetCurItem( NULL ); @@ -774,7 +751,7 @@ void FOOTPRINT_EDIT_FRAME::Process_Special_Functions( wxCommandEvent& event ) case ID_MODEDIT_MODULE_ROTATE: case ID_MODEDIT_MODULE_MIRROR: case ID_MODEDIT_MODULE_MOVE_EXACT: - SaveCopyInUndoList( GetBoard()->m_Modules, UR_MODEDIT ); + SaveCopyInUndoList( GetBoard()->m_Modules, UR_CHANGED ); Transform( (MODULE*) GetScreen()->GetCurItem(), id ); m_canvas->Refresh(); break; @@ -870,7 +847,7 @@ void FOOTPRINT_EDIT_FRAME::moveExact() if( ret == wxID_OK ) { - SaveCopyInUndoList( GetBoard()->m_Modules, UR_MODEDIT ); + SaveCopyInUndoList( GetBoard()->m_Modules, UR_CHANGED ); BOARD_ITEM* item = GetScreen()->GetCurItem(); diff --git a/pcbnew/modedit_onclick.cpp b/pcbnew/modedit_onclick.cpp index 6df77a19e9..97c1c090a5 100644 --- a/pcbnew/modedit_onclick.cpp +++ b/pcbnew/modedit_onclick.cpp @@ -61,7 +61,7 @@ void FOOTPRINT_EDIT_FRAME::OnLeftClick( wxDC* DC, const wxPoint& MousePos ) break; case PCB_MODULE_EDGE_T: - SaveCopyInUndoList( GetBoard()->m_Modules, UR_MODEDIT ); + SaveCopyInUndoList( GetBoard()->m_Modules, UR_CHANGED ); Place_EdgeMod( static_cast( item ) ); break; @@ -147,7 +147,7 @@ void FOOTPRINT_EDIT_FRAME::OnLeftClick( wxDC* DC, const wxPoint& MousePos ) if( item && item->Type() != PCB_MODULE_T ) // Cannot delete the module itself { - SaveCopyInUndoList( GetBoard()->m_Modules, UR_MODEDIT ); + SaveCopyInUndoList( GetBoard()->m_Modules, UR_CHANGED ); RemoveStruct( item ); SetCurItem( NULL ); } @@ -162,7 +162,7 @@ void FOOTPRINT_EDIT_FRAME::OnLeftClick( wxDC* DC, const wxPoint& MousePos ) || (module->GetFlags() != 0) ) break; - SaveCopyInUndoList( module, UR_MODEDIT ); + SaveCopyInUndoList( module, UR_CHANGED ); // set the new relative internal local coordinates of footprint items wxPoint moveVector = module->GetPosition() - GetCrossHairPosition(); @@ -187,14 +187,14 @@ void FOOTPRINT_EDIT_FRAME::OnLeftClick( wxDC* DC, const wxPoint& MousePos ) if( GetBoard()->m_Modules == NULL ) break; - SaveCopyInUndoList( GetBoard()->m_Modules, UR_MODEDIT ); + SaveCopyInUndoList( GetBoard()->m_Modules, UR_CHANGED ); CreateTextModule( GetBoard()->m_Modules, DC ); break; case ID_MODEDIT_PAD_TOOL: if( GetBoard()->m_Modules ) { - SaveCopyInUndoList( GetBoard()->m_Modules, UR_MODEDIT ); + SaveCopyInUndoList( GetBoard()->m_Modules, UR_CHANGED ); AddPad( GetBoard()->m_Modules, true ); } diff --git a/pcbnew/modedit_undo_redo.cpp b/pcbnew/modedit_undo_redo.cpp deleted file mode 100644 index 08b8674fdd..0000000000 --- a/pcbnew/modedit_undo_redo.cpp +++ /dev/null @@ -1,176 +0,0 @@ -/* - * This program source code file is part of KiCad, a free EDA CAD application. - * - * Copyright (C) 2007-2014 Jean-Pierre Charras, jp.charras at wanadoo.fr - * Copyright (C) 1992-2012 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 -using namespace std::placeholders; - -#include -#include -#include -#include -#include - -#include -#include - -#include -#include -#include - - -void FOOTPRINT_EDIT_FRAME::SaveCopyInUndoList( BOARD_ITEM* aItem, - UNDO_REDO_T aTypeCommand, - const wxPoint& aTransformPoint ) -{ - EDA_ITEM* item; - MODULE* CopyItem; - PICKED_ITEMS_LIST* lastcmd; - - CopyItem = new MODULE( *( (MODULE*) aItem ) ); - CopyItem->SetParent( GetBoard() ); - - lastcmd = new PICKED_ITEMS_LIST(); - ITEM_PICKER wrapper( CopyItem, UR_MODEDIT ); - lastcmd->PushItem( wrapper ); - - GetScreen()->PushCommandToUndoList( lastcmd ); - - /* Clear current flags (which can be temporary set by a current edit command) */ - for( item = CopyItem->GraphicalItems(); item != NULL; item = item->Next() ) - item->ClearFlags(); - - for( D_PAD* pad = CopyItem->Pads(); pad; pad = pad->Next() ) - pad->ClearFlags(); - - CopyItem->Reference().ClearFlags(); - CopyItem->Value().ClearFlags(); - - /* Clear redo list, because after new save there is no redo to do */ - GetScreen()->ClearUndoORRedoList( GetScreen()->m_RedoList ); -} - - -void FOOTPRINT_EDIT_FRAME::SaveCopyInUndoList( const PICKED_ITEMS_LIST& aItemsList, - UNDO_REDO_T aTypeCommand, - const wxPoint& aTransformPoint ) -{ - assert( aItemsList.GetPickedItem( 0 )->GetParent()->Type() == PCB_MODULE_T ); - MODULE* owner = static_cast( aItemsList.GetPickedItem( 0 )->GetParent() ); - -#ifndef NDEBUG - // All items should have the same parent (MODULE) to make undo/redo entry valid - for( unsigned int i = 0; i < aItemsList.GetCount(); ++i ) - assert( aItemsList.GetPickedItem( i )->GetParent() == owner ); -#endif /* not NDEBUG */ - - SaveCopyInUndoList( owner, aTypeCommand, aTransformPoint ); -} - - -void FOOTPRINT_EDIT_FRAME::RestoreCopyFromRedoList( wxCommandEvent& aEvent ) -{ - if( GetScreen()->GetRedoCommandCount() <= 0 ) - return; - - // Inform tools that undo command was issued - TOOL_EVENT event( TC_MESSAGE, TA_UNDO_REDO, AS_GLOBAL ); - m_toolManager->ProcessEvent( event ); - - // Save current module state in undo list - PICKED_ITEMS_LIST* lastcmd = new PICKED_ITEMS_LIST(); - MODULE* module = GetBoard()->m_Modules.PopFront(); - ITEM_PICKER wrapper( module, UR_MODEDIT ); - KIGFX::VIEW* view = GetGalCanvas()->GetView(); - lastcmd->PushItem( wrapper ); - GetScreen()->PushCommandToUndoList( lastcmd ); - - view->Remove( module ); - module->RunOnChildren( std::bind( &KIGFX::VIEW::Remove, view, _1 ) ); - - // Retrieve last module state from undo list - lastcmd = GetScreen()->PopCommandFromRedoList(); - wrapper = lastcmd->PopItem(); - module = (MODULE*) wrapper.GetItem(); - delete lastcmd; - - if( module ) - { - GetBoard()->Add( module ); - GetGalCanvas()->GetView()->Add( module ); - module->RunOnChildren( std::bind( &KIGFX::VIEW::Add, view, _1 ) ); - module->ViewUpdate(); - } - - SetCurItem( NULL ); - - OnModify(); - m_canvas->Refresh(); -} - - -void FOOTPRINT_EDIT_FRAME::RestoreCopyFromUndoList( wxCommandEvent& aEvent ) -{ - if( UndoRedoBlocked() ) - return; - - if( GetScreen()->GetUndoCommandCount() <= 0 ) - return; - - // Inform tools that undo command was issued - TOOL_EVENT event( TC_MESSAGE, TA_UNDO_REDO, AS_GLOBAL ); - m_toolManager->ProcessEvent( event ); - - if( UndoRedoBlocked() ) - return; - - // Save current module state in redo list - PICKED_ITEMS_LIST* lastcmd = new PICKED_ITEMS_LIST(); - MODULE* module = GetBoard()->m_Modules.PopFront(); - ITEM_PICKER wrapper( module, UR_MODEDIT ); - KIGFX::VIEW* view = GetGalCanvas()->GetView(); - lastcmd->PushItem( wrapper ); - GetScreen()->PushCommandToRedoList( lastcmd ); - - view->Remove( module ); - module->RunOnChildren( std::bind( &KIGFX::VIEW::Remove, view, _1 ) ); - - // Retrieve last module state from undo list - lastcmd = GetScreen()->PopCommandFromUndoList(); - wrapper = lastcmd->PopItem(); - module = (MODULE*) wrapper.GetItem(); - delete lastcmd; - - if( module ) - { - GetBoard()->Add( module, ADD_APPEND ); - view->Add( module ); - module->RunOnChildren( std::bind( &KIGFX::VIEW::Add, view, _1 ) ); - module->ViewUpdate(); - } - - SetCurItem( NULL ); - - OnModify(); - m_canvas->Refresh(); -} diff --git a/pcbnew/module_editor_frame.h b/pcbnew/module_editor_frame.h index 9d81f4876c..fb1a7ac799 100644 --- a/pcbnew/module_editor_frame.h +++ b/pcbnew/module_editor_frame.h @@ -54,6 +54,9 @@ public: */ static const wxChar* GetFootprintEditorFrameName(); + ///> @copydoc PCB_BASE_FRAME::GetModel() + BOARD_ITEM_CONTAINER* GetModel() const override; + BOARD_DESIGN_SETTINGS& GetDesignSettings() const; // overload PCB_BASE_FRAME, get parent's void SetDesignSettings( const BOARD_DESIGN_SETTINGS& aSettings ); // overload @@ -267,50 +270,6 @@ public: BOARD_ITEM* ModeditLocateAndDisplay( int aHotKeyCode = 0 ); - /* Undo and redo functions */ - - /** - * Function SaveCopyInUndoList. - * Creates a new entry in undo list of commands. - * add a picker to handle aItemToCopy - * @param aItem = the board item modified by the command to undo - * @param aTypeCommand = command type (see enum UNDO_REDO_T) - * @param aTransformPoint = the reference point of the transformation, for - * commands like move - */ - virtual void SaveCopyInUndoList( BOARD_ITEM* aItem, - UNDO_REDO_T aTypeCommand, - const wxPoint& aTransformPoint = wxPoint( 0, 0 ) ); - - /** - * Function SaveCopyInUndoList (overloaded). - * Creates a new entry in undo list of commands. - * add a list of pickers to handle a list of items - * @param aItemsList = the list of items modified by the command to undo - * @param aTypeCommand = command type (see enum UNDO_REDO_T) - * @param aTransformPoint = the reference point of the transformation, for - * commands like move - */ - virtual void SaveCopyInUndoList( const PICKED_ITEMS_LIST& aItemsList, - UNDO_REDO_T aTypeCommand, - const wxPoint& aTransformPoint = wxPoint( 0, 0 ) ); - - /** - * Function RestoreCopyFromUndoList - * performs an undo operation on the last edition: - * - Place the current edited library component in Redo list - * - Get old version of the current edited library component - */ - void RestoreCopyFromUndoList( wxCommandEvent& aEvent ); - - /** - * Function RestoreCopyFromRedoList - * performs a redo operation on the the last edition: - * - Place the current edited library component in undo list - * - Get old version of the current edited library component - */ - void RestoreCopyFromRedoList( wxCommandEvent& aEvent ); - /// Return the current library nickname. const wxString GetCurrentLib() const; diff --git a/pcbnew/moduleframe.cpp b/pcbnew/moduleframe.cpp index 932e1a2ad5..055fac4049 100644 --- a/pcbnew/moduleframe.cpp +++ b/pcbnew/moduleframe.cpp @@ -350,6 +350,12 @@ FOOTPRINT_EDIT_FRAME::~FOOTPRINT_EDIT_FRAME() } +BOARD_ITEM_CONTAINER* FOOTPRINT_EDIT_FRAME::GetModel() const +{ + return GetBoard()->m_Modules; +} + + const wxString FOOTPRINT_EDIT_FRAME::getLibPath() { try @@ -948,13 +954,12 @@ void FOOTPRINT_EDIT_FRAME::setupTools() m_toolManager->RegisterTool( new PLACEMENT_TOOL ); m_toolManager->RegisterTool( new PICKER_TOOL ); - m_toolManager->GetTool()->EditModules( true ); - m_toolManager->GetTool()->EditModules( true ); - m_toolManager->GetTool()->EditModules( true ); + m_toolManager->GetTool()->SetEditModules( true ); + m_toolManager->GetTool()->SetEditModules( true ); + m_toolManager->GetTool()->SetEditModules( true ); m_toolManager->ResetTools( TOOL_BASE::RUN ); m_toolManager->InvokeTool( "pcbnew.InteractiveSelection" ); - } diff --git a/pcbnew/pad_edition_functions.cpp b/pcbnew/pad_edition_functions.cpp index a892f92354..49ced41c22 100644 --- a/pcbnew/pad_edition_functions.cpp +++ b/pcbnew/pad_edition_functions.cpp @@ -52,7 +52,7 @@ void PCB_BASE_FRAME::Export_Pad_Settings( D_PAD* aPad ) D_PAD& mp = GetDesignSettings().m_Pad_Master; // Copy all settings. Some of them are not used, but they break anything - mp.Copy( aPad ); + mp = *aPad; // The pad orientation, for historical reasons is the // pad rotation + parent rotation. // store only the pad rotation. diff --git a/pcbnew/pcad2kicadpcb_plugin/pcb.cpp b/pcbnew/pcad2kicadpcb_plugin/pcb.cpp index feedb83135..1b27a8f725 100644 --- a/pcbnew/pcad2kicadpcb_plugin/pcb.cpp +++ b/pcbnew/pcad2kicadpcb_plugin/pcb.cpp @@ -925,7 +925,7 @@ void PCB::AddToBoard() { net = m_pcbNetlist[i]; - m_board->AppendNet( new NETINFO_ITEM( m_board, net->m_name, net->m_netCode ) ); + m_board->Add( new NETINFO_ITEM( m_board, net->m_name, net->m_netCode ) ); } for( i = 0; i < (int) m_pcbComponents.GetCount(); i++ ) diff --git a/pcbnew/pcad2kicadpcb_plugin/pcb_pad.cpp b/pcbnew/pcad2kicadpcb_plugin/pcb_pad.cpp index f1e9b91723..716a7cf9bb 100644 --- a/pcbnew/pcad2kicadpcb_plugin/pcb_pad.cpp +++ b/pcbnew/pcad2kicadpcb_plugin/pcb_pad.cpp @@ -278,7 +278,7 @@ void PCB_PAD::AddToModule( MODULE* aModule, int aRotation, bool aEncapsulatedPad { // It is a new net netinfo = new NETINFO_ITEM( m_board, m_net ); - m_board->AppendNet( netinfo ); + m_board->Add( netinfo ); } pad->SetNetCode( netinfo->GetNet() ); diff --git a/pcbnew/pcb_base_edit_frame.h b/pcbnew/pcb_base_edit_frame.h index d9cc1cbd6a..7fb313b5fa 100644 --- a/pcbnew/pcb_base_edit_frame.h +++ b/pcbnew/pcb_base_edit_frame.h @@ -27,6 +27,8 @@ #include +class BOARD_ITEM_CONTAINER; + /** * Common, abstract interface for edit frames. */ @@ -42,6 +44,12 @@ public: virtual ~PCB_BASE_EDIT_FRAME() {}; + /** + * Function GetModel() + * returns the primary data model. + */ + virtual BOARD_ITEM_CONTAINER* GetModel() const = 0; + /** * Function CreateNewLibrary * prompts user for a library path, then creates a new footprint library at that @@ -61,26 +69,62 @@ public: */ virtual void OnEditItemRequest( wxDC* aDC, BOARD_ITEM* aItem ) = 0; + // Undo buffer handling + + /** + * Function SaveCopyInUndoList + * Creates a new entry in undo list of commands. + * add a picker to handle aItemToCopy + * @param aItemToCopy = the board item modified by the command to undo + * @param aTypeCommand = command type (see enum UNDO_REDO_T) + * @param aTransformPoint = the reference point of the transformation, for + * commands like move + */ + void SaveCopyInUndoList( BOARD_ITEM* aItemToCopy, UNDO_REDO_T aTypeCommand, + const wxPoint& aTransformPoint = wxPoint( 0, 0 ) ) override; + + /** + * Function SaveCopyInUndoList + * Creates a new entry in undo list of commands. + * add a list of pickers to handle a list of items + * @param aItemsList = the list of items modified by the command to undo + * @param aTypeCommand = command type (see enum UNDO_REDO_T) + * @param aTransformPoint = the reference point of the transformation, + * for commands like move + */ + void SaveCopyInUndoList( const PICKED_ITEMS_LIST& aItemsList, UNDO_REDO_T aTypeCommand, + const wxPoint& aTransformPoint = wxPoint( 0, 0 ) ) override; /** * Function RestoreCopyFromRedoList * Redo the last edition: - * - Save the current data in Undo list - * - Get an old version of the data from Redo list + * - Save the current board in Undo list + * - Get an old version of the board from Redo list + * @return none */ - virtual void RestoreCopyFromRedoList( wxCommandEvent& aEvent ) = 0; + void RestoreCopyFromRedoList( wxCommandEvent& aEvent ); /** * Function RestoreCopyFromUndoList * Undo the last edition: * - Save the current board in Redo list - * - Get an old version of the data from Undo list + * - Get an old version of the board from Undo list + * @return none */ - virtual void RestoreCopyFromUndoList( wxCommandEvent& aEvent ) = 0; + void RestoreCopyFromUndoList( wxCommandEvent& aEvent ); - int GetRotationAngle() const { return m_rotationAngle; } - void SetRotationAngle( int aRotationAngle ); - - bool PostCommandMenuEvent( int evt_type ); + /** + * Function PutDataInPreviousState + * Used in undo or redo command. + * Put data pointed by List in the previous state, i.e. the state memorized by List + * @param aList = a PICKED_ITEMS_LIST pointer to the list of items to undo/redo + * @param aRedoCommand = a bool: true for redo, false for undo + * @param aRebuildRatsnet = a bool: true to rebuild ratsnest (normal use), false + * to just retrieve last state (used in abort commands that do not need to + * rebuild ratsnest) + */ + void PutDataInPreviousState( PICKED_ITEMS_LIST* aList, + bool aRedoCommand, + bool aRebuildRatsnet = true ); /** * Function UndoRedoBlocked @@ -100,6 +144,20 @@ public: m_undoRedoBlocked = aBlock; } + /** + * Function GetRotationAngle() + * Returns the angle used for rotate operations. + */ + int GetRotationAngle() const { return m_rotationAngle; } + + /** + * Function SetRotationAngle() + * Sets the angle used for rotate operations. + */ + void SetRotationAngle( int aRotationAngle ); + + bool PostCommandMenuEvent( int evt_type ); + ///> @copydoc EDA_DRAW_FRAME::UseGalCanvas() void UseGalCanvas( bool aEnable ); diff --git a/pcbnew/pcb_parser.cpp b/pcbnew/pcb_parser.cpp index e6413c878d..228cbe9913 100644 --- a/pcbnew/pcb_parser.cpp +++ b/pcbnew/pcb_parser.cpp @@ -1242,10 +1242,10 @@ void PCB_PARSER::parseNETINFO_ITEM() throw( IO_ERROR, PARSE_ERROR ) // net 0 should be already in list, so store this net // if it is not the net 0, or if the net 0 does not exists. // (TODO: a better test.) - if( netCode > 0 || m_board->FindNet( 0 ) == NULL ) + if( netCode > NETINFO_LIST::UNCONNECTED || !m_board->FindNet( NETINFO_LIST::UNCONNECTED ) ) { NETINFO_ITEM* net = new NETINFO_ITEM( m_board, name, netCode ); - m_board->AppendNet( net ); + m_board->Add( net ); // Store the new code mapping pushValueIntoMap( netCode, net->GetNet() ); @@ -2988,7 +2988,7 @@ ZONE_CONTAINER* PCB_PARSER::parseZONE_CONTAINER() throw( IO_ERROR, PARSE_ERROR ) { int newnetcode = m_board->GetNetCount(); net = new NETINFO_ITEM( m_board, netnameFromfile, newnetcode ); - m_board->AppendNet( net ); + m_board->Add( net ); // Store the new code mapping pushValueIntoMap( newnetcode, net->GetNet() ); diff --git a/pcbnew/pcbframe.cpp b/pcbnew/pcbframe.cpp index 89405495c6..df6f0bd4c0 100644 --- a/pcbnew/pcbframe.cpp +++ b/pcbnew/pcbframe.cpp @@ -196,8 +196,8 @@ BEGIN_EVENT_TABLE( PCB_EDIT_FRAME, PCB_BASE_FRAME ) EVT_TOOL( wxID_CUT, PCB_EDIT_FRAME::Process_Special_Functions ) EVT_TOOL( wxID_COPY, PCB_EDIT_FRAME::Process_Special_Functions ) EVT_TOOL( wxID_PASTE, PCB_EDIT_FRAME::Process_Special_Functions ) - EVT_TOOL( wxID_UNDO, PCB_EDIT_FRAME::RestoreCopyFromUndoList ) - EVT_TOOL( wxID_REDO, PCB_EDIT_FRAME::RestoreCopyFromRedoList ) + EVT_TOOL( wxID_UNDO, PCB_BASE_EDIT_FRAME::RestoreCopyFromUndoList ) + EVT_TOOL( wxID_REDO, PCB_BASE_EDIT_FRAME::RestoreCopyFromRedoList ) EVT_TOOL( wxID_PRINT, PCB_EDIT_FRAME::ToPrinter ) EVT_TOOL( ID_GEN_PLOT_SVG, PCB_EDIT_FRAME::SVG_Print ) EVT_TOOL( ID_GEN_PLOT, PCB_EDIT_FRAME::Process_Special_Functions ) @@ -481,7 +481,7 @@ void PCB_EDIT_FRAME::SetBoard( BOARD* aBoard ) if( IsGalCanvasActive() ) { - aBoard->GetRatsnest()->Recalculate(); + aBoard->GetRatsnest()->ProcessBoard(); // reload the worksheet SetPageSettings( aBoard->GetPageSettings() ); @@ -489,6 +489,12 @@ void PCB_EDIT_FRAME::SetBoard( BOARD* aBoard ) } +BOARD_ITEM_CONTAINER* PCB_EDIT_FRAME::GetModel() const +{ + return m_Pcb; +} + + void PCB_EDIT_FRAME::SetPageSettings( const PAGE_INFO& aPageSettings ) { PCB_BASE_FRAME::SetPageSettings( aPageSettings ); @@ -667,17 +673,8 @@ void PCB_EDIT_FRAME::Show3D_Frame( wxCommandEvent& event ) void PCB_EDIT_FRAME::UseGalCanvas( bool aEnable ) { - if( aEnable ) - { - BOARD* board = GetBoard(); - - if( board ) - board->GetRatsnest()->ProcessBoard(); - } - else - { + if( !aEnable ) Compile_Ratsnest( NULL, true ); - } PCB_BASE_EDIT_FRAME::UseGalCanvas( aEnable ); diff --git a/pcbnew/ratsnest_data.cpp b/pcbnew/ratsnest_data.cpp index f69557a509..9735814800 100644 --- a/pcbnew/ratsnest_data.cpp +++ b/pcbnew/ratsnest_data.cpp @@ -215,11 +215,11 @@ void RN_NET::validateEdge( RN_EDGE_MST_PTR& aEdge ) // If any of nodes belonging to the edge has the flag set, // change it to the closest node that has flag cleared - if( source->GetFlag() ) + if( source->GetNoLine() ) { valid = false; + std::list closest = GetClosestNodes( source, LINE_TARGET() ); - std::list closest = GetClosestNodes( source, WITHOUT_FLAG() ); for( RN_NODE_PTR& node : closest ) { if( node && node != target ) @@ -230,11 +230,11 @@ void RN_NET::validateEdge( RN_EDGE_MST_PTR& aEdge ) } } - if( target->GetFlag() ) + if( target->GetNoLine() ) { valid = false; + std::list closest = GetClosestNodes( target, LINE_TARGET() ); - std::list closest = GetClosestNodes( target, WITHOUT_FLAG() ); for( RN_NODE_PTR& node : closest ) { if( node && node != source ) @@ -398,7 +398,7 @@ RN_POLY::RN_POLY( const SHAPE_POLY_SET* aParent, // Mark it as not appropriate as a destination of ratsnest edges // (edges coming out from a polygon vertex look weird) - m_node->SetFlag( true ); + m_node->SetNoLine( true ); } @@ -761,7 +761,7 @@ void RN_NET::GetAllItems( std::list& aOutput, RN_ITEM_TYP void RN_NET::ClearSimple() { for( const RN_NODE_PTR& node : m_blockedNodes ) - node->SetFlag( false ); + node->SetNoLine( false ); m_blockedNodes.clear(); m_simpleNodes.clear(); @@ -1033,22 +1033,25 @@ void RN_NET::processPads() } -void RN_DATA::Add( const BOARD_ITEM* aItem ) +bool RN_DATA::Add( const BOARD_ITEM* aItem ) { int net; if( aItem->IsConnected() ) { net = static_cast( aItem )->GetNetCode(); - if( net < 1 ) // do not process unconnected items - return; - if( net >= (int) m_nets.size() ) // Autoresize + if( net < 1 ) // do not process unconnected items + return false; + + // Autoresize is necessary e.g. for module editor + if( net >= (int) m_nets.size() ) m_nets.resize( net + 1 ); } else if( aItem->Type() == PCB_MODULE_T ) { const MODULE* module = static_cast( aItem ); + for( const D_PAD* pad = module->Pads().GetFirst(); pad; pad = pad->Next() ) { net = pad->GetNetCode(); @@ -1056,16 +1059,24 @@ void RN_DATA::Add( const BOARD_ITEM* aItem ) if( net < 1 ) // do not process unconnected items continue; - if( net >= (int) m_nets.size() ) // Autoresize + // Autoresize is necessary e.g. for module editor + if( net >= (int) m_nets.size() ) m_nets.resize( net + 1 ); m_nets[net].AddItem( pad ); } - return; + return true; + } + else if( aItem->Type() == PCB_NETINFO_T ) + { + int netCount = m_board->GetNetCount(); + + if( (unsigned) netCount > m_nets.size() ) + m_nets.resize( netCount ); + + return true; } - else - return; switch( aItem->Type() ) { @@ -1086,12 +1097,15 @@ void RN_DATA::Add( const BOARD_ITEM* aItem ) break; default: + return false; break; } + + return true; } -void RN_DATA::Remove( const BOARD_ITEM* aItem ) +bool RN_DATA::Remove( const BOARD_ITEM* aItem ) { int net; @@ -1100,21 +1114,19 @@ void RN_DATA::Remove( const BOARD_ITEM* aItem ) net = static_cast( aItem )->GetNetCode(); if( net < 1 ) // do not process unconnected items - return; + return false; -#ifdef NDEBUG - if( net >= (int) m_nets.size() ) // Autoresize + // Autoresize is necessary e.g. for module editor + if( net >= (int) m_nets.size() ) { m_nets.resize( net + 1 ); - - return; // if it was resized, then surely the item had not been added before + return false; // if it was resized, then surely the item had not been added before } -#endif - assert( net < (int) m_nets.size() ); } else if( aItem->Type() == PCB_MODULE_T ) { const MODULE* module = static_cast( aItem ); + for( const D_PAD* pad = module->Pads().GetFirst(); pad; pad = pad->Next() ) { net = pad->GetNetCode(); @@ -1122,23 +1134,22 @@ void RN_DATA::Remove( const BOARD_ITEM* aItem ) if( net < 1 ) // do not process unconnected items continue; -#ifdef NDEBUG - if( net >= (int) m_nets.size() ) // Autoresize + // Autoresize is necessary e.g. for module editor + if( net >= (int) m_nets.size() ) { m_nets.resize( net + 1 ); - - return; // if it was resized, then surely the item had not been added before + return false; // if it was resized, then surely the item had not been added before } -#endif - assert( net < (int) m_nets.size() ); m_nets[net].RemoveItem( pad ); } - return; + return true; } else - return; + { + return false; + } switch( aItem->Type() ) { @@ -1159,15 +1170,24 @@ void RN_DATA::Remove( const BOARD_ITEM* aItem ) break; default: + return false; break; } + + return true; } -void RN_DATA::Update( const BOARD_ITEM* aItem ) +bool RN_DATA::Update( const BOARD_ITEM* aItem ) { - Remove( aItem ); - Add( aItem ); + if( Remove( aItem ) ) + { + bool res = Add( aItem ); + assert( res ); + return true; + } + + return false; } @@ -1227,9 +1247,6 @@ void RN_DATA::Recalculate( int aNet ) { unsigned int netCount = m_board->GetNetCount(); - if( netCount > m_nets.size() ) - m_nets.resize( netCount ); - if( aNet < 0 && netCount > 1 ) // Recompute everything { #ifdef PROFILE diff --git a/pcbnew/ratsnest_data.h b/pcbnew/ratsnest_data.h index d272e7903e..71dc17cf90 100644 --- a/pcbnew/ratsnest_data.h +++ b/pcbnew/ratsnest_data.h @@ -92,19 +92,19 @@ struct RN_NODE_FILTER : public std::unary_function RN_NODE_AND_FILTER operator&&( const RN_NODE_FILTER& aFilter1, const RN_NODE_FILTER& aFilter2 ); RN_NODE_OR_FILTER operator||( const RN_NODE_FILTER& aFilter1, const RN_NODE_FILTER& aFilter2 ); -///> Filters out nodes that have the flag set. -struct WITHOUT_FLAG : public RN_NODE_FILTER +///> Filters out nodes that cannot be a ratsnest line target +struct LINE_TARGET : public RN_NODE_FILTER { bool operator()( const RN_NODE_PTR& aNode ) const { - return !aNode->GetFlag(); + return !aNode->GetNoLine(); } }; ///> Filters out nodes with a specific tag -struct DIFFERENT_TAG : public RN_NODE_FILTER +struct DIFF_TAG : public RN_NODE_FILTER { - DIFFERENT_TAG( int aTag ) : + DIFF_TAG( int aTag ) : m_tag( aTag ) {} @@ -515,7 +515,7 @@ public: inline void AddBlockedNode( RN_NODE_PTR& aNode ) { m_blockedNodes.insert( aNode ); - aNode->SetFlag( true ); + aNode->SetNoLine( true ); } /** @@ -647,22 +647,26 @@ public: * Function Add() * Adds an item to the ratsnest data. * @param aItem is an item to be added. + * @return True if operation succeeded. */ - void Add( const BOARD_ITEM* aItem ); + bool Add( const BOARD_ITEM* aItem ); /** * Function Remove() * Removes an item from the ratsnest data. * @param aItem is an item to be updated. + * @return True if operation succeeded. */ - void Remove( const BOARD_ITEM* aItem ); + bool Remove( const BOARD_ITEM* aItem ); /** * Function Update() * Updates the ratsnest data for an item. * @param aItem is an item to be updated. + * @return True if operation succeeded. The item will not be updated if it was not previously + * added to the ratsnest. */ - void Update( const BOARD_ITEM* aItem ); + bool Update( const BOARD_ITEM* aItem ); /** * Function AddSimple() diff --git a/pcbnew/ratsnest_viewitem.cpp b/pcbnew/ratsnest_viewitem.cpp index a2b6c89bbb..9561b2e6c4 100644 --- a/pcbnew/ratsnest_viewitem.cpp +++ b/pcbnew/ratsnest_viewitem.cpp @@ -79,7 +79,7 @@ void RATSNEST_VIEWITEM::ViewDraw( int aLayer, GAL* aGal ) const if( node->GetRefCount() > 1 ) continue; - RN_NODE_PTR dest = net.GetClosestNode( node, WITHOUT_FLAG() ); + RN_NODE_PTR dest = net.GetClosestNode( node, LINE_TARGET() ); if( dest ) { diff --git a/pcbnew/router/length_tuner_tool.cpp b/pcbnew/router/length_tuner_tool.cpp index e7cc8064a2..29f49ecfbf 100644 --- a/pcbnew/router/length_tuner_tool.cpp +++ b/pcbnew/router/length_tuner_tool.cpp @@ -229,8 +229,6 @@ void LENGTH_TUNER_TOOL::performTuning() } m_router->StopRouting(); - m_frame->OnModify(); - highlightNet( false ); } diff --git a/pcbnew/router/pns_kicad_iface.cpp b/pcbnew/router/pns_kicad_iface.cpp index 2069539da7..db8c42580c 100644 --- a/pcbnew/router/pns_kicad_iface.cpp +++ b/pcbnew/router/pns_kicad_iface.cpp @@ -24,6 +24,7 @@ #include #include #include +#include #include #include #include @@ -154,7 +155,7 @@ int PNS_PCBNEW_RULE_RESOLVER::Clearance( const PNS::ITEM* aA, const PNS::ITEM* a int net_b = aB->Net(); int cl_b = ( net_b >= 0 ? m_clearanceCache[net_b].clearance : m_defaultClearance ); - bool linesOnly = aA->OfKind( PNS::ITEM::SEGMENT_T | PNS::ITEM::LINE_T ) + bool linesOnly = aA->OfKind( PNS::ITEM::SEGMENT_T | PNS::ITEM::LINE_T ) && aB->OfKind( PNS::ITEM::SEGMENT_T | PNS::ITEM::LINE_T ); if( linesOnly && net_a >= 0 && net_b >= 0 && m_clearanceCache[net_a].coupledNet == net_b ) @@ -413,11 +414,13 @@ PNS_KICAD_IFACE::PNS_KICAD_IFACE() m_world = nullptr; m_router = nullptr; m_debugDecorator = nullptr; + m_commit = nullptr; } PNS_KICAD_IFACE::~PNS_KICAD_IFACE() { + delete m_commit; delete m_ruleResolver; delete m_debugDecorator; @@ -738,12 +741,11 @@ void PNS_KICAD_IFACE::SyncWorld( PNS::NODE *aWorld ) for( TRACK* t = m_board->m_Track; t; t = t->Next() ) { KICAD_T type = t->Type(); - PNS::ITEM* item = NULL; if( type == PCB_TRACE_T ) { std::unique_ptr< PNS::SEGMENT > segment = syncTrack( t ); if( segment ) { - aWorld->Add( std::move( segment ) ); + aWorld->Add( std::move( segment ) ); } } else if( type == PCB_VIA_T ) { std::unique_ptr< PNS::VIA > via = syncVia( static_cast( t ) ); @@ -821,9 +823,8 @@ void PNS_KICAD_IFACE::RemoveItem( PNS::ITEM* aItem ) if( parent ) { - m_view->Remove( parent ); - m_board->Remove( parent ); - m_undoBuffer.PushItem( ITEM_PICKER( parent, UR_DELETED ) ); + assert( m_commit ); + m_commit->Remove( parent ); } } @@ -871,20 +872,16 @@ void PNS_KICAD_IFACE::AddItem( PNS::ITEM* aItem ) { aItem->SetParent( newBI ); newBI->ClearFlags(); - m_view->Add( newBI ); - m_board->Add( newBI ); - m_undoBuffer.PushItem( ITEM_PICKER( newBI, UR_NEW ) ); - newBI->ViewUpdate( KIGFX::VIEW_ITEM::GEOMETRY ); + + assert( m_commit ); + m_commit->Add( newBI ); } } void PNS_KICAD_IFACE::Commit() { - m_board->GetRatsnest()->Recalculate(); - m_frame->SaveCopyInUndoList( m_undoBuffer, UR_UNSPECIFIED ); - m_undoBuffer.ClearItemsList(); - m_frame->OnModify(); + m_commit->Push( wxT( "Added a track" ) ); } @@ -909,6 +906,7 @@ void PNS_KICAD_IFACE::SetView( KIGFX::VIEW *aView ) m_debugDecorator->SetView( m_view ); } + void PNS_KICAD_IFACE::UpdateNet( int aNetCode ) { wxLogTrace( "PNS", "Update-net %d", aNetCode ); @@ -924,7 +922,11 @@ void PNS_KICAD_IFACE::SetRouter( PNS::ROUTER* aRouter ) m_router = aRouter; } -void PNS_KICAD_IFACE::SetHostFrame( PCB_EDIT_FRAME *aFrame ) + +void PNS_KICAD_IFACE::SetHostFrame( PCB_EDIT_FRAME* aFrame ) { m_frame = aFrame; + + delete m_commit; + m_commit = new BOARD_COMMIT( aFrame ); } diff --git a/pcbnew/router/pns_kicad_iface.h b/pcbnew/router/pns_kicad_iface.h index 3cf6ffb2a8..b59228b296 100644 --- a/pcbnew/router/pns_kicad_iface.h +++ b/pcbnew/router/pns_kicad_iface.h @@ -30,6 +30,7 @@ class PNS_PCBNEW_RULE_RESOLVER; class PNS_PCBNEW_DEBUG_DECORATOR; class BOARD; +class BOARD_COMMIT; namespace KIGFX { class VIEW; @@ -75,6 +76,7 @@ private: BOARD* m_board; PICKED_ITEMS_LIST m_undoBuffer; PCB_EDIT_FRAME* m_frame; + BOARD_COMMIT* m_commit; }; #endif diff --git a/pcbnew/router/pns_router.cpp b/pcbnew/router/pns_router.cpp index 1a72718942..da30f9ac96 100644 --- a/pcbnew/router/pns_router.cpp +++ b/pcbnew/router/pns_router.cpp @@ -277,8 +277,8 @@ void ROUTER::updateView( NODE* aNode, ITEM_SET& aCurrent ) for ( auto item : added ) m_iface->DisplayItem( item ); - for ( auto item : removed ) - m_iface->HideItem ( item ); + for( auto item : removed ) + m_iface->HideItem( item ); } diff --git a/pcbnew/router/pns_router.h b/pcbnew/router/pns_router.h index 66b0e529a4..3f732bc9e7 100644 --- a/pcbnew/router/pns_router.h +++ b/pcbnew/router/pns_router.h @@ -144,7 +144,7 @@ public: void SwitchLayer( int layer ); void ToggleViaPlacement(); - void SetOrthoMode ( bool aEnable ); + void SetOrthoMode( bool aEnable ); int GetCurrentLayer() const; const std::vector GetCurrentNets() const; @@ -211,8 +211,7 @@ public: ITEM* QueryItemByParent( const BOARD_ITEM* aItem ) const; - - void SetFailureReason ( const wxString& aReason ) { m_failureReason = aReason; } + void SetFailureReason( const wxString& aReason ) { m_failureReason = aReason; } const wxString& FailureReason() const { return m_failureReason; } PLACEMENT_ALGO* Placer() { return m_placer.get(); } @@ -270,7 +269,6 @@ private: bool m_violation; ROUTING_SETTINGS m_settings; - ///> Stores list of modified items in the current operation SIZES_SETTINGS m_sizes; ROUTER_MODE m_mode; diff --git a/pcbnew/router/pns_tool_base.cpp b/pcbnew/router/pns_tool_base.cpp index 0e99918a35..f65649f5e5 100644 --- a/pcbnew/router/pns_tool_base.cpp +++ b/pcbnew/router/pns_tool_base.cpp @@ -105,7 +105,6 @@ void TOOL_BASE::Reset( RESET_REASON aReason ) m_board = getModel(); m_iface = new PNS_KICAD_IFACE; - m_iface->SetBoard( m_board ); m_iface->SetView( getView() ); m_iface->SetHostFrame( m_frame ); diff --git a/pcbnew/router/pns_tool_base.h b/pcbnew/router/pns_tool_base.h index ceae7b32b1..fea4c0fb4f 100644 --- a/pcbnew/router/pns_tool_base.h +++ b/pcbnew/router/pns_tool_base.h @@ -23,10 +23,12 @@ #ifndef __PNS_TOOL_BASE_H #define __PNS_TOOL_BASE_H +#include #include #include -#include +#include +#include #include diff --git a/pcbnew/router/router_preview_item.cpp b/pcbnew/router/router_preview_item.cpp index 7e15edac01..239985ef6b 100644 --- a/pcbnew/router/router_preview_item.cpp +++ b/pcbnew/router/router_preview_item.cpp @@ -120,7 +120,6 @@ void ROUTER_PREVIEW_ITEM::Update( const PNS::ITEM* aItem ) m_color = COLOR4D( 0, 1, 0, 1 ); ViewSetVisible( true ); - ViewUpdate( GEOMETRY | APPEARANCE ); } @@ -276,7 +275,6 @@ void ROUTER_PREVIEW_ITEM::Line( const SHAPE_LINE_CHAIN& aLine, int aWidth, int a m_shape = aLine.Clone(); ViewSetVisible( true ); - ViewUpdate( GEOMETRY | APPEARANCE ); } diff --git a/pcbnew/router/router_tool.cpp b/pcbnew/router/router_tool.cpp index 2e62349371..79f71a2205 100644 --- a/pcbnew/router/router_tool.cpp +++ b/pcbnew/router/router_tool.cpp @@ -534,8 +534,6 @@ bool ROUTER_TOOL::finishInteractive() { m_router->StopRouting(); - m_frame->OnModify(); - m_ctls->SetAutoPan( false ); m_ctls->ForceCursorPosition( false ); highlightNet( false ); @@ -740,7 +738,6 @@ int ROUTER_TOOL::mainLoop( PNS::ROUTER_MODE aMode ) void ROUTER_TOOL::performDragging() { - PCB_EDIT_FRAME* frame = getEditFrame(); VIEW_CONTROLS* ctls = getViewControls(); if( m_startItem && m_startItem->IsLocked() ) @@ -759,8 +756,6 @@ void ROUTER_TOOL::performDragging() ctls->SetAutoPan( true ); - bool modified = false; - while( OPT_TOOL_EVENT evt = Wait() ) { ctls->ForceCursorPosition( false ); @@ -775,10 +770,7 @@ void ROUTER_TOOL::performDragging() else if( evt->IsClick( BUT_LEFT ) ) { if( m_router->FixRoute( m_endSnapPoint, m_endItem ) ) - { - modified = true; break; - } } handleCommonEvents( *evt ); @@ -787,9 +779,6 @@ void ROUTER_TOOL::performDragging() if( m_router->RoutingInProgress() ) m_router->StopRouting(); - if( modified ) - frame->OnModify(); - m_startItem = NULL; ctls->SetAutoPan( false ); @@ -829,8 +818,6 @@ int ROUTER_TOOL::InlineDrag( const TOOL_EVENT& aEvent ) ctls->SetAutoPan( true ); frame->UndoRedoBlock( true ); - bool modified = false; - while( OPT_TOOL_EVENT evt = Wait() ) { p0 = ctls->GetCursorPosition(); @@ -845,7 +832,7 @@ int ROUTER_TOOL::InlineDrag( const TOOL_EVENT& aEvent ) } else if( evt->IsMouseUp( BUT_LEFT ) || evt->IsClick( BUT_LEFT ) ) { - modified = m_router->FixRoute( p0, NULL ); + m_router->FixRoute( p0, NULL ); break; } } @@ -853,9 +840,6 @@ int ROUTER_TOOL::InlineDrag( const TOOL_EVENT& aEvent ) if( m_router->RoutingInProgress() ) m_router->StopRouting(); - if( modified ) - frame->OnModify(); - ctls->SetAutoPan( false ); ctls->ShowCursor( false ); frame->UndoRedoBlock( false ); diff --git a/pcbnew/target_edit.cpp b/pcbnew/target_edit.cpp index 77d353db82..4e73ba3500 100644 --- a/pcbnew/target_edit.cpp +++ b/pcbnew/target_edit.cpp @@ -34,6 +34,7 @@ #include #include #include +#include #include #include @@ -128,12 +129,14 @@ void TARGET_PROPERTIES_DIALOG_EDITOR::OnCancelClick( wxCommandEvent& event ) */ void TARGET_PROPERTIES_DIALOG_EDITOR::OnOkClick( wxCommandEvent& event ) { + BOARD_COMMIT commit( m_Parent ); + commit.Modify( m_Target ); + if( m_DC ) m_Target->Draw( m_Parent->GetCanvas(), m_DC, GR_XOR ); // Save old item in undo list, if is is not currently edited (will be later if so) - if( m_Target->GetFlags() == 0 ) - m_Parent->SaveCopyInUndoList( m_Target, UR_CHANGED ); + bool pushCommit = ( m_Target->GetFlags() == 0 ); if( m_Target->GetFlags() != 0 ) // other edition in progress (MOVE, NEW ..) m_Target->SetFlags( IN_EDIT ); // set flag in edit to force @@ -150,7 +153,9 @@ void TARGET_PROPERTIES_DIALOG_EDITOR::OnOkClick( wxCommandEvent& event ) if( m_DC ) m_Target->Draw( m_Parent->GetCanvas(), m_DC, ( m_Target->IsMoving() ) ? GR_XOR : GR_OR ); - m_Parent->OnModify(); + if( pushCommit ) + commit.Push( _( "Modified alignment target" ) ); + EndModal( 1 ); } diff --git a/pcbnew/tools/common_actions.cpp b/pcbnew/tools/common_actions.cpp index 4d52d39043..b9af35915a 100644 --- a/pcbnew/tools/common_actions.cpp +++ b/pcbnew/tools/common_actions.cpp @@ -138,6 +138,10 @@ TOOL_ACTION COMMON_ACTIONS::properties( "pcbnew.InteractiveEdit.properties", AS_GLOBAL, TOOL_ACTION::LegacyHotKey( HK_EDIT_ITEM ), _( "Properties..." ), _( "Displays item properties dialog" ), editor_xpm ); +TOOL_ACTION COMMON_ACTIONS::editModifiedSelection( "pcbnew.InteractiveEdit.ModifiedSelection", + AS_GLOBAL, 0, + "", "" ); + // Drawing tool actions TOOL_ACTION COMMON_ACTIONS::drawLine( "pcbnew.InteractiveDrawing.line", @@ -564,10 +568,6 @@ TOOL_ACTION COMMON_ACTIONS::routerInlineDrag( "pcbnew.InteractiveRouter.InlineDr "", "" ); // Point editor -TOOL_ACTION COMMON_ACTIONS::pointEditorUpdate( "pcbnew.PointEditor.update", - AS_GLOBAL, 0, - "", "" ); // No description, it is not supposed to be shown anywhere - TOOL_ACTION COMMON_ACTIONS::pointEditorAddCorner( "pcbnew.PointEditor.addCorner", AS_GLOBAL, 0, _( "Create corner" ), _( "Create corner" ), add_corner_xpm ); diff --git a/pcbnew/tools/common_actions.h b/pcbnew/tools/common_actions.h index 3f69ac20a6..962b6b436f 100644 --- a/pcbnew/tools/common_actions.h +++ b/pcbnew/tools/common_actions.h @@ -79,6 +79,9 @@ public: /// Activation of the edit tool static TOOL_ACTION properties; + /// Modified selection notification + static TOOL_ACTION editModifiedSelection; + /// Activation of the exact move tool static TOOL_ACTION moveExact; @@ -161,9 +164,6 @@ public: static TOOL_ACTION routerInlineDrag; // Point Editor - /// Update edit points - static TOOL_ACTION pointEditorUpdate; - /// Break outline (insert additional points to an edge) static TOOL_ACTION pointEditorAddCorner; diff --git a/pcbnew/tools/drawing_tool.cpp b/pcbnew/tools/drawing_tool.cpp index c4ecdc9b0d..8215c0f60b 100644 --- a/pcbnew/tools/drawing_tool.cpp +++ b/pcbnew/tools/drawing_tool.cpp @@ -40,6 +40,7 @@ #include #include #include +#include #include #include @@ -49,8 +50,8 @@ #include DRAWING_TOOL::DRAWING_TOOL() : - TOOL_INTERACTIVE( "pcbnew.InteractiveDrawing" ), m_view( NULL ), - m_controls( NULL ), m_board( NULL ), m_frame( NULL ), m_editModules( false ), m_lineWidth( 1 ) + PCB_TOOL( "pcbnew.InteractiveDrawing" ), m_view( NULL ), + m_controls( NULL ), m_board( NULL ), m_frame( NULL ), m_lineWidth( 1 ) { } @@ -66,61 +67,34 @@ void DRAWING_TOOL::Reset( RESET_REASON aReason ) m_view = getView(); m_controls = getViewControls(); m_board = getModel(); - m_frame = getEditFrame(); + m_frame = getEditFrame(); } int DRAWING_TOOL::DrawLine( const TOOL_EVENT& aEvent ) { + BOARD_ITEM_CONTAINER* parent = m_frame->GetModel(); + DRAWSEGMENT* line = m_editModules ? new EDGE_MODULE( (MODULE*) parent ) : new DRAWSEGMENT; boost::optional startingPoint; + BOARD_COMMIT commit( m_frame ); - if( m_editModules ) + m_frame->SetToolID( m_editModules ? ID_MODEDIT_LINE_TOOL : ID_PCB_ADD_LINE_BUTT, + wxCURSOR_PENCIL, _( "Add graphic line" ) ); + + while( drawSegment( S_SEGMENT, line, startingPoint ) ) { - m_frame->SetToolID( ID_MODEDIT_LINE_TOOL, wxCURSOR_PENCIL, _( "Add graphic line" ) ); - - EDGE_MODULE* line = new EDGE_MODULE( m_board->m_Modules ); - - while( drawSegment( S_SEGMENT, reinterpret_cast( line ), startingPoint ) ) + if( line ) { - if( line ) - { - m_frame->OnModify(); - m_frame->SaveCopyInUndoList( m_board->m_Modules, UR_MODEDIT ); - line->SetParent( m_board->m_Modules ); - line->SetLocalCoord(); - m_board->m_Modules->GraphicalItems().PushFront( line ); - startingPoint = line->GetEnd(); - } - else - { - startingPoint = boost::none; - } - - line = new EDGE_MODULE( m_board->m_Modules ); + commit.Add( line ); + commit.Push( _( "Draw a line segment" ) ); + startingPoint = line->GetEnd(); } - } - else // !m_editModules case - { - m_frame->SetToolID( ID_PCB_ADD_LINE_BUTT, wxCURSOR_PENCIL, _( "Add graphic line" ) ); - - DRAWSEGMENT* line = new DRAWSEGMENT; - - while( drawSegment( S_SEGMENT, line, startingPoint ) ) + else { - if( line ) - { - m_board->Add( line ); - m_frame->OnModify(); - m_frame->SaveCopyInUndoList( line, UR_NEW ); - startingPoint = line->GetEnd(); - } - else - { - startingPoint = boost::none; - } - - line = new DRAWSEGMENT; + startingPoint = boost::none; } + + line = m_editModules ? new EDGE_MODULE( (MODULE*) parent ) : new DRAWSEGMENT; } m_frame->SetToolID( ID_NO_TOOL_SELECTED, wxCURSOR_DEFAULT, wxEmptyString ); @@ -131,43 +105,22 @@ int DRAWING_TOOL::DrawLine( const TOOL_EVENT& aEvent ) int DRAWING_TOOL::DrawCircle( const TOOL_EVENT& aEvent ) { - if( m_editModules ) + BOARD_ITEM_CONTAINER* parent = m_frame->GetModel(); + DRAWSEGMENT* circle = m_editModules ? new EDGE_MODULE( (MODULE*) parent ) : new DRAWSEGMENT; + BOARD_COMMIT commit( m_frame ); + + m_frame->SetToolID( m_editModules ? ID_MODEDIT_CIRCLE_TOOL : ID_PCB_CIRCLE_BUTT, + wxCURSOR_PENCIL, _( "Add graphic circle" ) ); + + while( drawSegment( S_CIRCLE, circle ) ) { - m_frame->SetToolID( ID_MODEDIT_CIRCLE_TOOL, wxCURSOR_PENCIL, _( "Add graphic circle" ) ); - - EDGE_MODULE* circle = new EDGE_MODULE( m_board->m_Modules ); - - while( drawSegment( S_CIRCLE, reinterpret_cast( circle ) ) ) + if( circle ) { - if( circle ) - { - m_frame->OnModify(); - m_frame->SaveCopyInUndoList( m_board->m_Modules, UR_MODEDIT ); - circle->SetParent( m_board->m_Modules ); - circle->SetLocalCoord(); - m_board->m_Modules->GraphicalItems().PushFront( circle ); - } - - circle = new EDGE_MODULE( m_board->m_Modules ); + commit.Add( circle ); + commit.Push( _( "Draw a circle" ) ); } - } - else // !m_editModules case - { - m_frame->SetToolID( ID_PCB_CIRCLE_BUTT, wxCURSOR_PENCIL, _( "Add graphic circle" ) ); - DRAWSEGMENT* circle = new DRAWSEGMENT; - - while( drawSegment( S_CIRCLE, circle ) ) - { - if( circle ) - { - m_board->Add( circle ); - m_frame->OnModify(); - m_frame->SaveCopyInUndoList( circle, UR_NEW ); - } - - circle = new DRAWSEGMENT; - } + circle = m_editModules ? new EDGE_MODULE( (MODULE*) parent ) : new DRAWSEGMENT; } m_frame->SetToolID( ID_NO_TOOL_SELECTED, wxCURSOR_DEFAULT, wxEmptyString ); @@ -178,43 +131,22 @@ int DRAWING_TOOL::DrawCircle( const TOOL_EVENT& aEvent ) int DRAWING_TOOL::DrawArc( const TOOL_EVENT& aEvent ) { - if( m_editModules ) + BOARD_ITEM_CONTAINER* parent = m_frame->GetModel(); + DRAWSEGMENT* arc = m_editModules ? new EDGE_MODULE( (MODULE*) parent ) : new DRAWSEGMENT; + BOARD_COMMIT commit( m_frame ); + + m_frame->SetToolID( m_editModules ? ID_MODEDIT_ARC_TOOL : ID_PCB_ARC_BUTT, + wxCURSOR_PENCIL, _( "Add graphic arc" ) ); + + while( drawArc( arc ) ) { - m_frame->SetToolID( ID_MODEDIT_ARC_TOOL, wxCURSOR_PENCIL, _( "Add graphic arc" ) ); - - EDGE_MODULE* arc = new EDGE_MODULE( m_board->m_Modules ); - - while( drawArc( reinterpret_cast( arc ) ) ) + if( arc ) { - if( arc ) - { - m_frame->OnModify(); - m_frame->SaveCopyInUndoList( m_board->m_Modules, UR_MODEDIT ); - arc->SetParent( m_board->m_Modules ); - arc->SetLocalCoord(); - m_board->m_Modules->GraphicalItems().PushFront( arc ); - } - - arc = new EDGE_MODULE( m_board->m_Modules ); + commit.Add( arc ); + commit.Push( _( "Draw an arc" ) ); } - } - else // !m_editModules case - { - m_frame->SetToolID( ID_PCB_ARC_BUTT, wxCURSOR_PENCIL, _( "Add graphic arc" ) ); - DRAWSEGMENT* arc = new DRAWSEGMENT; - - while( drawArc( arc ) ) - { - if( arc ) - { - m_board->Add( arc ); - m_frame->OnModify(); - m_frame->SaveCopyInUndoList( arc, UR_NEW ); - } - - arc = new DRAWSEGMENT; - } + arc = m_editModules ? new EDGE_MODULE( (MODULE*) parent ) : new DRAWSEGMENT; } m_frame->SetToolID( ID_NO_TOOL_SELECTED, wxCURSOR_DEFAULT, wxEmptyString ); @@ -225,22 +157,167 @@ int DRAWING_TOOL::DrawArc( const TOOL_EVENT& aEvent ) int DRAWING_TOOL::PlaceText( const TOOL_EVENT& aEvent ) { - if( m_editModules ) - return placeTextModule(); - else - return placeTextPcb(); + BOARD_ITEM* text = NULL; + const BOARD_DESIGN_SETTINGS& dsnSettings = m_frame->GetDesignSettings(); + BOARD_COMMIT commit( m_frame ); + + // Add a VIEW_GROUP that serves as a preview for the new item + KIGFX::VIEW_GROUP preview( m_view ); + m_view->Add( &preview ); + + m_toolMgr->RunAction( COMMON_ACTIONS::selectionClear, true ); + m_controls->ShowCursor( true ); + m_controls->SetSnapping( true ); + // do not capture or auto-pan until we start placing some text + + Activate(); + m_frame->SetToolID( m_editModules ? ID_MODEDIT_TEXT_TOOL : ID_PCB_ADD_TEXT_BUTT, + wxCURSOR_PENCIL, _( "Add text" ) ); + + // Main loop: keep receiving events + while( OPT_TOOL_EVENT evt = Wait() ) + { + VECTOR2I cursorPos = m_controls->GetCursorPosition(); + + if( evt->IsCancel() || evt->IsActivate() ) + { + if( text ) + { + // Delete the old text and have another try + delete text; + text = NULL; + + preview.Clear(); + + m_controls->SetAutoPan( false ); + m_controls->CaptureCursor( false ); + m_controls->ShowCursor( true ); + } + else + break; + + if( evt->IsActivate() ) // now finish unconditionally + break; + } + + else if( text && evt->Category() == TC_COMMAND ) + { + if( evt->IsAction( &COMMON_ACTIONS::rotate ) ) + { + text->Rotate( text->GetPosition(), m_frame->GetRotationAngle() ); + preview.ViewUpdate(); + } + // TODO rotate CCW + else if( evt->IsAction( &COMMON_ACTIONS::flip ) ) + { + text->Flip( text->GetPosition() ); + preview.ViewUpdate(); + } + } + + else if( evt->IsClick( BUT_LEFT ) ) + { + if( !text ) + { + // Init the new item attributes + if( m_editModules ) + { + TEXTE_MODULE* textMod = new TEXTE_MODULE( (MODULE*) m_frame->GetModel() ); + + textMod->SetLayer( m_frame->GetActiveLayer() ); + textMod->SetSize( dsnSettings.m_ModuleTextSize ); + textMod->SetThickness( dsnSettings.m_ModuleTextWidth ); + textMod->SetTextPosition( wxPoint( cursorPos.x, cursorPos.y ) ); + + DialogEditModuleText textDialog( m_frame, textMod, NULL ); + bool placing = textDialog.ShowModal() && ( textMod->GetText().Length() > 0 ); + + if( !placing ) + text = textMod; + else + delete textMod; + } + else + { + TEXTE_PCB* textPcb = new TEXTE_PCB( m_frame->GetModel() ); + // TODO we have to set IS_NEW, otherwise InstallTextPCB.. creates an undo entry :| LEGACY_CLEANUP + textPcb->SetFlags( IS_NEW ); + + LAYER_ID layer = m_frame->GetActiveLayer(); + textPcb->SetLayer( layer ); + + // Set the mirrored option for layers on the BACK side of the board + if( IsBackLayer( layer ) ) + textPcb->SetMirrored( true ); + + textPcb->SetSize( dsnSettings.m_PcbTextSize ); + textPcb->SetThickness( dsnSettings.m_PcbTextWidth ); + textPcb->SetTextPosition( wxPoint( cursorPos.x, cursorPos.y ) ); + + getEditFrame()->InstallTextPCBOptionsFrame( textPcb, NULL ); + + if( textPcb->GetText().IsEmpty() ) + delete textPcb; + else + text = textPcb; + } + + if( text == NULL ) + continue; + + m_controls->CaptureCursor( true ); + m_controls->SetAutoPan( true ); + //m_controls->ShowCursor( false ); + + preview.Add( text ); + } + else + { + //assert( text->GetText().Length() > 0 ); + //assert( text->GetSize().x > 0 && text->GetSize().y > 0 ); + + text->ClearFlags(); + preview.Remove( text ); + + commit.Add( text ); + commit.Push( _( "Place a text" ) ); + + m_controls->CaptureCursor( false ); + m_controls->SetAutoPan( false ); + m_controls->ShowCursor( true ); + + text = NULL; + } + } + + else if( text && evt->IsMotion() ) + { + text->SetPosition( wxPoint( cursorPos.x, cursorPos.y ) ); + + // Show a preview of the item + preview.ViewUpdate(); + } + } + + m_controls->ShowCursor( false ); + m_controls->SetSnapping( false ); + m_controls->SetAutoPan( false ); + m_controls->CaptureCursor( false ); + + m_view->Remove( &preview ); + m_frame->SetToolID( ID_NO_TOOL_SELECTED, wxCURSOR_DEFAULT, wxEmptyString ); + + return 0; + } int DRAWING_TOOL::DrawDimension( const TOOL_EVENT& aEvent ) { DIMENSION* dimension = NULL; + BOARD_COMMIT commit( m_frame ); int maxThickness; - // if one day it is possible to draw dimensions in the footprint editor, - // then hereby I'm letting you know that this tool does not handle UR_MODEDIT undo yet - assert( !m_editModules ); - // Add a VIEW_GROUP that serves as a preview for the new item KIGFX::VIEW_GROUP preview( m_view ); m_view->Add( &preview ); @@ -271,7 +348,6 @@ int DRAWING_TOOL::DrawDimension( const TOOL_EVENT& aEvent ) if( step != SET_ORIGIN ) // start from the beginning { preview.Clear(); - preview.ViewUpdate( KIGFX::VIEW_ITEM::GEOMETRY ); delete dimension; step = SET_ORIGIN; @@ -355,14 +431,11 @@ int DRAWING_TOOL::DrawDimension( const TOOL_EVENT& aEvent ) assert( dimension->GetOrigin() != dimension->GetEnd() ); assert( dimension->GetWidth() > 0 ); - m_view->Add( dimension ); - m_board->Add( dimension ); - //dimension->ViewUpdate( KIGFX::VIEW_ITEM::GEOMETRY ); - - m_frame->OnModify(); - m_frame->SaveCopyInUndoList( dimension, UR_NEW ); - preview.Remove( dimension ); + + commit.Add( dimension ); + commit.Push( _( "Draw a dimension" ) ); + } } break; @@ -435,7 +508,7 @@ int DRAWING_TOOL::DrawKeepout( const TOOL_EVENT& aEvent ) int DRAWING_TOOL::PlaceDXF( const TOOL_EVENT& aEvent ) { - if( m_editModules && !m_board->m_Modules ) + if( !m_frame->GetModel() ) return 0; DIALOG_DXF_IMPORT dlg( m_frame ); @@ -451,6 +524,7 @@ int DRAWING_TOOL::PlaceDXF( const TOOL_EVENT& aEvent ) // Add a VIEW_GROUP that serves as a preview for the new item KIGFX::VIEW_GROUP preview( m_view ); + BOARD_COMMIT commit( m_frame ); // Build the undo list & add items to the current view for( auto it = list.begin(), itEnd = list.end(); it != itEnd; ++it ) @@ -488,6 +562,7 @@ int DRAWING_TOOL::PlaceDXF( const TOOL_EVENT& aEvent ) else if( evt->Category() == TC_COMMAND ) { + // TODO it should be handled by EDIT_TOOL, so add items and select? if( evt->IsAction( &COMMON_ACTIONS::rotate ) ) { for( KIGFX::VIEW_GROUP::const_iter it = preview.Begin(), end = preview.End(); it != end; ++it ) @@ -513,33 +588,32 @@ int DRAWING_TOOL::PlaceDXF( const TOOL_EVENT& aEvent ) else if( evt->IsClick( BUT_LEFT ) ) { // Place the drawing - if( m_editModules ) + PICKED_ITEMS_LIST picklist; + BOARD_ITEM_CONTAINER* parent = m_frame->GetModel(); + + for( KIGFX::VIEW_GROUP::const_iter it = preview.Begin(); it != preview.End(); ++it ) { - assert( m_board->m_Modules ); - m_frame->SaveCopyInUndoList( m_board->m_Modules, UR_MODEDIT ); - m_board->m_Modules->SetLastEditTime(); + BOARD_ITEM* item = static_cast( *it ); - for( KIGFX::VIEW_GROUP::const_iter it = preview.Begin(), end = preview.End(); it != end; ++it ) + if( m_editModules ) { - BOARD_ITEM* item = static_cast( *it ); - BOARD_ITEM* converted = NULL; - // Modules use different types for the same things, // so we need to convert imported items to appropriate classes. + BOARD_ITEM* converted = NULL; + switch( item->Type() ) { case PCB_TEXT_T: - converted = new TEXTE_MODULE( m_board->m_Modules ); + converted = new TEXTE_MODULE( (MODULE*) parent ); + // Copy coordinates, layer, etc. - *static_cast( converted ) = *static_cast( item ); - static_cast( converted )->SetLocalCoord(); + *static_cast( converted ) = *static_cast( item ); break; case PCB_LINE_T: - converted = new EDGE_MODULE( m_board->m_Modules ); + converted = new EDGE_MODULE( (MODULE*) parent ); // Copy coordinates, layer, etc. *static_cast( converted ) = *static_cast( item ); - static_cast( converted )->SetLocalCoord(); break; default: @@ -548,33 +622,13 @@ int DRAWING_TOOL::PlaceDXF( const TOOL_EVENT& aEvent ) } delete item; - - if( converted ) - { - m_board->m_Modules->Add( converted ); - m_view->Add( converted ); - } - } - } - else // !m_editModules case - { - PICKED_ITEMS_LIST picklist; - - for( KIGFX::VIEW_GROUP::const_iter it = preview.Begin(), end = preview.End(); it != end; ++it ) - { - BOARD_ITEM* item = static_cast( *it ); - m_board->Add( item ); - - ITEM_PICKER itemWrapper( item, UR_NEW ); - picklist.PushItem( itemWrapper ); - - m_view->Add( item ); + item = converted; } - m_frame->SaveCopyInUndoList( picklist, UR_NEW ); + commit.Add( item ); } - m_frame->OnModify(); + commit.Push( _( "Place a DXF drawing" ) ); break; } } @@ -608,15 +662,16 @@ int DRAWING_TOOL::SetAnchor( const TOOL_EVENT& aEvent ) { if( evt->IsClick( BUT_LEFT ) ) { - m_frame->SaveCopyInUndoList( m_board->m_Modules, UR_MODEDIT ); - m_board->m_Modules->SetLastEditTime(); + MODULE* module = (MODULE*) m_frame->GetModel(); + BOARD_COMMIT commit( m_frame ); + commit.Modify( module ); // set the new relative internal local coordinates of footprint items VECTOR2I cursorPos = m_controls->GetCursorPosition(); - wxPoint moveVector = m_board->m_Modules->GetPosition() - wxPoint( cursorPos.x, cursorPos.y ); - m_board->m_Modules->MoveAnchorPosition( moveVector ); + wxPoint moveVector = module->GetPosition() - wxPoint( cursorPos.x, cursorPos.y ); + module->MoveAnchorPosition( moveVector ); - m_board->m_Modules->ViewUpdate(); + commit.Push( _( "Move the footprint reference anchor" ) ); // Usually, we do not need to change twice the anchor position, // so deselect the active tool @@ -751,51 +806,25 @@ bool DRAWING_TOOL::drawSegment( int aShape, DRAWSEGMENT*& aGraphic, ( evt->IsDblClick( BUT_LEFT ) && aShape == S_SEGMENT ) ) // User has clicked twice in the same spot { // a clear sign that the current drawing is finished + // Now we have to add the helper line as well if( direction45 ) { - // Now we have to add the helper line as well - if( m_editModules ) - { - EDGE_MODULE* l = new EDGE_MODULE( m_board->m_Modules ); + BOARD_ITEM_CONTAINER* parent = m_frame->GetModel(); + DRAWSEGMENT* l = m_editModules ? new EDGE_MODULE( (MODULE*) parent ) + : new DRAWSEGMENT; - // Copy coordinates, layer, etc. - *static_cast( l ) = line45; - l->SetEnd( aGraphic->GetStart() ); - l->SetLocalCoord(); + // Copy coordinates, layer, etc. + *static_cast( l ) = line45; + l->SetEnd( aGraphic->GetStart() ); - m_frame->SaveCopyInUndoList( m_board->m_Modules, UR_MODEDIT ); - m_board->m_Modules->SetLastEditTime(); - m_board->m_Modules->GraphicalItems().PushFront( l ); - - m_view->Add( l ); - l->ViewUpdate( KIGFX::VIEW_ITEM::GEOMETRY ); - } - else - { - DRAWSEGMENT* l = static_cast( line45.Clone() ); - l->SetEnd( aGraphic->GetStart() ); - - m_frame->SaveCopyInUndoList( l, UR_NEW ); - m_board->Add( l ); - - m_view->Add( l ); - l->ViewUpdate( KIGFX::VIEW_ITEM::GEOMETRY ); - } - - m_frame->OnModify(); + BOARD_COMMIT commit( m_frame ); + commit.Add( l ); + commit.Push( _( "Draw a line" ) ); } delete aGraphic; aGraphic = NULL; } - else - { - assert( aGraphic->GetLength() > 0 ); - assert( aGraphic->GetWidth() > 0 ); - - m_view->Add( aGraphic ); - aGraphic->ViewUpdate( KIGFX::VIEW_ITEM::GEOMETRY ); - } preview.Clear(); break; @@ -882,7 +911,6 @@ bool DRAWING_TOOL::drawArc( DRAWSEGMENT*& aGraphic ) if( evt->IsCancel() || evt->IsActivate() ) { preview.Clear(); - preview.ViewUpdate( KIGFX::VIEW_ITEM::GEOMETRY ); delete aGraphic; aGraphic = NULL; break; @@ -1031,10 +1059,7 @@ int DRAWING_TOOL::drawZone( bool aKeepout ) ZONE_CONTAINER* zone = NULL; DRAWSEGMENT line45; DRAWSEGMENT* helperLine = NULL; // we will need more than one helper line - - // if one day it is possible to draw zones in the footprint editor, - // then hereby I'm letting you know that this tool does not handle UR_MODEDIT undo yet - assert( !m_editModules ); + BOARD_COMMIT commit( m_frame ); // Add a VIEW_GROUP that serves as a preview for the new item KIGFX::VIEW_GROUP preview( m_view ); @@ -1118,17 +1143,11 @@ int DRAWING_TOOL::drawZone( bool aKeepout ) zone->Outline()->CloseLastContour(); zone->Outline()->RemoveNullSegments(); - m_board->Add( zone ); - m_view->Add( zone ); - if( !aKeepout ) static_cast( m_frame )->Fill_Zone( zone ); - zone->ViewUpdate( KIGFX::VIEW_ITEM::GEOMETRY ); - m_board->GetRatsnest()->Update( zone ); - - m_frame->OnModify(); - m_frame->SaveCopyInUndoList( zone, UR_NEW ); + commit.Add( zone ); + commit.Push( _( "Draw a zone" ) ); zone = NULL; } @@ -1246,248 +1265,6 @@ int DRAWING_TOOL::drawZone( bool aKeepout ) } -int DRAWING_TOOL::placeTextModule() -{ - TEXTE_MODULE* text = new TEXTE_MODULE( NULL ); - const BOARD_DESIGN_SETTINGS& dsnSettings = m_frame->GetDesignSettings(); - - assert( m_editModules ); - - // Add a VIEW_GROUP that serves as a preview for the new item - KIGFX::VIEW_GROUP preview( m_view ); - m_view->Add( &preview ); - - m_toolMgr->RunAction( COMMON_ACTIONS::selectionClear, true ); - m_controls->ShowCursor( true ); - m_controls->SetSnapping( true ); - // do not capture or auto-pan until we start placing some text - - Activate(); - m_frame->SetToolID( ID_MODEDIT_TEXT_TOOL, wxCURSOR_PENCIL, _( "Add text" ) ); - bool placing = false; - - // Main loop: keep receiving events - while( OPT_TOOL_EVENT evt = Wait() ) - { - VECTOR2I cursorPos = m_controls->GetCursorPosition(); - - if( evt->IsCancel() || evt->IsActivate() ) - { - preview.Clear(); - preview.ViewUpdate(); - m_controls->SetAutoPan( false ); - m_controls->CaptureCursor( false ); - m_controls->ShowCursor( true ); - - if( !placing || evt->IsActivate() ) - { - delete text; - break; - } - else - { - placing = false; // start from the beginning - } - } - - else if( text && evt->Category() == TC_COMMAND ) - { - if( evt->IsAction( &COMMON_ACTIONS::rotate ) ) - { - text->Rotate( text->GetPosition(), m_frame->GetRotationAngle() ); - preview.ViewUpdate( KIGFX::VIEW_ITEM::GEOMETRY ); - } - else if( evt->IsAction( &COMMON_ACTIONS::flip ) ) - { - text->Flip( text->GetPosition() ); - preview.ViewUpdate( KIGFX::VIEW_ITEM::GEOMETRY ); - } - } - - else if( evt->IsClick( BUT_LEFT ) ) - { - if( !placing ) - { - text->SetSize( dsnSettings.m_ModuleTextSize ); - text->SetThickness( dsnSettings.m_ModuleTextWidth ); - text->SetTextPosition( wxPoint( cursorPos.x, cursorPos.y ) ); - - DialogEditModuleText textDialog( m_frame, text, NULL ); - placing = textDialog.ShowModal() && ( text->GetText().Length() > 0 ); - - if( !placing ) - continue; - - m_controls->CaptureCursor( true ); - m_controls->SetAutoPan( true ); - m_controls->ShowCursor( false ); - text->SetParent( m_board->m_Modules ); // it has to set after the settings dialog - // otherwise the dialog stores it in undo buffer - preview.Add( text ); - } - else - { - assert( text->GetText().Length() > 0 ); - assert( text->GetSize().x > 0 && text->GetSize().y > 0 ); - - text->SetLocalCoord(); - text->ClearFlags(); - - // Module has to be saved before any modification is made - m_frame->SaveCopyInUndoList( m_board->m_Modules, UR_MODEDIT ); - m_board->m_Modules->SetLastEditTime(); - m_board->m_Modules->GraphicalItems().PushFront( text ); - - m_view->Add( text ); - text->ViewUpdate( KIGFX::VIEW_ITEM::GEOMETRY ); - - m_frame->OnModify(); - - preview.Remove( text ); - m_controls->CaptureCursor( false ); - m_controls->SetAutoPan( false ); - m_controls->ShowCursor( true ); - - text = new TEXTE_MODULE( NULL ); - placing = false; - } - } - - else if( text && evt->IsMotion() ) - { - text->SetTextPosition( wxPoint( cursorPos.x, cursorPos.y ) ); - - // Show a preview of the item - preview.ViewUpdate( KIGFX::VIEW_ITEM::GEOMETRY ); - } - } - - m_controls->ShowCursor( false ); - m_controls->SetSnapping( false ); - m_controls->SetAutoPan( false ); - m_controls->CaptureCursor( false ); - m_view->Remove( &preview ); - - m_frame->SetToolID( ID_NO_TOOL_SELECTED, wxCURSOR_DEFAULT, wxEmptyString ); - - return 0; -} - - -int DRAWING_TOOL::placeTextPcb() -{ - TEXTE_PCB* text = NULL; - - assert( !m_editModules ); - - // Add a VIEW_GROUP that serves as a preview for the new item - KIGFX::VIEW_GROUP preview( m_view ); - m_view->Add( &preview ); - - m_toolMgr->RunAction( COMMON_ACTIONS::selectionClear, true ); - m_controls->ShowCursor( true ); - m_controls->SetSnapping( true ); - // do not capture or auto-pan until we start placing some text - - Activate(); - m_frame->SetToolID( ID_PCB_ADD_TEXT_BUTT, wxCURSOR_PENCIL, _( "Add text" ) ); - - // Main loop: keep receiving events - while( OPT_TOOL_EVENT evt = Wait() ) - { - VECTOR2I cursorPos = m_controls->GetCursorPosition(); - - if( evt->IsCancel() || evt->IsActivate() ) - { - if( text ) - { - // Delete the old text and have another try - m_board->Delete( text ); // it was already added by CreateTextPcb() - text = NULL; - - preview.Clear(); - preview.ViewUpdate( KIGFX::VIEW_ITEM::GEOMETRY ); - m_controls->SetAutoPan( false ); - m_controls->CaptureCursor( false ); - m_controls->ShowCursor( true ); - } - else - break; - - if( evt->IsActivate() ) // now finish unconditionally - break; - } - - else if( text && evt->Category() == TC_COMMAND ) - { - if( evt->IsAction( &COMMON_ACTIONS::rotate ) ) - { - text->Rotate( text->GetPosition(), m_frame->GetRotationAngle() ); - preview.ViewUpdate( KIGFX::VIEW_ITEM::GEOMETRY ); - } - else if( evt->IsAction( &COMMON_ACTIONS::flip ) ) - { - text->Flip( text->GetPosition() ); - preview.ViewUpdate( KIGFX::VIEW_ITEM::GEOMETRY ); - } - } - - else if( evt->IsClick( BUT_LEFT ) ) - { - if( !text ) - { - // Init the new item attributes - text = static_cast( m_frame )->CreateTextePcb( NULL ); - - if( text == NULL ) - continue; - - m_controls->CaptureCursor( true ); - m_controls->SetAutoPan( true ); - preview.Add( text ); - } - else - { - assert( text->GetText().Length() > 0 ); - assert( text->GetSize().x > 0 && text->GetSize().y > 0 ); - - text->ClearFlags(); - m_view->Add( text ); - // m_board->Add( text ); // it is already added by CreateTextePcb() - text->ViewUpdate( KIGFX::VIEW_ITEM::GEOMETRY ); - - m_frame->OnModify(); - m_frame->SaveCopyInUndoList( text, UR_NEW ); - - preview.Remove( text ); - m_controls->CaptureCursor( false ); - m_controls->SetAutoPan( false ); - - text = NULL; - } - } - - else if( text && evt->IsMotion() ) - { - text->SetTextPosition( wxPoint( cursorPos.x, cursorPos.y ) ); - - // Show a preview of the item - preview.ViewUpdate( KIGFX::VIEW_ITEM::GEOMETRY ); - } - } - - m_controls->ShowCursor( false ); - m_controls->SetSnapping( false ); - m_controls->SetAutoPan( false ); - m_controls->CaptureCursor( false ); - m_view->Remove( &preview ); - - m_frame->SetToolID( ID_NO_TOOL_SELECTED, wxCURSOR_DEFAULT, wxEmptyString ); - - return 0; -} - - void DRAWING_TOOL::make45DegLine( DRAWSEGMENT* aSegment, DRAWSEGMENT* aHelper ) const { VECTOR2I cursorPos = m_controls->GetCursorPosition(); diff --git a/pcbnew/tools/drawing_tool.h b/pcbnew/tools/drawing_tool.h index 432da1e64b..dbf9aa6f4d 100644 --- a/pcbnew/tools/drawing_tool.h +++ b/pcbnew/tools/drawing_tool.h @@ -25,7 +25,7 @@ #ifndef __DRAWING_TOOL_H #define __DRAWING_TOOL_H -#include +#include #include namespace KIGFX @@ -34,7 +34,7 @@ namespace KIGFX class VIEW_CONTROLS; } class BOARD; -class PCB_EDIT_FRAME; +class PCB_BASE_EDIT_FRAME; class DRAWSEGMENT; /** @@ -43,7 +43,7 @@ class DRAWSEGMENT; * Tool responsible for drawing graphical elements like lines, arcs, circles, etc. */ -class DRAWING_TOOL : public TOOL_INTERACTIVE +class DRAWING_TOOL : public PCB_TOOL { public: DRAWING_TOOL(); @@ -121,17 +121,6 @@ public: */ int SetAnchor( const TOOL_EVENT& aEvent ); - /** - * Function EditModules() - * Toggles edit module mode. When enabled, one may select parts of modules individually - * (graphics, pads, etc.), so they can be modified. - * @param aEnabled decides if the mode should be enabled. - */ - void EditModules( bool aEnabled ) - { - m_editModules = aEnabled; - } - ///> Sets up handlers for various events. void SetTransitions(); @@ -156,20 +145,6 @@ private: ///> @param aKeepout decides if the drawn polygon is a zone or a keepout area. int drawZone( bool aKeepout ); - /** - * Function placeTextModule() - * Displays a dialog that allows to input text and its settings and then lets the user decide - * where to place the text in module . - */ - int placeTextModule(); - - /** - * Function placeTextPcb() - * Displays a dialog that allows to input text and its settings and then lets the user decide - * where to place the text in board editor. - */ - int placeTextPcb(); - /** * Function make45DegLine() * Forces a DRAWSEGMENT to be drawn at multiple of 45 degrees. The origin stays the same, @@ -185,10 +160,7 @@ private: KIGFX::VIEW* m_view; KIGFX::VIEW_CONTROLS* m_controls; BOARD* m_board; - PCB_EDIT_FRAME* m_frame; - - /// Edit module mode flag - bool m_editModules; + PCB_BASE_EDIT_FRAME* m_frame; /// Stores the current line width for multisegment drawing. unsigned int m_lineWidth; diff --git a/pcbnew/tools/edit_tool.cpp b/pcbnew/tools/edit_tool.cpp index 9d3b7dde1b..18021476ed 100644 --- a/pcbnew/tools/edit_tool.cpp +++ b/pcbnew/tools/edit_tool.cpp @@ -56,10 +56,11 @@ using namespace std::placeholders; #include #include +#include + EDIT_TOOL::EDIT_TOOL() : - TOOL_INTERACTIVE( "pcbnew.InteractiveEdit" ), m_selectionTool( NULL ), - m_dragging( false ), m_editModules( false ), m_undoInhibit( 0 ), - m_updateFlag( KIGFX::VIEW_ITEM::NONE ) + PCB_TOOL( "pcbnew.InteractiveEdit" ), m_selectionTool( NULL ), + m_dragging( false ), m_updateFlag( KIGFX::VIEW_ITEM::NONE ) { } @@ -68,6 +69,9 @@ void EDIT_TOOL::Reset( RESET_REASON aReason ) { m_dragging = false; m_updateFlag = KIGFX::VIEW_ITEM::NONE; + + if( aReason != RUN ) + m_commit.reset( new BOARD_COMMIT( this ) ); } @@ -111,9 +115,6 @@ bool EDIT_TOOL::invokeInlineRouter() TRACK* track = uniqueSelected(); VIA* via = uniqueSelected(); - if( isUndoInhibited() ) - return false; - if( track || via ) { ROUTER_TOOL* theRouter = static_cast( m_toolMgr->FindTool( "pcbnew.InteractiveRouter" ) ); @@ -143,7 +144,7 @@ int EDIT_TOOL::Main( const TOOL_EVENT& aEvent ) // Be sure that there is at least one item that we can modify. If nothing was selected before, // try looking for the stuff under mouse cursor (i.e. Kicad old-style hover selection) - if( !hoverSelection( selection ) ) + if( !hoverSelection() ) return 0; Activate(); @@ -215,11 +216,10 @@ int EDIT_TOOL::Main( const TOOL_EVENT& aEvent ) lockOverride = true; // Save items, so changes can be undone - if( !isUndoInhibited() ) + selection.ForAll( [&](BOARD_ITEM* item) { - editFrame->OnModify(); - editFrame->SaveCopyInUndoList( selection.items, UR_CHANGED ); - } + m_commit->Modify( item ); + } ); m_cursor = controls->GetCursorPosition(); @@ -244,17 +244,18 @@ int EDIT_TOOL::Main( const TOOL_EVENT& aEvent ) controls->SetAutoPan( true ); m_dragging = true; - incUndoInhibit(); } } selection.group->ViewUpdate( KIGFX::VIEW_ITEM::GEOMETRY ); - m_toolMgr->RunAction( COMMON_ACTIONS::pointEditorUpdate, true ); + m_toolMgr->RunAction( COMMON_ACTIONS::editModifiedSelection, true ); } // Dispatch TOOL_ACTIONs else if( evt->Category() == TC_COMMAND ) { + wxPoint modPoint = getModificationPoint( selection ); + if( evt->IsAction( &COMMON_ACTIONS::rotate ) ) { Rotate( aEvent ); @@ -302,6 +303,14 @@ int EDIT_TOOL::Main( const TOOL_EVENT& aEvent ) //MoveExact( aEvent ); break; // exit the loop - we move exactly, so we have finished moving } + + if( m_dragging ) + { + // Update dragging offset (distance between cursor and the first dragged item) + m_offset = selection.Item( 0 )->GetPosition() - modPoint; + selection.group->ViewUpdate( KIGFX::VIEW_ITEM::ALL ); + updateRatsnest( true ); + } } else if( evt->IsMouseUp( BUT_LEFT ) || evt->IsClick( BUT_LEFT ) ) @@ -313,31 +322,17 @@ int EDIT_TOOL::Main( const TOOL_EVENT& aEvent ) } } while( ( evt = Wait() ) ); //Should be assignment not equality test - if( m_dragging ) - decUndoInhibit(); - m_dragging = false; m_offset.x = 0; m_offset.y = 0; - if( restore ) - { - // Modifications have to be rollbacked, so restore the previous state of items - wxCommandEvent dummy; - editFrame->RestoreCopyFromUndoList( dummy ); - } - else - { - // Changes are applied, so update the items - selection.group->ItemsViewUpdate( m_updateFlag ); - } - - if( unselect ) + if( unselect || restore ) m_toolMgr->RunAction( COMMON_ACTIONS::selectionClear, true ); - RN_DATA* ratsnest = getModel()->GetRatsnest(); - ratsnest->ClearSimple(); - ratsnest->Recalculate(); + if( restore ) + m_commit->Revert(); + else + m_commit->Push( _( "Drag" ) ); controls->ShowCursor( false ); controls->SetAutoPan( false ); @@ -354,7 +349,7 @@ int EDIT_TOOL::Properties( const TOOL_EVENT& aEvent ) // Shall the selection be cleared at the end? bool unselect = selection.Empty(); - if( !hoverSelection( selection, false ) ) + if( !hoverSelection( false ) ) return 0; // Tracks & vias are treated in a special way: @@ -364,17 +359,8 @@ int EDIT_TOOL::Properties( const TOOL_EVENT& aEvent ) if( dlg.ShowModal() ) { - RN_DATA* ratsnest = getModel()->GetRatsnest(); - - editFrame->OnModify(); - editFrame->SaveCopyInUndoList( selection.items, UR_CHANGED ); - dlg.Apply(); - - selection.ForAll( std::bind( &KIGFX::VIEW_ITEM::ViewUpdate, - std::placeholders::_1, KIGFX::VIEW_ITEM::ALL ) ); - selection.ForAll( std::bind( &RN_DATA::Update, ratsnest, - std::placeholders::_1 ) ); - ratsnest->Recalculate(); + dlg.Apply( *m_commit ); + m_commit->Push( _( "Edit track/via properties" ) ); } } else if( selection.Size() == 1 ) // Properties are displayed when there is only one item selected @@ -382,34 +368,18 @@ int EDIT_TOOL::Properties( const TOOL_EVENT& aEvent ) // Display properties dialog BOARD_ITEM* item = selection.Item( 0 ); - // Store the head of the undo list to compare if anything has changed - std::vector& undoList = editFrame->GetScreen()->m_UndoList.m_CommandsList; - // Some of properties dialogs alter pointers, so we should deselect them m_toolMgr->RunAction( COMMON_ACTIONS::selectionClear, true ); + + // Store flags, so they can be restored later STATUS_FLAGS flags = item->GetFlags(); item->ClearFlags(); - // It is necessary to determine if anything has changed, so store the current undo save point - PICKED_ITEMS_LIST* undoSavePoint = undoList.empty() ? NULL : undoList.back(); - + // Do not handle undo buffer, it is done by the properties dialogs @todo LEGACY // Display properties dialog provided by the legacy canvas frame editFrame->OnEditItemRequest( NULL, item ); - if( !undoList.empty() && undoList.back() != undoSavePoint ) // Undo buffer has changed - { - // Process changes stored after undoSavePoint - processUndoBuffer( undoSavePoint ); - - // Update the modified item - item->ViewUpdate(); - RN_DATA* ratsnest = getModel()->GetRatsnest(); - ratsnest->Recalculate(); - - // TODO OBSERVER! I miss you so much.. - m_toolMgr->RunAction( COMMON_ACTIONS::pointEditorUpdate, true ); - } - + m_toolMgr->RunAction( COMMON_ACTIONS::editModifiedSelection, true ); item->SetFlags( flags ); } @@ -428,43 +398,26 @@ int EDIT_TOOL::Rotate( const TOOL_EVENT& aEvent ) // Shall the selection be cleared at the end? bool unselect = selection.Empty(); - if( !hoverSelection( selection ) || m_selectionTool->CheckLock() == SELECTION_LOCKED ) + if( !hoverSelection() || m_selectionTool->CheckLock() == SELECTION_LOCKED ) return 0; wxPoint rotatePoint = getModificationPoint( selection ); - // If it is being dragged, then it is already saved with UR_CHANGED flag - if( !isUndoInhibited() ) - { - editFrame->OnModify(); - editFrame->SaveCopyInUndoList( selection.items, UR_ROTATED, rotatePoint ); - } - for( unsigned int i = 0; i < selection.items.GetCount(); ++i ) { BOARD_ITEM* item = selection.Item( i ); - + m_commit->Modify( item ); item->Rotate( rotatePoint, editFrame->GetRotationAngle() ); - - if( !m_dragging ) - item->ViewUpdate( KIGFX::VIEW_ITEM::GEOMETRY ); } - updateRatsnest( m_dragging ); - - // Update dragging offset (distance between cursor and the first dragged item) - m_offset = static_cast( selection.items.GetPickedItem( 0 ) )->GetPosition() - - rotatePoint; - - if( m_dragging ) - selection.group->ViewUpdate( KIGFX::VIEW_ITEM::GEOMETRY ); - else - getModel()->GetRatsnest()->Recalculate(); + if( !m_dragging ) + m_commit->Push( _( "Rotate" ) ); if( unselect ) m_toolMgr->RunAction( COMMON_ACTIONS::selectionClear, true ); - m_toolMgr->RunAction( COMMON_ACTIONS::pointEditorUpdate, true ); + // TODO selectionModified + m_toolMgr->RunAction( COMMON_ACTIONS::editModifiedSelection, true ); return 0; } @@ -473,47 +426,29 @@ int EDIT_TOOL::Rotate( const TOOL_EVENT& aEvent ) int EDIT_TOOL::Flip( const TOOL_EVENT& aEvent ) { const SELECTION& selection = m_selectionTool->GetSelection(); - PCB_BASE_FRAME* editFrame = getEditFrame(); // Shall the selection be cleared at the end? bool unselect = selection.Empty(); - if( !hoverSelection( selection ) || m_selectionTool->CheckLock() == SELECTION_LOCKED ) + if( !hoverSelection() || m_selectionTool->CheckLock() == SELECTION_LOCKED ) return 0; wxPoint flipPoint = getModificationPoint( selection ); - if( !isUndoInhibited() ) // If it is being dragged, then it is already saved with UR_CHANGED flag - { - editFrame->OnModify(); - editFrame->SaveCopyInUndoList( selection.items, UR_FLIPPED, flipPoint ); - } - for( unsigned int i = 0; i < selection.items.GetCount(); ++i ) { BOARD_ITEM* item = selection.Item( i ); - + m_commit->Modify( item ); item->Flip( flipPoint ); - - if( !m_dragging ) - item->ViewUpdate( KIGFX::VIEW_ITEM::LAYERS ); } - updateRatsnest( m_dragging ); - - // Update dragging offset (distance between cursor and the first dragged item) - m_offset = static_cast( selection.items.GetPickedItem( 0 ) )->GetPosition() - - flipPoint; - - if( m_dragging ) - selection.group->ViewUpdate( KIGFX::VIEW_ITEM::GEOMETRY ); - else - getModel()->GetRatsnest()->Recalculate(); + if( !m_dragging ) + m_commit->Push( _( "Flip" ) ); if( unselect ) m_toolMgr->RunAction( COMMON_ACTIONS::selectionClear, true ); - m_toolMgr->RunAction( COMMON_ACTIONS::pointEditorUpdate, true ); + m_toolMgr->RunAction( COMMON_ACTIONS::editModifiedSelection, true ); return 0; } @@ -521,126 +456,27 @@ int EDIT_TOOL::Flip( const TOOL_EVENT& aEvent ) int EDIT_TOOL::Remove( const TOOL_EVENT& aEvent ) { - const SELECTION& selection = m_selectionTool->GetSelection(); - - if( !hoverSelection( selection ) || m_selectionTool->CheckLock() == SELECTION_LOCKED ) + if( !hoverSelection() || m_selectionTool->CheckLock() == SELECTION_LOCKED ) return 0; - // Get a copy of the selected items set - PICKED_ITEMS_LIST selectedItems = selection.items; - PCB_BASE_FRAME* editFrame = getEditFrame(); + // Get a copy instead of a reference, as we are going to clear current selection + SELECTION selection = m_selectionTool->GetSelection(); // As we are about to remove items, they have to be removed from the selection first m_toolMgr->RunAction( COMMON_ACTIONS::selectionClear, true ); - // Save them - for( unsigned int i = 0; i < selectedItems.GetCount(); ++i ) - selectedItems.SetPickedItemStatus( UR_DELETED, i ); + for( unsigned int i = 0; i < selection.items.GetCount(); ++i ) + { + BOARD_ITEM* item = selection.Item( i ); + m_commit->Remove( item ); + } - editFrame->OnModify(); - editFrame->SaveCopyInUndoList( selectedItems, UR_DELETED ); - - // And now remove - for( unsigned int i = 0; i < selectedItems.GetCount(); ++i ) - remove( static_cast( selectedItems.GetPickedItem( i ) ) ); - - getModel()->GetRatsnest()->Recalculate(); + m_commit->Push( _( "Delete" ) ); return 0; } -void EDIT_TOOL::remove( BOARD_ITEM* aItem ) -{ - BOARD* board = getModel(); - - switch( aItem->Type() ) - { - case PCB_MODULE_T: - { - MODULE* module = static_cast( aItem ); - module->ClearFlags(); - module->RunOnChildren( std::bind( &KIGFX::VIEW::Remove, getView(), std::placeholders::_1 ) ); - - // Module itself is deleted after the switch scope is finished - // list of pads is rebuild by BOARD::BuildListOfNets() - - // Clear flags to indicate, that the ratsnest, list of nets & pads are not valid anymore - board->m_Status_Pcb = 0; - } - break; - - // Default removal procedure - case PCB_MODULE_TEXT_T: - { - TEXTE_MODULE* text = static_cast( aItem ); - - switch( text->GetType() ) - { - case TEXTE_MODULE::TEXT_is_REFERENCE: - DisplayError( getEditFrame(), _( "Cannot delete component reference." ) ); - return; - - case TEXTE_MODULE::TEXT_is_VALUE: - DisplayError( getEditFrame(), _( "Cannot delete component value." ) ); - return; - - case TEXTE_MODULE::TEXT_is_DIVERS: // suppress warnings - break; - } - - if( m_editModules ) - { - MODULE* module = static_cast( aItem->GetParent() ); - module->SetLastEditTime(); - board->m_Status_Pcb = 0; // it is done in the legacy view - aItem->DeleteStructure(); - } - - return; - } - - case PCB_PAD_T: - case PCB_MODULE_EDGE_T: - { - MODULE* module = static_cast( aItem->GetParent() ); - module->SetLastEditTime(); - - board->m_Status_Pcb = 0; // it is done in the legacy view - - - if( !m_editModules ) - { - getView()->Remove( aItem ); - board->Remove( aItem ); - } - - aItem->DeleteStructure(); - - return; - } - - case PCB_LINE_T: // a segment not on copper layers - case PCB_TEXT_T: // a text on a layer - case PCB_TRACE_T: // a track segment (segment on a copper layer) - case PCB_VIA_T: // a via (like track segment on a copper layer) - case PCB_DIMENSION_T: // a dimension (graphic item) - case PCB_TARGET_T: // a target (graphic item) - case PCB_MARKER_T: // a marker used to show something - case PCB_ZONE_T: // SEG_ZONE items are now deprecated - case PCB_ZONE_AREA_T: - break; - - default: // other types do not need to (or should not) be handled - assert( false ); - return; - } - - getView()->Remove( aItem ); - board->Remove( aItem ); -} - - int EDIT_TOOL::MoveExact( const TOOL_EVENT& aEvent ) { const SELECTION& selection = m_selectionTool->GetSelection(); @@ -648,7 +484,7 @@ int EDIT_TOOL::MoveExact( const TOOL_EVENT& aEvent ) // Shall the selection be cleared at the end? bool unselect = selection.Empty(); - if( !hoverSelection( selection ) || m_selectionTool->CheckLock() == SELECTION_LOCKED ) + if( !hoverSelection() || m_selectionTool->CheckLock() == SELECTION_LOCKED ) return 0; wxPoint translation; @@ -661,13 +497,6 @@ int EDIT_TOOL::MoveExact( const TOOL_EVENT& aEvent ) if( ret == wxID_OK ) { - if( !isUndoInhibited() ) - { - editFrame->OnModify(); - // Record an action of move and rotate - editFrame->SaveCopyInUndoList( selection.items, UR_CHANGED ); - } - VECTOR2I rp = selection.GetCenter(); wxPoint rotPoint( rp.x, rp.y ); @@ -675,6 +504,7 @@ int EDIT_TOOL::MoveExact( const TOOL_EVENT& aEvent ) { BOARD_ITEM* item = selection.Item( i ); + m_commit->Modify( item ); item->Move( translation ); item->Rotate( rotPoint, rotation ); @@ -682,17 +512,12 @@ int EDIT_TOOL::MoveExact( const TOOL_EVENT& aEvent ) item->ViewUpdate( KIGFX::VIEW_ITEM::GEOMETRY ); } - updateRatsnest( m_dragging ); - - if( m_dragging ) - selection.group->ViewUpdate( KIGFX::VIEW_ITEM::GEOMETRY ); - else - getModel()->GetRatsnest()->Recalculate(); + m_commit->Push( _( "Move exact" ) ); if( unselect ) m_toolMgr->RunAction( COMMON_ACTIONS::selectionClear, true ); - m_toolMgr->RunAction( COMMON_ACTIONS::pointEditorUpdate, true ); + m_toolMgr->RunAction( COMMON_ACTIONS::editModifiedSelection, true ); } return 0; @@ -710,21 +535,11 @@ int EDIT_TOOL::Duplicate( const TOOL_EVENT& aEvent ) const SELECTION& selection = selTool->GetSelection(); // Be sure that there is at least one item that we can modify - if( !hoverSelection( selection ) ) + if( !hoverSelection() ) return 0; // we have a selection to work on now, so start the tool process - - PCB_BASE_FRAME* editFrame = getEditFrame(); - editFrame->OnModify(); - - // prevent other tools making undo points while the duplicate is going on - // so that if you cancel, you don't get a duplicate object hiding over - // the original - incUndoInhibit(); - - if( m_editModules ) - editFrame->SaveCopyInUndoList( editFrame->GetBoard()->m_Modules, UR_MODEDIT ); + PCB_BASE_EDIT_FRAME* editFrame = getEditFrame(); std::vector old_items; @@ -748,7 +563,7 @@ int EDIT_TOOL::Duplicate( const TOOL_EVENT& aEvent ) BOARD_ITEM* new_item = NULL; if( m_editModules ) - new_item = editFrame->GetBoard()->m_Modules->DuplicateAndAddItem( item, increment ); + new_item = editFrame->GetBoard()->m_Modules->Duplicate( item, increment ); else { #if 0 @@ -757,18 +572,12 @@ int EDIT_TOOL::Duplicate( const TOOL_EVENT& aEvent ) // so zones are not duplicated if( item->Type() != PCB_ZONE_AREA_T ) #endif - new_item = editFrame->GetBoard()->DuplicateAndAddItem( item ); + new_item = editFrame->GetBoard()->Duplicate( item ); } if( new_item ) { - if( new_item->Type() == PCB_MODULE_T ) - { - static_cast( new_item )->RunOnChildren( std::bind( &KIGFX::VIEW::Add, - getView(), std::placeholders::_1 ) ); - } - - editFrame->GetGalCanvas()->GetView()->Add( new_item ); + m_commit->Add( new_item ); // Select the new item, so we can pick it up m_toolMgr->RunAction( COMMON_ACTIONS::selectItem, true, new_item ); @@ -776,22 +585,17 @@ int EDIT_TOOL::Duplicate( const TOOL_EVENT& aEvent ) } // record the new items as added - if( !m_editModules && !selection.Empty() ) + if( !selection.Empty() ) { - editFrame->SaveCopyInUndoList( selection.items, UR_NEW ); - editFrame->DisplayToolMsg( wxString::Format( _( "Duplicated %d item(s)" ), (int) old_items.size() ) ); // If items were duplicated, pick them up - // this works well for "dropping" copies around + // this works well for "dropping" copies around and pushes the commit TOOL_EVENT evt = COMMON_ACTIONS::editActivate.MakeEvent(); Main( evt ); } - // and re-enable undos - decUndoInhibit(); - return 0; }; @@ -801,11 +605,9 @@ class GAL_ARRAY_CREATOR: public ARRAY_CREATOR public: GAL_ARRAY_CREATOR( PCB_BASE_FRAME& editFrame, bool editModules, - RN_DATA* ratsnest, const SELECTION& selection ): ARRAY_CREATOR( editFrame ), m_editModules( editModules ), - m_ratsnest( ratsnest ), m_selection( selection ) {} @@ -848,24 +650,13 @@ private: void postPushAction( BOARD_ITEM* new_item ) //override { - KIGFX::VIEW* view = m_parent.GetToolManager()->GetView(); - if( new_item->Type() == PCB_MODULE_T) - { - static_cast(new_item)->RunOnChildren( - std::bind(&KIGFX::VIEW::Add, view, std::placeholders::_1)); - } - - m_parent.GetGalCanvas()->GetView()->Add( new_item ); - m_ratsnest->Update( new_item ); } void finalise() // override { - m_ratsnest->Recalculate(); } bool m_editModules; - RN_DATA* m_ratsnest; const SELECTION& m_selection; }; @@ -877,18 +668,12 @@ int EDIT_TOOL::CreateArray( const TOOL_EVENT& aEvent ) const SELECTION& selection = selTool->GetSelection(); // pick up items under the cursor if needed - if( !hoverSelection( selection ) ) + if( !hoverSelection() ) return 0; // we have a selection to work on now, so start the tool process - PCB_BASE_FRAME* editFrame = getEditFrame(); - editFrame->OnModify(); - - GAL_ARRAY_CREATOR array_creator( *editFrame, m_editModules, - getModel()->GetRatsnest(), - selection ); - + GAL_ARRAY_CREATOR array_creator( *editFrame, m_editModules, selection ); array_creator.Invoke(); return 0; @@ -947,9 +732,11 @@ wxPoint EDIT_TOOL::getModificationPoint( const SELECTION& aSelection ) } -bool EDIT_TOOL::hoverSelection( const SELECTION& aSelection, bool aSanitize ) +bool EDIT_TOOL::hoverSelection( bool aSanitize ) { - if( aSelection.Empty() ) // Try to find an item that could be modified + const SELECTION& selection = m_selectionTool->GetSelection(); + + if( selection.Empty() ) // Try to find an item that could be modified { m_toolMgr->RunAction( COMMON_ACTIONS::selectionCursor, true ); @@ -963,79 +750,10 @@ bool EDIT_TOOL::hoverSelection( const SELECTION& aSelection, bool aSanitize ) if( aSanitize ) m_selectionTool->SanitizeSelection(); - if( aSelection.Empty() ) // TODO is it necessary? + if( selection.Empty() ) // TODO is it necessary? m_toolMgr->RunAction( COMMON_ACTIONS::selectionClear, true ); - return !aSelection.Empty(); -} - -void EDIT_TOOL::processUndoBuffer( const PICKED_ITEMS_LIST* aLastChange ) -{ - PCB_BASE_EDIT_FRAME* editFrame = getEditFrame(); - const std::vector& undoList = editFrame->GetScreen()->m_UndoList.m_CommandsList; - bool process = false; - - for( const PICKED_ITEMS_LIST* list : undoList ) - { - if( process ) - processPickedList( list ); - else if( list == aLastChange ) - process = true; // Start processing starting with the next undo save point - } - - // If we could not find the requested save point in the current undo list - // then the undo list must have been completely altered, so process everything - if( !process ) - { - for( const PICKED_ITEMS_LIST* list : undoList ) - processPickedList( list ); - } -} - - -void EDIT_TOOL::processPickedList( const PICKED_ITEMS_LIST* aList ) -{ - KIGFX::VIEW* view = getView(); - RN_DATA* ratsnest = getModel()->GetRatsnest(); - - for( unsigned int i = 0; i < aList->GetCount(); ++i ) - { - UNDO_REDO_T operation = aList->GetPickedItemStatus( i ); - BOARD_ITEM* updItem = static_cast( aList->GetPickedItem( i ) ); - - switch( operation ) - { - case UR_CHANGED: - ratsnest->Update( updItem ); - // fall through - - case UR_MODEDIT: - updItem->ViewUpdate( KIGFX::VIEW_ITEM::ALL ); - break; - - case UR_DELETED: - if( updItem->Type() == PCB_MODULE_T ) - static_cast( updItem )->RunOnChildren( std::bind( &KIGFX::VIEW::Remove, - view, std::placeholders::_1 ) ); - - view->Remove( updItem ); - //ratsnest->Remove( updItem ); // this is done in BOARD::Remove - break; - - case UR_NEW: - if( updItem->Type() == PCB_MODULE_T ) - static_cast( updItem )->RunOnChildren( std::bind( &KIGFX::VIEW::Add, - view, std::placeholders::_1 ) ); - - view->Add( updItem ); - //ratsnest->Add( updItem ); // this is done in BOARD::Add - break; - - default: - assert( false ); // Not handled - break; - } - } + return !selection.Empty(); } @@ -1044,7 +762,7 @@ int EDIT_TOOL::editFootprintInFpEditor( const TOOL_EVENT& aEvent ) const SELECTION& selection = m_selectionTool->GetSelection(); bool unselect = selection.Empty(); - if( !hoverSelection( selection ) ) + if( !hoverSelection() ) return 0; MODULE* mod = uniqueSelected(); @@ -1054,7 +772,7 @@ int EDIT_TOOL::editFootprintInFpEditor( const TOOL_EVENT& aEvent ) PCB_BASE_EDIT_FRAME* editFrame = getEditFrame(); - editFrame-> SetCurItem( mod ); + editFrame->SetCurItem( mod ); if( editFrame->GetCurItem()->GetTimeStamp() == 0 ) // Module Editor needs a non null timestamp { diff --git a/pcbnew/tools/edit_tool.h b/pcbnew/tools/edit_tool.h index 8adaf5cb49..640caf569b 100644 --- a/pcbnew/tools/edit_tool.h +++ b/pcbnew/tools/edit_tool.h @@ -27,9 +27,10 @@ #define __EDIT_TOOL_H #include -#include +#include #include +class BOARD_COMMIT; class BOARD_ITEM; class SELECTION_TOOL; @@ -45,7 +46,7 @@ class VIEW_GROUP; * using the pcbnew.InteractiveSelection tool. */ -class EDIT_TOOL : public TOOL_INTERACTIVE +class EDIT_TOOL : public PCB_TOOL { public: EDIT_TOOL(); @@ -114,17 +115,6 @@ public: */ int CreateArray( const TOOL_EVENT& aEvent ); - /** - * Function EditModules() - * - * Toggles edit module mode. When enabled, one may select parts of modules individually - * (graphics, pads, etc.), so they can be modified. - * @param aEnabled decides if the mode should be enabled. - */ - void EditModules( bool aEnabled ) - { - m_editModules = aEnabled; - } ///> Sets up handlers for various events. void SetTransitions(); @@ -143,15 +133,6 @@ private: ///> of edit reference point). VECTOR2I m_cursor; - /// Edit module mode flag - bool m_editModules; - - /// Counter of undo inhibitions. When zero, undo is not inhibited. - int m_undoInhibit; - - ///> Removes and frees a single BOARD_ITEM. - void remove( BOARD_ITEM* aItem ); - ///> The required update flag for modified items KIGFX::VIEW_ITEM::VIEW_UPDATE_FLAGS m_updateFlag; @@ -172,49 +153,8 @@ private: wxPoint getModificationPoint( const SELECTION& aSelection ); ///> If there are no items currently selected, it tries to choose the item that is under - ///> the cursor or displays a disambiguation menu if there are multpile items. - bool hoverSelection( const SELECTION& aSelection, bool aSanitize = true ); - - ///> Processes the current undo buffer since the last change. If the last change does not occur - ///> in the current buffer, then the whole list is processed. - void processUndoBuffer( const PICKED_ITEMS_LIST* aLastChange ); - - ///> Updates items stored in the list. - void processPickedList( const PICKED_ITEMS_LIST* aList ); - - /** - * Increments the undo inhibit counter. This will indicate that tools - * should not create an undo point, as another tool is doing it already, - * and considers that its operation is atomic, even if it calls another one - * (for example a duplicate calls a move). - */ - inline void incUndoInhibit() - { - m_undoInhibit++; - } - - /** - * Decrements the inhibit counter. An assert is raised if the counter drops - * below zero. - */ - inline void decUndoInhibit() - { - m_undoInhibit--; - - wxASSERT_MSG( m_undoInhibit >= 0, wxT( "Undo inhibit count decremented past zero" ) ); - } - - /** - * Report if the tool manager has been told at least once that undo - * points should not be created. This can be ignored if the undo point - * is still required. - * - * @return true if undo are inhibited - */ - inline bool isUndoInhibited() const - { - return m_undoInhibit > 0; - } + ///> the cursor or displays a disambiguation menu if there are multiple items. + bool hoverSelection( bool aSanitize = true ); int editFootprintInFpEditor( const TOOL_EVENT& aEvent ); @@ -230,6 +170,8 @@ private: BOARD_ITEM* item = selection.Item( 0 ); return dyn_cast( item ); } + + std::unique_ptr m_commit; }; #endif diff --git a/pcbnew/tools/module_tools.cpp b/pcbnew/tools/module_tools.cpp index 2e5ae48c8f..d41f6e55f8 100644 --- a/pcbnew/tools/module_tools.cpp +++ b/pcbnew/tools/module_tools.cpp @@ -43,6 +43,7 @@ #include #include #include +#include #include using namespace std::placeholders; @@ -157,24 +158,17 @@ int MODULE_TOOLS::PlacePad( const TOOL_EVENT& aEvent ) else if( evt->IsClick( BUT_LEFT ) ) { - m_frame->OnModify(); - m_frame->SaveCopyInUndoList( m_board->m_Modules, UR_MODEDIT ); + BOARD_COMMIT commit( m_frame ); + commit.Add( pad ); m_board->m_Status_Pcb = 0; // I have no clue why, but it is done in the legacy view - pad->SetParent( m_board->m_Modules ); - m_board->m_Modules->SetLastEditTime(); - m_board->m_Modules->Pads().PushBack( pad ); - - // Set the relative pad position - // ( pad position for module orient, 0, and relative to the module position) - pad->SetLocalCoord(); // Take the next available pad number pad->IncrementPadName( true, true ); // Handle the view aspect preview.Remove( pad ); - m_view->Add( pad ); + commit.Push( _( "Add a pad" ) ); // Start placing next pad pad = new D_PAD( m_board->m_Modules ); @@ -307,15 +301,17 @@ int MODULE_TOOLS::EnumeratePads( const TOOL_EVENT& aEvent ) evt->IsDblClick( BUT_LEFT ) ) { // Accept changes + BOARD_COMMIT commit( m_frame ); m_frame->OnModify(); - m_frame->SaveCopyInUndoList( m_board->m_Modules, UR_MODEDIT ); for( D_PAD* pad : pads ) { + commit.Modify( pad ); pad->SetPadName( wxString::Format( wxT( "%s%d" ), padPrefix.c_str(), padNumber++ ) ); - pad->ViewUpdate(); } + commit.Push( _( "Enumerate pads" ) ); + break; } @@ -409,7 +405,6 @@ int MODULE_TOOLS::PasteItems( const TOOL_EVENT& aEvent ) { // Parse clipboard PCB_IO io( CTL_FOR_CLIPBOARD ); - MODULE* currentModule = m_board->m_Modules; MODULE* pastedModule = NULL; try @@ -475,11 +470,9 @@ int MODULE_TOOLS::PasteItems( const TOOL_EVENT& aEvent ) else if( evt->IsClick( BUT_LEFT ) ) { - m_frame->OnModify(); - m_frame->SaveCopyInUndoList( currentModule, UR_MODEDIT ); + BOARD_COMMIT commit( m_frame ); m_board->m_Status_Pcb = 0; // I have no clue why, but it is done in the legacy view - currentModule->SetLastEditTime(); // MODULE::RunOnChildren is infeasible here: we need to create copies of items, do not // directly modify them @@ -487,10 +480,7 @@ int MODULE_TOOLS::PasteItems( const TOOL_EVENT& aEvent ) for( D_PAD* pad = pastedModule->Pads(); pad; pad = pad->Next() ) { D_PAD* clone = static_cast( pad->Clone() ); - - currentModule->Add( clone ); - clone->SetLocalCoord(); - m_view->Add( clone ); + commit.Add( clone ); } for( BOARD_ITEM* drawing = pastedModule->GraphicalItems(); @@ -502,22 +492,17 @@ int MODULE_TOOLS::PasteItems( const TOOL_EVENT& aEvent ) { // Do not add reference/value - convert them to the common type text->SetType( TEXTE_MODULE::TEXT_is_DIVERS ); - currentModule->Add( text ); - text->SetLocalCoord(); // Whyyyyyyyyyyyyyyyyyyyyyy?! All other items conform to rotation performed // on its parent module, but texts are so independent.. text->Rotate( text->GetPosition(), pastedModule->GetOrientation() ); - } - else if( EDGE_MODULE* edge = dyn_cast( clone ) ) - { - currentModule->Add( edge ); - edge->SetLocalCoord(); + commit.Add( text ); } - m_view->Add( clone ); + commit.Add( clone ); } + commit.Push( _( "Paste clipboard contents" ) ); preview.Clear(); break; diff --git a/pcbnew/tools/pcb_editor_control.cpp b/pcbnew/tools/pcb_editor_control.cpp index 0476bb4614..b72d770865 100644 --- a/pcbnew/tools/pcb_editor_control.cpp +++ b/pcbnew/tools/pcb_editor_control.cpp @@ -41,6 +41,7 @@ #include #include #include +#include #include #include @@ -249,11 +250,10 @@ int PCB_EDITOR_CONTROL::PlaceModule( const TOOL_EVENT& aEvent ) { if( module ) { - board->Delete( module ); // it was added by LoadModuleFromLibrary() + delete module; module = NULL; preview.Clear(); - preview.ViewUpdate( KIGFX::VIEW_ITEM::GEOMETRY ); controls->ShowCursor( true ); } else @@ -285,26 +285,24 @@ int PCB_EDITOR_CONTROL::PlaceModule( const TOOL_EVENT& aEvent ) module = m_frame->LoadModuleFromLibrary( wxEmptyString, m_frame->Prj().PcbFootprintLibs(), true, NULL ); + if( module == NULL ) continue; + // Module has been added in LoadModuleFromLibrary(), + // so we have to remove it before committing the change @todo LEGACY + board->Remove( module ); module->SetPosition( wxPoint( cursorPos.x, cursorPos.y ) ); // Add all the drawable parts to preview preview.Add( module ); module->RunOnChildren( std::bind( &KIGFX::VIEW_GROUP::Add, &preview, _1 ) ); - - preview.ViewUpdate( KIGFX::VIEW_ITEM::GEOMETRY ); } else { - // Place the selected module - module->RunOnChildren( std::bind( &KIGFX::VIEW::Add, view, _1 ) ); - view->Add( module ); - module->ViewUpdate( KIGFX::VIEW_ITEM::GEOMETRY ); - - m_frame->OnModify(); - m_frame->SaveCopyInUndoList( module, UR_NEW ); + BOARD_COMMIT commit( m_frame ); + commit.Add( module ); + commit.Push( _( "Place a module" ) ); // Remove from preview preview.Remove( module ); @@ -416,7 +414,6 @@ int PCB_EDITOR_CONTROL::PlaceTarget( const TOOL_EVENT& aEvent ) KIGFX::VIEW_GROUP preview( view ); preview.Add( target ); view->Add( &preview ); - preview.ViewUpdate( KIGFX::VIEW_ITEM::GEOMETRY ); m_toolMgr->RunAction( COMMON_ACTIONS::selectionClear, true ); controls->SetSnapping( true ); @@ -454,12 +451,9 @@ int PCB_EDITOR_CONTROL::PlaceTarget( const TOOL_EVENT& aEvent ) assert( target->GetSize() > 0 ); assert( target->GetWidth() > 0 ); - view->Add( target ); - board->Add( target ); - target->ViewUpdate( KIGFX::VIEW_ITEM::GEOMETRY ); - - m_frame->OnModify(); - m_frame->SaveCopyInUndoList( target, UR_NEW ); + BOARD_COMMIT commit( m_frame ); + commit.Add( target ); + commit.Push( _( "Place a layer alignment target" ) ); preview.Remove( target ); @@ -579,6 +573,7 @@ int PCB_EDITOR_CONTROL::ZoneMerge( const TOOL_EVENT& aEvent ) BOARD* board = getModel(); RN_DATA* ratsnest = board->GetRatsnest(); KIGFX::VIEW* view = getView(); + BOARD_COMMIT commit( m_frame ); if( selection.Size() < 2 ) return 0; @@ -646,7 +641,8 @@ int PCB_EDITOR_CONTROL::ZoneMerge( const TOOL_EVENT& aEvent ) } m_toolMgr->RunAction( COMMON_ACTIONS::selectionClear, true ); - m_frame->SaveCopyInUndoList( changes, UR_UNSPECIFIED ); + + commit.Stage( changes ); for( unsigned i = 0; i < changes.GetCount(); ++i ) { @@ -660,11 +656,12 @@ int PCB_EDITOR_CONTROL::ZoneMerge( const TOOL_EVENT& aEvent ) } else if( picker.GetStatus() == UR_CHANGED ) { - item->ViewUpdate( KIGFX::VIEW_ITEM::ALL ); m_toolMgr->RunAction( COMMON_ACTIONS::selectItem, true, item ); } } + commit.Push( _( "Merge zones" ) ); + return 0; } diff --git a/pcbnew/tools/pcb_tool.h b/pcbnew/tools/pcb_tool.h new file mode 100644 index 0000000000..f235945512 --- /dev/null +++ b/pcbnew/tools/pcb_tool.h @@ -0,0 +1,87 @@ +/* + * This program source code file is part of KiCad, a free EDA CAD application. + * + * Copyright (C) 2016 CERN + * @author Tomasz Wlostowski + * + * 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 + */ + +#ifndef __PCB_TOOL_H +#define __PCB_TOOL_H + +#include + +#include +#include +#include +#include + +/** + * Class PCB_TOOL + * + * A tool operating on a BOARD object +**/ + +class PCB_TOOL : public TOOL_INTERACTIVE +{ +public: + /** + * Constructor + * + * Creates a tool with given id & name. The name must be unique. */ + PCB_TOOL( TOOL_ID aId, const std::string& aName ) : + TOOL_INTERACTIVE ( aId, aName ), + m_editModules( false ) {}; + + /** + * Constructor + * + * Creates a tool with given name. The name must be unique. */ + PCB_TOOL( const std::string& aName ) : + TOOL_INTERACTIVE ( aName ), + m_editModules( false ) {}; + + virtual ~PCB_TOOL() {}; + + /** + * Function SetEditModules() + * + * Toggles edit module mode. When enabled, one may select parts of modules individually + * (graphics, pads, etc.), so they can be modified. + * @param aEnabled decides if the mode should be enabled. + */ + void SetEditModules( bool aEnabled ) + { + m_editModules = aEnabled; + } + + bool EditingModules() const + { + return m_editModules; + } + +protected: + KIGFX::VIEW* view() const { return getView(); } + PCB_EDIT_FRAME* frame() const { return getEditFrame(); } + BOARD* board() const { return getModel(); } + + bool m_editModules; +}; + +#endif diff --git a/pcbnew/tools/pcbnew_control.cpp b/pcbnew/tools/pcbnew_control.cpp index fae470ed8e..ecc7e4fd79 100644 --- a/pcbnew/tools/pcbnew_control.cpp +++ b/pcbnew/tools/pcbnew_control.cpp @@ -48,6 +48,7 @@ #include #include #include +#include #include using namespace std::placeholders; @@ -770,12 +771,10 @@ int PCBNEW_CONTROL::AppendBoard( const TOOL_EVENT& aEvent ) { int open_ctl; wxString fileName; - PICKED_ITEMS_LIST undoListPicker; - ITEM_PICKER picker( NULL, UR_NEW ); PCB_EDIT_FRAME* editFrame = dynamic_cast( m_frame ); BOARD* board = getModel(); - KIGFX::VIEW* view = getView(); + BOARD_COMMIT commit( editFrame ); if( !editFrame ) return 0; @@ -839,9 +838,7 @@ int PCBNEW_CONTROL::AppendBoard( const TOOL_EVENT& aEvent ) continue; } - picker.SetItem( track ); - undoListPicker.PushItem( picker ); - view->Add( track ); + commit.Added( track ); m_toolMgr->RunAction( COMMON_ACTIONS::selectItem, true, track ); } @@ -849,11 +846,7 @@ int PCBNEW_CONTROL::AppendBoard( const TOOL_EVENT& aEvent ) for( ; module; module = module->Next() ) { - picker.SetItem( module ); - undoListPicker.PushItem( picker ); - - module->RunOnChildren( std::bind( &KIGFX::VIEW::Add, view, _1 ) ); - view->Add( module ); + commit.Added( module ); m_toolMgr->RunAction( COMMON_ACTIONS::selectItem, true, module ); } @@ -861,26 +854,22 @@ int PCBNEW_CONTROL::AppendBoard( const TOOL_EVENT& aEvent ) for( ; drawing; drawing = drawing->Next() ) { - picker.SetItem( drawing ); - undoListPicker.PushItem( picker ); - view->Add( drawing ); + commit.Added( drawing ); m_toolMgr->RunAction( COMMON_ACTIONS::selectItem, true, drawing ); } for( ZONE_CONTAINER* zone = board->GetArea( zonescount ); zone; zone = board->GetArea( zonescount ) ) { - picker.SetItem( zone ); - undoListPicker.PushItem( picker ); - zonescount++; - view->Add( zone ); + ++zonescount; + commit.Added( zone ); m_toolMgr->RunAction( COMMON_ACTIONS::selectItem, true, zone ); } - if( undoListPicker.GetCount() == 0 ) + if( commit.Empty() ) return 0; - editFrame->SaveCopyInUndoList( undoListPicker, UR_NEW ); + commit.Push( _( "Append a board" ) ); // Synchronize layers // we should not ask PLUGINs to do these items: @@ -901,10 +890,12 @@ int PCBNEW_CONTROL::AppendBoard( const TOOL_EVENT& aEvent ) // Ratsnest board->BuildListOfNets(); board->SynchronizeNetsAndNetClasses(); - board->GetRatsnest()->Recalculate(); + board->GetRatsnest()->ProcessBoard(); // Start dragging the appended board - VECTOR2D v( static_cast( undoListPicker.GetPickedItem( 0 ) )->GetPosition() ); + SELECTION_TOOL* selectionTool = m_toolMgr->GetTool(); + const SELECTION& selection = selectionTool->GetSelection(); + VECTOR2D v( selection.Item( 0 )->GetPosition() ); getViewControls()->WarpCursor( v, true, true ); m_toolMgr->InvokeTool( "pcbnew.InteractiveEdit" ); diff --git a/pcbnew/tools/placement_tool.cpp b/pcbnew/tools/placement_tool.cpp index 8452d18816..c5c6a5d723 100644 --- a/pcbnew/tools/placement_tool.cpp +++ b/pcbnew/tools/placement_tool.cpp @@ -1,7 +1,7 @@ /* * This program source code file is part of KiCad, a free EDA CAD application. * - * Copyright (C) 2014 CERN + * Copyright (C) 2014-2016 CERN * @author Maciej Suminski * * This program is free software; you can redistribute it and/or @@ -30,6 +30,7 @@ #include #include #include +#include #include @@ -75,39 +76,34 @@ int PLACEMENT_TOOL::AlignTop( const TOOL_EVENT& aEvent ) { const SELECTION& selection = m_selectionTool->GetSelection(); - if( selection.Size() > 1 ) + if( selection.Size() <= 1 ) + return 0; + + BOARD_COMMIT commit( getEditFrame() ); + commit.Stage( selection.items, UR_CHANGED ); + + // Compute the highest point of selection - it will be the edge of alignment + int top = selection.Item( 0 )->GetBoundingBox().GetY(); + + for( int i = 1; i < selection.Size(); ++i ) { - PCB_BASE_FRAME* editFrame = getEditFrame(); - RN_DATA* ratsnest = getModel()->GetRatsnest(); + int currentTop = selection.Item( i )->GetBoundingBox().GetY(); - editFrame->OnModify(); - editFrame->SaveCopyInUndoList( selection.items, UR_CHANGED ); - - // Compute the highest point of selection - it will be the edge of alignment - int top = selection.Item( 0 )->GetBoundingBox().GetY(); - - for( int i = 1; i < selection.Size(); ++i ) - { - int currentTop = selection.Item( i )->GetBoundingBox().GetY(); - - if( top > currentTop ) // Y decreases when going up - top = currentTop; - } - - // Move the selected items - for( int i = 0; i < selection.Size(); ++i ) - { - BOARD_ITEM* item = selection.Item( i ); - int difference = top - item->GetBoundingBox().GetY(); - - item->Move( wxPoint( 0, difference ) ); - item->ViewUpdate(); - ratsnest->Update( item ); - } - - getModel()->GetRatsnest()->Recalculate(); + if( top > currentTop ) // Y decreases when going up + top = currentTop; } + // Move the selected items + for( int i = 0; i < selection.Size(); ++i ) + { + BOARD_ITEM* item = selection.Item( i ); + int difference = top - item->GetBoundingBox().GetY(); + + item->Move( wxPoint( 0, difference ) ); + } + + commit.Push( _( "Align to top" ) ); + return 0; } @@ -116,39 +112,34 @@ int PLACEMENT_TOOL::AlignBottom( const TOOL_EVENT& aEvent ) { const SELECTION& selection = m_selectionTool->GetSelection(); - if( selection.Size() > 1 ) + if( selection.Size() <= 1 ) + return 0; + + BOARD_COMMIT commit( getEditFrame() ); + commit.Stage( selection.items, UR_CHANGED ); + + // Compute the lowest point of selection - it will be the edge of alignment + int bottom = selection.Item( 0 )->GetBoundingBox().GetBottom(); + + for( int i = 1; i < selection.Size(); ++i ) { - PCB_BASE_FRAME* editFrame = getEditFrame(); - RN_DATA* ratsnest = getModel()->GetRatsnest(); + int currentBottom = selection.Item( i )->GetBoundingBox().GetBottom(); - editFrame->OnModify(); - editFrame->SaveCopyInUndoList( selection.items, UR_CHANGED ); - - // Compute the lowest point of selection - it will be the edge of alignment - int bottom = selection.Item( 0 )->GetBoundingBox().GetBottom(); - - for( int i = 1; i < selection.Size(); ++i ) - { - int currentBottom = selection.Item( i )->GetBoundingBox().GetBottom(); - - if( bottom < currentBottom ) // Y increases when going down - bottom = currentBottom; - } - - // Move the selected items - for( int i = 0; i < selection.Size(); ++i ) - { - BOARD_ITEM* item = selection.Item( i ); - int difference = bottom - item->GetBoundingBox().GetBottom(); - - item->Move( wxPoint( 0, difference ) ); - item->ViewUpdate(); - ratsnest->Update( item ); - } - - getModel()->GetRatsnest()->Recalculate(); + if( bottom < currentBottom ) // Y increases when going down + bottom = currentBottom; } + // Move the selected items + for( int i = 0; i < selection.Size(); ++i ) + { + BOARD_ITEM* item = selection.Item( i ); + int difference = bottom - item->GetBoundingBox().GetBottom(); + + item->Move( wxPoint( 0, difference ) ); + } + + commit.Push( _( "Align to bottom" ) ); + return 0; } @@ -157,39 +148,34 @@ int PLACEMENT_TOOL::AlignLeft( const TOOL_EVENT& aEvent ) { const SELECTION& selection = m_selectionTool->GetSelection(); - if( selection.Size() > 1 ) + if( selection.Size() <= 1 ) + return 0; + + BOARD_COMMIT commit( getEditFrame() ); + commit.Stage( selection.items, UR_CHANGED ); + + // Compute the leftmost point of selection - it will be the edge of alignment + int left = selection.Item( 0 )->GetBoundingBox().GetX(); + + for( int i = 1; i < selection.Size(); ++i ) { - PCB_BASE_FRAME* editFrame = getEditFrame(); - RN_DATA* ratsnest = getModel()->GetRatsnest(); + int currentLeft = selection.Item( i )->GetBoundingBox().GetX(); - editFrame->OnModify(); - editFrame->SaveCopyInUndoList( selection.items, UR_CHANGED ); - - // Compute the leftmost point of selection - it will be the edge of alignment - int left = selection.Item( 0 )->GetBoundingBox().GetX(); - - for( int i = 1; i < selection.Size(); ++i ) - { - int currentLeft = selection.Item( i )->GetBoundingBox().GetX(); - - if( left > currentLeft ) // X decreases when going left - left = currentLeft; - } - - // Move the selected items - for( int i = 0; i < selection.Size(); ++i ) - { - BOARD_ITEM* item = selection.Item( i ); - int difference = left - item->GetBoundingBox().GetX(); - - item->Move( wxPoint( difference, 0 ) ); - item->ViewUpdate(); - ratsnest->Update( item ); - } - - getModel()->GetRatsnest()->Recalculate(); + if( left > currentLeft ) // X decreases when going left + left = currentLeft; } + // Move the selected items + for( int i = 0; i < selection.Size(); ++i ) + { + BOARD_ITEM* item = selection.Item( i ); + int difference = left - item->GetBoundingBox().GetX(); + + item->Move( wxPoint( difference, 0 ) ); + } + + commit.Push( _( "Align to left" ) ); + return 0; } @@ -198,39 +184,34 @@ int PLACEMENT_TOOL::AlignRight( const TOOL_EVENT& aEvent ) { const SELECTION& selection = m_selectionTool->GetSelection(); - if( selection.Size() > 1 ) + if( selection.Size() <= 1 ) + return 0; + + BOARD_COMMIT commit( getEditFrame() ); + commit.Stage( selection.items, UR_CHANGED ); + + // Compute the rightmost point of selection - it will be the edge of alignment + int right = selection.Item( 0 )->GetBoundingBox().GetRight(); + + for( int i = 1; i < selection.Size(); ++i ) { - PCB_BASE_FRAME* editFrame = getEditFrame(); - RN_DATA* ratsnest = getModel()->GetRatsnest(); + int currentRight = selection.Item( i )->GetBoundingBox().GetRight(); - editFrame->OnModify(); - editFrame->SaveCopyInUndoList( selection.items, UR_CHANGED ); - - // Compute the rightmost point of selection - it will be the edge of alignment - int right = selection.Item( 0 )->GetBoundingBox().GetRight(); - - for( int i = 1; i < selection.Size(); ++i ) - { - int currentRight = selection.Item( i )->GetBoundingBox().GetRight(); - - if( right < currentRight ) // X increases when going right - right = currentRight; - } - - // Move the selected items - for( int i = 0; i < selection.Size(); ++i ) - { - BOARD_ITEM* item = selection.Item( i ); - int difference = right - item->GetBoundingBox().GetRight(); - - item->Move( wxPoint( difference, 0 ) ); - item->ViewUpdate(); - ratsnest->Update( item ); - } - - getModel()->GetRatsnest()->Recalculate(); + if( right < currentRight ) // X increases when going right + right = currentRight; } + // Move the selected items + for( int i = 0; i < selection.Size(); ++i ) + { + BOARD_ITEM* item = selection.Item( i ); + int difference = right - item->GetBoundingBox().GetRight(); + + item->Move( wxPoint( difference, 0 ) ); + } + + commit.Push( _( "Align to right" ) ); + return 0; } @@ -251,45 +232,40 @@ int PLACEMENT_TOOL::DistributeHorizontally( const TOOL_EVENT& aEvent ) { const SELECTION& selection = m_selectionTool->GetSelection(); - if( selection.Size() > 1 ) + if( selection.Size() <= 1 ) + return 0; + + BOARD_COMMIT commit( getEditFrame() ); + commit.Stage( selection.items, UR_CHANGED ); + + // Prepare a list, so the items can be sorted by their X coordinate + std::list itemsList; + for( int i = 0; i < selection.Size(); ++i ) + itemsList.push_back( selection.Item( i ) ); + + // Sort items by X coordinate + itemsList.sort( compareX ); + + // Expected X coordinate for the next item (=minX) + int position = (*itemsList.begin())->GetBoundingBox().Centre().x; + + // X coordinate for the last item + const int maxX = (*itemsList.rbegin())->GetBoundingBox().Centre().x; + + // Distance between items + const int distance = ( maxX - position ) / ( itemsList.size() - 1 ); + + for( BOARD_ITEM* item : itemsList ) { - PCB_BASE_FRAME* editFrame = getEditFrame(); - RN_DATA* ratsnest = getModel()->GetRatsnest(); + int difference = position - item->GetBoundingBox().Centre().x; - editFrame->OnModify(); - editFrame->SaveCopyInUndoList( selection.items, UR_CHANGED ); + item->Move( wxPoint( difference, 0 ) ); - // Prepare a list, so the items can be sorted by their X coordinate - std::list itemsList; - for( int i = 0; i < selection.Size(); ++i ) - itemsList.push_back( selection.Item( i ) ); - - // Sort items by X coordinate - itemsList.sort( compareX ); - - // Expected X coordinate for the next item (=minX) - int position = (*itemsList.begin())->GetBoundingBox().Centre().x; - - // X coordinate for the last item - const int maxX = (*itemsList.rbegin())->GetBoundingBox().Centre().x; - - // Distance between items - const int distance = ( maxX - position ) / ( itemsList.size() - 1 ); - - for( BOARD_ITEM* item : itemsList ) - { - int difference = position - item->GetBoundingBox().Centre().x; - - item->Move( wxPoint( difference, 0 ) ); - item->ViewUpdate(); - ratsnest->Update( item ); - - position += distance; - } - - getModel()->GetRatsnest()->Recalculate(); + position += distance; } + commit.Push( _( "Distribute horizontally" ) ); + return 0; } @@ -298,45 +274,40 @@ int PLACEMENT_TOOL::DistributeVertically( const TOOL_EVENT& aEvent ) { const SELECTION& selection = m_selectionTool->GetSelection(); - if( selection.Size() > 1 ) + if( selection.Size() <= 1 ) + return 0; + + BOARD_COMMIT commit( getEditFrame() ); + commit.Stage( selection.items, UR_CHANGED ); + + // Prepare a list, so the items can be sorted by their Y coordinate + std::list itemsList; + for( int i = 0; i < selection.Size(); ++i ) + itemsList.push_back( selection.Item( i ) ); + + // Sort items by Y coordinate + itemsList.sort( compareY ); + + // Expected Y coordinate for the next item (=minY) + int position = (*itemsList.begin())->GetBoundingBox().Centre().y; + + // Y coordinate for the last item + const int maxY = (*itemsList.rbegin())->GetBoundingBox().Centre().y; + + // Distance between items + const int distance = ( maxY - position ) / ( itemsList.size() - 1 ); + + for( BOARD_ITEM* item : itemsList ) { - PCB_BASE_FRAME* editFrame = getEditFrame(); - RN_DATA* ratsnest = getModel()->GetRatsnest(); + int difference = position - item->GetBoundingBox().Centre().y; - editFrame->OnModify(); - editFrame->SaveCopyInUndoList( selection.items, UR_CHANGED ); + item->Move( wxPoint( 0, difference ) ); - // Prepare a list, so the items can be sorted by their Y coordinate - std::list itemsList; - for( int i = 0; i < selection.Size(); ++i ) - itemsList.push_back( selection.Item( i ) ); - - // Sort items by Y coordinate - itemsList.sort( compareY ); - - // Expected Y coordinate for the next item (=minY) - int position = (*itemsList.begin())->GetBoundingBox().Centre().y; - - // Y coordinate for the last item - const int maxY = (*itemsList.rbegin())->GetBoundingBox().Centre().y; - - // Distance between items - const int distance = ( maxY - position ) / ( itemsList.size() - 1 ); - - for( BOARD_ITEM* item : itemsList ) - { - int difference = position - item->GetBoundingBox().Centre().y; - - item->Move( wxPoint( 0, difference ) ); - item->ViewUpdate(); - ratsnest->Update( item ); - - position += distance; - } - - getModel()->GetRatsnest()->Recalculate(); + position += distance; } + commit.Push( _( "Distribute vertically" ) ); + return 0; } diff --git a/pcbnew/tools/point_editor.cpp b/pcbnew/tools/point_editor.cpp index 98d866c0e0..48705ae7cc 100644 --- a/pcbnew/tools/point_editor.cpp +++ b/pcbnew/tools/point_editor.cpp @@ -34,6 +34,7 @@ using namespace std::placeholders; #include "common_actions.h" #include "selection_tool.h" #include "point_editor.h" +#include #include #include @@ -259,6 +260,8 @@ int POINT_EDITOR::OnSelectionChange( const TOOL_EVENT& aEvent ) m_editedPoint = NULL; bool modified = false; + BOARD_COMMIT commit( editFrame ); + // Main loop: keep receiving events while( OPT_TOOL_EVENT evt = Wait() ) { @@ -292,9 +295,8 @@ int POINT_EDITOR::OnSelectionChange( const TOOL_EVENT& aEvent ) { if( !modified ) { - // Save items, so changes can be undone - editFrame->OnModify(); - editFrame->SaveCopyInUndoList( selection.items, UR_CHANGED ); + commit.Stage( selection.items, UR_CHANGED ); + controls->ForceCursorPosition( false ); m_original = *m_editedPoint; // Save the original position controls->SetAutoPan( true ); @@ -302,6 +304,7 @@ int POINT_EDITOR::OnSelectionChange( const TOOL_EVENT& aEvent ) } bool enableAltConstraint = !!evt->Modifier( MD_CTRL ); + if( enableAltConstraint != (bool) m_altConstraint ) // alternative constraint setAltConstraint( enableAltConstraint ); @@ -314,11 +317,9 @@ int POINT_EDITOR::OnSelectionChange( const TOOL_EVENT& aEvent ) updateItem(); updatePoints(); - - m_editPoints->ViewUpdate( KIGFX::VIEW_ITEM::GEOMETRY ); } - else if( evt->IsAction( &COMMON_ACTIONS::pointEditorUpdate ) ) + else if( evt->IsAction( &COMMON_ACTIONS::editModifiedSelection ) ) { updatePoints(); } @@ -327,7 +328,13 @@ int POINT_EDITOR::OnSelectionChange( const TOOL_EVENT& aEvent ) { controls->SetAutoPan( false ); setAltConstraint( false ); - modified = false; + + if( modified ) + { + commit.Push( _( "Drag a line ending" ) ); + modified = false; + } + m_toolMgr->PassEvent(); } @@ -335,9 +342,7 @@ int POINT_EDITOR::OnSelectionChange( const TOOL_EVENT& aEvent ) { if( modified ) // Restore the last change { - wxCommandEvent dummy; - editFrame->RestoreCopyFromUndoList( dummy ); - + commit.Revert(); updatePoints(); modified = false; } @@ -357,7 +362,6 @@ int POINT_EDITOR::OnSelectionChange( const TOOL_EVENT& aEvent ) if( m_editPoints ) { finishItem(); - item->ViewUpdate( KIGFX::VIEW_ITEM::GEOMETRY ); view->Remove( m_editPoints.get() ); m_editPoints.reset(); } @@ -615,6 +619,8 @@ void POINT_EDITOR::updatePoints() default: break; } + + m_editPoints->ViewUpdate(); } @@ -719,16 +725,16 @@ EDIT_POINT POINT_EDITOR::get45DegConstrainer() const void POINT_EDITOR::addCorner( const VECTOR2I& aBreakPoint ) { EDA_ITEM* item = m_editPoints->GetParent(); - const SELECTION& selection = m_selectionTool->GetSelection(); + PCB_BASE_EDIT_FRAME* frame = getEditFrame(); + BOARD_COMMIT commit( frame ); if( item->Type() == PCB_ZONE_AREA_T ) { - getEditFrame()->OnModify(); - getEditFrame()->SaveCopyInUndoList( selection.items, UR_CHANGED ); - ZONE_CONTAINER* zone = static_cast( item ); CPolyLine* outline = zone->Outline(); + commit.Modify( zone ); + // Handle the last segment, so other segments can be easily handled in a loop unsigned int nearestIdx = outline->GetCornersCount() - 1, nextNearestIdx = 0; SEG side( VECTOR2I( outline->GetPos( nearestIdx ) ), @@ -760,24 +766,21 @@ void POINT_EDITOR::addCorner( const VECTOR2I& aBreakPoint ) nearestPoint = ( sideOrigin + sideEnd ) / 2; outline->InsertCorner( nearestIdx, nearestPoint.x, nearestPoint.y ); + + commit.Push( _( "Add a zone corner" ) ); } else if( item->Type() == PCB_LINE_T || item->Type() == PCB_MODULE_EDGE_T ) { bool moduleEdge = item->Type() == PCB_MODULE_EDGE_T; - PCB_BASE_FRAME* frame = getEditFrame(); - - frame->OnModify(); - - if( moduleEdge ) - frame->SaveCopyInUndoList( getModel()->m_Modules, UR_MODEDIT ); - else - frame->SaveCopyInUndoList( selection.items, UR_CHANGED ); DRAWSEGMENT* segment = static_cast( item ); if( segment->GetShape() == S_SEGMENT ) { + BOARD_COMMIT commit( frame ); + commit.Modify( segment ); + SEG seg( segment->GetStart(), segment->GetEnd() ); VECTOR2I nearestPoint = seg.NearestPoint( aBreakPoint ); @@ -790,9 +793,9 @@ void POINT_EDITOR::addCorner( const VECTOR2I& aBreakPoint ) if( moduleEdge ) { EDGE_MODULE* edge = static_cast( segment ); - assert( segment->GetParent()->Type() == PCB_MODULE_T ); + assert( edge->Type() == PCB_MODULE_EDGE_T ); + assert( edge->GetParent()->Type() == PCB_MODULE_T ); newSegment = new EDGE_MODULE( *edge ); - edge->SetLocalCoord(); } else { @@ -803,17 +806,8 @@ void POINT_EDITOR::addCorner( const VECTOR2I& aBreakPoint ) newSegment->SetStart( wxPoint( nearestPoint.x, nearestPoint.y ) ); newSegment->SetEnd( wxPoint( seg.B.x, seg.B.y ) ); - if( moduleEdge ) - { - static_cast( newSegment )->SetLocalCoord(); - getModel()->m_Modules->Add( newSegment ); - } - else - { - getModel()->Add( newSegment ); - } - - getView()->Add( newSegment ); + commit.Add( newSegment ); + commit.Push( _( "Split segment" ) ); } } } @@ -825,20 +819,20 @@ void POINT_EDITOR::removeCorner( EDIT_POINT* aPoint ) if( item->Type() == PCB_ZONE_AREA_T ) { - const SELECTION& selection = m_selectionTool->GetSelection(); PCB_BASE_FRAME* frame = getEditFrame(); + BOARD_COMMIT commit( frame ); ZONE_CONTAINER* zone = static_cast( item ); CPolyLine* outline = zone->Outline(); + commit.Modify( zone ); for( int i = 0; i < outline->GetCornersCount(); ++i ) { if( VECTOR2I( outline->GetPos( i ) ) == aPoint->GetPosition() ) { - frame->OnModify(); - frame->SaveCopyInUndoList( selection.items, UR_CHANGED ); outline->DeleteCorner( i ); setEditedPoint( NULL ); + commit.Push( _( "Remove a zone corner" ) ); break; } } diff --git a/pcbnew/tools/selection_tool.cpp b/pcbnew/tools/selection_tool.cpp index d08ca74c50..97c32a5bae 100644 --- a/pcbnew/tools/selection_tool.cpp +++ b/pcbnew/tools/selection_tool.cpp @@ -68,8 +68,8 @@ public: SELECTION_TOOL::SELECTION_TOOL() : - TOOL_INTERACTIVE( "pcbnew.InteractiveSelection" ), - m_frame( NULL ), m_additive( false ), m_multiple( false ), m_editModules( false ), + PCB_TOOL( "pcbnew.InteractiveSelection" ), + m_frame( NULL ), m_additive( false ), m_multiple( false ), m_locked( true ), m_menu( this ), m_contextMenu( NULL ), m_selectMenu( NULL ), m_zoomMenu( NULL ), m_gridMenu( NULL ) { @@ -360,12 +360,9 @@ bool SELECTION_TOOL::selectPoint( const VECTOR2I& aWhere, bool aOnDrag ) GENERAL_COLLECTORS_GUIDE guide = m_frame->GetCollectorsGuide(); GENERAL_COLLECTOR collector; - if( m_editModules ) - collector.Collect( getModel(), GENERAL_COLLECTOR::ModuleItems, - wxPoint( aWhere.x, aWhere.y ), guide ); - else - collector.Collect( getModel(), GENERAL_COLLECTOR::AllBoardItems, - wxPoint( aWhere.x, aWhere.y ), guide ); + collector.Collect( getModel(), + m_editModules ? GENERAL_COLLECTOR::ModuleItems : GENERAL_COLLECTOR::AllBoardItems, + wxPoint( aWhere.x, aWhere.y ), guide ); bool anyCollected = collector.GetCount() != 0; diff --git a/pcbnew/tools/selection_tool.h b/pcbnew/tools/selection_tool.h index 4a04516f28..508d35f16a 100644 --- a/pcbnew/tools/selection_tool.h +++ b/pcbnew/tools/selection_tool.h @@ -27,7 +27,7 @@ #define __SELECTION_TOOL_H #include -#include +#include #include #include @@ -111,7 +111,7 @@ enum SELECTION_LOCK_FLAGS * - takes into account high-contrast & layer visibility settings * - invokes InteractiveEdit tool when user starts to drag selected items */ -class SELECTION_TOOL : public TOOL_INTERACTIVE +class SELECTION_TOOL : public PCB_TOOL { public: SELECTION_TOOL(); @@ -137,18 +137,6 @@ public: */ const SELECTION& GetSelection(); - /** - * Function EditModules() - * - * Toggles edit module mode. When enabled, one may select parts of modules individually - * (graphics, pads, etc.), so they can be modified. - * @param aEnabled decides if the mode should be enabled. - */ - inline void EditModules( bool aEnabled ) - { - m_editModules = aEnabled; - } - inline CONDITIONAL_MENU& GetMenu() { return m_menu; @@ -339,9 +327,6 @@ private: /// Flag saying if multiple selection mode is active. bool m_multiple; - /// Edit module mode flag. - bool m_editModules; - /// Can other tools modify locked items. bool m_locked; diff --git a/pcbnew/board_undo_redo.cpp b/pcbnew/undo_redo.cpp similarity index 74% rename from pcbnew/board_undo_redo.cpp rename to pcbnew/undo_redo.cpp index c7aecac947..cd6e3d0900 100644 --- a/pcbnew/board_undo_redo.cpp +++ b/pcbnew/undo_redo.cpp @@ -3,7 +3,9 @@ * * Copyright (C) 2012 Jean-Pierre Charras, jean-pierre.charras@ujf-grenoble.fr * Copyright (C) 2012 SoftPLC Corporation, Dick Hollenbeck - * Copyright (C) 1992-2012 KiCad Developers, see AUTHORS.txt for contributors. + * Copyright (C) 2016 CERN + * @author Maciej Suminski + * Copyright (C) 1992-2016 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 @@ -120,40 +122,13 @@ using namespace std::placeholders; static bool TestForExistingItem( BOARD* aPcb, BOARD_ITEM* aItem ) { - static std::vector itemsList; + static std::list itemsList; if( aItem == NULL ) // Build list { // Count items to store in itemsList: - int icnt = 0; BOARD_ITEM* item; - - // Count tracks: - for( item = aPcb->m_Track; item != NULL; item = item->Next() ) - icnt++; - - // Count modules: - for( item = aPcb->m_Modules; item != NULL; item = item->Next() ) - icnt++; - - // Count drawings - for( item = aPcb->m_Drawings; item != NULL; item = item->Next() ) - icnt++; - - // Count zones outlines - icnt += aPcb->GetAreaCount(); - - // Count zones segm (now obsolete): - for( item = aPcb->m_Zone; item != NULL; item = item->Next() ) - icnt++; - - NETINFO_LIST& netInfo = aPcb->GetNetInfo(); - - icnt += netInfo.GetNetCount(); - - // Build candidate list: itemsList.clear(); - itemsList.reserve(icnt); // Store items in list: // Append tracks: @@ -176,11 +151,14 @@ static bool TestForExistingItem( BOARD* aPcb, BOARD_ITEM* aItem ) for( item = aPcb->m_Zone; item != NULL; item = item->Next() ) itemsList.push_back( item ); + NETINFO_LIST& netInfo = aPcb->GetNetInfo(); + for( NETINFO_LIST::iterator i = netInfo.begin(); i != netInfo.end(); ++i ) itemsList.push_back( *i ); // Sort list - std::sort( itemsList.begin(), itemsList.end() ); + itemsList.sort(); + return false; } @@ -189,222 +167,42 @@ static bool TestForExistingItem( BOARD* aPcb, BOARD_ITEM* aItem ) } -void BOARD_ITEM::SwapData( BOARD_ITEM* aImage ) +void PCB_BASE_EDIT_FRAME::SaveCopyInUndoList( BOARD_ITEM* aItem, UNDO_REDO_T aCommandType, + const wxPoint& aTransformPoint ) { - if( aImage == NULL ) - return; - - // Remark: to create images of edited items to undo, we are using Clone method - // which can duplication of items foe copy, but does not clone all members - // mainly pointers in chain and time stamp, which is set to new, unique value. - // So we have to use the current values of these parameters. - - EDA_ITEM * pnext = Next(); - EDA_ITEM * pback = Back(); - DHEAD* mylist = m_List; - time_t timestamp = GetTimeStamp(); - - switch( Type() ) - { - case PCB_MODULE_T: - { - MODULE* tmp = (MODULE*) aImage->Clone(); - ( (MODULE*) aImage )->Copy( (MODULE*) this ); - ( (MODULE*) this )->Copy( tmp ); - delete tmp; - } - break; - - case PCB_ZONE_AREA_T: - { - ZONE_CONTAINER* tmp = (ZONE_CONTAINER*) aImage->Clone(); - ( (ZONE_CONTAINER*) aImage )->Copy( (ZONE_CONTAINER*) this ); - ( (ZONE_CONTAINER*) this )->Copy( tmp ); - delete tmp; - } - break; - - case PCB_LINE_T: - std::swap( *((DRAWSEGMENT*)this), *((DRAWSEGMENT*)aImage) ); - break; - - case PCB_TRACE_T: - case PCB_VIA_T: - { - TRACK* track = (TRACK*) this; - TRACK* image = (TRACK*) aImage; - - std::swap(track->m_Layer, image->m_Layer ); - - // swap start, end, width and shape for track and image. - wxPoint exchp = track->GetStart(); - track->SetStart( image->GetStart() ); - image->SetStart( exchp ); - exchp = track->GetEnd(); - track->SetEnd( image->GetEnd() ); - image->SetEnd( exchp ); - - int atmp = track->GetWidth(); - track->SetWidth( image->GetWidth() ); - image->SetWidth( atmp ); - - if( Type() == PCB_VIA_T ) - { - VIA *via = static_cast( this ); - VIA *viaimage = static_cast( aImage ); - - VIATYPE_T viatmp = via->GetViaType(); - via->SetViaType( viaimage->GetViaType() ); - viaimage->SetViaType( viatmp ); - - int drilltmp = via->GetDrillValue(); - - if( via->IsDrillDefault() ) - drilltmp = -1; - - int itmp = viaimage->GetDrillValue(); - - if( viaimage->IsDrillDefault() ) - itmp = -1; - - std::swap(itmp, drilltmp ); - - if( drilltmp > 0 ) - via->SetDrill( drilltmp ); - else - via->SetDrillDefault(); - - if( itmp > 0 ) - viaimage->SetDrill( itmp ); - else - viaimage->SetDrillDefault(); - } - } - break; - - case PCB_TEXT_T: - std::swap( *((TEXTE_PCB*)this), *((TEXTE_PCB*)aImage) ); - break; - - case PCB_TARGET_T: - std::swap( *((PCB_TARGET*)this), *((PCB_TARGET*)aImage) ); - break; - - case PCB_DIMENSION_T: - std::swap( *((DIMENSION*)this), *((DIMENSION*)aImage) ); - break; - - case PCB_ZONE_T: - default: - wxLogMessage( wxT( "SwapData() error: unexpected type %d" ), Type() ); - break; - } - - // Restore pointers and time stamp, to be sure they are not broken - Pnext = pnext; - Pback = pback; - m_List = mylist; - SetTimeStamp( timestamp ); + PICKED_ITEMS_LIST commandToUndo; + commandToUndo.PushItem( ITEM_PICKER( aItem, aCommandType ) ); + SaveCopyInUndoList( commandToUndo, aCommandType, aTransformPoint ); } -void PCB_EDIT_FRAME::SaveCopyInUndoList( BOARD_ITEM* aItem, - UNDO_REDO_T aCommandType, - const wxPoint& aTransformPoint ) -{ - if( aItem == NULL ) // Nothing to save - return; - - // For texts belonging to modules, we need to save state of the parent module - if( aItem->Type() == PCB_MODULE_TEXT_T ) - { - aItem = aItem->GetParent(); - wxASSERT( aItem->Type() == PCB_MODULE_T ); - aCommandType = UR_CHANGED; - - if( aItem == NULL ) - return; - } - - PICKED_ITEMS_LIST* commandToUndo = new PICKED_ITEMS_LIST(); - - commandToUndo->m_TransformPoint = aTransformPoint; - - ITEM_PICKER itemWrapper( aItem, aCommandType ); - - switch( aCommandType ) - { - case UR_CHANGED: // Create a copy of item - if( itemWrapper.GetLink() == NULL ) // When not null, the copy is already done - itemWrapper.SetLink( aItem->Clone() ); - commandToUndo->PushItem( itemWrapper ); - break; - - case UR_NEW: - case UR_DELETED: -#ifdef USE_WX_OVERLAY - // Avoid to redraw when autoplacing - if( aItem->Type() == PCB_MODULE_T ) - if( ((MODULE*)aItem)->GetFlags() & MODULE_to_PLACE ) - break; - m_canvas->Refresh(); -#endif - case UR_MOVED: - case UR_FLIPPED: - case UR_ROTATED: - case UR_ROTATED_CLOCKWISE: - commandToUndo->PushItem( itemWrapper ); - break; - - default: - { - wxString msg; - msg.Printf( wxT( "SaveCopyInUndoList() error (unknown code %X)" ), aCommandType ); - wxMessageBox( msg ); - } - break; - } - - if( commandToUndo->GetCount() ) - { - /* Save the copy in undo list */ - GetScreen()->PushCommandToUndoList( commandToUndo ); - - /* Clear redo list, because after new save there is no redo to do */ - GetScreen()->ClearUndoORRedoList( GetScreen()->m_RedoList ); - } - else - { - delete commandToUndo; - } -} - - -void PCB_EDIT_FRAME::SaveCopyInUndoList( const PICKED_ITEMS_LIST& aItemsList, - UNDO_REDO_T aTypeCommand, - const wxPoint& aTransformPoint ) +void PCB_BASE_EDIT_FRAME::SaveCopyInUndoList( const PICKED_ITEMS_LIST& aItemsList, + UNDO_REDO_T aTypeCommand, const wxPoint& aTransformPoint ) { PICKED_ITEMS_LIST* commandToUndo = new PICKED_ITEMS_LIST(); commandToUndo->m_TransformPoint = aTransformPoint; // First, filter unnecessary stuff from the list (i.e. for multiple pads / labels modified), - // take the first occurence of the module. - + // take the first occurence of the module (we save copies of modules when one of its subitems + // is changed). for( unsigned ii = 0; ii < aItemsList.GetCount(); ii++ ) { ITEM_PICKER picker = aItemsList.GetItemWrapper(ii); BOARD_ITEM* item = (BOARD_ITEM*) aItemsList.GetPickedItem( ii ); - // For texts belonging to modules, we need to save state of the parent module - if( item->Type() == PCB_MODULE_TEXT_T || item->Type() == PCB_PAD_T ) + // For items belonging to modules, we need to save state of the parent module + if( item->Type() == PCB_MODULE_TEXT_T || item->Type() == PCB_MODULE_EDGE_T + || item->Type() == PCB_PAD_T ) { + // Item to be stored in the undo buffer is the parent module item = item->GetParent(); - wxASSERT( item->Type() == PCB_MODULE_T ); + wxASSERT( item && item->Type() == PCB_MODULE_T ); if( item == NULL ) continue; + // Check if the parent module has already been saved in another entry bool found = false; for( unsigned j = 0; j < commandToUndo->GetCount(); j++ ) @@ -417,11 +215,35 @@ void PCB_EDIT_FRAME::SaveCopyInUndoList( const PICKED_ITEMS_LIST& aItemsList, } if( !found ) - commandToUndo->PushItem( ITEM_PICKER(item, UR_CHANGED ) ); + { + // Create a clean copy of the parent module + MODULE* orig = static_cast( item ); + MODULE* clone = new MODULE( *orig ); + clone->SetParent( GetBoard() ); + + // Clear current flags (which can be temporary set by a current edit command) + for( EDA_ITEM* item = clone->GraphicalItems(); item; item = item->Next() ) + item->ClearFlags(); + + for( D_PAD* pad = clone->Pads(); pad; pad = pad->Next() ) + pad->ClearFlags(); + + clone->Reference().ClearFlags(); + clone->Value().ClearFlags(); + + ITEM_PICKER picker( item, UR_CHANGED ); + picker.SetLink( clone ); + commandToUndo->PushItem( picker ); + + orig->SetLastEditTime(); + } else + { continue; + } } else { + // Normal case: all other BOARD_ITEMs, are simply copied to the new list commandToUndo->PushItem( picker ); } } @@ -468,7 +290,6 @@ void PCB_EDIT_FRAME::SaveCopyInUndoList( const PICKED_ITEMS_LIST& aItemsList, msg.Printf( wxT( "SaveCopyInUndoList() error (unknown code %X)" ), command ); wxMessageBox( msg ); } - break; } @@ -482,14 +303,70 @@ void PCB_EDIT_FRAME::SaveCopyInUndoList( const PICKED_ITEMS_LIST& aItemsList, /* Clear redo list, because after a new command one cannot redo a command */ GetScreen()->ClearUndoORRedoList( GetScreen()->m_RedoList ); } - else // Should not occur + else { + // Should not occur + wxASSERT( false ); delete commandToUndo; } } -void PCB_EDIT_FRAME::PutDataInPreviousState( PICKED_ITEMS_LIST* aList, bool aRedoCommand, +void PCB_BASE_EDIT_FRAME::RestoreCopyFromUndoList( wxCommandEvent& aEvent ) +{ + if( UndoRedoBlocked() ) + return; + + if( GetScreen()->GetUndoCommandCount() <= 0 ) + return; + + // Inform tools that undo command was issued + TOOL_EVENT event( TC_MESSAGE, TA_UNDO_REDO, AS_GLOBAL ); + m_toolManager->ProcessEvent( event ); + + // Get the old list + PICKED_ITEMS_LIST* List = GetScreen()->PopCommandFromUndoList(); + + // Undo the command + PutDataInPreviousState( List, false ); + + // Put the old list in RedoList + List->ReversePickersListOrder(); + GetScreen()->PushCommandToRedoList( List ); + + OnModify(); + m_canvas->Refresh(); +} + + +void PCB_BASE_EDIT_FRAME::RestoreCopyFromRedoList( wxCommandEvent& aEvent ) +{ + if( UndoRedoBlocked() ) + return; + + if( GetScreen()->GetRedoCommandCount() == 0 ) + return; + + // Inform tools that redo command was issued + TOOL_EVENT event( TC_MESSAGE, TA_UNDO_REDO, AS_GLOBAL ); + m_toolManager->ProcessEvent( event ); + + // Get the old list + PICKED_ITEMS_LIST* List = GetScreen()->PopCommandFromRedoList(); + + // Redo the command + PutDataInPreviousState( List, true ); + + // Put the old list in UndoList + List->ReversePickersListOrder(); + GetScreen()->PushCommandToUndoList( List ); + + OnModify(); + m_canvas->Refresh(); +} + + +void PCB_BASE_EDIT_FRAME::PutDataInPreviousState( PICKED_ITEMS_LIST* aList, bool aRedoCommand, bool aRebuildRatsnet ) { BOARD_ITEM* item; @@ -505,6 +382,7 @@ void PCB_EDIT_FRAME::PutDataInPreviousState( PICKED_ITEMS_LIST* aList, bool aRed bool build_item_list = true; // if true the list of existing items must be rebuilt + // Restore changes in reverse order for( int ii = aList->GetCount() - 1; ii >= 0 ; ii-- ) { item = (BOARD_ITEM*) aList->GetPickedItem( ii ); @@ -529,6 +407,9 @@ void PCB_EDIT_FRAME::PutDataInPreviousState( PICKED_ITEMS_LIST* aList, bool aRed if( !TestForExistingItem( GetBoard(), item ) ) { + // Checking if it ever happens + wxASSERT_MSG( false, "Item in the undo buffer does not exist" ); + // Remove this non existent item aList->RemovePicker( ii ); ii++; // the current item was removed, ii points now the next item @@ -559,6 +440,9 @@ void PCB_EDIT_FRAME::PutDataInPreviousState( PICKED_ITEMS_LIST* aList, bool aRed break; } + // It is possible that we are going to replace the selected item, so clear it + SetCurItem( NULL ); + switch( aList->GetPickedItemStatus( ii ) ) { case UR_CHANGED: /* Exchange old and new data for each item */ @@ -572,6 +456,7 @@ void PCB_EDIT_FRAME::PutDataInPreviousState( PICKED_ITEMS_LIST* aList, bool aRed MODULE* oldModule = static_cast( item ); oldModule->RunOnChildren( std::bind( &KIGFX::VIEW::Remove, view, _1 ) ); } + view->Remove( item ); ratsnest->Remove( item ); @@ -583,18 +468,19 @@ void PCB_EDIT_FRAME::PutDataInPreviousState( PICKED_ITEMS_LIST* aList, bool aRed { MODULE* newModule = static_cast( item ); newModule->RunOnChildren( std::bind( &KIGFX::VIEW::Add, view, _1 ) ); + newModule->RunOnChildren( std::bind( &BOARD_ITEM::ClearFlags, _1, EDA_ITEM_ALL_FLAGS )); } + view->Add( item ); ratsnest->Add( item ); - - item->ClearFlags( SELECTED ); + item->ClearFlags(); item->ViewUpdate( KIGFX::VIEW_ITEM::LAYERS ); } break; case UR_NEW: /* new items are deleted */ aList->SetPickedItemStatus( UR_DELETED, ii ); - GetBoard()->Remove( item ); + GetModel()->Remove( item ); if( item->Type() == PCB_MODULE_T ) { @@ -608,15 +494,15 @@ void PCB_EDIT_FRAME::PutDataInPreviousState( PICKED_ITEMS_LIST* aList, bool aRed case UR_DELETED: /* deleted items are put in List, as new items */ aList->SetPickedItemStatus( UR_NEW, ii ); - GetBoard()->Add( item ); + GetModel()->Add( item ); if( item->Type() == PCB_MODULE_T ) { MODULE* module = static_cast( item ); module->RunOnChildren( std::bind( &KIGFX::VIEW::Add, view, _1) ); } - view->Add( item ); + view->Add( item ); item->ViewUpdate( KIGFX::VIEW_ITEM::GEOMETRY ); build_item_list = true; break; @@ -664,7 +550,10 @@ void PCB_EDIT_FRAME::PutDataInPreviousState( PICKED_ITEMS_LIST* aList, bool aRed // Rebuild pointers and ratsnest that can be changed. if( reBuild_ratsnest ) { - Compile_Ratsnest( NULL, true ); + // Compile ratsnest propagates nets from pads to tracks + /// @todo LEGACY Compile_Ratsnest() has to be rewritten and moved to RN_DATA + if( deep_reBuild_ratsnest ) + Compile_Ratsnest( NULL, false ); if( IsGalCanvasActive() ) { @@ -673,61 +562,74 @@ void PCB_EDIT_FRAME::PutDataInPreviousState( PICKED_ITEMS_LIST* aList, bool aRed else ratsnest->Recalculate(); } - } } -void PCB_EDIT_FRAME::RestoreCopyFromUndoList( wxCommandEvent& aEvent ) +void BOARD_ITEM::SwapData( BOARD_ITEM* aImage ) { - if( UndoRedoBlocked() ) + if( aImage == NULL ) return; - if( GetScreen()->GetUndoCommandCount() <= 0 ) - return; + wxASSERT( Type() == aImage->Type() ); - // Inform tools that undo command was issued - TOOL_EVENT event( TC_MESSAGE, TA_UNDO_REDO, AS_GLOBAL ); - m_toolManager->ProcessEvent( event ); + // Remark: to create images of edited items to undo, we are using Clone method + // which can duplication of items foe copy, but does not clone all members + // mainly pointers in chain and time stamp, which is set to new, unique value. + // So we have to use the current values of these parameters. - /* Get the old list */ - PICKED_ITEMS_LIST* List = GetScreen()->PopCommandFromUndoList(); - /* Undo the command */ - PutDataInPreviousState( List, false ); + EDA_ITEM* pnext = Next(); + EDA_ITEM* pback = Back(); + DHEAD* mylist = m_List; + time_t timestamp = GetTimeStamp(); + EDA_ITEM* parent = GetParent(); - /* Put the old list in RedoList */ - List->ReversePickersListOrder(); - GetScreen()->PushCommandToRedoList( List ); + switch( Type() ) + { + case PCB_MODULE_T: + std::swap( *((MODULE*) this), *((MODULE*) aImage) ); + break; - OnModify(); - m_canvas->Refresh(); -} + case PCB_ZONE_AREA_T: + std::swap( *((ZONE_CONTAINER*) this), *((ZONE_CONTAINER*) aImage) ); + break; + case PCB_LINE_T: + std::swap( *((DRAWSEGMENT*) this), *((DRAWSEGMENT*) aImage) ); + break; -void PCB_EDIT_FRAME::RestoreCopyFromRedoList( wxCommandEvent& aEvent ) -{ - if( UndoRedoBlocked() ) - return; + case PCB_TRACE_T: + std::swap( *((TRACK*) this), *((TRACK*) aImage) ); + break; - if( GetScreen()->GetRedoCommandCount() == 0 ) - return; + case PCB_VIA_T: + std::swap( *((VIA*) this), *((VIA*) aImage) ); + break; - // Inform tools that redo command was issued - TOOL_EVENT event( TC_MESSAGE, TA_UNDO_REDO, AS_GLOBAL ); - m_toolManager->ProcessEvent( event ); + case PCB_TEXT_T: + std::swap( *((TEXTE_PCB*)this), *((TEXTE_PCB*)aImage) ); + break; - /* Get the old list */ - PICKED_ITEMS_LIST* List = GetScreen()->PopCommandFromRedoList(); + case PCB_TARGET_T: + std::swap( *((PCB_TARGET*)this), *((PCB_TARGET*)aImage) ); + break; - /* Redo the command: */ - PutDataInPreviousState( List, true ); + case PCB_DIMENSION_T: + std::swap( *((DIMENSION*)this), *((DIMENSION*)aImage) ); + break; - /* Put the old list in UndoList */ - List->ReversePickersListOrder(); - GetScreen()->PushCommandToUndoList( List ); + case PCB_ZONE_T: + default: + wxLogMessage( wxT( "SwapData() error: unexpected type %d" ), Type() ); + break; + } - OnModify(); - m_canvas->Refresh(); + // Restore pointers and time stamp, to be sure they are not broken + Pnext = pnext; + Pback = pback; + m_List = mylist; + SetTimeStamp( timestamp ); + SetParent( parent ); } @@ -753,3 +655,4 @@ void PCB_SCREEN::ClearUndoORRedoList( UNDO_REDO_CONTAINER& aList, int aItemCount delete curr_cmd; // Delete command } } + diff --git a/pcbnew/xchgmod.cpp b/pcbnew/xchgmod.cpp index 649e66d882..87f98343e9 100644 --- a/pcbnew/xchgmod.cpp +++ b/pcbnew/xchgmod.cpp @@ -35,6 +35,7 @@ #include #include #include +#include #include #include @@ -76,7 +77,7 @@ private: const FPID& aNewFootprintFPID, bool eShowError ); - PICKED_ITEMS_LIST m_undoPickList; + BOARD_COMMIT m_commit; }; @@ -84,7 +85,7 @@ int DIALOG_EXCHANGE_MODULE::m_selectionMode = 0; DIALOG_EXCHANGE_MODULE::DIALOG_EXCHANGE_MODULE( PCB_EDIT_FRAME* parent, MODULE* Module ) : - DIALOG_EXCHANGE_MODULE_BASE( parent ) + DIALOG_EXCHANGE_MODULE_BASE( parent ), m_commit( parent ) { m_parent = parent; m_currentModule = Module; @@ -141,7 +142,6 @@ void DIALOG_EXCHANGE_MODULE::init() void DIALOG_EXCHANGE_MODULE::OnOkClick( wxCommandEvent& event ) { - m_undoPickList.ClearItemsList(); m_selectionMode = m_Selection->GetSelection(); bool result = false; @@ -172,8 +172,7 @@ void DIALOG_EXCHANGE_MODULE::OnOkClick( wxCommandEvent& event ) m_parent->GetCanvas()->Refresh(); } - if( m_undoPickList.GetCount() ) - m_parent->SaveCopyInUndoList( m_undoPickList, UR_UNSPECIFIED ); + m_commit.Push( wxT( "Changed footprint" ) ); } @@ -341,7 +340,7 @@ bool DIALOG_EXCHANGE_MODULE::change_1_Module( MODULE* aModule, const FPID& aNewFootprintFPID, bool aShowError ) { - MODULE* newModule; + MODULE* newModule; wxString line; if( aModule == NULL ) @@ -367,8 +366,7 @@ bool DIALOG_EXCHANGE_MODULE::change_1_Module( MODULE* aModule, return false; } - m_parent->Exchange_Module( aModule, newModule, &m_undoPickList ); - m_parent->GetBoard()->Add( newModule, ADD_APPEND ); + m_parent->Exchange_Module( aModule, newModule, m_commit ); if( aModule == m_currentModule ) m_currentModule = newModule; @@ -379,15 +377,14 @@ bool DIALOG_EXCHANGE_MODULE::change_1_Module( MODULE* aModule, } -void PCB_EDIT_FRAME::Exchange_Module( MODULE* aOldModule, - MODULE* aNewModule, - PICKED_ITEMS_LIST* aUndoPickList ) +void PCB_EDIT_FRAME::Exchange_Module( MODULE* aOldModule, + MODULE* aNewModule, + BOARD_COMMIT& aCommit ) { aNewModule->SetParent( GetBoard() ); /* place module without ratsnest refresh: this will be made later - * when all modules are on board - */ + * when all modules are on board */ PlaceModule( aNewModule, NULL, true ); // Copy full placement and pad net names (when possible) @@ -402,23 +399,12 @@ void PCB_EDIT_FRAME::Exchange_Module( MODULE* aOldModule, aNewModule->SetTimeStamp( aOldModule->GetTimeStamp() ); aNewModule->SetPath( aOldModule->GetPath() ); - if( aUndoPickList ) - { - GetBoard()->Remove( aOldModule ); - ITEM_PICKER picker_old( aOldModule, UR_DELETED ); - ITEM_PICKER picker_new( aNewModule, UR_NEW ); - aUndoPickList->PushItem( picker_old ); - aUndoPickList->PushItem( picker_new ); - } - else - { - GetGalCanvas()->GetView()->Remove( aOldModule ); - aOldModule->DeleteStructure(); - } + aCommit.Remove( aOldModule ); + aCommit.Add( aNewModule ); + // @todo LEGACY should be unnecessary GetBoard()->m_Status_Pcb = 0; aNewModule->ClearFlags(); - OnModify(); } diff --git a/pcbnew/zones_by_polygon.cpp b/pcbnew/zones_by_polygon.cpp index ddb5f48452..f6c45d0f06 100644 --- a/pcbnew/zones_by_polygon.cpp +++ b/pcbnew/zones_by_polygon.cpp @@ -33,6 +33,7 @@ #include #include #include +#include #include #include @@ -108,8 +109,7 @@ void PCB_EDIT_FRAME::Add_Zone_Cutout( wxDC* DC, ZONE_CONTAINER* aZone ) void PCB_EDIT_FRAME::duplicateZone( wxDC* aDC, ZONE_CONTAINER* aZone ) { - ZONE_CONTAINER* newZone = new ZONE_CONTAINER( GetBoard() ); - newZone->Copy( aZone ); + ZONE_CONTAINER* newZone = new ZONE_CONTAINER( *aZone ); newZone->UnFill(); ZONE_SETTINGS zoneSettings; zoneSettings << *aZone; @@ -860,13 +860,14 @@ void PCB_EDIT_FRAME::Edit_Zone_Params( wxDC* DC, ZONE_CONTAINER* aZone ) ZONE_EDIT_T edited; ZONE_SETTINGS zoneInfo = GetZoneSettings(); + BOARD_COMMIT commit( this ); m_canvas->SetIgnoreMouseEvents( true ); // Save initial zones configuration, for undo/redo, before adding new zone // note the net name and the layer can be changed, so we must save all zones s_AuxiliaryList.ClearListAndDeleteItems(); s_PickedList.ClearListAndDeleteItems(); - SaveCopyOfZones(s_PickedList, GetBoard(), -1, UNDEFINED_LAYER ); + SaveCopyOfZones( s_PickedList, GetBoard(), -1, UNDEFINED_LAYER ); if( aZone->GetIsKeepout() ) { @@ -902,7 +903,8 @@ void PCB_EDIT_FRAME::Edit_Zone_Params( wxDC* DC, ZONE_CONTAINER* aZone ) if( edited == ZONE_EXPORT_VALUES ) { UpdateCopyOfZonesList( s_PickedList, s_AuxiliaryList, GetBoard() ); - SaveCopyInUndoList(s_PickedList, UR_UNSPECIFIED); + commit.Stage( s_PickedList ); + commit.Push( _( "Modify zone properties" ) ); s_PickedList.ClearItemsList(); // s_ItemsListPicker is no more owner of picked items return; } @@ -928,11 +930,10 @@ void PCB_EDIT_FRAME::Edit_Zone_Params( wxDC* DC, ZONE_CONTAINER* aZone ) GetBoard()->RedrawAreasOutlines( m_canvas, DC, GR_OR, UNDEFINED_LAYER ); UpdateCopyOfZonesList( s_PickedList, s_AuxiliaryList, GetBoard() ); - SaveCopyInUndoList(s_PickedList, UR_UNSPECIFIED); + commit.Stage( s_PickedList ); + commit.Push( _( "Modify zone properties" ) ); s_PickedList.ClearItemsList(); // s_ItemsListPicker is no longer owner of picked items - - OnModify(); } diff --git a/pcbnew/zones_functions_for_undo_redo.cpp b/pcbnew/zones_functions_for_undo_redo.cpp index 65e761f0e0..35d1392453 100644 --- a/pcbnew/zones_functions_for_undo_redo.cpp +++ b/pcbnew/zones_functions_for_undo_redo.cpp @@ -237,7 +237,7 @@ void UpdateCopyOfZonesList( PICKED_ITEMS_LIST& aPickList, wxASSERT_MSG( zcopy != NULL, wxT( "UpdateCopyOfZonesList() error: link = NULL" ) ); - ref->Copy( zcopy ); + *ref = *zcopy; // the copy was deleted; the link does not exists now. aPickList.SetPickedItemLink( NULL, kk );