diff --git a/pcbnew/board_undo_redo.cpp b/pcbnew/board_undo_redo.cpp index 36a073d065..fb8578fa4f 100644 --- a/pcbnew/board_undo_redo.cpp +++ b/pcbnew/board_undo_redo.cpp @@ -25,6 +25,7 @@ #include #include +#include #include #include @@ -40,6 +41,8 @@ #include #include +#include +#include /* Functions to undo and redo edit commands. * commands to undo are stored in CurrentScreen->m_UndoList @@ -424,6 +427,7 @@ void PCB_EDIT_FRAME::PutDataInPreviousState( PICKED_ITEMS_LIST* aList, bool aRed BOARD_ITEM* item; bool not_found = false; bool reBuild_ratsnest = false; + KIGFX::VIEW* view = m_galCanvas->GetView(); // Undo in the reverse order of list creation: (this can allow stacked changes // like the same item can be changes and deleted in the same complex command @@ -484,35 +488,80 @@ void PCB_EDIT_FRAME::PutDataInPreviousState( PICKED_ITEMS_LIST* aList, bool aRed case UR_CHANGED: /* Exchange old and new data for each item */ { BOARD_ITEM* image = (BOARD_ITEM*) aList->GetPickedItemLink( ii ); + + // Remove all pads/drawings/texts, as they become invalid + // for the VIEW after SwapData() called for modules + if( item->Type() == PCB_MODULE_T ) + { + MODULE* oldModule = static_cast( item ); + oldModule->RunOnChildren( std::bind1st( std::mem_fun( &KIGFX::VIEW::Remove ), + view ) ); + } + item->SwapData( image ); + + // 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( std::bind1st( std::mem_fun( &KIGFX::VIEW::Add ), + view ) ); + } + + item->ViewUpdate( KIGFX::VIEW_ITEM::LAYERS ); } break; case UR_NEW: /* new items are deleted */ aList->SetPickedItemStatus( UR_DELETED, ii ); GetBoard()->Remove( item ); + + if( item->Type() == PCB_MODULE_T ) + { + MODULE* module = static_cast( item ); + module->RunOnChildren( std::bind1st( std::mem_fun( &KIGFX::VIEW::Remove ), + view ) ); + } + view->Remove( item ); + + item->ViewUpdate( KIGFX::VIEW_ITEM::GEOMETRY ); break; case UR_DELETED: /* deleted items are put in List, as new items */ aList->SetPickedItemStatus( UR_NEW, ii ); GetBoard()->Add( item ); + + if( item->Type() == PCB_MODULE_T ) + { + MODULE* module = static_cast( item ); + module->RunOnChildren( std::bind1st( std::mem_fun( &KIGFX::VIEW::Add ), + view ) ); + } + view->Add( item ); + + item->ViewUpdate( KIGFX::VIEW_ITEM::GEOMETRY ); build_item_list = true; break; case UR_MOVED: item->Move( aRedoCommand ? aList->m_TransformPoint : -aList->m_TransformPoint ); + item->ViewUpdate( KIGFX::VIEW_ITEM::GEOMETRY ); break; case UR_ROTATED: item->Rotate( aList->m_TransformPoint, aRedoCommand ? 900 : -900 ); + item->ViewUpdate( KIGFX::VIEW_ITEM::GEOMETRY ); break; case UR_ROTATED_CLOCKWISE: item->Rotate( aList->m_TransformPoint, aRedoCommand ? -900 : 900 ); + item->ViewUpdate( KIGFX::VIEW_ITEM::GEOMETRY ); break; case UR_FLIPPED: item->Flip( aList->m_TransformPoint ); + item->ViewUpdate( KIGFX::VIEW_ITEM::LAYERS ); break; default: @@ -540,6 +589,11 @@ void PCB_EDIT_FRAME::GetBoardFromUndoList( wxCommandEvent& event ) if( GetScreen()->GetUndoCommandCount() <= 0 ) return; + // Clear the selection, as it may be altered with undone items + SELECTION_TOOL* selectionTool = static_cast( m_toolManager->FindTool( + "pcbnew.InteractiveSelection" ) ); + selectionTool->ClearSelection(); + /* Get the old list */ PICKED_ITEMS_LIST* List = GetScreen()->PopCommandFromUndoList(); /* Undo the command */ @@ -559,6 +613,10 @@ void PCB_EDIT_FRAME::GetBoardFromRedoList( wxCommandEvent& event ) if( GetScreen()->GetRedoCommandCount() == 0 ) return; + // Clear the selection, as it may be altered with redone items + SELECTION_TOOL* selectionTool = static_cast( m_toolManager->FindTool( + "pcbnew.InteractiveSelection" ) ); + selectionTool->ClearSelection(); /* Get the old list */ PICKED_ITEMS_LIST* List = GetScreen()->PopCommandFromRedoList(); diff --git a/pcbnew/tools/edit_tool.cpp b/pcbnew/tools/edit_tool.cpp index f790ca1679..e8accb4ca7 100644 --- a/pcbnew/tools/edit_tool.cpp +++ b/pcbnew/tools/edit_tool.cpp @@ -72,11 +72,15 @@ bool EDIT_TOOL::Init() int EDIT_TOOL::Main( TOOL_EVENT& aEvent ) { const SELECTION_TOOL::SELECTION& selection = m_selectionTool->GetSelection(); + PCB_EDIT_FRAME* editFrame = static_cast( m_toolMgr->GetEditFrame() ); + + // By default, modified items need to update their geometry + m_updateFlag = KIGFX::VIEW_ITEM::GEOMETRY; if( selection.Empty() ) return 0; // there are no items to operate on - VECTOR2D dragPosition; + VECTOR2D dragPosition; // The last position of the cursor while dragging m_dragging = false; bool restore = false; // Should items' state be restored when finishing the tool? @@ -98,9 +102,16 @@ int EDIT_TOOL::Main( TOOL_EVENT& aEvent ) else if( evt->Category() == TC_COMMAND ) { if( evt->IsAction( &COMMON_ACTIONS::rotate ) ) + { Rotate( aEvent ); + } else if( evt->IsAction( &COMMON_ACTIONS::flip ) ) + { Flip( aEvent ); + + // Flip causes change of layers + enableUpdateFlag( KIGFX::VIEW_ITEM::LAYERS ); + } } else if( evt->IsMotion() || evt->IsDrag( BUT_LEFT ) ) @@ -109,19 +120,24 @@ int EDIT_TOOL::Main( TOOL_EVENT& aEvent ) { // Drag items to the current cursor position VECTOR2D movement = ( evt->Position() - dragPosition ); - m_state.Move( movement ); + for( unsigned int i = 0; i < selection.items.GetCount(); ++i ) + { + BOARD_ITEM* item = static_cast( selection.items.GetPickedItem( i ) ); + item->Move( wxPoint( movement.x, movement.y ) ); + } } else { - // Prepare to drag - std::set::iterator it; - - for( it = selection.items.begin(); it != selection.items.end(); ++it ) + // Prepare to drag - save items, so changes can be undone + for( unsigned int i = 0; i < selection.items.GetCount(); ++i ) { - // Save the state of the selected items, in case it has to be restored - m_state.Save( *it ); + BOARD_ITEM* item = static_cast( selection.items.GetPickedItem( i ) ); + std::cout << "saved " << (unsigned long) item << std::endl; } + editFrame->OnModify(); + editFrame->SaveCopyInUndoList( selection.items, UR_CHANGED ); + m_dragging = true; } @@ -138,14 +154,13 @@ int EDIT_TOOL::Main( TOOL_EVENT& aEvent ) if( restore ) { // Modifications has to be rollbacked, so restore the previous state of items - selection.group->ItemsViewUpdate( VIEW_ITEM::APPEARANCE ); - m_state.RestoreAll(); + wxCommandEvent dummy; + editFrame->GetBoardFromUndoList( dummy ); } else { // Changes are applied, so update the items - selection.group->ItemsViewUpdate( m_state.GetUpdateFlag() ); - m_state.Apply(); + selection.group->ItemsViewUpdate( m_updateFlag ); } controls->ShowCursor( false ); @@ -161,13 +176,20 @@ int EDIT_TOOL::Main( TOOL_EVENT& aEvent ) int EDIT_TOOL::Properties( TOOL_EVENT& aEvent ) { const SELECTION_TOOL::SELECTION& selection = m_selectionTool->GetSelection(); + PCB_EDIT_FRAME* editFrame = static_cast( m_toolMgr->GetEditFrame() ); // Properties are displayed when there is only one item selected - if( selection.items.size() == 1 ) + if( selection.Size() == 1 ) { // Display properties dialog - PCB_EDIT_FRAME* editFrame = static_cast( m_toolMgr->GetEditFrame() ); - BOARD_ITEM* item = *selection.items.begin(); + BOARD_ITEM* item = static_cast( selection.items.GetPickedItem( 0 ) ); + + if( !m_dragging ) // If it is being dragged, then it is already saved with UR_CHANGED flag + { + editFrame->SaveCopyInUndoList( item, UR_CHANGED ); + editFrame->OnModify(); + } + editFrame->OnEditItemRequest( NULL, item ); item->ViewUpdate( KIGFX::VIEW_ITEM::GEOMETRY ); @@ -182,25 +204,28 @@ int EDIT_TOOL::Properties( TOOL_EVENT& aEvent ) int EDIT_TOOL::Rotate( TOOL_EVENT& aEvent ) { const SELECTION_TOOL::SELECTION& selection = m_selectionTool->GetSelection(); - VECTOR2D cursorPos = getView()->ToWorld( getViewControls()->GetCursorPosition() ); + VECTOR2D cursor = getView()->ToWorld( getViewControls()->GetCursorPosition() ); + PCB_EDIT_FRAME* editFrame = static_cast( m_toolMgr->GetEditFrame() ); + + if( !m_dragging ) // If it is being dragged, then it is already saved with UR_CHANGED flag + { + editFrame->OnModify(); + editFrame->SaveCopyInUndoList( selection.items, UR_ROTATED, wxPoint( cursor.x, cursor.y ) ); + } + + for( unsigned int i = 0; i < selection.items.GetCount(); ++i ) + { + BOARD_ITEM* item = static_cast( selection.items.GetPickedItem( i ) ); + + item->Rotate( wxPoint( cursor.x, cursor.y ), 900.0 ); + if( !m_dragging ) + item->ViewUpdate( KIGFX::VIEW_ITEM::GEOMETRY ); + } if( m_dragging ) - { - m_state.Rotate( cursorPos, 900.0 ); - selection.group->ViewUpdate( VIEW_ITEM::GEOMETRY ); - } - else - { - std::set::iterator it; + selection.group->ViewUpdate( KIGFX::VIEW_ITEM::GEOMETRY ); - for( it = selection.items.begin(); it != selection.items.end(); ++it ) - { - (*it)->Rotate( wxPoint( cursorPos.x, cursorPos.y ), 900.0 ); - (*it)->ViewUpdate( KIGFX::VIEW_ITEM::GEOMETRY ); - } - - setTransitions(); - } + setTransitions(); return 0; } @@ -209,25 +234,28 @@ int EDIT_TOOL::Rotate( TOOL_EVENT& aEvent ) int EDIT_TOOL::Flip( TOOL_EVENT& aEvent ) { const SELECTION_TOOL::SELECTION& selection = m_selectionTool->GetSelection(); - VECTOR2D cursorPos = getView()->ToWorld( getViewControls()->GetCursorPosition() ); + VECTOR2D cursor = getView()->ToWorld( getViewControls()->GetCursorPosition() ); + PCB_EDIT_FRAME* editFrame = static_cast( m_toolMgr->GetEditFrame() ); + + if( !m_dragging ) // If it is being dragged, then it is already saved with UR_CHANGED flag + { + editFrame->OnModify(); + editFrame->SaveCopyInUndoList( selection.items, UR_FLIPPED, wxPoint( cursor.x, cursor.y ) ); + } + + for( unsigned int i = 0; i < selection.items.GetCount(); ++i ) + { + BOARD_ITEM* item = static_cast( selection.items.GetPickedItem( i ) ); + + item->Flip( wxPoint( cursor.x, cursor.y ) ); + if( !m_dragging ) + item->ViewUpdate( KIGFX::VIEW_ITEM::LAYERS ); + } if( m_dragging ) - { - m_state.Flip( cursorPos ); - selection.group->ViewUpdate( VIEW_ITEM::GEOMETRY ); - } - else - { - std::set::iterator it; + selection.group->ViewUpdate( KIGFX::VIEW_ITEM::GEOMETRY ); - for( it = selection.items.begin(); it != selection.items.end(); ++it ) - { - (*it)->Flip( wxPoint( cursorPos.x, cursorPos.y ) ); - (*it)->ViewUpdate( KIGFX::VIEW_ITEM::LAYERS ); - } - - setTransitions(); - } + setTransitions(); return 0; } @@ -236,14 +264,24 @@ int EDIT_TOOL::Flip( TOOL_EVENT& aEvent ) int EDIT_TOOL::Remove( TOOL_EVENT& aEvent ) { // Get a copy of the selected items set - std::set selectedItems = m_selectionTool->GetSelection().items; + PICKED_ITEMS_LIST selectedItems = m_selectionTool->GetSelection().items; + PCB_EDIT_FRAME* editFrame = static_cast( m_toolMgr->GetEditFrame() ); // As we are about to remove items, they have to be removed from the selection first m_selectionTool->ClearSelection(); - std::set::iterator it; - for( it = selectedItems.begin(); it != selectedItems.end(); ++it ) - remove( *it ); + // Save them + for( unsigned int i = 0; i < selectedItems.GetCount(); ++i ) + selectedItems.SetPickedItemStatus( UR_DELETED, i ); + editFrame->OnModify(); + editFrame->SaveCopyInUndoList( selectedItems, UR_DELETED ); + + // And now remove + for( unsigned int i = 0; i < selectedItems.GetCount(); ++i ) + { + BOARD_ITEM* item = static_cast( selectedItems.GetPickedItem( i ) ); + remove( item ); + } // Rebuild list of pads and nets if necessary BOARD* board = getModel( PCB_T ); @@ -265,6 +303,7 @@ void EDIT_TOOL::remove( BOARD_ITEM* aItem ) case PCB_MODULE_T: { MODULE* module = static_cast( aItem ); + module->ClearFlags(); for( D_PAD* pad = module->Pads().GetFirst(); pad; pad = pad->Next() ) getView()->Remove( pad ); @@ -305,7 +344,6 @@ void EDIT_TOOL::remove( BOARD_ITEM* aItem ) case PCB_ZONE_T: // SEG_ZONE items are now deprecated break; - // TODO default: // other types do not need to (or should not) be handled assert( false ); return; @@ -313,7 +351,7 @@ void EDIT_TOOL::remove( BOARD_ITEM* aItem ) } getView()->Remove( aItem ); - board->Delete( aItem ); + board->Remove( aItem ); } diff --git a/pcbnew/tools/edit_tool.h b/pcbnew/tools/edit_tool.h index 2e60a21fa3..5ddcb84f5d 100644 --- a/pcbnew/tools/edit_tool.h +++ b/pcbnew/tools/edit_tool.h @@ -28,7 +28,6 @@ #include #include #include -#include "item_state.h" class BOARD_ITEM; class SELECTION_TOOL; @@ -93,9 +92,6 @@ public: int Remove( TOOL_EVENT& aEvent ); private: - ///> Saves the state of items and allows to restore them - ITEM_STATE m_state; - ///> Selection tool used for obtaining selected items SELECTION_TOOL* m_selectionTool; @@ -107,6 +103,16 @@ private: ///> Sets up handlers for various events void setTransitions(); + + ///> The required update flag for modified items + KIGFX::VIEW_ITEM::VIEW_UPDATE_FLAGS m_updateFlag; + + ///> Enables higher order update flag + void enableUpdateFlag( KIGFX::VIEW_ITEM::VIEW_UPDATE_FLAGS aFlag ) + { + if( m_updateFlag < aFlag ) + m_updateFlag = aFlag; + } }; #endif diff --git a/pcbnew/tools/item_state.h b/pcbnew/tools/item_state.h deleted file mode 100644 index ed562c623d..0000000000 --- a/pcbnew/tools/item_state.h +++ /dev/null @@ -1,284 +0,0 @@ -/* - * This program source code file is part of KiCad, a free EDA CAD application. - * - * Copyright (C) 2013 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 ITEM_STATE_H_ -#define ITEM_STATE_H_ - -#include -#include - -/** - * Class ITEM_STATE - * - * Provides means for modifying properties of groups of items and gives possibility of rolling back - * the introduced changes. Does not take ownership of modified items, neither takes care of - * refreshing. - */ -class ITEM_STATE -{ -public: - ITEM_STATE() : - m_movement( 0.0, 0.0 ), m_flips( 0 ), m_rotation( 0.0 ) - { -#ifdef __WXDEBUG__ - m_canSave = true; -#endif - } - - /** - * Function Save() - * - * Adds an item and saves it's state. - * @param aItem is the item to be added. - */ - void Save( BOARD_ITEM* aItem ) - { -#ifdef __WXDEBUG__ - wxASSERT_MSG( m_canSave, wxT( "You cannot save items after issuing commands. You have " - "either RestoreAll() or Apply() before adding items!" ) ); -#endif - m_items.push_back( aItem ); - } - - /** - * Function RestoreAll() - * - * Rollbacks all the changes to the initial state. - */ - void RestoreAll() - { - // Check if there is a not saved movement command - saveMovement(); - - std::deque::iterator it, it_end; - std::deque::iterator cmd, cmd_end; - - for( it = m_items.begin(), it_end = m_items.end(); it != it_end; ++it ) - { - for( cmd = m_commands.begin(), cmd_end = m_commands.end(); cmd != cmd_end; ++cmd ) - cmd->Revert( *it ); - } - - reset(); - } - - /** - * Function Apply() - * - * Resets the state, clears the list of items & changes, so the object can be reused for - * other items. - */ - void Apply() - { - reset(); - } - - /** - * Function Move() - * - * Moves stored items by a given vector. - * @param aMovement is the movement vector. - */ - void Move( const VECTOR2D& aMovement ) - { -#ifdef __WXDEBUG__ - m_canSave = false; -#endif - std::deque::iterator it, it_end; - - for( it = m_items.begin(), it_end = m_items.end(); it != it_end; ++it ) - (*it)->Move( wxPoint( aMovement.x, aMovement.y ) ); - - m_movement += aMovement; - } - - /** - * Function Rotate() - * - * Rotates stored items by a given angle. - * @param aAngle is the angle (in decidegrees). - */ - void Rotate( const VECTOR2D& aPoint, double aAngle ) - { -#ifdef __WXDEBUG__ - m_canSave = false; -#endif - saveMovement(); - m_commands.push_front( COMMAND( COMMAND::ROTATE, aPoint, aAngle ) ); - - std::deque::iterator it, it_end; - - for( it = m_items.begin(), it_end = m_items.end(); it != it_end; ++it ) - (*it)->Rotate( wxPoint( aPoint.x, aPoint.y ), aAngle ); - - m_rotation += aAngle; - } - - /** - * Function Flip() - * - * Changes the board side for stored items. - * @param aPoint is the rotation point. - */ - void Flip( const VECTOR2D& aPoint ) - { -#ifdef __WXDEBUG__ - m_canSave = false; -#endif - saveMovement(); - m_commands.push_front( COMMAND( COMMAND::FLIP, aPoint ) ); - - std::deque::iterator it, it_end; - - for( it = m_items.begin(), it_end = m_items.end(); it != it_end; ++it ) - (*it)->Flip( wxPoint( aPoint.x, aPoint.y ) ); - - m_flips++; - } - - /** - * Function ToggleVisibility() - * - * Switches the visibility property of stored items. - */ - void ToggleVisibility() - { -#ifdef __WXDEBUG__ - m_canSave = false; -#endif - m_commands.push_front( COMMAND( COMMAND::VISIBILITY ) ); - - std::deque::iterator it, it_end; - - for( it = m_items.begin(), it_end = m_items.end(); it != it_end; ++it ) - (*it)->ViewSetVisible( !(*it)->ViewIsVisible() ); - } - - /** - * Function GetUpdateFlag() - * - * Returns information on what kind of update should be applied to items in order to display - * them properly. - * @return Flag required to refresh items. - */ - KIGFX::VIEW_ITEM::VIEW_UPDATE_FLAGS GetUpdateFlag() const - { - if( m_flips % 2 == 1 ) // If number of flips is odd, then we need to change layers - return KIGFX::VIEW_ITEM::LAYERS; - else if( m_movement.x != 0.0 || m_movement.y != 0.0 || m_rotation != 0.0 ) - return KIGFX::VIEW_ITEM::GEOMETRY; - - return KIGFX::VIEW_ITEM::APPEARANCE; - } - -private: - /// COMMAND stores modifications that were done to items - struct COMMAND - { - /// Type of command - enum TYPE { MOVE, ROTATE, FLIP, VISIBILITY }; - TYPE m_type; - - /// Point where flip/rotation occurred or movement vector - VECTOR2D m_point; - - /// Used only for rotation - double m_angle; - - COMMAND( TYPE aType, VECTOR2D aPoint = VECTOR2D( 0.0, 0.0 ), double aAngle = 0.0 ) : - m_type( aType ), m_point( aPoint ), m_angle( aAngle ) {}; - - void Revert( BOARD_ITEM* aItem ) - { - switch( m_type ) - { - case MOVE: - aItem->Move( wxPoint( -m_point.x, -m_point.y ) ); - break; - - case ROTATE: - aItem->Rotate( wxPoint( m_point.x, m_point.y ), -m_angle ); - break; - - case FLIP: - aItem->Flip( wxPoint( m_point.x, m_point.y ) ); - break; - - case VISIBILITY: - aItem->ViewSetVisible( !aItem->ViewIsVisible() ); - break; - } - } - }; - - /// Adds a MOVEMENT command basing on the current movement vector - void saveMovement() - { - if( m_movement.x != 0.0 || m_movement.y != 0.0 ) - { - m_commands.push_front( COMMAND( COMMAND::MOVE, m_movement ) ); - - m_movement.x = 0.0; - m_movement.y = 0.0; - } - } - - /// Restores the initial state - void reset() - { - m_movement.x = 0.0; - m_movement.y = 0.0; - m_flips = 0; - m_rotation = 0.0; - - m_items.clear(); - m_commands.clear(); - -#ifdef __WXDEBUG__ - m_canSave = true; -#endif - } - - /// List of issued commands - std::deque m_items; - - /// List of items that are affected by commands - std::deque m_commands; - - /// Current movement vector (updated by Move() command) - VECTOR2D m_movement; - - /// Number of flips applied to items - unsigned int m_flips; - - /// Total rotation applied to items - double m_rotation; - -#ifdef __WXDEBUG__ - /// Debug flag assuring that functions are called in proper order - bool m_canSave; -#endif -}; - -#endif /* ITEM_STATE_H_ */ diff --git a/pcbnew/tools/selection_tool.cpp b/pcbnew/tools/selection_tool.cpp index bf78405612..dabf03dda8 100644 --- a/pcbnew/tools/selection_tool.cpp +++ b/pcbnew/tools/selection_tool.cpp @@ -182,9 +182,9 @@ void SELECTION_TOOL::AddMenuItem( const TOOL_ACTION& aAction ) void SELECTION_TOOL::toggleSelection( BOARD_ITEM* aItem ) { - if( isSelected( aItem ) ) + if( aItem->IsSelected() ) { - deselectItem( aItem ); + deselect( aItem ); } else { @@ -193,17 +193,11 @@ void SELECTION_TOOL::toggleSelection( BOARD_ITEM* aItem ) // Prevent selection of invisible or inactive items if( selectable( aItem ) ) - selectItem( aItem ); + select( aItem ); } } -bool SELECTION_TOOL::isSelected( const BOARD_ITEM* aItem ) const -{ - return ( m_selection.items.find( const_cast( aItem ) ) != m_selection.items.end() ); -} - - void SELECTION_TOOL::selectSingle( const VECTOR2I& aWhere ) { BOARD* pcb = getModel( PCB_T ); @@ -219,7 +213,6 @@ void SELECTION_TOOL::selectSingle( const VECTOR2I& aWhere ) case 0: if( !m_additive ) ClearSelection(); - break; case 1: @@ -231,7 +224,7 @@ void SELECTION_TOOL::selectSingle( const VECTOR2I& aWhere ) // contain anything but module footprint and not selectable items for( int i = collector.GetCount() - 1; i >= 0 ; --i ) { - BOARD_ITEM* boardItem = ( collector )[i]; + BOARD_ITEM* boardItem = collector[i]; if( boardItem->Type() == PCB_MODULE_T || !selectable( boardItem ) ) collector.Remove( i ); @@ -338,8 +331,8 @@ bool SELECTION_TOOL::selectMultiple() BOARD_ITEM* item = static_cast( it->first ); // Add only those items that are visible and fully within the selection box - if( selectable( item ) && selectionBox.Contains( item->ViewBBox() ) ) - selectItem( item ); + if( !item->IsSelected() && selectable( item ) && selectionBox.Contains( item->ViewBBox() ) ) + select( item ); } // Do not display information about selected item,as there is more than one @@ -502,49 +495,23 @@ bool SELECTION_TOOL::selectable( const BOARD_ITEM* aItem ) const } -void SELECTION_TOOL::selectItem( BOARD_ITEM* aItem ) +void SELECTION_TOOL::select( BOARD_ITEM* aItem ) { - /// Selecting an item needs a few operations, so they are wrapped in a functor - class selectBase_ - { - SELECTION& s; - - public: - selectBase_( SELECTION& s_ ) : s( s_ ) {} - - void operator()( BOARD_ITEM* item ) - { - s.group->Add( item ); - // Hide the original item, so it is shown only on overlay - item->ViewSetVisible( false ); - item->SetSelected(); - } - } selectBase( m_selection ); - - // Modules are treated in a special way - when they are selected, we have to - // select all the parts that make the module, not the module itself + // Modules are treated in a special way - when they are selected, we have to mark + // all the parts that make the module as selected if( aItem->Type() == PCB_MODULE_T ) { MODULE* module = static_cast( aItem ); + module->RunOnChildren( std::bind1st( std::mem_fun( &SELECTION_TOOL::selectVisually ), this ) ); - // Add everything that belongs to the module (besides the module itself) - for( D_PAD* pad = module->Pads().GetFirst(); pad; pad = pad->Next() ) - selectBase( pad ); - - for( BOARD_ITEM* drawing = module->GraphicalItems().GetFirst(); drawing; - drawing = drawing->Next() ) - selectBase( drawing ); - - selectBase( &module->Reference() ); - selectBase( &module->Value() ); } - // Add items to the VIEW_GROUP, so they will be displayed on the overlay - selectBase( aItem ); - m_selection.items.insert( aItem ); + selectVisually( aItem ); + ITEM_PICKER picker( aItem ); + m_selection.items.PushItem( picker ); // It is enough to do it only for the first selected item - if( m_selection.items.size() == 1 ) + if( m_selection.Size() == 1 ) { // Set as the current item, so the information about selection is displayed getEditFrame()->SetCurItem( aItem, true ); @@ -552,48 +519,30 @@ void SELECTION_TOOL::selectItem( BOARD_ITEM* aItem ) // Now the context menu should be enabled SetContextMenu( &m_menu, CMENU_BUTTON ); } + else + { + // If multiple items are selected, do not show the information about the selected item + getEditFrame()->SetCurItem( NULL, true ); + } } -void SELECTION_TOOL::deselectItem( BOARD_ITEM* aItem ) +void SELECTION_TOOL::deselect( BOARD_ITEM* aItem ) { - /// Deselecting an item needs a few operations, so they are wrapped in a functor - class deselectBase_ - { - SELECTION& s; - - public: - deselectBase_( SELECTION& s_ ) : s( s_ ) {} - - void operator()( BOARD_ITEM* item ) - { - s.group->Remove( item ); - // Restore original item visibility - item->ViewSetVisible( true ); - item->ClearSelected(); - } - } deselectBase( m_selection ); - // Modules are treated in a special way - when they are selected, we have to - // select all the parts that make the module, not the module itself + // deselect all the parts that make the module, not the module itself if( aItem->Type() == PCB_MODULE_T ) { MODULE* module = static_cast( aItem ); + module->RunOnChildren( std::bind1st( std::mem_fun( &SELECTION_TOOL::deselectVisually ), this ) ); - // Add everything that belongs to the module (besides the module itself) - for( D_PAD* pad = module->Pads().GetFirst(); pad; pad = pad->Next() ) - deselectBase( pad ); - - for( BOARD_ITEM* drawing = module->GraphicalItems().GetFirst(); drawing; - drawing = drawing->Next() ) - deselectBase( drawing ); - - deselectBase( &module->Reference() ); - deselectBase( &module->Value() ); } - deselectBase( aItem ); - m_selection.items.erase( aItem ); + deselectVisually( aItem ); + + int itemIdx = m_selection.items.FindItem( aItem ); + if( itemIdx >= 0 ) + m_selection.items.RemovePicker( itemIdx ); // If there is nothing selected, disable the context menu if( m_selection.Empty() ) @@ -604,6 +553,26 @@ void SELECTION_TOOL::deselectItem( BOARD_ITEM* aItem ) } +void SELECTION_TOOL::selectVisually( BOARD_ITEM* aItem ) const +{ + m_selection.group->Add( aItem ); + + // Hide the original item, so it is shown only on overlay + aItem->ViewSetVisible( false ); + aItem->SetSelected(); +} + + +void SELECTION_TOOL::deselectVisually( BOARD_ITEM* aItem ) const +{ + m_selection.group->Remove( aItem ); + + // Restore original item visibility + aItem->ViewSetVisible( true ); + aItem->ClearSelected(); +} + + bool SELECTION_TOOL::containsSelected( const VECTOR2I& aPoint ) const { const unsigned GRIP_MARGIN = 500000; @@ -611,9 +580,10 @@ bool SELECTION_TOOL::containsSelected( const VECTOR2I& aPoint ) const // Check if the point is located within any of the currently selected items bounding boxes std::set::iterator it, it_end; - for( it = m_selection.items.begin(), it_end = m_selection.items.end(); it != it_end; ++it ) + for( unsigned int i = 0; i < m_selection.items.GetCount(); ++i ) { - BOX2I itemBox = (*it)->ViewBBox(); + BOARD_ITEM* item = static_cast( m_selection.items.GetPickedItem( i ) ); + BOX2I itemBox = item->ViewBBox(); itemBox.Inflate( GRIP_MARGIN ); // Give some margin for gripping an item if( itemBox.Contains( aPoint ) ) @@ -626,6 +596,6 @@ bool SELECTION_TOOL::containsSelected( const VECTOR2I& aPoint ) const void SELECTION_TOOL::SELECTION::Clear() { - items.clear(); + items.ClearItemsList(); group->Clear(); } diff --git a/pcbnew/tools/selection_tool.h b/pcbnew/tools/selection_tool.h index 33fc4b2494..168f2288da 100644 --- a/pcbnew/tools/selection_tool.h +++ b/pcbnew/tools/selection_tool.h @@ -26,11 +26,10 @@ #ifndef __SELECTION_TOOL_H #define __SELECTION_TOOL_H -#include - #include #include #include +#include class SELECTION_AREA; class BOARD_ITEM; @@ -62,7 +61,7 @@ public: struct SELECTION { /// Set of selected items - std::set items; + PICKED_ITEMS_LIST items; /// VIEW_GROUP that holds currently selected items KIGFX::VIEW_GROUP* group; @@ -70,13 +69,13 @@ public: /// Checks if there is anything selected bool Empty() const { - return items.empty(); + return ( items.GetCount() == 0 ); } /// Returns the number of selected parts int Size() const { - return items.size(); + return items.GetCount(); } /// Clears both the VIEW_GROUP and set of selected items. Please note that it does not @@ -111,7 +110,7 @@ public: void ClearSelection(); /** - * Function AddAction() + * Function AddMenuItem() * * Adds a menu entry to run a TOOL_ACTION on selected items. * @param aAction is a menu entry to be added. @@ -161,15 +160,6 @@ private: */ void toggleSelection( BOARD_ITEM* aItem ); - /** - * Function isSelected() - * Tests if an item is currently selected. - * - * @param aItem is the item to be checked. - * @return True if the item is selected, false otherwise. - */ - bool isSelected( const BOARD_ITEM* aItem ) const; - /** * Function selectable() * Checks conditions for an item to be selected. @@ -184,7 +174,7 @@ private: * * @param aItem is an item to be selected. */ - void selectItem( BOARD_ITEM* aItem ); + void select( BOARD_ITEM* aItem ); /** * Function deselectItem() @@ -192,7 +182,21 @@ private: * * @param aItem is an item to be deselected. */ - void deselectItem( BOARD_ITEM* aItem ); + void deselect( BOARD_ITEM* aItem ); + + /** + * Function deselectVisually() + * Marks item as selected, but does not add it to the ITEMS_PICKED_LIST. + * @param aItem is an item to be be marked. + */ + void selectVisually( BOARD_ITEM* aItem ) const; + + /** + * Function deselectVisually() + * Marks item as selected, but does not add it to the ITEMS_PICKED_LIST. + * @param aItem is an item to be be marked. + */ + void deselectVisually( BOARD_ITEM* aItem ) const; /** * Function containsSelected()