Loading pcbnew/tools/common_actions.cpp +20 −1 Original line number Original line Diff line number Diff line Loading @@ -58,8 +58,27 @@ TOOL_ACTION COMMON_ACTIONS::findDummy( "pcbnew.Find.Dummy", // only block the ho TOOL_ACTION COMMON_ACTIONS::findMove( "pcbnew.InteractiveSelection.FindMove", TOOL_ACTION COMMON_ACTIONS::findMove( "pcbnew.InteractiveSelection.FindMove", AS_GLOBAL, 'T'); AS_GLOBAL, 'T'); // Edit tool actions // Edit tool actions TOOL_ACTION COMMON_ACTIONS::editFootprintInFpEditor( "pcbnew.InteractiveEdit.editFootprintInFpEditor", AS_CONTEXT, MD_CTRL + 'E', "Open in Footprint Editor", "Opens the selected footprint in the Footprint Editor" ); TOOL_ACTION COMMON_ACTIONS::copyPadToSettings ( "pcbnew.InteractiveEdit.copyPadToSettings", AS_CONTEXT, 0, "Copy pad settings to Current Settings", "Copies the properties of selected pad to the current template pad settings." ); TOOL_ACTION COMMON_ACTIONS::copySettingsToPads ( "pcbnew.InteractiveEdit.copySettingsToPads", AS_CONTEXT, 0, "Copy Current Settings to pads", "Copies the current template pad settings to the selected pad(s)." ); TOOL_ACTION COMMON_ACTIONS::globalEditPads ( "pcbnew.InteractiveEdit.globalPadEdit", AS_CONTEXT, 0, "Global Pad Edition", "Changes pad properties globally." ); TOOL_ACTION COMMON_ACTIONS::editActivate( "pcbnew.InteractiveEdit", TOOL_ACTION COMMON_ACTIONS::editActivate( "pcbnew.InteractiveEdit", AS_GLOBAL, 'M', AS_GLOBAL, 'M', "Move", "Moves the selected item(s)", AF_ACTIVATE ); "Move", "Moves the selected item(s)", AF_ACTIVATE ); Loading pcbnew/tools/common_actions.h +7 −0 Original line number Original line Diff line number Diff line Loading @@ -236,6 +236,13 @@ public: /// Blocks CTRL+F, it is handled by wxWidgets /// Blocks CTRL+F, it is handled by wxWidgets static TOOL_ACTION findDummy; static TOOL_ACTION findDummy; static TOOL_ACTION editFootprintInFpEditor; static TOOL_ACTION copyPadToSettings; static TOOL_ACTION copySettingsToPads; static TOOL_ACTION globalEditPads; /** /** * Function TranslateLegacyId() * Function TranslateLegacyId() * Translates legacy tool ids to the corresponding TOOL_ACTION name. * Translates legacy tool ids to the corresponding TOOL_ACTION name. Loading pcbnew/tools/edit_tool.cpp +166 −57 Original line number Original line Diff line number Diff line Loading @@ -22,11 +22,15 @@ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA */ */ #include <limits> #include <class_board.h> #include <class_board.h> #include <class_module.h> #include <class_module.h> #include <class_edge_mod.h> #include <class_edge_mod.h> #include <class_zone.h> #include <class_zone.h> #include <wxPcbStruct.h> #include <wxPcbStruct.h> #include <kiway.h> #include <module_editor_frame.h> #include <tool/tool_manager.h> #include <tool/tool_manager.h> #include <view/view_controls.h> #include <view/view_controls.h> Loading @@ -41,6 +45,7 @@ #include "common_actions.h" #include "common_actions.h" #include "selection_tool.h" #include "selection_tool.h" #include "edit_tool.h" #include "edit_tool.h" #include "grid_helper.h" EDIT_TOOL::EDIT_TOOL() : EDIT_TOOL::EDIT_TOOL() : TOOL_INTERACTIVE( "pcbnew.InteractiveEdit" ), m_selectionTool( NULL ), TOOL_INTERACTIVE( "pcbnew.InteractiveEdit" ), m_selectionTool( NULL ), Loading Loading @@ -74,6 +79,11 @@ bool EDIT_TOOL::Init() m_selectionTool->AddMenuItem( COMMON_ACTIONS::remove, SELECTION_CONDITIONS::NotEmpty ); m_selectionTool->AddMenuItem( COMMON_ACTIONS::remove, SELECTION_CONDITIONS::NotEmpty ); m_selectionTool->AddMenuItem( COMMON_ACTIONS::properties, SELECTION_CONDITIONS::NotEmpty ); m_selectionTool->AddMenuItem( COMMON_ACTIONS::properties, SELECTION_CONDITIONS::NotEmpty ); // Footprint actions m_selectionTool->AddMenuItem( COMMON_ACTIONS::editFootprintInFpEditor, SELECTION_CONDITIONS::OnlyType ( PCB_MODULE_T ) && SELECTION_CONDITIONS::Count ( 1 ) ); m_offset.x = 0; m_offset.x = 0; m_offset.y = 0; m_offset.y = 0; Loading @@ -82,6 +92,20 @@ bool EDIT_TOOL::Init() return true; return true; } } bool EDIT_TOOL::invokeInlineRouter() { TRACK *track = uniqueSelected<TRACK> (); VIA *via = uniqueSelected<VIA> (); if( track || via ) { printf("Calling interactive drag\n"); m_toolMgr->RunAction( COMMON_ACTIONS::routerInlineDrag, true ); return true; } return false; } int EDIT_TOOL::Main( const TOOL_EVENT& aEvent ) int EDIT_TOOL::Main( const TOOL_EVENT& aEvent ) { { Loading @@ -90,11 +114,11 @@ int EDIT_TOOL::Main( const TOOL_EVENT& aEvent ) // Shall the selection be cleared at the end? // Shall the selection be cleared at the end? bool unselect = selection.Empty(); bool unselect = selection.Empty(); // Be sure that there is at least one item that we can modify // Be sure that there is at least one item that we can modify. If nothing was selected before, if( !makeSelection( selection ) ) // try looking for the stuff under mouse cursor (i.e. Kicad old-style hover selection) if( !hoverSelection( selection ) ) { { setTransitions(); setTransitions(); return 0; return 0; } } Loading @@ -102,6 +126,8 @@ int EDIT_TOOL::Main( const TOOL_EVENT& aEvent ) m_dragging = false; // Are selected items being dragged? m_dragging = false; // Are selected items being dragged? bool restore = false; // Should items' state be restored when finishing the tool? bool restore = false; // Should items' state be restored when finishing the tool? bool lockOverride = false; bool isDragAndDrop = false; // By default, modified items need to update their geometry // By default, modified items need to update their geometry m_updateFlag = KIGFX::VIEW_ITEM::GEOMETRY; m_updateFlag = KIGFX::VIEW_ITEM::GEOMETRY; Loading @@ -109,9 +135,11 @@ int EDIT_TOOL::Main( const TOOL_EVENT& aEvent ) KIGFX::VIEW_CONTROLS* controls = getViewControls(); KIGFX::VIEW_CONTROLS* controls = getViewControls(); PCB_BASE_EDIT_FRAME* editFrame = getEditFrame<PCB_BASE_EDIT_FRAME>(); PCB_BASE_EDIT_FRAME* editFrame = getEditFrame<PCB_BASE_EDIT_FRAME>(); controls->ShowCursor( true ); controls->ShowCursor( true ); controls->SetSnapping( true ); //controls->SetSnapping( true ); controls->ForceCursorPosition( false ); controls->ForceCursorPosition( false ); GRID_HELPER grid ( editFrame ); // Main loop: keep receiving events // Main loop: keep receiving events while( OPT_TOOL_EVENT evt = Wait() ) while( OPT_TOOL_EVENT evt = Wait() ) { { Loading Loading @@ -151,10 +179,22 @@ int EDIT_TOOL::Main( const TOOL_EVENT& aEvent ) else if( evt->IsMotion() || evt->IsDrag( BUT_LEFT ) ) else if( evt->IsMotion() || evt->IsDrag( BUT_LEFT ) ) { { m_cursor = controls->GetCursorPosition(); //if ( invokeInlineRouter ( ) ) // break; VECTOR2I mousePos = evt->Position(); m_cursor = grid.Align ( evt->Position() ); isDragAndDrop = evt->IsDrag( BUT_LEFT ); if( m_dragging ) if( m_dragging ) { { m_cursor = grid.BestSnapAnchor ( evt->Position(), selection.Item<BOARD_ITEM>( 0 ) ); getViewControls()->ForceCursorPosition ( true, m_cursor ); wxPoint movement = wxPoint( m_cursor.x, m_cursor.y ) - wxPoint movement = wxPoint( m_cursor.x, m_cursor.y ) - selection.Item<BOARD_ITEM>( 0 )->GetPosition(); selection.Item<BOARD_ITEM>( 0 )->GetPosition(); Loading @@ -166,33 +206,52 @@ int EDIT_TOOL::Main( const TOOL_EVENT& aEvent ) } } else // Prepare to start dragging else // Prepare to start dragging { { if( m_selectionTool->CheckLock() || selection.Empty() ) m_selectionTool->SanitizeSelection( ); if ( selection.Empty() ) break; break; // deal with locked items (override lock or abort the operation) SELECTION_LOCK_FLAGS lockFlags = m_selectionTool->CheckLock(); if ( lockFlags == SELECTION_LOCKED ) break; else if ( lockFlags == SELECTION_LOCK_OVERRIDE ) lockOverride = true; // Save items, so changes can be undone // Save items, so changes can be undone editFrame->OnModify(); editFrame->OnModify(); editFrame->SaveCopyInUndoList( selection.items, UR_CHANGED ); editFrame->SaveCopyInUndoList( selection.items, UR_CHANGED ); VECTOR2I origin; if( evt->IsDrag( BUT_LEFT ) ) mousePos = evt->DragOrigin(); // origin = grid.Align ( evt->DragOrigin() ); //else origin = grid.Align ( mousePos ); if( selection.Size() == 1 ) if( selection.Size() == 1 ) { { // Set the current cursor position to the first dragged item origin, so the // Set the current cursor position to the first dragged item origin, so the // movement vector could be computed later // movement vector could be computed later m_cursor = VECTOR2I( selection.Item<BOARD_ITEM>( 0 )->GetPosition() ); m_cursor = grid.BestDragOrigin ( mousePos, selection.Item<BOARD_ITEM>( 0 ) ); m_offset.x = 0; getViewControls()->ForceCursorPosition ( true, m_cursor ); m_offset.y = 0; grid.SetAuxAxes ( true, m_cursor ); VECTOR2I o = VECTOR2I( selection.Item<BOARD_ITEM>( 0 )->GetPosition() ); m_offset.x = o.x - m_cursor.x; m_offset.y = o.y - m_cursor.y; } } else else { { VECTOR2D origin; if( evt->IsDrag( BUT_LEFT ) ) origin = getView()->GetGAL()->GetGridPoint( evt->DragOrigin() ); else origin = getViewControls()->GetCursorPosition(); // Update dragging offset (distance between cursor and the first dragged item) m_offset = static_cast<BOARD_ITEM*>( selection.items.GetPickedItem( 0 ) )->GetPosition() - m_offset = static_cast<BOARD_ITEM*>( selection.items.GetPickedItem( 0 ) )->GetPosition() - wxPoint( origin.x, origin.y ); wxPoint( origin.x, origin.y ); getViewControls()->ForceCursorPosition ( true, origin ); } } controls->SetAutoPan( true ); controls->SetAutoPan( true ); Loading @@ -204,7 +263,12 @@ int EDIT_TOOL::Main( const TOOL_EVENT& aEvent ) } } else if( evt->IsMouseUp( BUT_LEFT ) || evt->IsClick( BUT_LEFT ) ) else if( evt->IsMouseUp( BUT_LEFT ) || evt->IsClick( BUT_LEFT ) ) { if (!isDragAndDrop || !lockOverride ) break; // Finish break; // Finish lockOverride = false; } } } m_dragging = false; m_dragging = false; Loading @@ -231,7 +295,7 @@ int EDIT_TOOL::Main( const TOOL_EVENT& aEvent ) ratsnest->Recalculate(); ratsnest->Recalculate(); controls->ShowCursor( false ); controls->ShowCursor( false ); controls->SetSnapping( false ); //controls->SetSnapping( false ); controls->SetAutoPan( false ); controls->SetAutoPan( false ); setTransitions(); setTransitions(); Loading @@ -245,7 +309,7 @@ int EDIT_TOOL::Properties( const TOOL_EVENT& aEvent ) const SELECTION& selection = m_selectionTool->GetSelection(); const SELECTION& selection = m_selectionTool->GetSelection(); PCB_BASE_EDIT_FRAME* editFrame = getEditFrame<PCB_BASE_EDIT_FRAME>(); PCB_BASE_EDIT_FRAME* editFrame = getEditFrame<PCB_BASE_EDIT_FRAME>(); if( !makeSelection( selection ) ) if( !hoverSelection( selection, false ) ) { { setTransitions(); setTransitions(); Loading @@ -258,22 +322,6 @@ int EDIT_TOOL::Properties( const TOOL_EVENT& aEvent ) // Display properties dialog // Display properties dialog BOARD_ITEM* item = selection.Item<BOARD_ITEM>( 0 ); BOARD_ITEM* item = selection.Item<BOARD_ITEM>( 0 ); // Check if user wants to edit pad or module properties if( item->Type() == PCB_MODULE_T ) { VECTOR2D cursor = getViewControls()->GetCursorPosition(); for( D_PAD* pad = static_cast<MODULE*>( item )->Pads(); pad; pad = pad->Next() ) { if( pad->ViewBBox().Contains( cursor ) ) { // Turns out that user wants to edit a pad properties item = pad; break; } } } std::vector<PICKED_ITEMS_LIST*>& undoList = editFrame->GetScreen()->m_UndoList.m_CommandsList; std::vector<PICKED_ITEMS_LIST*>& undoList = editFrame->GetScreen()->m_UndoList.m_CommandsList; // Some of properties dialogs alter pointers, so we should deselect them // Some of properties dialogs alter pointers, so we should deselect them Loading Loading @@ -317,7 +365,7 @@ int EDIT_TOOL::Rotate( const TOOL_EVENT& aEvent ) // Shall the selection be cleared at the end? // Shall the selection be cleared at the end? bool unselect = selection.Empty(); bool unselect = selection.Empty(); if( !makeSelection( selection ) || m_selectionTool->CheckLock() ) if( !hoverSelection( selection ) ) { { setTransitions(); setTransitions(); Loading Loading @@ -371,7 +419,7 @@ int EDIT_TOOL::Flip( const TOOL_EVENT& aEvent ) // Shall the selection be cleared at the end? // Shall the selection be cleared at the end? bool unselect = selection.Empty(); bool unselect = selection.Empty(); if( !makeSelection( selection ) || m_selectionTool->CheckLock() ) if( !hoverSelection( selection ) ) { { setTransitions(); setTransitions(); Loading Loading @@ -421,7 +469,7 @@ int EDIT_TOOL::Remove( const TOOL_EVENT& aEvent ) { { const SELECTION& selection = m_selectionTool->GetSelection(); const SELECTION& selection = m_selectionTool->GetSelection(); if( !makeSelection( selection ) || m_selectionTool->CheckLock() ) if( !hoverSelection( selection ) ) { { setTransitions(); setTransitions(); Loading Loading @@ -476,41 +524,59 @@ void EDIT_TOOL::remove( BOARD_ITEM* aItem ) // Default removal procedure // Default removal procedure case PCB_MODULE_TEXT_T: case PCB_MODULE_TEXT_T: { if( m_editModules ) { { TEXTE_MODULE* text = static_cast<TEXTE_MODULE*>( aItem ); TEXTE_MODULE* text = static_cast<TEXTE_MODULE*>( aItem ); switch( text->GetType() ) switch( text->GetType() ) { { case TEXTE_MODULE::TEXT_is_REFERENCE: case TEXTE_MODULE::TEXT_is_REFERENCE: DisplayError( getEditFrame<PCB_BASE_FRAME>(), _( "Cannot delete REFERENCE!" ) ); DisplayError( getEditFrame<PCB_BASE_FRAME>(), _( "Cannot delete component reference." ) ); return; return; case TEXTE_MODULE::TEXT_is_VALUE: case TEXTE_MODULE::TEXT_is_VALUE: DisplayError( getEditFrame<PCB_BASE_FRAME>(), _( "Cannot delete VALUE!" ) ); DisplayError( getEditFrame<PCB_BASE_FRAME>(), _( "Cannot delete component value." ) ); return; return; case TEXTE_MODULE::TEXT_is_DIVERS: // suppress warnings case TEXTE_MODULE::TEXT_is_DIVERS: // suppress warnings break; break; } } if( m_editModules ) { MODULE* module = static_cast<MODULE*>( aItem->GetParent() ); module->SetLastEditTime(); board->m_Status_Pcb = 0; // it is done in the legacy view aItem->DeleteStructure(); } } return; } } /* no break */ case PCB_PAD_T: case PCB_PAD_T: case PCB_MODULE_EDGE_T: case PCB_MODULE_EDGE_T: if( m_editModules ) { { MODULE* module = static_cast<MODULE*>( aItem->GetParent() ); MODULE* module = static_cast<MODULE*>( aItem->GetParent() ); module->SetLastEditTime(); module->SetLastEditTime(); board->m_Status_Pcb = 0; // it is done in the legacy view board->m_Status_Pcb = 0; // it is done in the legacy view aItem->DeleteStructure(); if(!m_editModules) { if(aItem->Type() == PCB_PAD_T && module->GetPadCount() == 1) { DisplayError( getEditFrame<PCB_BASE_FRAME>(), _( "Cannot delete the only remaining pad of the module (modules on PCB must have at least one pad)." ) ); return; } getView()->Remove( aItem ); board->Remove( aItem ); } } aItem->DeleteStructure(); return; return; break; } case PCB_LINE_T: // a segment not on copper layers case PCB_LINE_T: // a segment not on copper layers case PCB_TEXT_T: // a text on a layer case PCB_TEXT_T: // a text on a layer Loading @@ -526,7 +592,6 @@ void EDIT_TOOL::remove( BOARD_ITEM* aItem ) default: // other types do not need to (or should not) be handled default: // other types do not need to (or should not) be handled assert( false ); assert( false ); return; return; break; } } getView()->Remove( aItem ); getView()->Remove( aItem ); Loading @@ -541,6 +606,8 @@ void EDIT_TOOL::setTransitions() Go( &EDIT_TOOL::Flip, COMMON_ACTIONS::flip.MakeEvent() ); Go( &EDIT_TOOL::Flip, COMMON_ACTIONS::flip.MakeEvent() ); Go( &EDIT_TOOL::Remove, COMMON_ACTIONS::remove.MakeEvent() ); Go( &EDIT_TOOL::Remove, COMMON_ACTIONS::remove.MakeEvent() ); Go( &EDIT_TOOL::Properties, COMMON_ACTIONS::properties.MakeEvent() ); Go( &EDIT_TOOL::Properties, COMMON_ACTIONS::properties.MakeEvent() ); Go( &EDIT_TOOL::editFootprintInFpEditor, COMMON_ACTIONS::editFootprintInFpEditor.MakeEvent() ); } } Loading @@ -550,6 +617,7 @@ void EDIT_TOOL::updateRatsnest( bool aRedraw ) RN_DATA* ratsnest = getModel<BOARD>()->GetRatsnest(); RN_DATA* ratsnest = getModel<BOARD>()->GetRatsnest(); ratsnest->ClearSimple(); ratsnest->ClearSimple(); for( unsigned int i = 0; i < selection.items.GetCount(); ++i ) for( unsigned int i = 0; i < selection.items.GetCount(); ++i ) { { BOARD_ITEM* item = selection.Item<BOARD_ITEM>( i ); BOARD_ITEM* item = selection.Item<BOARD_ITEM>( i ); Loading Loading @@ -579,15 +647,27 @@ wxPoint EDIT_TOOL::getModificationPoint( const SELECTION& aSelection ) } } } } bool EDIT_TOOL::hoverSelection( const SELECTION& aSelection, bool aSanitize ) bool EDIT_TOOL::makeSelection( const SELECTION& aSelection ) { { if( aSelection.Empty() ) // Try to find an item that could be modified if( aSelection.Empty() ) // Try to find an item that could be modified { m_toolMgr->RunAction( COMMON_ACTIONS::selectionCursor, true ); m_toolMgr->RunAction( COMMON_ACTIONS::selectionCursor, true ); return !aSelection.Empty(); if ( m_selectionTool->CheckLock() == SELECTION_LOCKED ) { m_toolMgr->RunAction( COMMON_ACTIONS::selectionClear, true ); return false; } } } if ( aSanitize ) m_selectionTool->SanitizeSelection(); if ( aSelection.Empty() ) m_toolMgr->RunAction( COMMON_ACTIONS::selectionClear, true ); return !aSelection.Empty(); } void EDIT_TOOL::processChanges( const PICKED_ITEMS_LIST* aList ) void EDIT_TOOL::processChanges( const PICKED_ITEMS_LIST* aList ) { { Loading Loading @@ -626,3 +706,32 @@ void EDIT_TOOL::processChanges( const PICKED_ITEMS_LIST* aList ) } } } } } } int EDIT_TOOL::editFootprintInFpEditor( const TOOL_EVENT& aEvent ) { MODULE *mod = uniqueSelected <MODULE> (); if( !mod ) return 0; PCB_BASE_EDIT_FRAME* editFrame = getEditFrame<PCB_BASE_EDIT_FRAME>(); editFrame-> SetCurItem( mod ); if( editFrame->GetCurItem()->GetTimeStamp() == 0 ) // Module Editor needs a non null timestamp { editFrame->GetCurItem()->SetTimeStamp( GetNewTimeStamp() ); editFrame->OnModify(); } FOOTPRINT_EDIT_FRAME* editor = (FOOTPRINT_EDIT_FRAME*) editFrame->Kiway().Player( FRAME_PCB_MODULE_EDITOR, true ); editor->Load_Module_From_BOARD( (MODULE*)editFrame->GetCurItem() ); editFrame->SetCurItem( NULL ); // the current module could be deleted by editor->Show( true ); editor->Raise(); // Iconize( false ); setTransitions(); return 0; } pcbnew/tools/edit_tool.h +16 −1 Original line number Original line Diff line number Diff line Loading @@ -147,10 +147,25 @@ private: ///> If there are no items currently selected, it tries to choose the item that is under ///> If there are no items currently selected, it tries to choose the item that is under ///> the cursor or displays a disambiguation menu if there are multpile items. ///> the cursor or displays a disambiguation menu if there are multpile items. bool makeSelection( const SELECTION& aSelection ); bool hoverSelection( const SELECTION& aSelection, bool aSanitize = true ); ///> Updates view with the changes in the list. ///> Updates view with the changes in the list. void processChanges( const PICKED_ITEMS_LIST* aList ); void processChanges( const PICKED_ITEMS_LIST* aList ); int editFootprintInFpEditor( const TOOL_EVENT& aEvent ); bool invokeInlineRouter(); template <class T> T* uniqueSelected() { const SELECTION& selection = m_selectionTool->GetSelection(); if(selection.items.GetCount() > 1) return NULL; BOARD_ITEM *item = selection.Item<BOARD_ITEM>( 0 ); return dyn_cast<T*> (item); } }; }; #endif #endif pcbnew/tools/grid_helper.cpp 0 → 100644 +334 −0 Original line number Original line Diff line number Diff line /* * This program source code file is part of KiCad, a free EDA CAD application. * * Copyright (C) 2014 CERN * @author Tomasz Wlostowski <tomasz.wlostowski@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 */ #include <boost/foreach.hpp> #include <boost/bind.hpp> #include <wxPcbStruct.h> #include <class_board.h> #include <class_module.h> #include <class_edge_mod.h> #include <class_zone.h> #include <class_draw_panel_gal.h> #include <view/view_controls.h> #include <gal/graphics_abstraction_layer.h> #include <geometry/shape_line_chain.h> #include "grid_helper.h" GRID_HELPER::GRID_HELPER ( PCB_BASE_FRAME *aFrame ) : m_frame ( aFrame ) { } GRID_HELPER::~GRID_HELPER () { } void GRID_HELPER::SetGrid ( int aSize ) { assert ( false ); } void GRID_HELPER::SetOrigin ( const VECTOR2I& aOrigin ) { } VECTOR2I GRID_HELPER::GetGrid () { PCB_SCREEN *screen = m_frame->GetScreen(); const wxRealPoint& size = screen->GetGridSize(); return VECTOR2I ( KiROUND ( size.x ), KiROUND ( size.y ) ); } VECTOR2I GRID_HELPER::GetOrigin () { return VECTOR2I ( 0, 0 ); } void GRID_HELPER::SetAuxAxes ( bool aEnable, const VECTOR2I aOrigin, bool aEnableDiagonal) { if( aEnable ) m_auxAxis = aOrigin; else m_auxAxis = boost::optional <VECTOR2I> (); m_diagonalAuxAxesEnable = aEnable; } VECTOR2I GRID_HELPER::Align ( const VECTOR2I& aPoint ) { const VECTOR2D gridOffset ( GetOrigin () ); const VECTOR2D gridSize ( GetGrid() ); VECTOR2I nearest ( round( ( aPoint.x - gridOffset.x ) / gridSize.x ) * gridSize.x + gridOffset.x, round( ( aPoint.y - gridOffset.y ) / gridSize.y ) * gridSize.y + gridOffset.y ); if ( !m_auxAxis ) return nearest; if ( std::abs ( m_auxAxis->x - aPoint.x) < std::abs ( nearest.x - aPoint.x ) ) nearest.x = m_auxAxis->x; if ( std::abs ( m_auxAxis->y - aPoint.y) < std::abs ( nearest.y - aPoint.y ) ) nearest.y = m_auxAxis->y; return nearest; } VECTOR2I GRID_HELPER::BestDragOrigin ( const VECTOR2I &aMousePos, BOARD_ITEM *aItem ) { clearAnchors(); computeAnchors( aItem, aMousePos ); double worldScale = m_frame->GetGalCanvas()->GetGAL()->GetWorldScale(); double lineSnapMinCornerDistance = 50.0 / worldScale; ANCHOR* nearestOutline = nearestAnchor ( aMousePos, OUTLINE, LSET::AllLayersMask() ); ANCHOR* nearestCorner = nearestAnchor ( aMousePos, CORNER, LSET::AllLayersMask() ); ANCHOR* nearestOrigin = nearestAnchor ( aMousePos, ORIGIN, LSET::AllLayersMask() ); ANCHOR* best = NULL; double minDist = std::numeric_limits<double>::max(); if (nearestOrigin) { minDist = nearestOrigin->Distance(aMousePos); best = nearestOrigin; } if (nearestCorner) { double dist = nearestCorner->Distance(aMousePos); if (dist < minDist) { minDist = dist; best = nearestCorner; } } if (nearestOutline) { double dist = nearestOutline->Distance(aMousePos); if (minDist > lineSnapMinCornerDistance && dist < minDist) best = nearestOutline; } return best ? best->pos : aMousePos; } std::set<BOARD_ITEM *> GRID_HELPER::queryVisible ( const BOX2I& aArea ) { std::set <BOARD_ITEM *> items; std::vector<KIGFX::VIEW::LAYER_ITEM_PAIR> selectedItems; std::vector<KIGFX::VIEW::LAYER_ITEM_PAIR>::iterator it, it_end; m_frame->GetGalCanvas()->GetView()->Query( aArea, selectedItems ); // Get the list of selected items for( it = selectedItems.begin(), it_end = selectedItems.end(); it != it_end; ++it ) { BOARD_ITEM* item = static_cast<BOARD_ITEM*>( it->first ); if( item->ViewIsVisible() ) items.insert ( item ); } return items; } VECTOR2I GRID_HELPER::BestSnapAnchor ( const VECTOR2I &aOrigin, BOARD_ITEM *aDraggedItem ) { double worldScale = m_frame->GetGalCanvas()->GetGAL()->GetWorldScale(); int snapRange = (int) (100.0 / worldScale); BOX2I bb ( VECTOR2I ( aOrigin.x - snapRange / 2, aOrigin.y - snapRange/2) , VECTOR2I (snapRange, snapRange) ); clearAnchors(); BOOST_FOREACH ( BOARD_ITEM *item, queryVisible ( bb ) ) { computeAnchors(item, aOrigin); } LSET layers ( aDraggedItem->GetLayer() ); ANCHOR *nearest = nearestAnchor ( aOrigin, CORNER | SNAPPABLE, layers ); VECTOR2I nearestGrid = Align ( aOrigin ); double gridDist = (nearestGrid - aOrigin).EuclideanNorm(); if (nearest) { double snapDist = nearest->Distance ( aOrigin ); if(nearest && snapDist < gridDist) return nearest->pos; } return nearestGrid; } void GRID_HELPER::computeAnchors ( BOARD_ITEM *aItem, const VECTOR2I& aRefPos ) { VECTOR2I origin; switch ( aItem->Type() ) { case PCB_MODULE_T: { MODULE *mod = static_cast <MODULE *> (aItem); addAnchor ( mod->GetPosition(), ORIGIN | SNAPPABLE, mod ); for (D_PAD *pad = mod->Pads(); pad; pad = pad->Next() ) addAnchor ( pad->GetPosition(), CORNER | SNAPPABLE, pad ); break; } case PCB_MODULE_EDGE_T: case PCB_LINE_T: { DRAWSEGMENT *dseg = static_cast <DRAWSEGMENT*> (aItem); VECTOR2I start = dseg->GetStart(); VECTOR2I end = dseg->GetEnd(); //LAYER_ID layer = dseg->GetLayer(); switch( dseg->GetShape() ) { case S_CIRCLE: { int r = (start - end).EuclideanNorm(); addAnchor ( start, ORIGIN | SNAPPABLE, dseg ); addAnchor ( start + VECTOR2I ( -r, 0 ) , OUTLINE | SNAPPABLE, dseg ); addAnchor ( start + VECTOR2I ( r, 0 ) , OUTLINE | SNAPPABLE, dseg ); addAnchor ( start + VECTOR2I ( 0, -r ) , OUTLINE | SNAPPABLE, dseg); addAnchor ( start + VECTOR2I ( 0, r ) , OUTLINE | SNAPPABLE, dseg ); break; } case S_ARC: { origin = dseg->GetCenter(); addAnchor ( dseg->GetArcStart(), CORNER | SNAPPABLE, dseg ); addAnchor ( dseg->GetArcEnd(), CORNER | SNAPPABLE, dseg ); addAnchor ( origin, ORIGIN | SNAPPABLE, dseg ); break; } case S_SEGMENT: { origin.x = start.x + ( start.x - end.x ) / 2; origin.y = start.y + ( start.y - end.y ) / 2; addAnchor ( start, CORNER | SNAPPABLE, dseg ); addAnchor ( end, CORNER | SNAPPABLE, dseg ); addAnchor ( origin, ORIGIN, dseg ); break; } default: { origin = dseg->GetStart(); addAnchor ( origin, ORIGIN | SNAPPABLE, dseg ); break; } } break; } case PCB_TRACE_T: { TRACK *track = static_cast <TRACK*> (aItem); VECTOR2I start = track->GetStart(); VECTOR2I end = track->GetEnd(); origin.x = start.x + ( start.x - end.x ) / 2; origin.y = start.y + ( start.y - end.y ) / 2; addAnchor ( start, CORNER | SNAPPABLE, track ); addAnchor ( end, CORNER | SNAPPABLE, track ); addAnchor ( origin, ORIGIN, track); break; } case PCB_ZONE_AREA_T: { const CPolyLine* outline = static_cast<const ZONE_CONTAINER*>( aItem )->Outline(); int cornersCount = outline->GetCornersCount(); SHAPE_LINE_CHAIN lc; lc.SetClosed ( true ); for( int i = 0; i < cornersCount; ++i ) { const VECTOR2I p ( outline->GetPos( i ) ); addAnchor ( p, CORNER, aItem ); lc.Append ( p ); } addAnchor( lc.NearestPoint ( aRefPos ), OUTLINE, aItem ); break; } case PCB_MODULE_TEXT_T: case PCB_TEXT_T: addAnchor ( aItem->GetPosition(), ORIGIN, aItem ); default: break; } } GRID_HELPER::ANCHOR* GRID_HELPER::nearestAnchor ( VECTOR2I aPos, int aFlags, LSET aMatchLayers ) { double minDist = std::numeric_limits<double>::max(); ANCHOR *best = NULL; BOOST_FOREACH( ANCHOR& a, m_anchors ) { if ( !aMatchLayers [ a.item->GetLayer() ] ) continue; if ( ( aFlags & a.flags ) != aFlags ) continue; double dist = a.Distance(aPos); if(dist < minDist) { minDist = dist; best = &a; } } return best; } No newline at end of file Loading
pcbnew/tools/common_actions.cpp +20 −1 Original line number Original line Diff line number Diff line Loading @@ -58,8 +58,27 @@ TOOL_ACTION COMMON_ACTIONS::findDummy( "pcbnew.Find.Dummy", // only block the ho TOOL_ACTION COMMON_ACTIONS::findMove( "pcbnew.InteractiveSelection.FindMove", TOOL_ACTION COMMON_ACTIONS::findMove( "pcbnew.InteractiveSelection.FindMove", AS_GLOBAL, 'T'); AS_GLOBAL, 'T'); // Edit tool actions // Edit tool actions TOOL_ACTION COMMON_ACTIONS::editFootprintInFpEditor( "pcbnew.InteractiveEdit.editFootprintInFpEditor", AS_CONTEXT, MD_CTRL + 'E', "Open in Footprint Editor", "Opens the selected footprint in the Footprint Editor" ); TOOL_ACTION COMMON_ACTIONS::copyPadToSettings ( "pcbnew.InteractiveEdit.copyPadToSettings", AS_CONTEXT, 0, "Copy pad settings to Current Settings", "Copies the properties of selected pad to the current template pad settings." ); TOOL_ACTION COMMON_ACTIONS::copySettingsToPads ( "pcbnew.InteractiveEdit.copySettingsToPads", AS_CONTEXT, 0, "Copy Current Settings to pads", "Copies the current template pad settings to the selected pad(s)." ); TOOL_ACTION COMMON_ACTIONS::globalEditPads ( "pcbnew.InteractiveEdit.globalPadEdit", AS_CONTEXT, 0, "Global Pad Edition", "Changes pad properties globally." ); TOOL_ACTION COMMON_ACTIONS::editActivate( "pcbnew.InteractiveEdit", TOOL_ACTION COMMON_ACTIONS::editActivate( "pcbnew.InteractiveEdit", AS_GLOBAL, 'M', AS_GLOBAL, 'M', "Move", "Moves the selected item(s)", AF_ACTIVATE ); "Move", "Moves the selected item(s)", AF_ACTIVATE ); Loading
pcbnew/tools/common_actions.h +7 −0 Original line number Original line Diff line number Diff line Loading @@ -236,6 +236,13 @@ public: /// Blocks CTRL+F, it is handled by wxWidgets /// Blocks CTRL+F, it is handled by wxWidgets static TOOL_ACTION findDummy; static TOOL_ACTION findDummy; static TOOL_ACTION editFootprintInFpEditor; static TOOL_ACTION copyPadToSettings; static TOOL_ACTION copySettingsToPads; static TOOL_ACTION globalEditPads; /** /** * Function TranslateLegacyId() * Function TranslateLegacyId() * Translates legacy tool ids to the corresponding TOOL_ACTION name. * Translates legacy tool ids to the corresponding TOOL_ACTION name. Loading
pcbnew/tools/edit_tool.cpp +166 −57 Original line number Original line Diff line number Diff line Loading @@ -22,11 +22,15 @@ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA */ */ #include <limits> #include <class_board.h> #include <class_board.h> #include <class_module.h> #include <class_module.h> #include <class_edge_mod.h> #include <class_edge_mod.h> #include <class_zone.h> #include <class_zone.h> #include <wxPcbStruct.h> #include <wxPcbStruct.h> #include <kiway.h> #include <module_editor_frame.h> #include <tool/tool_manager.h> #include <tool/tool_manager.h> #include <view/view_controls.h> #include <view/view_controls.h> Loading @@ -41,6 +45,7 @@ #include "common_actions.h" #include "common_actions.h" #include "selection_tool.h" #include "selection_tool.h" #include "edit_tool.h" #include "edit_tool.h" #include "grid_helper.h" EDIT_TOOL::EDIT_TOOL() : EDIT_TOOL::EDIT_TOOL() : TOOL_INTERACTIVE( "pcbnew.InteractiveEdit" ), m_selectionTool( NULL ), TOOL_INTERACTIVE( "pcbnew.InteractiveEdit" ), m_selectionTool( NULL ), Loading Loading @@ -74,6 +79,11 @@ bool EDIT_TOOL::Init() m_selectionTool->AddMenuItem( COMMON_ACTIONS::remove, SELECTION_CONDITIONS::NotEmpty ); m_selectionTool->AddMenuItem( COMMON_ACTIONS::remove, SELECTION_CONDITIONS::NotEmpty ); m_selectionTool->AddMenuItem( COMMON_ACTIONS::properties, SELECTION_CONDITIONS::NotEmpty ); m_selectionTool->AddMenuItem( COMMON_ACTIONS::properties, SELECTION_CONDITIONS::NotEmpty ); // Footprint actions m_selectionTool->AddMenuItem( COMMON_ACTIONS::editFootprintInFpEditor, SELECTION_CONDITIONS::OnlyType ( PCB_MODULE_T ) && SELECTION_CONDITIONS::Count ( 1 ) ); m_offset.x = 0; m_offset.x = 0; m_offset.y = 0; m_offset.y = 0; Loading @@ -82,6 +92,20 @@ bool EDIT_TOOL::Init() return true; return true; } } bool EDIT_TOOL::invokeInlineRouter() { TRACK *track = uniqueSelected<TRACK> (); VIA *via = uniqueSelected<VIA> (); if( track || via ) { printf("Calling interactive drag\n"); m_toolMgr->RunAction( COMMON_ACTIONS::routerInlineDrag, true ); return true; } return false; } int EDIT_TOOL::Main( const TOOL_EVENT& aEvent ) int EDIT_TOOL::Main( const TOOL_EVENT& aEvent ) { { Loading @@ -90,11 +114,11 @@ int EDIT_TOOL::Main( const TOOL_EVENT& aEvent ) // Shall the selection be cleared at the end? // Shall the selection be cleared at the end? bool unselect = selection.Empty(); bool unselect = selection.Empty(); // Be sure that there is at least one item that we can modify // Be sure that there is at least one item that we can modify. If nothing was selected before, if( !makeSelection( selection ) ) // try looking for the stuff under mouse cursor (i.e. Kicad old-style hover selection) if( !hoverSelection( selection ) ) { { setTransitions(); setTransitions(); return 0; return 0; } } Loading @@ -102,6 +126,8 @@ int EDIT_TOOL::Main( const TOOL_EVENT& aEvent ) m_dragging = false; // Are selected items being dragged? m_dragging = false; // Are selected items being dragged? bool restore = false; // Should items' state be restored when finishing the tool? bool restore = false; // Should items' state be restored when finishing the tool? bool lockOverride = false; bool isDragAndDrop = false; // By default, modified items need to update their geometry // By default, modified items need to update their geometry m_updateFlag = KIGFX::VIEW_ITEM::GEOMETRY; m_updateFlag = KIGFX::VIEW_ITEM::GEOMETRY; Loading @@ -109,9 +135,11 @@ int EDIT_TOOL::Main( const TOOL_EVENT& aEvent ) KIGFX::VIEW_CONTROLS* controls = getViewControls(); KIGFX::VIEW_CONTROLS* controls = getViewControls(); PCB_BASE_EDIT_FRAME* editFrame = getEditFrame<PCB_BASE_EDIT_FRAME>(); PCB_BASE_EDIT_FRAME* editFrame = getEditFrame<PCB_BASE_EDIT_FRAME>(); controls->ShowCursor( true ); controls->ShowCursor( true ); controls->SetSnapping( true ); //controls->SetSnapping( true ); controls->ForceCursorPosition( false ); controls->ForceCursorPosition( false ); GRID_HELPER grid ( editFrame ); // Main loop: keep receiving events // Main loop: keep receiving events while( OPT_TOOL_EVENT evt = Wait() ) while( OPT_TOOL_EVENT evt = Wait() ) { { Loading Loading @@ -151,10 +179,22 @@ int EDIT_TOOL::Main( const TOOL_EVENT& aEvent ) else if( evt->IsMotion() || evt->IsDrag( BUT_LEFT ) ) else if( evt->IsMotion() || evt->IsDrag( BUT_LEFT ) ) { { m_cursor = controls->GetCursorPosition(); //if ( invokeInlineRouter ( ) ) // break; VECTOR2I mousePos = evt->Position(); m_cursor = grid.Align ( evt->Position() ); isDragAndDrop = evt->IsDrag( BUT_LEFT ); if( m_dragging ) if( m_dragging ) { { m_cursor = grid.BestSnapAnchor ( evt->Position(), selection.Item<BOARD_ITEM>( 0 ) ); getViewControls()->ForceCursorPosition ( true, m_cursor ); wxPoint movement = wxPoint( m_cursor.x, m_cursor.y ) - wxPoint movement = wxPoint( m_cursor.x, m_cursor.y ) - selection.Item<BOARD_ITEM>( 0 )->GetPosition(); selection.Item<BOARD_ITEM>( 0 )->GetPosition(); Loading @@ -166,33 +206,52 @@ int EDIT_TOOL::Main( const TOOL_EVENT& aEvent ) } } else // Prepare to start dragging else // Prepare to start dragging { { if( m_selectionTool->CheckLock() || selection.Empty() ) m_selectionTool->SanitizeSelection( ); if ( selection.Empty() ) break; break; // deal with locked items (override lock or abort the operation) SELECTION_LOCK_FLAGS lockFlags = m_selectionTool->CheckLock(); if ( lockFlags == SELECTION_LOCKED ) break; else if ( lockFlags == SELECTION_LOCK_OVERRIDE ) lockOverride = true; // Save items, so changes can be undone // Save items, so changes can be undone editFrame->OnModify(); editFrame->OnModify(); editFrame->SaveCopyInUndoList( selection.items, UR_CHANGED ); editFrame->SaveCopyInUndoList( selection.items, UR_CHANGED ); VECTOR2I origin; if( evt->IsDrag( BUT_LEFT ) ) mousePos = evt->DragOrigin(); // origin = grid.Align ( evt->DragOrigin() ); //else origin = grid.Align ( mousePos ); if( selection.Size() == 1 ) if( selection.Size() == 1 ) { { // Set the current cursor position to the first dragged item origin, so the // Set the current cursor position to the first dragged item origin, so the // movement vector could be computed later // movement vector could be computed later m_cursor = VECTOR2I( selection.Item<BOARD_ITEM>( 0 )->GetPosition() ); m_cursor = grid.BestDragOrigin ( mousePos, selection.Item<BOARD_ITEM>( 0 ) ); m_offset.x = 0; getViewControls()->ForceCursorPosition ( true, m_cursor ); m_offset.y = 0; grid.SetAuxAxes ( true, m_cursor ); VECTOR2I o = VECTOR2I( selection.Item<BOARD_ITEM>( 0 )->GetPosition() ); m_offset.x = o.x - m_cursor.x; m_offset.y = o.y - m_cursor.y; } } else else { { VECTOR2D origin; if( evt->IsDrag( BUT_LEFT ) ) origin = getView()->GetGAL()->GetGridPoint( evt->DragOrigin() ); else origin = getViewControls()->GetCursorPosition(); // Update dragging offset (distance between cursor and the first dragged item) m_offset = static_cast<BOARD_ITEM*>( selection.items.GetPickedItem( 0 ) )->GetPosition() - m_offset = static_cast<BOARD_ITEM*>( selection.items.GetPickedItem( 0 ) )->GetPosition() - wxPoint( origin.x, origin.y ); wxPoint( origin.x, origin.y ); getViewControls()->ForceCursorPosition ( true, origin ); } } controls->SetAutoPan( true ); controls->SetAutoPan( true ); Loading @@ -204,7 +263,12 @@ int EDIT_TOOL::Main( const TOOL_EVENT& aEvent ) } } else if( evt->IsMouseUp( BUT_LEFT ) || evt->IsClick( BUT_LEFT ) ) else if( evt->IsMouseUp( BUT_LEFT ) || evt->IsClick( BUT_LEFT ) ) { if (!isDragAndDrop || !lockOverride ) break; // Finish break; // Finish lockOverride = false; } } } m_dragging = false; m_dragging = false; Loading @@ -231,7 +295,7 @@ int EDIT_TOOL::Main( const TOOL_EVENT& aEvent ) ratsnest->Recalculate(); ratsnest->Recalculate(); controls->ShowCursor( false ); controls->ShowCursor( false ); controls->SetSnapping( false ); //controls->SetSnapping( false ); controls->SetAutoPan( false ); controls->SetAutoPan( false ); setTransitions(); setTransitions(); Loading @@ -245,7 +309,7 @@ int EDIT_TOOL::Properties( const TOOL_EVENT& aEvent ) const SELECTION& selection = m_selectionTool->GetSelection(); const SELECTION& selection = m_selectionTool->GetSelection(); PCB_BASE_EDIT_FRAME* editFrame = getEditFrame<PCB_BASE_EDIT_FRAME>(); PCB_BASE_EDIT_FRAME* editFrame = getEditFrame<PCB_BASE_EDIT_FRAME>(); if( !makeSelection( selection ) ) if( !hoverSelection( selection, false ) ) { { setTransitions(); setTransitions(); Loading @@ -258,22 +322,6 @@ int EDIT_TOOL::Properties( const TOOL_EVENT& aEvent ) // Display properties dialog // Display properties dialog BOARD_ITEM* item = selection.Item<BOARD_ITEM>( 0 ); BOARD_ITEM* item = selection.Item<BOARD_ITEM>( 0 ); // Check if user wants to edit pad or module properties if( item->Type() == PCB_MODULE_T ) { VECTOR2D cursor = getViewControls()->GetCursorPosition(); for( D_PAD* pad = static_cast<MODULE*>( item )->Pads(); pad; pad = pad->Next() ) { if( pad->ViewBBox().Contains( cursor ) ) { // Turns out that user wants to edit a pad properties item = pad; break; } } } std::vector<PICKED_ITEMS_LIST*>& undoList = editFrame->GetScreen()->m_UndoList.m_CommandsList; std::vector<PICKED_ITEMS_LIST*>& undoList = editFrame->GetScreen()->m_UndoList.m_CommandsList; // Some of properties dialogs alter pointers, so we should deselect them // Some of properties dialogs alter pointers, so we should deselect them Loading Loading @@ -317,7 +365,7 @@ int EDIT_TOOL::Rotate( const TOOL_EVENT& aEvent ) // Shall the selection be cleared at the end? // Shall the selection be cleared at the end? bool unselect = selection.Empty(); bool unselect = selection.Empty(); if( !makeSelection( selection ) || m_selectionTool->CheckLock() ) if( !hoverSelection( selection ) ) { { setTransitions(); setTransitions(); Loading Loading @@ -371,7 +419,7 @@ int EDIT_TOOL::Flip( const TOOL_EVENT& aEvent ) // Shall the selection be cleared at the end? // Shall the selection be cleared at the end? bool unselect = selection.Empty(); bool unselect = selection.Empty(); if( !makeSelection( selection ) || m_selectionTool->CheckLock() ) if( !hoverSelection( selection ) ) { { setTransitions(); setTransitions(); Loading Loading @@ -421,7 +469,7 @@ int EDIT_TOOL::Remove( const TOOL_EVENT& aEvent ) { { const SELECTION& selection = m_selectionTool->GetSelection(); const SELECTION& selection = m_selectionTool->GetSelection(); if( !makeSelection( selection ) || m_selectionTool->CheckLock() ) if( !hoverSelection( selection ) ) { { setTransitions(); setTransitions(); Loading Loading @@ -476,41 +524,59 @@ void EDIT_TOOL::remove( BOARD_ITEM* aItem ) // Default removal procedure // Default removal procedure case PCB_MODULE_TEXT_T: case PCB_MODULE_TEXT_T: { if( m_editModules ) { { TEXTE_MODULE* text = static_cast<TEXTE_MODULE*>( aItem ); TEXTE_MODULE* text = static_cast<TEXTE_MODULE*>( aItem ); switch( text->GetType() ) switch( text->GetType() ) { { case TEXTE_MODULE::TEXT_is_REFERENCE: case TEXTE_MODULE::TEXT_is_REFERENCE: DisplayError( getEditFrame<PCB_BASE_FRAME>(), _( "Cannot delete REFERENCE!" ) ); DisplayError( getEditFrame<PCB_BASE_FRAME>(), _( "Cannot delete component reference." ) ); return; return; case TEXTE_MODULE::TEXT_is_VALUE: case TEXTE_MODULE::TEXT_is_VALUE: DisplayError( getEditFrame<PCB_BASE_FRAME>(), _( "Cannot delete VALUE!" ) ); DisplayError( getEditFrame<PCB_BASE_FRAME>(), _( "Cannot delete component value." ) ); return; return; case TEXTE_MODULE::TEXT_is_DIVERS: // suppress warnings case TEXTE_MODULE::TEXT_is_DIVERS: // suppress warnings break; break; } } if( m_editModules ) { MODULE* module = static_cast<MODULE*>( aItem->GetParent() ); module->SetLastEditTime(); board->m_Status_Pcb = 0; // it is done in the legacy view aItem->DeleteStructure(); } } return; } } /* no break */ case PCB_PAD_T: case PCB_PAD_T: case PCB_MODULE_EDGE_T: case PCB_MODULE_EDGE_T: if( m_editModules ) { { MODULE* module = static_cast<MODULE*>( aItem->GetParent() ); MODULE* module = static_cast<MODULE*>( aItem->GetParent() ); module->SetLastEditTime(); module->SetLastEditTime(); board->m_Status_Pcb = 0; // it is done in the legacy view board->m_Status_Pcb = 0; // it is done in the legacy view aItem->DeleteStructure(); if(!m_editModules) { if(aItem->Type() == PCB_PAD_T && module->GetPadCount() == 1) { DisplayError( getEditFrame<PCB_BASE_FRAME>(), _( "Cannot delete the only remaining pad of the module (modules on PCB must have at least one pad)." ) ); return; } getView()->Remove( aItem ); board->Remove( aItem ); } } aItem->DeleteStructure(); return; return; break; } case PCB_LINE_T: // a segment not on copper layers case PCB_LINE_T: // a segment not on copper layers case PCB_TEXT_T: // a text on a layer case PCB_TEXT_T: // a text on a layer Loading @@ -526,7 +592,6 @@ void EDIT_TOOL::remove( BOARD_ITEM* aItem ) default: // other types do not need to (or should not) be handled default: // other types do not need to (or should not) be handled assert( false ); assert( false ); return; return; break; } } getView()->Remove( aItem ); getView()->Remove( aItem ); Loading @@ -541,6 +606,8 @@ void EDIT_TOOL::setTransitions() Go( &EDIT_TOOL::Flip, COMMON_ACTIONS::flip.MakeEvent() ); Go( &EDIT_TOOL::Flip, COMMON_ACTIONS::flip.MakeEvent() ); Go( &EDIT_TOOL::Remove, COMMON_ACTIONS::remove.MakeEvent() ); Go( &EDIT_TOOL::Remove, COMMON_ACTIONS::remove.MakeEvent() ); Go( &EDIT_TOOL::Properties, COMMON_ACTIONS::properties.MakeEvent() ); Go( &EDIT_TOOL::Properties, COMMON_ACTIONS::properties.MakeEvent() ); Go( &EDIT_TOOL::editFootprintInFpEditor, COMMON_ACTIONS::editFootprintInFpEditor.MakeEvent() ); } } Loading @@ -550,6 +617,7 @@ void EDIT_TOOL::updateRatsnest( bool aRedraw ) RN_DATA* ratsnest = getModel<BOARD>()->GetRatsnest(); RN_DATA* ratsnest = getModel<BOARD>()->GetRatsnest(); ratsnest->ClearSimple(); ratsnest->ClearSimple(); for( unsigned int i = 0; i < selection.items.GetCount(); ++i ) for( unsigned int i = 0; i < selection.items.GetCount(); ++i ) { { BOARD_ITEM* item = selection.Item<BOARD_ITEM>( i ); BOARD_ITEM* item = selection.Item<BOARD_ITEM>( i ); Loading Loading @@ -579,15 +647,27 @@ wxPoint EDIT_TOOL::getModificationPoint( const SELECTION& aSelection ) } } } } bool EDIT_TOOL::hoverSelection( const SELECTION& aSelection, bool aSanitize ) bool EDIT_TOOL::makeSelection( const SELECTION& aSelection ) { { if( aSelection.Empty() ) // Try to find an item that could be modified if( aSelection.Empty() ) // Try to find an item that could be modified { m_toolMgr->RunAction( COMMON_ACTIONS::selectionCursor, true ); m_toolMgr->RunAction( COMMON_ACTIONS::selectionCursor, true ); return !aSelection.Empty(); if ( m_selectionTool->CheckLock() == SELECTION_LOCKED ) { m_toolMgr->RunAction( COMMON_ACTIONS::selectionClear, true ); return false; } } } if ( aSanitize ) m_selectionTool->SanitizeSelection(); if ( aSelection.Empty() ) m_toolMgr->RunAction( COMMON_ACTIONS::selectionClear, true ); return !aSelection.Empty(); } void EDIT_TOOL::processChanges( const PICKED_ITEMS_LIST* aList ) void EDIT_TOOL::processChanges( const PICKED_ITEMS_LIST* aList ) { { Loading Loading @@ -626,3 +706,32 @@ void EDIT_TOOL::processChanges( const PICKED_ITEMS_LIST* aList ) } } } } } } int EDIT_TOOL::editFootprintInFpEditor( const TOOL_EVENT& aEvent ) { MODULE *mod = uniqueSelected <MODULE> (); if( !mod ) return 0; PCB_BASE_EDIT_FRAME* editFrame = getEditFrame<PCB_BASE_EDIT_FRAME>(); editFrame-> SetCurItem( mod ); if( editFrame->GetCurItem()->GetTimeStamp() == 0 ) // Module Editor needs a non null timestamp { editFrame->GetCurItem()->SetTimeStamp( GetNewTimeStamp() ); editFrame->OnModify(); } FOOTPRINT_EDIT_FRAME* editor = (FOOTPRINT_EDIT_FRAME*) editFrame->Kiway().Player( FRAME_PCB_MODULE_EDITOR, true ); editor->Load_Module_From_BOARD( (MODULE*)editFrame->GetCurItem() ); editFrame->SetCurItem( NULL ); // the current module could be deleted by editor->Show( true ); editor->Raise(); // Iconize( false ); setTransitions(); return 0; }
pcbnew/tools/edit_tool.h +16 −1 Original line number Original line Diff line number Diff line Loading @@ -147,10 +147,25 @@ private: ///> If there are no items currently selected, it tries to choose the item that is under ///> If there are no items currently selected, it tries to choose the item that is under ///> the cursor or displays a disambiguation menu if there are multpile items. ///> the cursor or displays a disambiguation menu if there are multpile items. bool makeSelection( const SELECTION& aSelection ); bool hoverSelection( const SELECTION& aSelection, bool aSanitize = true ); ///> Updates view with the changes in the list. ///> Updates view with the changes in the list. void processChanges( const PICKED_ITEMS_LIST* aList ); void processChanges( const PICKED_ITEMS_LIST* aList ); int editFootprintInFpEditor( const TOOL_EVENT& aEvent ); bool invokeInlineRouter(); template <class T> T* uniqueSelected() { const SELECTION& selection = m_selectionTool->GetSelection(); if(selection.items.GetCount() > 1) return NULL; BOARD_ITEM *item = selection.Item<BOARD_ITEM>( 0 ); return dyn_cast<T*> (item); } }; }; #endif #endif
pcbnew/tools/grid_helper.cpp 0 → 100644 +334 −0 Original line number Original line Diff line number Diff line /* * This program source code file is part of KiCad, a free EDA CAD application. * * Copyright (C) 2014 CERN * @author Tomasz Wlostowski <tomasz.wlostowski@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 */ #include <boost/foreach.hpp> #include <boost/bind.hpp> #include <wxPcbStruct.h> #include <class_board.h> #include <class_module.h> #include <class_edge_mod.h> #include <class_zone.h> #include <class_draw_panel_gal.h> #include <view/view_controls.h> #include <gal/graphics_abstraction_layer.h> #include <geometry/shape_line_chain.h> #include "grid_helper.h" GRID_HELPER::GRID_HELPER ( PCB_BASE_FRAME *aFrame ) : m_frame ( aFrame ) { } GRID_HELPER::~GRID_HELPER () { } void GRID_HELPER::SetGrid ( int aSize ) { assert ( false ); } void GRID_HELPER::SetOrigin ( const VECTOR2I& aOrigin ) { } VECTOR2I GRID_HELPER::GetGrid () { PCB_SCREEN *screen = m_frame->GetScreen(); const wxRealPoint& size = screen->GetGridSize(); return VECTOR2I ( KiROUND ( size.x ), KiROUND ( size.y ) ); } VECTOR2I GRID_HELPER::GetOrigin () { return VECTOR2I ( 0, 0 ); } void GRID_HELPER::SetAuxAxes ( bool aEnable, const VECTOR2I aOrigin, bool aEnableDiagonal) { if( aEnable ) m_auxAxis = aOrigin; else m_auxAxis = boost::optional <VECTOR2I> (); m_diagonalAuxAxesEnable = aEnable; } VECTOR2I GRID_HELPER::Align ( const VECTOR2I& aPoint ) { const VECTOR2D gridOffset ( GetOrigin () ); const VECTOR2D gridSize ( GetGrid() ); VECTOR2I nearest ( round( ( aPoint.x - gridOffset.x ) / gridSize.x ) * gridSize.x + gridOffset.x, round( ( aPoint.y - gridOffset.y ) / gridSize.y ) * gridSize.y + gridOffset.y ); if ( !m_auxAxis ) return nearest; if ( std::abs ( m_auxAxis->x - aPoint.x) < std::abs ( nearest.x - aPoint.x ) ) nearest.x = m_auxAxis->x; if ( std::abs ( m_auxAxis->y - aPoint.y) < std::abs ( nearest.y - aPoint.y ) ) nearest.y = m_auxAxis->y; return nearest; } VECTOR2I GRID_HELPER::BestDragOrigin ( const VECTOR2I &aMousePos, BOARD_ITEM *aItem ) { clearAnchors(); computeAnchors( aItem, aMousePos ); double worldScale = m_frame->GetGalCanvas()->GetGAL()->GetWorldScale(); double lineSnapMinCornerDistance = 50.0 / worldScale; ANCHOR* nearestOutline = nearestAnchor ( aMousePos, OUTLINE, LSET::AllLayersMask() ); ANCHOR* nearestCorner = nearestAnchor ( aMousePos, CORNER, LSET::AllLayersMask() ); ANCHOR* nearestOrigin = nearestAnchor ( aMousePos, ORIGIN, LSET::AllLayersMask() ); ANCHOR* best = NULL; double minDist = std::numeric_limits<double>::max(); if (nearestOrigin) { minDist = nearestOrigin->Distance(aMousePos); best = nearestOrigin; } if (nearestCorner) { double dist = nearestCorner->Distance(aMousePos); if (dist < minDist) { minDist = dist; best = nearestCorner; } } if (nearestOutline) { double dist = nearestOutline->Distance(aMousePos); if (minDist > lineSnapMinCornerDistance && dist < minDist) best = nearestOutline; } return best ? best->pos : aMousePos; } std::set<BOARD_ITEM *> GRID_HELPER::queryVisible ( const BOX2I& aArea ) { std::set <BOARD_ITEM *> items; std::vector<KIGFX::VIEW::LAYER_ITEM_PAIR> selectedItems; std::vector<KIGFX::VIEW::LAYER_ITEM_PAIR>::iterator it, it_end; m_frame->GetGalCanvas()->GetView()->Query( aArea, selectedItems ); // Get the list of selected items for( it = selectedItems.begin(), it_end = selectedItems.end(); it != it_end; ++it ) { BOARD_ITEM* item = static_cast<BOARD_ITEM*>( it->first ); if( item->ViewIsVisible() ) items.insert ( item ); } return items; } VECTOR2I GRID_HELPER::BestSnapAnchor ( const VECTOR2I &aOrigin, BOARD_ITEM *aDraggedItem ) { double worldScale = m_frame->GetGalCanvas()->GetGAL()->GetWorldScale(); int snapRange = (int) (100.0 / worldScale); BOX2I bb ( VECTOR2I ( aOrigin.x - snapRange / 2, aOrigin.y - snapRange/2) , VECTOR2I (snapRange, snapRange) ); clearAnchors(); BOOST_FOREACH ( BOARD_ITEM *item, queryVisible ( bb ) ) { computeAnchors(item, aOrigin); } LSET layers ( aDraggedItem->GetLayer() ); ANCHOR *nearest = nearestAnchor ( aOrigin, CORNER | SNAPPABLE, layers ); VECTOR2I nearestGrid = Align ( aOrigin ); double gridDist = (nearestGrid - aOrigin).EuclideanNorm(); if (nearest) { double snapDist = nearest->Distance ( aOrigin ); if(nearest && snapDist < gridDist) return nearest->pos; } return nearestGrid; } void GRID_HELPER::computeAnchors ( BOARD_ITEM *aItem, const VECTOR2I& aRefPos ) { VECTOR2I origin; switch ( aItem->Type() ) { case PCB_MODULE_T: { MODULE *mod = static_cast <MODULE *> (aItem); addAnchor ( mod->GetPosition(), ORIGIN | SNAPPABLE, mod ); for (D_PAD *pad = mod->Pads(); pad; pad = pad->Next() ) addAnchor ( pad->GetPosition(), CORNER | SNAPPABLE, pad ); break; } case PCB_MODULE_EDGE_T: case PCB_LINE_T: { DRAWSEGMENT *dseg = static_cast <DRAWSEGMENT*> (aItem); VECTOR2I start = dseg->GetStart(); VECTOR2I end = dseg->GetEnd(); //LAYER_ID layer = dseg->GetLayer(); switch( dseg->GetShape() ) { case S_CIRCLE: { int r = (start - end).EuclideanNorm(); addAnchor ( start, ORIGIN | SNAPPABLE, dseg ); addAnchor ( start + VECTOR2I ( -r, 0 ) , OUTLINE | SNAPPABLE, dseg ); addAnchor ( start + VECTOR2I ( r, 0 ) , OUTLINE | SNAPPABLE, dseg ); addAnchor ( start + VECTOR2I ( 0, -r ) , OUTLINE | SNAPPABLE, dseg); addAnchor ( start + VECTOR2I ( 0, r ) , OUTLINE | SNAPPABLE, dseg ); break; } case S_ARC: { origin = dseg->GetCenter(); addAnchor ( dseg->GetArcStart(), CORNER | SNAPPABLE, dseg ); addAnchor ( dseg->GetArcEnd(), CORNER | SNAPPABLE, dseg ); addAnchor ( origin, ORIGIN | SNAPPABLE, dseg ); break; } case S_SEGMENT: { origin.x = start.x + ( start.x - end.x ) / 2; origin.y = start.y + ( start.y - end.y ) / 2; addAnchor ( start, CORNER | SNAPPABLE, dseg ); addAnchor ( end, CORNER | SNAPPABLE, dseg ); addAnchor ( origin, ORIGIN, dseg ); break; } default: { origin = dseg->GetStart(); addAnchor ( origin, ORIGIN | SNAPPABLE, dseg ); break; } } break; } case PCB_TRACE_T: { TRACK *track = static_cast <TRACK*> (aItem); VECTOR2I start = track->GetStart(); VECTOR2I end = track->GetEnd(); origin.x = start.x + ( start.x - end.x ) / 2; origin.y = start.y + ( start.y - end.y ) / 2; addAnchor ( start, CORNER | SNAPPABLE, track ); addAnchor ( end, CORNER | SNAPPABLE, track ); addAnchor ( origin, ORIGIN, track); break; } case PCB_ZONE_AREA_T: { const CPolyLine* outline = static_cast<const ZONE_CONTAINER*>( aItem )->Outline(); int cornersCount = outline->GetCornersCount(); SHAPE_LINE_CHAIN lc; lc.SetClosed ( true ); for( int i = 0; i < cornersCount; ++i ) { const VECTOR2I p ( outline->GetPos( i ) ); addAnchor ( p, CORNER, aItem ); lc.Append ( p ); } addAnchor( lc.NearestPoint ( aRefPos ), OUTLINE, aItem ); break; } case PCB_MODULE_TEXT_T: case PCB_TEXT_T: addAnchor ( aItem->GetPosition(), ORIGIN, aItem ); default: break; } } GRID_HELPER::ANCHOR* GRID_HELPER::nearestAnchor ( VECTOR2I aPos, int aFlags, LSET aMatchLayers ) { double minDist = std::numeric_limits<double>::max(); ANCHOR *best = NULL; BOOST_FOREACH( ANCHOR& a, m_anchors ) { if ( !aMatchLayers [ a.item->GetLayer() ] ) continue; if ( ( aFlags & a.flags ) != aFlags ) continue; double dist = a.Distance(aPos); if(dist < minDist) { minDist = dist; best = &a; } } return best; } No newline at end of file