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:
parent
e4efe212d6
commit
873235304e
|
@ -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,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 );
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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_ */
|
|
@ -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()
|
||||
|
|
Loading…
Reference in New Issue