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.
This commit is contained in:
Maciej Suminski 2013-12-18 14:33:34 +01:00
parent e4efe212d6
commit 873235304e
6 changed files with 231 additions and 439 deletions

View File

@ -25,6 +25,7 @@
#include <fctsys.h>
#include <class_drawpanel.h>
#include <class_drawpanel_gal.h>
#include <macros.h>
#include <pcbnew.h>
@ -40,6 +41,8 @@
#include <class_zone.h>
#include <class_edge_mod.h>
#include <tools/selection_tool.h>
#include <tool/tool_manager.h>
/* 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<MODULE*>( 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<MODULE*>( 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<MODULE*>( 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<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;
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<SELECTION_TOOL*>( 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<SELECTION_TOOL*>( m_toolManager->FindTool(
"pcbnew.InteractiveSelection" ) );
selectionTool->ClearSelection();
/* Get the old list */
PICKED_ITEMS_LIST* List = GetScreen()->PopCommandFromRedoList();

View File

@ -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<PCB_EDIT_FRAME*>( 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<BOARD_ITEM*>( selection.items.GetPickedItem( i ) );
item->Move( wxPoint( movement.x, movement.y ) );
}
}
else
{
// Prepare to drag
std::set<BOARD_ITEM*>::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<BOARD_ITEM*>( 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<PCB_EDIT_FRAME*>( 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<PCB_EDIT_FRAME*>( m_toolMgr->GetEditFrame() );
BOARD_ITEM* item = *selection.items.begin();
BOARD_ITEM* item = static_cast<BOARD_ITEM*>( 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<PCB_EDIT_FRAME*>( 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<BOARD_ITEM*>( 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<BOARD_ITEM*>::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<PCB_EDIT_FRAME*>( 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<BOARD_ITEM*>( 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<BOARD_ITEM*>::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<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
m_selectionTool->ClearSelection();
std::set<BOARD_ITEM*>::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<BOARD_ITEM*>( selectedItems.GetPickedItem( i ) );
remove( item );
}
// Rebuild list of pads and nets if necessary
BOARD* board = getModel<BOARD>( PCB_T );
@ -265,6 +303,7 @@ void EDIT_TOOL::remove( BOARD_ITEM* aItem )
case PCB_MODULE_T:
{
MODULE* module = static_cast<MODULE*>( 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 );
}

View File

@ -28,7 +28,6 @@
#include <math/vector2d.h>
#include <tool/tool_interactive.h>
#include <view/view_group.h>
#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

View File

@ -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 <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_ */

View File

@ -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<BOARD_ITEM*>( aItem ) ) != m_selection.items.end() );
}
void SELECTION_TOOL::selectSingle( const VECTOR2I& aWhere )
{
BOARD* pcb = getModel<BOARD>( 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<BOARD_ITEM*>( 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<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
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<PCB_EDIT_FRAME>()->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<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
// 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<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 );
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<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
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();
}

View File

@ -26,11 +26,10 @@
#ifndef __SELECTION_TOOL_H
#define __SELECTION_TOOL_H
#include <set>
#include <math/vector2d.h>
#include <tool/tool_interactive.h>
#include <tool/context_menu.h>
#include <class_undoredo_container.h>
class SELECTION_AREA;
class BOARD_ITEM;
@ -62,7 +61,7 @@ public:
struct SELECTION
{
/// Set of selected items
std::set<BOARD_ITEM*> 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()