Moved VIEW_GROUP creation to the selection tool. In this way selected items are always drawn on overlay, not only when dragged.
This commit is contained in:
parent
86000832fe
commit
2ee858072f
|
@ -78,15 +78,15 @@ bool MOVE_TOOL::Init()
|
|||
|
||||
int MOVE_TOOL::Main( TOOL_EVENT& aEvent )
|
||||
{
|
||||
const SELECTION_TOOL::SELECTION selection = m_selectionTool->GetSelection();
|
||||
if( selection.Empty() )
|
||||
return 0; // there are no items to operate on
|
||||
|
||||
VECTOR2D dragPosition;
|
||||
bool dragging = false;
|
||||
bool restore = false; // Should items' state be restored when finishing the tool?
|
||||
VIEW* view = getView();
|
||||
|
||||
VIEW_CONTROLS* controls = getViewControls();
|
||||
|
||||
// Add a VIEW_GROUP that will hold all modified items
|
||||
view->Add( &m_items );
|
||||
|
||||
controls->ShowCursor( true );
|
||||
controls->SetSnapping( true );
|
||||
controls->SetAutoPan( true );
|
||||
|
@ -108,12 +108,12 @@ int MOVE_TOOL::Main( TOOL_EVENT& aEvent )
|
|||
if( evt->IsAction( &COMMON_ACTIONS::rotate ) ) // got rotation event?
|
||||
{
|
||||
m_state.Rotate( cursorPos, 900.0 );
|
||||
m_items.ViewUpdate( VIEW_ITEM::GEOMETRY );
|
||||
selection.group->ViewUpdate( VIEW_ITEM::GEOMETRY );
|
||||
}
|
||||
else if( evt->IsAction( &COMMON_ACTIONS::flip ) ) // got flip event?
|
||||
{
|
||||
m_state.Flip( cursorPos );
|
||||
m_items.ViewUpdate( VIEW_ITEM::GEOMETRY );
|
||||
selection.group->ViewUpdate( VIEW_ITEM::GEOMETRY );
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -128,98 +128,38 @@ int MOVE_TOOL::Main( TOOL_EVENT& aEvent )
|
|||
else
|
||||
{
|
||||
// Prepare to drag
|
||||
m_selection = m_selectionTool->GetSelection();
|
||||
if( m_selection.empty() )
|
||||
break; // there are no items to operate on
|
||||
|
||||
std::set<BOARD_ITEM*>::iterator it;
|
||||
for( it = m_selection.begin(); it != m_selection.end(); ++it )
|
||||
for( it = selection.items.begin(); it != selection.items.end(); ++it )
|
||||
{
|
||||
// Save the state of the selected items, in case it has to be restored
|
||||
m_state.Save( *it );
|
||||
|
||||
// Gather all selected items into one VIEW_GROUP
|
||||
vgAdd( *it, &m_items );
|
||||
}
|
||||
|
||||
// Hide the original items, they are temporarily shown in VIEW_GROUP on overlay
|
||||
vgSetVisibility( &m_items, false );
|
||||
vgUpdate( &m_items, VIEW_ITEM::APPEARANCE );
|
||||
|
||||
dragging = true;
|
||||
}
|
||||
|
||||
m_items.ViewUpdate( VIEW_ITEM::GEOMETRY );
|
||||
selection.group->ViewUpdate( VIEW_ITEM::GEOMETRY );
|
||||
dragPosition = evt->Position();
|
||||
}
|
||||
else if( evt->IsMouseUp( MB_Left ) || evt->IsClick( MB_Left ) )
|
||||
break; // Finish
|
||||
}
|
||||
|
||||
// Restore visibility of the original items
|
||||
vgSetVisibility( &m_items, true );
|
||||
|
||||
if( restore )
|
||||
{
|
||||
// Modifications has to be rollbacked, so restore the previous state of items
|
||||
vgUpdate( &m_items, VIEW_ITEM::APPEARANCE );
|
||||
m_state.RestoreAll();
|
||||
}
|
||||
else
|
||||
{
|
||||
// Changes are applied, so update the items
|
||||
vgUpdate( &m_items, m_state.GetUpdateFlag() );
|
||||
selection.group->ItemsViewUpdate( m_state.GetUpdateFlag() );
|
||||
m_state.Apply();
|
||||
}
|
||||
|
||||
m_items.Clear();
|
||||
view->Remove( &m_items );
|
||||
|
||||
controls->ShowCursor( false );
|
||||
controls->SetSnapping( false );
|
||||
controls->SetAutoPan( false );
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
void MOVE_TOOL::vgAdd( BOARD_ITEM* aItem, VIEW_GROUP* aGroup )
|
||||
{
|
||||
// Modules are treated in a special way - when they are moved, we have to
|
||||
// move all the parts that make the module, not the module itself
|
||||
if( aItem->Type() == PCB_MODULE_T )
|
||||
{
|
||||
MODULE* module = static_cast<MODULE*>( aItem );
|
||||
|
||||
// Add everything that belongs to the module (besides the module itself)
|
||||
for( D_PAD* pad = module->Pads().GetFirst(); pad; pad = pad->Next() )
|
||||
aGroup->Add( pad );
|
||||
|
||||
for( BOARD_ITEM* drawing = module->GraphicalItems().GetFirst(); drawing;
|
||||
drawing = drawing->Next() )
|
||||
aGroup->Add( drawing );
|
||||
|
||||
aGroup->Add( &module->Reference() );
|
||||
aGroup->Add( &module->Value() );
|
||||
}
|
||||
|
||||
// Add items to the VIEW_GROUP, so they will be displayed on the overlay
|
||||
// while dragging
|
||||
aGroup->Add( aItem );
|
||||
}
|
||||
|
||||
|
||||
void MOVE_TOOL::vgSetVisibility( VIEW_GROUP* aGroup, bool aVisible ) const
|
||||
{
|
||||
std::set<VIEW_ITEM*>::const_iterator it, it_end;
|
||||
for( it = aGroup->Begin(), it_end = aGroup->End(); it != it_end; ++it )
|
||||
(*it)->ViewSetVisible( aVisible );
|
||||
}
|
||||
|
||||
|
||||
void MOVE_TOOL::vgUpdate( VIEW_GROUP* aGroup, VIEW_ITEM::ViewUpdateFlags aFlags ) const
|
||||
{
|
||||
std::set<VIEW_ITEM*>::const_iterator it, it_end;
|
||||
for( it = aGroup->Begin(), it_end = aGroup->End(); it != it_end; ++it )
|
||||
(*it)->ViewUpdate( aFlags );
|
||||
}
|
||||
|
|
|
@ -65,26 +65,11 @@ public:
|
|||
int Main( TOOL_EVENT& aEvent );
|
||||
|
||||
private:
|
||||
/// Adds an item to the VIEW_GROUP that holds all moved items and displays them on the overlay
|
||||
void vgAdd( BOARD_ITEM* aItem, KiGfx::VIEW_GROUP* aGroup );
|
||||
|
||||
/// Changes visibility settings for items stored in a VIEW_GROUP
|
||||
void vgSetVisibility( KiGfx::VIEW_GROUP* aGroup, bool aVisible ) const;
|
||||
|
||||
/// Updates items stored in a VIEW_GROUP with selected update flag
|
||||
void vgUpdate( KiGfx::VIEW_GROUP* aGroup, KiGfx::VIEW_ITEM::ViewUpdateFlags aFlags ) const;
|
||||
|
||||
/// 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;
|
||||
|
||||
/// Set of selected items (obtained from pcbnew.InteractiveSelection tool)
|
||||
std::set<BOARD_ITEM*> m_selection;
|
||||
|
||||
/// VIEW_GROUP that helds currently moved items
|
||||
KiGfx::VIEW_GROUP m_items;
|
||||
};
|
||||
|
||||
#endif
|
||||
|
|
|
@ -36,6 +36,7 @@
|
|||
#include <wxPcbStruct.h>
|
||||
#include <collectors.h>
|
||||
#include <view/view_controls.h>
|
||||
#include <view/view_group.h>
|
||||
#include <painter.h>
|
||||
|
||||
#include <tool/tool_event.h>
|
||||
|
@ -53,20 +54,19 @@ SELECTION_TOOL::SELECTION_TOOL() :
|
|||
TOOL_INTERACTIVE( "pcbnew.InteractiveSelection" ), m_multiple( false )
|
||||
{
|
||||
m_selArea = new SELECTION_AREA;
|
||||
m_selection.group = new KiGfx::VIEW_GROUP;
|
||||
}
|
||||
|
||||
|
||||
SELECTION_TOOL::~SELECTION_TOOL()
|
||||
{
|
||||
if( m_selArea )
|
||||
delete m_selArea;
|
||||
delete m_selArea;
|
||||
delete m_selection.group;
|
||||
}
|
||||
|
||||
|
||||
void SELECTION_TOOL::Reset()
|
||||
{
|
||||
m_selectedItems.clear();
|
||||
|
||||
// The tool launches upon reception of action event ("pcbnew.InteractiveSelection")
|
||||
Go( &SELECTION_TOOL::Main, COMMON_ACTIONS::selectionActivate.MakeEvent() );
|
||||
}
|
||||
|
@ -75,8 +75,11 @@ void SELECTION_TOOL::Reset()
|
|||
int SELECTION_TOOL::Main( TOOL_EVENT& aEvent )
|
||||
{
|
||||
BOARD* board = getModel<BOARD>( PCB_T );
|
||||
VIEW* view = getView();
|
||||
assert( board != NULL );
|
||||
|
||||
view->Add( m_selection.group );
|
||||
|
||||
// Main loop: keep receiving events
|
||||
while( OPT_TOOL_EVENT evt = Wait() )
|
||||
{
|
||||
|
@ -86,7 +89,7 @@ int SELECTION_TOOL::Main( TOOL_EVENT& aEvent )
|
|||
|
||||
if( evt->IsCancel() )
|
||||
{
|
||||
if( !m_selectedItems.empty() ) // Cancel event deselects items...
|
||||
if( !m_selection.Empty() ) // Cancel event deselects items...
|
||||
clearSelection();
|
||||
else // ...unless there is nothing selected
|
||||
break; // then exit the tool
|
||||
|
@ -99,7 +102,7 @@ int SELECTION_TOOL::Main( TOOL_EVENT& aEvent )
|
|||
// drag with LMB? Select multiple objects (or at least draw a selection box) or drag them
|
||||
if( evt->IsDrag( MB_Left ) )
|
||||
{
|
||||
if( m_selectedItems.empty() || m_additive )
|
||||
if( m_selection.Empty() || m_additive )
|
||||
{
|
||||
// If nothings has been selected or user wants to select more
|
||||
// draw the selection box
|
||||
|
@ -112,7 +115,6 @@ int SELECTION_TOOL::Main( TOOL_EVENT& aEvent )
|
|||
{
|
||||
// Yes -> run the move tool and wait till it finishes
|
||||
m_toolMgr->InvokeTool( "pcbnew.InteractiveMove" );
|
||||
Wait();
|
||||
}
|
||||
else
|
||||
{
|
||||
|
@ -123,6 +125,9 @@ int SELECTION_TOOL::Main( TOOL_EVENT& aEvent )
|
|||
}
|
||||
}
|
||||
|
||||
m_selection.group->Clear();
|
||||
view->Remove( m_selection.group );
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -137,9 +142,13 @@ void SELECTION_TOOL::AddMenuItem( const TOOL_ACTION& aAction )
|
|||
|
||||
void SELECTION_TOOL::toggleSelection( BOARD_ITEM* aItem )
|
||||
{
|
||||
if( m_selectedItems.find( aItem ) != m_selectedItems.end() )
|
||||
if( m_selection.items.find( aItem ) != m_selection.items.end() )
|
||||
{
|
||||
deselectItem( aItem );
|
||||
|
||||
// If there is nothing selected, disable the context menu
|
||||
if( m_selection.Empty() )
|
||||
SetContextMenu( &m_menu, CMENU_OFF );
|
||||
}
|
||||
else
|
||||
{
|
||||
|
@ -148,19 +157,29 @@ void SELECTION_TOOL::toggleSelection( BOARD_ITEM* aItem )
|
|||
|
||||
// Prevent selection of invisible or inactive items
|
||||
if( selectable( aItem ) )
|
||||
{
|
||||
selectItem( aItem );
|
||||
|
||||
// Now the context menu should be enabled
|
||||
SetContextMenu( &m_menu, CMENU_BUTTON );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void SELECTION_TOOL::clearSelection()
|
||||
{
|
||||
BOOST_FOREACH( BOARD_ITEM* item, m_selectedItems )
|
||||
VIEW_GROUP::const_iter it, it_end;
|
||||
for( it = m_selection.group->Begin(), it_end = m_selection.group->End(); it != it_end; ++it )
|
||||
{
|
||||
BOARD_ITEM* item = static_cast<BOARD_ITEM*>( *it );
|
||||
|
||||
item->ViewSetVisible( true );
|
||||
item->ClearSelected();
|
||||
}
|
||||
|
||||
m_selectedItems.clear();
|
||||
m_selection.group->Clear();
|
||||
m_selection.items.clear();
|
||||
|
||||
// Do not show the context menu when there is nothing selected
|
||||
SetContextMenu( &m_menu, CMENU_OFF );
|
||||
|
@ -258,9 +277,6 @@ bool SELECTION_TOOL::selectMultiple()
|
|||
VIEW* view = getView();
|
||||
getViewControls()->SetAutoPan( true );
|
||||
|
||||
// These 2 lines remove the blink-in-the-random-place effect
|
||||
m_selArea->SetOrigin( VECTOR2I( 0, 0 ) );
|
||||
m_selArea->SetEnd( VECTOR2I( 0, 0 ) );
|
||||
view->Add( m_selArea );
|
||||
|
||||
while( OPT_TOOL_EVENT evt = Wait() )
|
||||
|
@ -300,14 +316,11 @@ bool SELECTION_TOOL::selectMultiple()
|
|||
|
||||
// Add only those items that are visible and fully within the selection box
|
||||
if( selectable( item ) && selectionBox.Contains( item->ViewBBox() ) )
|
||||
{
|
||||
item->SetSelected();
|
||||
m_selectedItems.insert( item );
|
||||
}
|
||||
selectItem( item );
|
||||
}
|
||||
|
||||
// Now the context menu should be enabled
|
||||
if( !m_selectedItems.empty() )
|
||||
if( !m_selection.Empty() )
|
||||
SetContextMenu( &m_menu, CMENU_BUTTON );
|
||||
|
||||
break;
|
||||
|
@ -377,6 +390,7 @@ BOARD_ITEM* SELECTION_TOOL::disambiguationMenu( GENERAL_COLLECTOR* aCollector )
|
|||
}
|
||||
}
|
||||
|
||||
// Removes possible brighten mark
|
||||
getView()->MarkTargetDirty( TARGET_OVERLAY );
|
||||
|
||||
// Restore the original menu
|
||||
|
@ -464,13 +478,98 @@ bool SELECTION_TOOL::selectable( const BOARD_ITEM* aItem ) const
|
|||
}
|
||||
|
||||
|
||||
void SELECTION_TOOL::selectItem( 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 moved, we have to
|
||||
// move all the parts that make the module, not the module itself
|
||||
if( aItem->Type() == PCB_MODULE_T )
|
||||
{
|
||||
MODULE* module = static_cast<MODULE*>( aItem );
|
||||
|
||||
// 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 );
|
||||
}
|
||||
|
||||
|
||||
void SELECTION_TOOL::deselectItem( 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 moved, we have to
|
||||
// move all the parts that make the module, not the module itself
|
||||
if( aItem->Type() == PCB_MODULE_T )
|
||||
{
|
||||
MODULE* module = static_cast<MODULE*>( aItem );
|
||||
|
||||
// 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 );
|
||||
}
|
||||
|
||||
|
||||
bool SELECTION_TOOL::containsSelected( const VECTOR2I& aPoint ) const
|
||||
{
|
||||
const unsigned GRIP_MARGIN = 500000;
|
||||
|
||||
// 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_selectedItems.begin(), it_end = m_selectedItems.end(); it != it_end; ++it )
|
||||
for( it = m_selection.items.begin(), it_end = m_selection.items.end(); it != it_end; ++it )
|
||||
{
|
||||
BOX2I itemBox = (*it)->ViewBBox();
|
||||
itemBox.Inflate( GRIP_MARGIN ); // Give some margin for gripping an item
|
||||
|
|
|
@ -36,6 +36,11 @@ class SELECTION_AREA;
|
|||
class BOARD_ITEM;
|
||||
class GENERAL_COLLECTOR;
|
||||
|
||||
namespace KiGfx
|
||||
{
|
||||
class VIEW_GROUP;
|
||||
}
|
||||
|
||||
/**
|
||||
* Class SELECTION_TOOL
|
||||
*
|
||||
|
@ -54,6 +59,18 @@ public:
|
|||
SELECTION_TOOL();
|
||||
~SELECTION_TOOL();
|
||||
|
||||
struct SELECTION
|
||||
{
|
||||
/// Set of selected items
|
||||
std::set<BOARD_ITEM*> items;
|
||||
|
||||
/// VIEW_GROUP that holds currently selected items
|
||||
KiGfx::VIEW_GROUP* group;
|
||||
|
||||
/// Checks if there is anything selected
|
||||
bool Empty() const { return items.empty(); }
|
||||
};
|
||||
|
||||
/// @copydoc TOOL_INTERACTIVE::Reset()
|
||||
void Reset();
|
||||
|
||||
|
@ -69,9 +86,9 @@ public:
|
|||
*
|
||||
* Returns the set of currently selected items.
|
||||
*/
|
||||
const std::set<BOARD_ITEM*>& GetSelection() const
|
||||
const SELECTION& GetSelection() const
|
||||
{
|
||||
return m_selectedItems;
|
||||
return m_selection;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -145,14 +162,7 @@ private:
|
|||
*
|
||||
* @param aItem is an item to be selected.
|
||||
*/
|
||||
void selectItem( BOARD_ITEM* aItem )
|
||||
{
|
||||
aItem->SetSelected();
|
||||
m_selectedItems.insert( aItem );
|
||||
|
||||
// Now the context menu should be enabled
|
||||
SetContextMenu( &m_menu, CMENU_BUTTON );
|
||||
}
|
||||
void selectItem( BOARD_ITEM* aItem );
|
||||
|
||||
/**
|
||||
* Function deselectItem()
|
||||
|
@ -160,15 +170,7 @@ private:
|
|||
*
|
||||
* @param aItem is an item to be deselected.
|
||||
*/
|
||||
void deselectItem( BOARD_ITEM* aItem )
|
||||
{
|
||||
aItem->ClearSelected();
|
||||
m_selectedItems.erase( aItem );
|
||||
|
||||
if( m_selectedItems.empty() )
|
||||
// If there is nothing selected, disable the context menu
|
||||
SetContextMenu( &m_menu, CMENU_OFF );
|
||||
}
|
||||
void deselectItem( BOARD_ITEM* aItem );
|
||||
|
||||
/**
|
||||
* Function containsSelected()
|
||||
|
@ -178,12 +180,12 @@ private:
|
|||
*/
|
||||
bool containsSelected( const VECTOR2I& aPoint ) const;
|
||||
|
||||
/// Container storing currently selected items
|
||||
std::set<BOARD_ITEM*> m_selectedItems;
|
||||
|
||||
/// Visual representation of selection box
|
||||
SELECTION_AREA* m_selArea;
|
||||
|
||||
/// Current state of selection
|
||||
SELECTION m_selection;
|
||||
|
||||
/// Flag saying if items should be added to the current selection or rather replace it
|
||||
bool m_additive;
|
||||
|
||||
|
|
Loading…
Reference in New Issue