|
|
@ -33,7 +33,6 @@ using namespace std::placeholders; |
|
|
|
#include <bitmaps.h>
|
|
|
|
#include <tool/tool_event.h>
|
|
|
|
#include <tool/tool_manager.h>
|
|
|
|
#include <preview_items/bright_box.h>
|
|
|
|
#include <preview_items/ruler_item.h>
|
|
|
|
#include <preview_items/selection_area.h>
|
|
|
|
#include <gerbview_id.h>
|
|
|
@ -108,10 +107,12 @@ private: |
|
|
|
|
|
|
|
GERBVIEW_SELECTION_TOOL::GERBVIEW_SELECTION_TOOL() : |
|
|
|
TOOL_INTERACTIVE( "gerbview.InteractiveSelection" ), |
|
|
|
m_frame( NULL ), m_additive( false ), m_subtractive( false ), |
|
|
|
m_frame( NULL ), |
|
|
|
m_additive( false ), |
|
|
|
m_subtractive( false ), |
|
|
|
m_exclusive_or( false ), |
|
|
|
m_multiple( false ) |
|
|
|
{ |
|
|
|
// these members are initialized to avoid warnings about non initialized vars
|
|
|
|
m_preliminary = true; |
|
|
|
} |
|
|
|
|
|
|
@ -131,7 +132,6 @@ int GERBVIEW_SELECTION_TOOL::UpdateMenu( const TOOL_EVENT& aEvent ) |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
GERBVIEW_SELECTION_TOOL::~GERBVIEW_SELECTION_TOOL() |
|
|
|
{ |
|
|
|
getView()->Remove( &m_selection ); |
|
|
@ -186,6 +186,15 @@ int GERBVIEW_SELECTION_TOOL::Main( const TOOL_EVENT& aEvent ) |
|
|
|
if( m_frame->ToolStackIsEmpty() ) |
|
|
|
m_frame->GetCanvas()->SetCurrentCursor( wxCURSOR_ARROW ); |
|
|
|
|
|
|
|
m_additive = m_subtractive = m_exclusive_or = false; |
|
|
|
|
|
|
|
if( evt->Modifier( MD_SHIFT ) && evt->Modifier( MD_CTRL ) ) |
|
|
|
m_subtractive = true; |
|
|
|
else if( evt->Modifier( MD_SHIFT ) ) |
|
|
|
m_additive = true; |
|
|
|
else if( evt->Modifier( MD_CTRL ) ) |
|
|
|
m_exclusive_or = true; |
|
|
|
|
|
|
|
// This is kind of hacky: activate RMB drag on any event.
|
|
|
|
// There doesn't seem to be any other good way to tell when another tool
|
|
|
|
// is canceled and control returns to the selection tool, except by the
|
|
|
@ -204,9 +213,6 @@ int GERBVIEW_SELECTION_TOOL::Main( const TOOL_EVENT& aEvent ) |
|
|
|
// single click? Select single object
|
|
|
|
if( evt->IsClick( BUT_LEFT ) ) |
|
|
|
{ |
|
|
|
if( !m_additive ) |
|
|
|
clearSelection(); |
|
|
|
|
|
|
|
selectPoint( evt->Position() ); |
|
|
|
} |
|
|
|
|
|
|
@ -244,34 +250,6 @@ GERBVIEW_SELECTION& GERBVIEW_SELECTION_TOOL::GetSelection() |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
void GERBVIEW_SELECTION_TOOL::toggleSelection( EDA_ITEM* aItem ) |
|
|
|
{ |
|
|
|
if( aItem->IsSelected() ) |
|
|
|
{ |
|
|
|
unselect( aItem ); |
|
|
|
|
|
|
|
// Inform other potentially interested tools
|
|
|
|
m_toolMgr->ProcessEvent( EVENTS::UnselectedEvent ); |
|
|
|
} |
|
|
|
else |
|
|
|
{ |
|
|
|
if( !m_additive ) |
|
|
|
clearSelection(); |
|
|
|
|
|
|
|
// Prevent selection of invisible or inactive items
|
|
|
|
if( selectable( aItem ) ) |
|
|
|
{ |
|
|
|
select( aItem ); |
|
|
|
|
|
|
|
// Inform other potentially interested tools
|
|
|
|
m_toolMgr->ProcessEvent( EVENTS::SelectedEvent ); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
m_frame->GetCanvas()->ForceRefresh(); |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
bool GERBVIEW_SELECTION_TOOL::selectPoint( const VECTOR2I& aWhere, bool aOnDrag ) |
|
|
|
{ |
|
|
|
EDA_ITEM* item = NULL; |
|
|
@ -280,8 +258,6 @@ bool GERBVIEW_SELECTION_TOOL::selectPoint( const VECTOR2I& aWhere, bool aOnDrag |
|
|
|
|
|
|
|
collector.Collect( model, GERBER_COLLECTOR::AllItems, wxPoint( aWhere.x, aWhere.y ) ); |
|
|
|
|
|
|
|
bool anyCollected = collector.GetCount() != 0; |
|
|
|
|
|
|
|
// Remove unselectable items
|
|
|
|
for( int i = collector.GetCount() - 1; i >= 0; --i ) |
|
|
|
{ |
|
|
@ -289,42 +265,39 @@ bool GERBVIEW_SELECTION_TOOL::selectPoint( const VECTOR2I& aWhere, bool aOnDrag |
|
|
|
collector.Remove( i ); |
|
|
|
} |
|
|
|
|
|
|
|
switch( collector.GetCount() ) |
|
|
|
if( collector.GetCount() > 1 ) |
|
|
|
{ |
|
|
|
case 0: |
|
|
|
if( !m_additive && anyCollected ) |
|
|
|
clearSelection(); |
|
|
|
if( aOnDrag ) |
|
|
|
Wait( TOOL_EVENT( TC_ANY, TA_MOUSE_UP, BUT_LEFT ) ); |
|
|
|
|
|
|
|
return false; |
|
|
|
item = disambiguationMenu( &collector ); |
|
|
|
|
|
|
|
case 1: |
|
|
|
toggleSelection( collector[0] ); |
|
|
|
|
|
|
|
return true; |
|
|
|
|
|
|
|
default: |
|
|
|
// Let's see if there is still disambiguation in selection..
|
|
|
|
if( collector.GetCount() == 1 ) |
|
|
|
if( item ) |
|
|
|
{ |
|
|
|
toggleSelection( collector[0] ); |
|
|
|
|
|
|
|
return true; |
|
|
|
collector.Empty(); |
|
|
|
collector.Append( item ); |
|
|
|
} |
|
|
|
else if( collector.GetCount() > 1 ) |
|
|
|
{ |
|
|
|
if( aOnDrag ) |
|
|
|
Wait( TOOL_EVENT( TC_ANY, TA_MOUSE_UP, BUT_LEFT ) ); |
|
|
|
} |
|
|
|
|
|
|
|
item = disambiguationMenu( &collector ); |
|
|
|
if( !m_additive && !m_subtractive && !m_exclusive_or ) |
|
|
|
clearSelection(); |
|
|
|
|
|
|
|
if( item ) |
|
|
|
{ |
|
|
|
toggleSelection( item ); |
|
|
|
if( collector.GetCount() == 1 ) |
|
|
|
{ |
|
|
|
item = collector[ 0 ]; |
|
|
|
|
|
|
|
return true; |
|
|
|
} |
|
|
|
if( m_subtractive || ( m_exclusive_or && item->IsSelected() ) ) |
|
|
|
{ |
|
|
|
unselect( item ); |
|
|
|
m_toolMgr->ProcessEvent( EVENTS::UnselectedEvent ); |
|
|
|
return false; |
|
|
|
} |
|
|
|
else |
|
|
|
{ |
|
|
|
select( item ); |
|
|
|
m_toolMgr->ProcessEvent( EVENTS::SelectedEvent ); |
|
|
|
return true; |
|
|
|
} |
|
|
|
break; |
|
|
|
} |
|
|
|
|
|
|
|
return false; |
|
|
@ -343,120 +316,14 @@ bool GERBVIEW_SELECTION_TOOL::selectCursor( bool aSelectAlways ) |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
bool GERBVIEW_SELECTION_TOOL::selectMultiple() |
|
|
|
{ |
|
|
|
bool cancelled = false; // Was the tool cancelled while it was running?
|
|
|
|
m_multiple = true; // Multiple selection mode is active
|
|
|
|
KIGFX::VIEW* view = getView(); |
|
|
|
getViewControls()->SetAutoPan( true ); |
|
|
|
|
|
|
|
KIGFX::PREVIEW::SELECTION_AREA area; |
|
|
|
view->Add( &area ); |
|
|
|
|
|
|
|
while( TOOL_EVENT* evt = Wait() ) |
|
|
|
{ |
|
|
|
if( evt->IsCancelInteractive() ) |
|
|
|
{ |
|
|
|
cancelled = true; |
|
|
|
break; |
|
|
|
} |
|
|
|
|
|
|
|
if( evt->IsDrag( BUT_LEFT ) ) |
|
|
|
{ |
|
|
|
|
|
|
|
// Start drawing a selection box
|
|
|
|
area.SetOrigin( evt->DragOrigin() ); |
|
|
|
area.SetEnd( evt->Position() ); |
|
|
|
area.SetAdditive( m_additive ); |
|
|
|
area.SetSubtractive( m_subtractive ); |
|
|
|
|
|
|
|
view->SetVisible( &area, true ); |
|
|
|
view->Update( &area ); |
|
|
|
} |
|
|
|
|
|
|
|
if( evt->IsMouseUp( BUT_LEFT ) ) |
|
|
|
{ |
|
|
|
// End drawing the selection box
|
|
|
|
view->SetVisible( &area, false ); |
|
|
|
|
|
|
|
// Mark items within the selection box as selected
|
|
|
|
std::vector<KIGFX::VIEW::LAYER_ITEM_PAIR> selectedItems; |
|
|
|
|
|
|
|
// Filter the view items based on the selection box
|
|
|
|
BOX2I selectionBox = area.ViewBBox(); |
|
|
|
view->Query( selectionBox, selectedItems ); // Get the list of selected items
|
|
|
|
|
|
|
|
std::vector<KIGFX::VIEW::LAYER_ITEM_PAIR>::iterator it, it_end; |
|
|
|
|
|
|
|
int width = area.GetEnd().x - area.GetOrigin().x; |
|
|
|
int height = area.GetEnd().y - area.GetOrigin().y; |
|
|
|
|
|
|
|
// Construct an EDA_RECT to determine EDA_ITEM selection
|
|
|
|
EDA_RECT selectionRect( wxPoint( area.GetOrigin().x, area.GetOrigin().y ), |
|
|
|
wxSize( width, height ) ); |
|
|
|
|
|
|
|
selectionRect.Normalize(); |
|
|
|
|
|
|
|
for( it = selectedItems.begin(), it_end = selectedItems.end(); it != it_end; ++it ) |
|
|
|
{ |
|
|
|
auto item = static_cast<GERBER_DRAW_ITEM*>( it->first ); |
|
|
|
|
|
|
|
if( !item || !selectable( item ) ) |
|
|
|
continue; |
|
|
|
|
|
|
|
/* Selection mode depends on direction of drag-selection:
|
|
|
|
* Left > Right : Select objects that are fully enclosed by selection |
|
|
|
* Right > Left : Select objects that are crossed by selection |
|
|
|
*/ |
|
|
|
if( item->HitTest( selectionRect, width >= 0 ) ) |
|
|
|
{ |
|
|
|
if( m_subtractive ) |
|
|
|
unselect( item ); |
|
|
|
else |
|
|
|
select( item ); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
// Inform other potentially interested tools
|
|
|
|
if( !m_selection.Empty() ) |
|
|
|
m_toolMgr->ProcessEvent( EVENTS::SelectedEvent ); |
|
|
|
|
|
|
|
break; // Stop waiting for events
|
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
// Stop drawing the selection box
|
|
|
|
view->Remove( &area ); |
|
|
|
m_multiple = false; // Multiple selection mode is inactive
|
|
|
|
getViewControls()->SetAutoPan( false ); |
|
|
|
|
|
|
|
return cancelled; |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
void GERBVIEW_SELECTION_TOOL::setTransitions() |
|
|
|
{ |
|
|
|
Go( &GERBVIEW_SELECTION_TOOL::UpdateMenu, ACTIONS::updateMenu.MakeEvent() ); |
|
|
|
Go( &GERBVIEW_SELECTION_TOOL::Main, GERBVIEW_ACTIONS::selectionActivate.MakeEvent() ); |
|
|
|
Go( &GERBVIEW_SELECTION_TOOL::CursorSelection, GERBVIEW_ACTIONS::selectionCursor.MakeEvent() ); |
|
|
|
Go( &GERBVIEW_SELECTION_TOOL::ClearSelection, GERBVIEW_ACTIONS::selectionClear.MakeEvent() ); |
|
|
|
Go( &GERBVIEW_SELECTION_TOOL::SelectItem, GERBVIEW_ACTIONS::selectItem.MakeEvent() ); |
|
|
|
Go( &GERBVIEW_SELECTION_TOOL::UnselectItem, GERBVIEW_ACTIONS::unselectItem.MakeEvent() ); |
|
|
|
Go( &GERBVIEW_SELECTION_TOOL::MeasureTool, ACTIONS::measureTool.MakeEvent() ); |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
int GERBVIEW_SELECTION_TOOL::CursorSelection( const TOOL_EVENT& aEvent ) |
|
|
|
{ |
|
|
|
if( m_selection.Empty() ) // Try to find an item that could be modified
|
|
|
|
{ |
|
|
|
selectCursor( true ); |
|
|
|
|
|
|
|
clearSelection(); |
|
|
|
return 0; |
|
|
|
} |
|
|
|
|
|
|
|
return 0; |
|
|
|
Go( &GERBVIEW_SELECTION_TOOL::UpdateMenu, ACTIONS::updateMenu.MakeEvent() ); |
|
|
|
Go( &GERBVIEW_SELECTION_TOOL::Main, GERBVIEW_ACTIONS::selectionActivate.MakeEvent() ); |
|
|
|
Go( &GERBVIEW_SELECTION_TOOL::ClearSelection, GERBVIEW_ACTIONS::selectionClear.MakeEvent() ); |
|
|
|
Go( &GERBVIEW_SELECTION_TOOL::SelectItem, GERBVIEW_ACTIONS::selectItem.MakeEvent() ); |
|
|
|
Go( &GERBVIEW_SELECTION_TOOL::UnselectItem, GERBVIEW_ACTIONS::unselectItem.MakeEvent() ); |
|
|
|
Go( &GERBVIEW_SELECTION_TOOL::MeasureTool, ACTIONS::measureTool.MakeEvent() ); |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
@ -474,12 +341,9 @@ int GERBVIEW_SELECTION_TOOL::SelectItems( const TOOL_EVENT& aEvent ) |
|
|
|
|
|
|
|
if( items ) |
|
|
|
{ |
|
|
|
// Perform individual selection of each item
|
|
|
|
// before processing the event.
|
|
|
|
// Perform individual selection of each item before processing the event.
|
|
|
|
for( auto item : *items ) |
|
|
|
{ |
|
|
|
select( item ); |
|
|
|
} |
|
|
|
|
|
|
|
m_toolMgr->ProcessEvent( EVENTS::SelectedEvent ); |
|
|
|
} |
|
|
@ -511,12 +375,9 @@ int GERBVIEW_SELECTION_TOOL::UnselectItems( const TOOL_EVENT& aEvent ) |
|
|
|
|
|
|
|
if( items ) |
|
|
|
{ |
|
|
|
// Perform individual unselection of each item
|
|
|
|
// before processing the event
|
|
|
|
// Perform individual unselection of each item before processing the event
|
|
|
|
for( auto item : *items ) |
|
|
|
{ |
|
|
|
unselect( item ); |
|
|
|
} |
|
|
|
|
|
|
|
m_toolMgr->ProcessEvent( EVENTS::UnselectedEvent ); |
|
|
|
} |
|
|
@ -557,28 +418,6 @@ void GERBVIEW_SELECTION_TOOL::clearSelection() |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
void GERBVIEW_SELECTION_TOOL::zoomFitSelection( void ) |
|
|
|
{ |
|
|
|
//Should recalculate the view to zoom in on the selection
|
|
|
|
auto selectionBox = m_selection.ViewBBox(); |
|
|
|
auto view = getView(); |
|
|
|
|
|
|
|
VECTOR2D screenSize = view->ToWorld( m_frame->GetCanvas()->GetClientSize(), false ); |
|
|
|
|
|
|
|
if( !( selectionBox.GetWidth() == 0 ) || !( selectionBox.GetHeight() == 0 ) ) |
|
|
|
{ |
|
|
|
VECTOR2D vsize = selectionBox.GetSize(); |
|
|
|
double scale = view->GetScale() / std::max( fabs( vsize.x / screenSize.x ), |
|
|
|
fabs( vsize.y / screenSize.y ) ); |
|
|
|
view->SetScale( scale ); |
|
|
|
view->SetCenter( selectionBox.Centre() ); |
|
|
|
view->Add( &m_selection ); |
|
|
|
} |
|
|
|
|
|
|
|
m_frame->GetCanvas()->ForceRefresh(); |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
EDA_ITEM* GERBVIEW_SELECTION_TOOL::disambiguationMenu( GERBER_COLLECTOR* aCollector ) |
|
|
|
{ |
|
|
|
EDA_ITEM* current = NULL; |
|
|
@ -684,9 +523,7 @@ bool GERBVIEW_SELECTION_TOOL::selectable( const EDA_ITEM* aItem ) const |
|
|
|
void GERBVIEW_SELECTION_TOOL::select( EDA_ITEM* aItem ) |
|
|
|
{ |
|
|
|
if( aItem->IsSelected() ) |
|
|
|
{ |
|
|
|
return; |
|
|
|
} |
|
|
|
|
|
|
|
m_selection.Add( aItem ); |
|
|
|
getView()->Add( &m_selection ); |
|
|
@ -732,25 +569,6 @@ void GERBVIEW_SELECTION_TOOL::unselectVisually( EDA_ITEM* aItem ) |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
bool GERBVIEW_SELECTION_TOOL::selectionContains( const VECTOR2I& aPoint ) const |
|
|
|
{ |
|
|
|
const unsigned GRIP_MARGIN = 20; |
|
|
|
VECTOR2D margin = getView()->ToWorld( VECTOR2D( GRIP_MARGIN, GRIP_MARGIN ), false ); |
|
|
|
|
|
|
|
// Check if the point is located within any of the currently selected items bounding boxes
|
|
|
|
for( auto item : m_selection ) |
|
|
|
{ |
|
|
|
BOX2I itemBox = item->ViewBBox(); |
|
|
|
itemBox.Inflate( margin.x, margin.y ); // Give some margin for gripping an item
|
|
|
|
|
|
|
|
if( itemBox.Contains( aPoint ) ) |
|
|
|
return true; |
|
|
|
} |
|
|
|
|
|
|
|
return false; |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
int GERBVIEW_SELECTION_TOOL::MeasureTool( const TOOL_EVENT& aEvent ) |
|
|
|
{ |
|
|
|
auto& view = *getView(); |
|
|
|