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 @@
#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();
......
......@@ -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,26 +204,29 @@ 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( !m_dragging ) // If it is being dragged, then it is already saved with UR_CHANGED flag
{
m_state.Rotate( cursorPos, 900.0 );
selection.group->ViewUpdate( VIEW_ITEM::GEOMETRY );
editFrame->OnModify();
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 )
{
(*it)->Rotate( wxPoint( cursorPos.x, cursorPos.y ), 900.0 );
(*it)->ViewUpdate( KIGFX::VIEW_ITEM::GEOMETRY );
}
for( unsigned int i = 0; i < selection.items.GetCount(); ++i )
{
BOARD_ITEM* item = static_cast<BOARD_ITEM*>( selection.items.GetPickedItem( i ) );
setTransitions();
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();
return 0;
}
......@@ -209,26 +234,29 @@ 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( !m_dragging ) // If it is being dragged, then it is already saved with UR_CHANGED flag
{
m_state.Flip( cursorPos );
selection.group->ViewUpdate( VIEW_ITEM::GEOMETRY );
editFrame->OnModify();
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 )
{
(*it)->Flip( wxPoint( cursorPos.x, cursorPos.y ) );
(*it)->ViewUpdate( KIGFX::VIEW_ITEM::LAYERS );
}
for( unsigned int i = 0; i < selection.items.GetCount(); ++i )
{
BOARD_ITEM* item = static_cast<BOARD_ITEM*>( selection.items.GetPickedItem( i ) );
setTransitions();
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();
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 );
}
......
......@@ -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
/*
* 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 )
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();
}
......@@ -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()
......
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