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( OPT_TOOL_EVENT evt = Wait() ) { if( evt->IsCancel() ) { 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( width >= 0 ) { if( selectionBox.Contains( item->ViewBBox() ) ) { if( m_subtractive ) unselect( item ); else select( item ); } } else { if( item->HitTest( selectionRect ) ) { if( m_subtractive ) unselect( item ); else select( item ); } } } if( m_selection.Size() == 1 ) m_frame->SetCurItem( static_cast<GERBER_DRAW_ITEM*>( m_selection.Front() ) ); else m_frame->SetCurItem( NULL ); // Inform other potentially interested tools if( !m_selection.Empty() ) m_toolMgr->ProcessEvent( 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 BOARD_COMMIT::Push( const wxString& aMessage, bool aCreateUndoEntry, bool aSetDirtyBit ) { // Objects potentially interested in changes: PICKED_ITEMS_LIST undoList; KIGFX::VIEW* view = m_toolMgr->GetView(); BOARD* board = (BOARD*) m_toolMgr->GetModel(); PCB_BASE_FRAME* frame = (PCB_BASE_FRAME*) m_toolMgr->GetEditFrame(); auto connectivity = board->GetConnectivity(); std::set<EDA_ITEM*> savedModules; std::vector<BOARD_ITEM*> itemsToDeselect; if( Empty() ) return; for( COMMIT_LINE& ent : m_changes ) { int changeType = ent.m_type & CHT_TYPE; int changeFlags = ent.m_type & CHT_FLAGS; BOARD_ITEM* boardItem = static_cast<BOARD_ITEM*>( ent.m_item ); // Module items need to be saved in the undo buffer before modification if( m_editModules ) { // Be sure that we are storing a module if( ent.m_item->Type() != PCB_MODULE_T ) ent.m_item = ent.m_item->GetParent(); // We have not saved the module yet, so let's create an entry if( savedModules.count( ent.m_item ) == 0 ) { if( !ent.m_copy ) { wxASSERT( changeType != CHT_MODIFY ); // too late to make a copy.. ent.m_copy = ent.m_item->Clone(); } wxASSERT( ent.m_item->Type() == PCB_MODULE_T ); wxASSERT( ent.m_copy->Type() == PCB_MODULE_T ); if( aCreateUndoEntry ) { ITEM_PICKER itemWrapper( ent.m_item, UR_CHANGED ); itemWrapper.SetLink( ent.m_copy ); undoList.PushItem( itemWrapper ); frame->SaveCopyInUndoList( undoList, UR_CHANGED ); } savedModules.insert( ent.m_item ); static_cast<MODULE*>( ent.m_item )->SetLastEditTime(); } } switch( changeType ) { case CHT_ADD: { if( !m_editModules ) { if( aCreateUndoEntry ) { undoList.PushItem( ITEM_PICKER( boardItem, UR_NEW ) ); } if( !( changeFlags & CHT_DONE ) ) board->Add( boardItem ); // handles connectivity } else { // modules inside modules are not supported yet wxASSERT( boardItem->Type() != PCB_MODULE_T ); boardItem->SetParent( board->m_Modules.GetFirst() ); if( !( changeFlags & CHT_DONE ) ) board->m_Modules->Add( boardItem ); } view->Add( boardItem ); break; } case CHT_REMOVE: { if( !m_editModules && aCreateUndoEntry ) undoList.PushItem( ITEM_PICKER( boardItem, UR_DELETED ) ); switch( boardItem->Type() ) { // Module items case PCB_PAD_T: case PCB_MODULE_EDGE_T: case PCB_MODULE_TEXT_T: // This level can only handle module items when editing modules if( !m_editModules ) break; if( boardItem->Type() == PCB_MODULE_TEXT_T ) { TEXTE_MODULE* text = static_cast<TEXTE_MODULE*>( boardItem ); // don't allow deletion of Reference or Value if( text->GetType() != TEXTE_MODULE::TEXT_is_DIVERS ) break; } view->Remove( boardItem ); if( !( changeFlags & CHT_DONE ) ) { MODULE* module = static_cast<MODULE*>( boardItem->GetParent() ); wxASSERT( module && module->Type() == PCB_MODULE_T ); module->Delete( boardItem ); } board->m_Status_Pcb = 0; // it is done in the legacy view (ratsnest perhaps?) break; // Board items case PCB_LINE_T: // a segment not on copper layers case PCB_TEXT_T: // a text on a layer case PCB_TRACE_T: // a track segment (segment on a copper layer) case PCB_VIA_T: // a via (like track segment on a copper layer) case PCB_DIMENSION_T: // a dimension (graphic item) case PCB_TARGET_T: // a target (graphic item) case PCB_MARKER_T: // a marker used to show something case PCB_ZONE_AREA_T: itemsToDeselect.push_back( boardItem ); view->Remove( boardItem ); if( !( changeFlags & CHT_DONE ) ) board->Remove( boardItem ); break; case PCB_MODULE_T: { itemsToDeselect.push_back( boardItem ); // There are no modules inside a module yet wxASSERT( !m_editModules ); MODULE* module = static_cast<MODULE*>( boardItem ); view->Remove( module ); module->ClearFlags(); if( !( changeFlags & CHT_DONE ) ) board->Remove( module ); // handles connectivity // Clear flags to indicate, that the ratsnest, list of nets & pads are not valid anymore board->m_Status_Pcb = 0; } break; default: // other types do not need to (or should not) be handled wxASSERT( false ); break; } break; } case CHT_MODIFY: { if( !m_editModules && aCreateUndoEntry ) { ITEM_PICKER itemWrapper( boardItem, UR_CHANGED ); wxASSERT( ent.m_copy ); itemWrapper.SetLink( ent.m_copy ); undoList.PushItem( itemWrapper ); } if( ent.m_copy ) connectivity->MarkItemNetAsDirty( static_cast<BOARD_ITEM*>( ent.m_copy ) ); connectivity->Update( boardItem ); view->Update( boardItem ); // if no undo entry is needed, the copy would create a memory leak if( !aCreateUndoEntry ) delete ent.m_copy; break; } default: wxASSERT( false ); break; } } // Removing an item should trigger the unselect action // but only after all items are removed otherwise we can get // flickering depending on the system if( itemsToDeselect.size() > 0 ) m_toolMgr->RunAction( PCB_ACTIONS::unselectItems, true, &itemsToDeselect ); if( !m_editModules && aCreateUndoEntry ) frame->SaveCopyInUndoList( undoList, UR_UNSPECIFIED ); if( TOOL_MANAGER* toolMgr = frame->GetToolManager() ) toolMgr->PostEvent( { TC_MESSAGE, TA_MODEL_CHANGE, AS_GLOBAL } ); if ( !m_editModules ) { auto panel = static_cast<PCB_DRAW_PANEL_GAL*>( frame->GetGalCanvas() ); connectivity->RecalculateRatsnest(); connectivity->ClearDynamicRatsnest(); panel->RedrawRatsnest(); } if( aSetDirtyBit ) frame->OnModify(); frame->UpdateMsgPanel(); clear(); }
bool PL_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(); KIGFX::PREVIEW::SELECTION_AREA area; view->Add( &area ); while( OPT_TOOL_EVENT evt = Wait() ) { if( evt->IsAction( &ACTIONS::cancelInteractive ) || evt->IsActivate() || evt->IsCancel() ) { 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 ); getViewControls()->SetAutoPan( true ); } if( evt->IsMouseUp( BUT_LEFT ) ) { getViewControls()->SetAutoPan( false ); // End drawing the selection box view->SetVisible( &area, false ); int width = area.GetEnd().x - area.GetOrigin().x; int height = area.GetEnd().y - area.GetOrigin().y; /* 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 */ bool windowSelection = width >= 0 ? true : false; // Construct an EDA_RECT to determine EDA_ITEM selection EDA_RECT selectionRect( (wxPoint)area.GetOrigin(), wxSize( width, height ) ); selectionRect.Normalize(); for( WS_DATA_ITEM* dataItem : WS_DATA_MODEL::GetTheInstance().GetItems() ) { for( WS_DRAW_ITEM_BASE* item : dataItem->GetDrawItems() ) { if( item->HitTest( selectionRect, windowSelection ) ) { 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 } } getViewControls()->SetAutoPan( false ); // Stop drawing the selection box view->Remove( &area ); m_multiple = false; // Multiple selection mode is inactive if( !cancelled ) m_selection.ClearReferencePoint(); return cancelled; }
int PCB_EDITOR_CONTROL::PlaceTarget( const TOOL_EVENT& aEvent ) { KIGFX::VIEW* view = getView(); KIGFX::VIEW_CONTROLS* controls = getViewControls(); BOARD* board = getModel<BOARD>(); PCB_TARGET* target = new PCB_TARGET( board ); // Init the new item attributes target->SetLayer( Edge_Cuts ); target->SetWidth( board->GetDesignSettings().m_EdgeSegmentWidth ); target->SetSize( Millimeter2iu( 5 ) ); VECTOR2I cursorPos = controls->GetCursorPosition(); target->SetPosition( wxPoint( cursorPos.x, cursorPos.y ) ); // Add a VIEW_GROUP that serves as a preview for the new item KIGFX::VIEW_GROUP preview( view ); preview.Add( target ); view->Add( &preview ); m_toolMgr->RunAction( PCB_ACTIONS::selectionClear, true ); controls->SetSnapping( true ); Activate(); m_frame->SetToolID( ID_PCB_MIRE_BUTT, wxCURSOR_PENCIL, _( "Add layer alignment target" ) ); // Main loop: keep receiving events while( OPT_TOOL_EVENT evt = Wait() ) { cursorPos = controls->GetCursorPosition(); if( evt->IsCancel() || evt->IsActivate() ) break; else if( evt->IsAction( &PCB_ACTIONS::incWidth ) ) { target->SetWidth( target->GetWidth() + WIDTH_STEP ); view->Update( &preview ); } else if( evt->IsAction( &PCB_ACTIONS::decWidth ) ) { int width = target->GetWidth(); if( width > WIDTH_STEP ) { target->SetWidth( width - WIDTH_STEP ); view->Update( &preview ); } } else if( evt->IsClick( BUT_LEFT ) ) { assert( target->GetSize() > 0 ); assert( target->GetWidth() > 0 ); BOARD_COMMIT commit( m_frame ); commit.Add( target ); commit.Push( _( "Place a layer alignment target" ) ); preview.Remove( target ); // Create next PCB_TARGET target = new PCB_TARGET( *target ); preview.Add( target ); } else if( evt->IsMotion() ) { target->SetPosition( wxPoint( cursorPos.x, cursorPos.y ) ); view->Update( &preview ); } } delete target; controls->SetSnapping( false ); view->Remove( &preview ); m_frame->SetToolID( ID_NO_TOOL_SELECTED, wxCURSOR_DEFAULT, wxEmptyString ); return 0; }
int PCB_EDITOR_CONTROL::PlaceModule( const TOOL_EVENT& aEvent ) { MODULE* module = NULL; KIGFX::VIEW* view = getView(); KIGFX::VIEW_CONTROLS* controls = getViewControls(); BOARD* board = getModel<BOARD>(); // Add a VIEW_GROUP that serves as a preview for the new item KIGFX::VIEW_GROUP preview( view ); view->Add( &preview ); m_toolMgr->RunAction( PCB_ACTIONS::selectionClear, true ); controls->ShowCursor( true ); controls->SetSnapping( true ); Activate(); m_frame->SetToolID( ID_PCB_MODULE_BUTT, wxCURSOR_HAND, _( "Add footprint" ) ); // Main loop: keep receiving events while( OPT_TOOL_EVENT evt = Wait() ) { VECTOR2I cursorPos = controls->GetCursorPosition(); if( evt->IsCancel() || evt->IsActivate() ) { if( module ) { delete module; module = NULL; preview.Clear(); controls->ShowCursor( true ); } else break; if( evt->IsActivate() ) // now finish unconditionally break; } else if( module && evt->Category() == TC_COMMAND ) { if( TOOL_EVT_UTILS::IsRotateToolEvt( *evt ) ) { const auto rotationAngle = TOOL_EVT_UTILS::GetEventRotationAngle( *m_frame, *evt ); module->Rotate( module->GetPosition(), rotationAngle ); view->Update( &preview ); } else if( evt->IsAction( &PCB_ACTIONS::flip ) ) { module->Flip( module->GetPosition() ); view->Update( &preview ); } } else if( evt->IsClick( BUT_LEFT ) ) { if( !module ) { // Pick the module to be placed module = m_frame->LoadModuleFromLibrary( wxEmptyString, m_frame->Prj().PcbFootprintLibs(), true, NULL ); if( module == NULL ) continue; // Module has been added in LoadModuleFromLibrary(), // so we have to remove it before committing the change @todo LEGACY board->Remove( module ); module->SetPosition( wxPoint( cursorPos.x, cursorPos.y ) ); // Add all the drawable parts to preview preview.Add( module ); module->RunOnChildren( std::bind( &KIGFX::VIEW_GROUP::Add, &preview, _1 ) ); } else { BOARD_COMMIT commit( m_frame ); commit.Add( module ); commit.Push( _( "Place a module" ) ); // Remove from preview preview.Remove( module ); module->RunOnChildren( std::bind( &KIGFX::VIEW_GROUP::Remove, &preview, _1 ) ); module = NULL; // to indicate that there is no module that we currently modify } bool placing = ( module != NULL ); controls->SetAutoPan( placing ); controls->CaptureCursor( placing ); controls->ShowCursor( !placing ); } else if( module && evt->IsMotion() ) { module->SetPosition( wxPoint( cursorPos.x, cursorPos.y ) ); view->Update( &preview ); } } view->Remove( &preview ); m_frame->SetToolID( ID_NO_TOOL_SELECTED, wxCURSOR_DEFAULT, wxEmptyString ); return 0; }
bool 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 ); SELECTION_AREA area; view->Add( &area ); while( OPT_TOOL_EVENT evt = Wait() ) { if( evt->IsCancel() ) { cancelled = true; break; } if( evt->IsDrag( BUT_LEFT ) ) { if( !m_additive ) clearSelection(); // Start drawing a selection box area.SetOrigin( evt->DragOrigin() ); area.SetEnd( evt->Position() ); 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; 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; for( it = selectedItems.begin(), it_end = selectedItems.end(); it != it_end; ++it ) { BOARD_ITEM* item = static_cast<BOARD_ITEM*>( it->first ); // Add only those items that are visible and fully within the selection box if( !item->IsSelected() && selectable( item ) && selectionBox.Contains( item->ViewBBox() ) ) { select( item ); } } if( m_selection.Size() == 1 ) m_frame->SetCurItem( m_selection.Front() ); else m_frame->SetCurItem( NULL ); // Inform other potentially interested tools if( !m_selection.Empty() ) m_toolMgr->ProcessEvent( 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; }