Commit 87323530 authored by Maciej Suminski's avatar Maciej Suminski

SELECTION_TOOL uses ITEMS_PICKED_LIST to store selected items.

Modifications done using the EDIT_TOOL are saved using the default KiCad's undo buffer.
If there is only one item selected, info about the item is displayed in the bottom status bar.
parent e4efe212
...@@ -25,6 +25,7 @@ ...@@ -25,6 +25,7 @@
#include <fctsys.h> #include <fctsys.h>
#include <class_drawpanel.h> #include <class_drawpanel.h>
#include <class_drawpanel_gal.h>
#include <macros.h> #include <macros.h>
#include <pcbnew.h> #include <pcbnew.h>
...@@ -40,6 +41,8 @@ ...@@ -40,6 +41,8 @@
#include <class_zone.h> #include <class_zone.h>
#include <class_edge_mod.h> #include <class_edge_mod.h>
#include <tools/selection_tool.h>
#include <tool/tool_manager.h>
/* Functions to undo and redo edit commands. /* Functions to undo and redo edit commands.
* commands to undo are stored in CurrentScreen->m_UndoList * commands to undo are stored in CurrentScreen->m_UndoList
...@@ -424,6 +427,7 @@ void PCB_EDIT_FRAME::PutDataInPreviousState( PICKED_ITEMS_LIST* aList, bool aRed ...@@ -424,6 +427,7 @@ void PCB_EDIT_FRAME::PutDataInPreviousState( PICKED_ITEMS_LIST* aList, bool aRed
BOARD_ITEM* item; BOARD_ITEM* item;
bool not_found = false; bool not_found = false;
bool reBuild_ratsnest = false; bool reBuild_ratsnest = false;
KIGFX::VIEW* view = m_galCanvas->GetView();
// Undo in the reverse order of list creation: (this can allow stacked changes // 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 // 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 ...@@ -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 */ case UR_CHANGED: /* Exchange old and new data for each item */
{ {
BOARD_ITEM* image = (BOARD_ITEM*) aList->GetPickedItemLink( ii ); 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<MODULE*>( item );
oldModule->RunOnChildren( std::bind1st( std::mem_fun( &KIGFX::VIEW::Remove ),
view ) );
}
item->SwapData( image ); 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<MODULE*>( item );
newModule->RunOnChildren( std::bind1st( std::mem_fun( &KIGFX::VIEW::Add ),
view ) );
}
item->ViewUpdate( KIGFX::VIEW_ITEM::LAYERS );
} }
break; break;
case UR_NEW: /* new items are deleted */ case UR_NEW: /* new items are deleted */
aList->SetPickedItemStatus( UR_DELETED, ii ); aList->SetPickedItemStatus( UR_DELETED, ii );
GetBoard()->Remove( item ); GetBoard()->Remove( item );
if( item->Type() == PCB_MODULE_T )
{
MODULE* module = static_cast<MODULE*>( item );
module->RunOnChildren( std::bind1st( std::mem_fun( &KIGFX::VIEW::Remove ),
view ) );
}
view->Remove( item );
item->ViewUpdate( KIGFX::VIEW_ITEM::GEOMETRY );
break; break;
case UR_DELETED: /* deleted items are put in List, as new items */ case UR_DELETED: /* deleted items are put in List, as new items */
aList->SetPickedItemStatus( UR_NEW, ii ); aList->SetPickedItemStatus( UR_NEW, ii );
GetBoard()->Add( item ); GetBoard()->Add( item );
if( item->Type() == PCB_MODULE_T )
{
MODULE* module = static_cast<MODULE*>( 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; build_item_list = true;
break; break;
case UR_MOVED: case UR_MOVED:
item->Move( aRedoCommand ? aList->m_TransformPoint : -aList->m_TransformPoint ); item->Move( aRedoCommand ? aList->m_TransformPoint : -aList->m_TransformPoint );
item->ViewUpdate( KIGFX::VIEW_ITEM::GEOMETRY );
break; break;
case UR_ROTATED: case UR_ROTATED:
item->Rotate( aList->m_TransformPoint, aRedoCommand ? 900 : -900 ); item->Rotate( aList->m_TransformPoint, aRedoCommand ? 900 : -900 );
item->ViewUpdate( KIGFX::VIEW_ITEM::GEOMETRY );
break; break;
case UR_ROTATED_CLOCKWISE: case UR_ROTATED_CLOCKWISE:
item->Rotate( aList->m_TransformPoint, aRedoCommand ? -900 : 900 ); item->Rotate( aList->m_TransformPoint, aRedoCommand ? -900 : 900 );
item->ViewUpdate( KIGFX::VIEW_ITEM::GEOMETRY );
break; break;
case UR_FLIPPED: case UR_FLIPPED:
item->Flip( aList->m_TransformPoint ); item->Flip( aList->m_TransformPoint );
item->ViewUpdate( KIGFX::VIEW_ITEM::LAYERS );
break; break;
default: default:
...@@ -540,6 +589,11 @@ void PCB_EDIT_FRAME::GetBoardFromUndoList( wxCommandEvent& event ) ...@@ -540,6 +589,11 @@ void PCB_EDIT_FRAME::GetBoardFromUndoList( wxCommandEvent& event )
if( GetScreen()->GetUndoCommandCount() <= 0 ) if( GetScreen()->GetUndoCommandCount() <= 0 )
return; return;
// Clear the selection, as it may be altered with undone items
SELECTION_TOOL* selectionTool = static_cast<SELECTION_TOOL*>( m_toolManager->FindTool(
"pcbnew.InteractiveSelection" ) );
selectionTool->ClearSelection();
/* Get the old list */ /* Get the old list */
PICKED_ITEMS_LIST* List = GetScreen()->PopCommandFromUndoList(); PICKED_ITEMS_LIST* List = GetScreen()->PopCommandFromUndoList();
/* Undo the command */ /* Undo the command */
...@@ -559,6 +613,10 @@ void PCB_EDIT_FRAME::GetBoardFromRedoList( wxCommandEvent& event ) ...@@ -559,6 +613,10 @@ void PCB_EDIT_FRAME::GetBoardFromRedoList( wxCommandEvent& event )
if( GetScreen()->GetRedoCommandCount() == 0 ) if( GetScreen()->GetRedoCommandCount() == 0 )
return; return;
// Clear the selection, as it may be altered with redone items
SELECTION_TOOL* selectionTool = static_cast<SELECTION_TOOL*>( m_toolManager->FindTool(
"pcbnew.InteractiveSelection" ) );
selectionTool->ClearSelection();
/* Get the old list */ /* Get the old list */
PICKED_ITEMS_LIST* List = GetScreen()->PopCommandFromRedoList(); PICKED_ITEMS_LIST* List = GetScreen()->PopCommandFromRedoList();
......
...@@ -72,11 +72,15 @@ bool EDIT_TOOL::Init() ...@@ -72,11 +72,15 @@ bool EDIT_TOOL::Init()
int EDIT_TOOL::Main( TOOL_EVENT& aEvent ) int EDIT_TOOL::Main( TOOL_EVENT& aEvent )
{ {
const SELECTION_TOOL::SELECTION& selection = m_selectionTool->GetSelection(); const SELECTION_TOOL::SELECTION& selection = m_selectionTool->GetSelection();
PCB_EDIT_FRAME* editFrame = static_cast<PCB_EDIT_FRAME*>( m_toolMgr->GetEditFrame() );
// By default, modified items need to update their geometry
m_updateFlag = KIGFX::VIEW_ITEM::GEOMETRY;
if( selection.Empty() ) if( selection.Empty() )
return 0; // there are no items to operate on return 0; // there are no items to operate on
VECTOR2D dragPosition; VECTOR2D dragPosition; // The last position of the cursor while dragging
m_dragging = false; m_dragging = false;
bool restore = false; // Should items' state be restored when finishing the tool? bool restore = false; // Should items' state be restored when finishing the tool?
...@@ -98,9 +102,16 @@ int EDIT_TOOL::Main( TOOL_EVENT& aEvent ) ...@@ -98,9 +102,16 @@ int EDIT_TOOL::Main( TOOL_EVENT& aEvent )
else if( evt->Category() == TC_COMMAND ) else if( evt->Category() == TC_COMMAND )
{ {
if( evt->IsAction( &COMMON_ACTIONS::rotate ) ) if( evt->IsAction( &COMMON_ACTIONS::rotate ) )
{
Rotate( aEvent ); Rotate( aEvent );
}
else if( evt->IsAction( &COMMON_ACTIONS::flip ) ) else if( evt->IsAction( &COMMON_ACTIONS::flip ) )
{
Flip( aEvent ); Flip( aEvent );
// Flip causes change of layers
enableUpdateFlag( KIGFX::VIEW_ITEM::LAYERS );
}
} }
else if( evt->IsMotion() || evt->IsDrag( BUT_LEFT ) ) else if( evt->IsMotion() || evt->IsDrag( BUT_LEFT ) )
...@@ -109,19 +120,24 @@ int EDIT_TOOL::Main( TOOL_EVENT& aEvent ) ...@@ -109,19 +120,24 @@ int EDIT_TOOL::Main( TOOL_EVENT& aEvent )
{ {
// Drag items to the current cursor position // Drag items to the current cursor position
VECTOR2D movement = ( evt->Position() - dragPosition ); VECTOR2D movement = ( evt->Position() - dragPosition );
m_state.Move( movement ); for( unsigned int i = 0; i < selection.items.GetCount(); ++i )
{
BOARD_ITEM* item = static_cast<BOARD_ITEM*>( selection.items.GetPickedItem( i ) );
item->Move( wxPoint( movement.x, movement.y ) );
}
} }
else else
{ {
// Prepare to drag // Prepare to drag - save items, so changes can be undone
std::set<BOARD_ITEM*>::iterator it; for( unsigned int i = 0; i < selection.items.GetCount(); ++i )
for( it = selection.items.begin(); it != selection.items.end(); ++it )
{ {
// Save the state of the selected items, in case it has to be restored BOARD_ITEM* item = static_cast<BOARD_ITEM*>( selection.items.GetPickedItem( i ) );
m_state.Save( *it ); std::cout << "saved " << (unsigned long) item << std::endl;
} }
editFrame->OnModify();
editFrame->SaveCopyInUndoList( selection.items, UR_CHANGED );
m_dragging = true; m_dragging = true;
} }
...@@ -138,14 +154,13 @@ int EDIT_TOOL::Main( TOOL_EVENT& aEvent ) ...@@ -138,14 +154,13 @@ int EDIT_TOOL::Main( TOOL_EVENT& aEvent )
if( restore ) if( restore )
{ {
// Modifications has to be rollbacked, so restore the previous state of items // Modifications has to be rollbacked, so restore the previous state of items
selection.group->ItemsViewUpdate( VIEW_ITEM::APPEARANCE ); wxCommandEvent dummy;
m_state.RestoreAll(); editFrame->GetBoardFromUndoList( dummy );
} }
else else
{ {
// Changes are applied, so update the items // Changes are applied, so update the items
selection.group->ItemsViewUpdate( m_state.GetUpdateFlag() ); selection.group->ItemsViewUpdate( m_updateFlag );
m_state.Apply();
} }
controls->ShowCursor( false ); controls->ShowCursor( false );
...@@ -161,13 +176,20 @@ int EDIT_TOOL::Main( TOOL_EVENT& aEvent ) ...@@ -161,13 +176,20 @@ int EDIT_TOOL::Main( TOOL_EVENT& aEvent )
int EDIT_TOOL::Properties( TOOL_EVENT& aEvent ) int EDIT_TOOL::Properties( TOOL_EVENT& aEvent )
{ {
const SELECTION_TOOL::SELECTION& selection = m_selectionTool->GetSelection(); const SELECTION_TOOL::SELECTION& selection = m_selectionTool->GetSelection();
PCB_EDIT_FRAME* editFrame = static_cast<PCB_EDIT_FRAME*>( m_toolMgr->GetEditFrame() );
// Properties are displayed when there is only one item selected // Properties are displayed when there is only one item selected
if( selection.items.size() == 1 ) if( selection.Size() == 1 )
{ {
// Display properties dialog // Display properties dialog
PCB_EDIT_FRAME* editFrame = static_cast<PCB_EDIT_FRAME*>( m_toolMgr->GetEditFrame() ); BOARD_ITEM* item = static_cast<BOARD_ITEM*>( selection.items.GetPickedItem( 0 ) );
BOARD_ITEM* item = *selection.items.begin();
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 ); editFrame->OnEditItemRequest( NULL, item );
item->ViewUpdate( KIGFX::VIEW_ITEM::GEOMETRY ); item->ViewUpdate( KIGFX::VIEW_ITEM::GEOMETRY );
...@@ -182,25 +204,28 @@ int EDIT_TOOL::Properties( TOOL_EVENT& aEvent ) ...@@ -182,25 +204,28 @@ int EDIT_TOOL::Properties( TOOL_EVENT& aEvent )
int EDIT_TOOL::Rotate( TOOL_EVENT& aEvent ) int EDIT_TOOL::Rotate( TOOL_EVENT& aEvent )
{ {
const SELECTION_TOOL::SELECTION& selection = m_selectionTool->GetSelection(); 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<PCB_EDIT_FRAME*>( m_toolMgr->GetEditFrame() );
if( m_dragging ) if( !m_dragging ) // If it is being dragged, then it is already saved with UR_CHANGED flag
{ {
m_state.Rotate( cursorPos, 900.0 ); editFrame->OnModify();
selection.group->ViewUpdate( VIEW_ITEM::GEOMETRY ); editFrame->SaveCopyInUndoList( selection.items, UR_ROTATED, wxPoint( cursor.x, cursor.y ) );
} }
else
{
std::set<BOARD_ITEM*>::iterator it;
for( it = selection.items.begin(); it != selection.items.end(); ++it ) for( unsigned int i = 0; i < selection.items.GetCount(); ++i )
{ {
(*it)->Rotate( wxPoint( cursorPos.x, cursorPos.y ), 900.0 ); BOARD_ITEM* item = static_cast<BOARD_ITEM*>( selection.items.GetPickedItem( i ) );
(*it)->ViewUpdate( KIGFX::VIEW_ITEM::GEOMETRY );
item->Rotate( wxPoint( cursor.x, cursor.y ), 900.0 );
if( !m_dragging )
item->ViewUpdate( KIGFX::VIEW_ITEM::GEOMETRY );
} }
if( m_dragging )
selection.group->ViewUpdate( KIGFX::VIEW_ITEM::GEOMETRY );
setTransitions(); setTransitions();
}
return 0; return 0;
} }
...@@ -209,25 +234,28 @@ int EDIT_TOOL::Rotate( TOOL_EVENT& aEvent ) ...@@ -209,25 +234,28 @@ int EDIT_TOOL::Rotate( TOOL_EVENT& aEvent )
int EDIT_TOOL::Flip( TOOL_EVENT& aEvent ) int EDIT_TOOL::Flip( TOOL_EVENT& aEvent )
{ {
const SELECTION_TOOL::SELECTION& selection = m_selectionTool->GetSelection(); 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<PCB_EDIT_FRAME*>( m_toolMgr->GetEditFrame() );
if( m_dragging ) if( !m_dragging ) // If it is being dragged, then it is already saved with UR_CHANGED flag
{ {
m_state.Flip( cursorPos ); editFrame->OnModify();
selection.group->ViewUpdate( VIEW_ITEM::GEOMETRY ); editFrame->SaveCopyInUndoList( selection.items, UR_FLIPPED, wxPoint( cursor.x, cursor.y ) );
} }
else
{
std::set<BOARD_ITEM*>::iterator it;
for( it = selection.items.begin(); it != selection.items.end(); ++it ) for( unsigned int i = 0; i < selection.items.GetCount(); ++i )
{ {
(*it)->Flip( wxPoint( cursorPos.x, cursorPos.y ) ); BOARD_ITEM* item = static_cast<BOARD_ITEM*>( selection.items.GetPickedItem( i ) );
(*it)->ViewUpdate( KIGFX::VIEW_ITEM::LAYERS );
item->Flip( wxPoint( cursor.x, cursor.y ) );
if( !m_dragging )
item->ViewUpdate( KIGFX::VIEW_ITEM::LAYERS );
} }
if( m_dragging )
selection.group->ViewUpdate( KIGFX::VIEW_ITEM::GEOMETRY );
setTransitions(); setTransitions();
}
return 0; return 0;
} }
...@@ -236,14 +264,24 @@ int EDIT_TOOL::Flip( TOOL_EVENT& aEvent ) ...@@ -236,14 +264,24 @@ int EDIT_TOOL::Flip( TOOL_EVENT& aEvent )
int EDIT_TOOL::Remove( TOOL_EVENT& aEvent ) int EDIT_TOOL::Remove( TOOL_EVENT& aEvent )
{ {
// Get a copy of the selected items set // Get a copy of the selected items set
std::set<BOARD_ITEM*> selectedItems = m_selectionTool->GetSelection().items; PICKED_ITEMS_LIST selectedItems = m_selectionTool->GetSelection().items;
PCB_EDIT_FRAME* editFrame = static_cast<PCB_EDIT_FRAME*>( m_toolMgr->GetEditFrame() );
// As we are about to remove items, they have to be removed from the selection first // As we are about to remove items, they have to be removed from the selection first
m_selectionTool->ClearSelection(); m_selectionTool->ClearSelection();
std::set<BOARD_ITEM*>::iterator it; // Save them
for( it = selectedItems.begin(); it != selectedItems.end(); ++it ) for( unsigned int i = 0; i < selectedItems.GetCount(); ++i )
remove( *it ); 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<BOARD_ITEM*>( selectedItems.GetPickedItem( i ) );
remove( item );
}
// Rebuild list of pads and nets if necessary // Rebuild list of pads and nets if necessary
BOARD* board = getModel<BOARD>( PCB_T ); BOARD* board = getModel<BOARD>( PCB_T );
...@@ -265,6 +303,7 @@ void EDIT_TOOL::remove( BOARD_ITEM* aItem ) ...@@ -265,6 +303,7 @@ void EDIT_TOOL::remove( BOARD_ITEM* aItem )
case PCB_MODULE_T: case PCB_MODULE_T:
{ {
MODULE* module = static_cast<MODULE*>( aItem ); MODULE* module = static_cast<MODULE*>( aItem );
module->ClearFlags();
for( D_PAD* pad = module->Pads().GetFirst(); pad; pad = pad->Next() ) for( D_PAD* pad = module->Pads().GetFirst(); pad; pad = pad->Next() )
getView()->Remove( pad ); getView()->Remove( pad );
...@@ -305,7 +344,6 @@ void EDIT_TOOL::remove( BOARD_ITEM* aItem ) ...@@ -305,7 +344,6 @@ void EDIT_TOOL::remove( BOARD_ITEM* aItem )
case PCB_ZONE_T: // SEG_ZONE items are now deprecated case PCB_ZONE_T: // SEG_ZONE items are now deprecated
break; break;
// TODO
default: // other types do not need to (or should not) be handled default: // other types do not need to (or should not) be handled
assert( false ); assert( false );
return; return;
...@@ -313,7 +351,7 @@ void EDIT_TOOL::remove( BOARD_ITEM* aItem ) ...@@ -313,7 +351,7 @@ void EDIT_TOOL::remove( BOARD_ITEM* aItem )
} }
getView()->Remove( aItem ); getView()->Remove( aItem );
board->Delete( aItem ); board->Remove( aItem );
} }
......
...@@ -28,7 +28,6 @@ ...@@ -28,7 +28,6 @@
#include <math/vector2d.h> #include <math/vector2d.h>
#include <tool/tool_interactive.h> #include <tool/tool_interactive.h>
#include <view/view_group.h> #include <view/view_group.h>
#include "item_state.h"
class BOARD_ITEM; class BOARD_ITEM;
class SELECTION_TOOL; class SELECTION_TOOL;
...@@ -93,9 +92,6 @@ public: ...@@ -93,9 +92,6 @@ public:
int Remove( TOOL_EVENT& aEvent ); int Remove( TOOL_EVENT& aEvent );
private: private:
///> Saves the state of items and allows to restore them
ITEM_STATE m_state;
///> Selection tool used for obtaining selected items ///> Selection tool used for obtaining selected items
SELECTION_TOOL* m_selectionTool; SELECTION_TOOL* m_selectionTool;
...@@ -107,6 +103,16 @@ private: ...@@ -107,6 +103,16 @@ private:
///> Sets up handlers for various events ///> Sets up handlers for various events
void setTransitions(); 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 #endif
/*
* This program source code file is part of KiCad, a free EDA CAD application.
*
* Copyright (C) 2013 CERN
* @author Maciej Suminski <maciej.suminski@cern.ch>
*
* 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 <deque>
#include <class_board_item.h>
/**
* 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<BOARD_ITEM*>::iterator it, it_end;
std::deque<COMMAND>::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<BOARD_ITEM*>::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<BOARD_ITEM*>::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<BOARD_ITEM*>::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<BOARD_ITEM*>::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<BOARD_ITEM*> m_items;
/// List of items that are affected by commands
std::deque<COMMAND> 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_ */
...@@ -182,9 +182,9 @@ void SELECTION_TOOL::AddMenuItem( const TOOL_ACTION& aAction ) ...@@ -182,9 +182,9 @@ void SELECTION_TOOL::AddMenuItem( const TOOL_ACTION& aAction )
void SELECTION_TOOL::toggleSelection( BOARD_ITEM* aItem ) void SELECTION_TOOL::toggleSelection( BOARD_ITEM* aItem )
{ {
if( isSelected( aItem ) ) if( aItem->IsSelected() )
{ {
deselectItem( aItem ); deselect( aItem );
} }
else else
{ {
...@@ -193,17 +193,11 @@ void SELECTION_TOOL::toggleSelection( BOARD_ITEM* aItem ) ...@@ -193,17 +193,11 @@ void SELECTION_TOOL::toggleSelection( BOARD_ITEM* aItem )
// Prevent selection of invisible or inactive items // Prevent selection of invisible or inactive items
if( selectable( aItem ) ) if( selectable( aItem ) )
selectItem( aItem ); select( aItem );
} }
} }
bool SELECTION_TOOL::isSelected( const BOARD_ITEM* aItem ) const
{
return ( m_selection.items.find( const_cast<BOARD_ITEM*>( aItem ) ) != m_selection.items.end() );
}
void SELECTION_TOOL::selectSingle( const VECTOR2I& aWhere ) void SELECTION_TOOL::selectSingle( const VECTOR2I& aWhere )
{ {
BOARD* pcb = getModel<BOARD>( PCB_T ); BOARD* pcb = getModel<BOARD>( PCB_T );
...@@ -219,7 +213,6 @@ void SELECTION_TOOL::selectSingle( const VECTOR2I& aWhere ) ...@@ -219,7 +213,6 @@ void SELECTION_TOOL::selectSingle( const VECTOR2I& aWhere )
case 0: case 0:
if( !m_additive ) if( !m_additive )
ClearSelection(); ClearSelection();
break; break;
case 1: case 1:
...@@ -231,7 +224,7 @@ void SELECTION_TOOL::selectSingle( const VECTOR2I& aWhere ) ...@@ -231,7 +224,7 @@ void SELECTION_TOOL::selectSingle( const VECTOR2I& aWhere )
// contain anything but module footprint and not selectable items // contain anything but module footprint and not selectable items
for( int i = collector.GetCount() - 1; i >= 0 ; --i ) 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 ) ) if( boardItem->Type() == PCB_MODULE_T || !selectable( boardItem ) )
collector.Remove( i ); collector.Remove( i );
...@@ -338,8 +331,8 @@ bool SELECTION_TOOL::selectMultiple() ...@@ -338,8 +331,8 @@ bool SELECTION_TOOL::selectMultiple()
BOARD_ITEM* item = static_cast<BOARD_ITEM*>( it->first ); BOARD_ITEM* item = static_cast<BOARD_ITEM*>( it->first );
// Add only those items that are visible and fully within the selection box // Add only those items that are visible and fully within the selection box
if( selectable( item ) && selectionBox.Contains( item->ViewBBox() ) ) if( !item->IsSelected() && selectable( item ) && selectionBox.Contains( item->ViewBBox() ) )
selectItem( item ); select( item );
} }
// Do not display information about selected item,as there is more than one // 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 ...@@ -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 // Modules are treated in a special way - when they are selected, we have to mark
class selectBase_ // all the parts that make the module as selected
{
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
if( aItem->Type() == PCB_MODULE_T ) if( aItem->Type() == PCB_MODULE_T )
{ {
MODULE* module = static_cast<MODULE*>( aItem ); MODULE* module = static_cast<MODULE*>( 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 selectVisually( aItem );
selectBase( aItem ); ITEM_PICKER picker( aItem );
m_selection.items.insert( aItem ); m_selection.items.PushItem( picker );
// It is enough to do it only for the first selected item // 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 // Set as the current item, so the information about selection is displayed
getEditFrame<PCB_EDIT_FRAME>()->SetCurItem( aItem, true ); getEditFrame<PCB_EDIT_FRAME>()->SetCurItem( aItem, true );
...@@ -552,48 +519,30 @@ void SELECTION_TOOL::selectItem( BOARD_ITEM* aItem ) ...@@ -552,48 +519,30 @@ void SELECTION_TOOL::selectItem( BOARD_ITEM* aItem )
// Now the context menu should be enabled // Now the context menu should be enabled
SetContextMenu( &m_menu, CMENU_BUTTON ); SetContextMenu( &m_menu, CMENU_BUTTON );
} }
else
{
// If multiple items are selected, do not show the information about the selected item
getEditFrame<PCB_EDIT_FRAME>()->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 // 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 ) if( aItem->Type() == PCB_MODULE_T )
{ {
MODULE* module = static_cast<MODULE*>( aItem ); MODULE* module = static_cast<MODULE*>( 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 ); deselectVisually( aItem );
m_selection.items.erase( 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 there is nothing selected, disable the context menu
if( m_selection.Empty() ) if( m_selection.Empty() )
...@@ -604,6 +553,26 @@ void SELECTION_TOOL::deselectItem( BOARD_ITEM* aItem ) ...@@ -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 bool SELECTION_TOOL::containsSelected( const VECTOR2I& aPoint ) const
{ {
const unsigned GRIP_MARGIN = 500000; const unsigned GRIP_MARGIN = 500000;
...@@ -611,9 +580,10 @@ bool SELECTION_TOOL::containsSelected( const VECTOR2I& aPoint ) const ...@@ -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 // Check if the point is located within any of the currently selected items bounding boxes
std::set<BOARD_ITEM*>::iterator it, it_end; std::set<BOARD_ITEM*>::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<BOARD_ITEM*>( m_selection.items.GetPickedItem( i ) );
BOX2I itemBox = item->ViewBBox();
itemBox.Inflate( GRIP_MARGIN ); // Give some margin for gripping an item itemBox.Inflate( GRIP_MARGIN ); // Give some margin for gripping an item
if( itemBox.Contains( aPoint ) ) if( itemBox.Contains( aPoint ) )
...@@ -626,6 +596,6 @@ bool SELECTION_TOOL::containsSelected( const VECTOR2I& aPoint ) const ...@@ -626,6 +596,6 @@ bool SELECTION_TOOL::containsSelected( const VECTOR2I& aPoint ) const
void SELECTION_TOOL::SELECTION::Clear() void SELECTION_TOOL::SELECTION::Clear()
{ {
items.clear(); items.ClearItemsList();
group->Clear(); group->Clear();
} }
...@@ -26,11 +26,10 @@ ...@@ -26,11 +26,10 @@
#ifndef __SELECTION_TOOL_H #ifndef __SELECTION_TOOL_H
#define __SELECTION_TOOL_H #define __SELECTION_TOOL_H
#include <set>
#include <math/vector2d.h> #include <math/vector2d.h>
#include <tool/tool_interactive.h> #include <tool/tool_interactive.h>
#include <tool/context_menu.h> #include <tool/context_menu.h>
#include <class_undoredo_container.h>
class SELECTION_AREA; class SELECTION_AREA;
class BOARD_ITEM; class BOARD_ITEM;
...@@ -62,7 +61,7 @@ public: ...@@ -62,7 +61,7 @@ public:
struct SELECTION struct SELECTION
{ {
/// Set of selected items /// Set of selected items
std::set<BOARD_ITEM*> items; PICKED_ITEMS_LIST items;
/// VIEW_GROUP that holds currently selected items /// VIEW_GROUP that holds currently selected items
KIGFX::VIEW_GROUP* group; KIGFX::VIEW_GROUP* group;
...@@ -70,13 +69,13 @@ public: ...@@ -70,13 +69,13 @@ public:
/// Checks if there is anything selected /// Checks if there is anything selected
bool Empty() const bool Empty() const
{ {
return items.empty(); return ( items.GetCount() == 0 );
} }
/// Returns the number of selected parts /// Returns the number of selected parts
int Size() const 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 /// Clears both the VIEW_GROUP and set of selected items. Please note that it does not
...@@ -111,7 +110,7 @@ public: ...@@ -111,7 +110,7 @@ public:
void ClearSelection(); void ClearSelection();
/** /**
* Function AddAction() * Function AddMenuItem()
* *
* Adds a menu entry to run a TOOL_ACTION on selected items. * Adds a menu entry to run a TOOL_ACTION on selected items.
* @param aAction is a menu entry to be added. * @param aAction is a menu entry to be added.
...@@ -161,15 +160,6 @@ private: ...@@ -161,15 +160,6 @@ private:
*/ */
void toggleSelection( BOARD_ITEM* aItem ); 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() * Function selectable()
* Checks conditions for an item to be selected. * Checks conditions for an item to be selected.
...@@ -184,7 +174,7 @@ private: ...@@ -184,7 +174,7 @@ private:
* *
* @param aItem is an item to be selected. * @param aItem is an item to be selected.
*/ */
void selectItem( BOARD_ITEM* aItem ); void select( BOARD_ITEM* aItem );
/** /**
* Function deselectItem() * Function deselectItem()
...@@ -192,7 +182,21 @@ private: ...@@ -192,7 +182,21 @@ private:
* *
* @param aItem is an item to be deselected. * @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() * Function containsSelected()
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment