diff --git a/pcbnew/tools/move_tool.cpp b/pcbnew/tools/move_tool.cpp index 7ab86b1b7a..b1fdd28c0b 100644 --- a/pcbnew/tools/move_tool.cpp +++ b/pcbnew/tools/move_tool.cpp @@ -36,7 +36,9 @@ using boost::optional; MOVE_TOOL::MOVE_TOOL() : TOOL_INTERACTIVE( "pcbnew.InteractiveMove" ), m_selectionTool( NULL ), - m_activate( m_toolName, AS_GLOBAL, 'M', "Move", "Moves the selected item(s)" ) + m_activate( m_toolName, AS_GLOBAL, 'M', "Move", "Moves the selected item(s)" ), + m_rotate( m_toolName + ".rotate", AS_CONTEXT, ' ', "Rotate", "Rotates selected item(s)" ), + m_flip( m_toolName + ".flip", AS_CONTEXT, 'F', "Flip", "Flips selected item(s)" ) { } @@ -48,8 +50,6 @@ MOVE_TOOL::~MOVE_TOOL() void MOVE_TOOL::Reset() { - m_toolMgr->RegisterAction( &m_activate ); - // Find the selection tool, so they can cooperate TOOL_BASE* selectionTool = m_toolMgr->FindTool( std::string( "pcbnew.InteractiveSelection" ) ); @@ -63,6 +63,11 @@ void MOVE_TOOL::Reset() return; } + // Activate hotkeys + m_toolMgr->RegisterAction( &m_activate ); + m_toolMgr->RegisterAction( &m_rotate ); + m_toolMgr->RegisterAction( &m_flip ); + // the tool launches upon reception of action event ("pcbnew.InteractiveMove") Go( &MOVE_TOOL::Main, m_activate.GetEvent() ); } @@ -90,17 +95,30 @@ int MOVE_TOOL::Main( TOOL_EVENT& aEvent ) break; // Finish } - if( evt->IsMotion() || evt->IsDrag( MB_Left ) ) + // Dispatch TOOL_ACTIONs + else if( evt->Category() == TC_Command ) + { + VECTOR2D cursorPos = getView()->ToWorld( getViewControls()->GetCursorPosition() ); + + if( evt->Matches( m_rotate.GetEvent() ) ) + { + m_state.Rotate( cursorPos, 900.0 ); + m_items.ViewUpdate( VIEW_ITEM::GEOMETRY ); + } + else if( evt->Matches( m_flip.GetEvent() ) ) + { + m_state.Flip( cursorPos ); + m_items.ViewUpdate( VIEW_ITEM::GEOMETRY ); + } + } + + else if( evt->IsMotion() || evt->IsDrag( MB_Left ) ) { if( dragging ) { - // Dragging is already active + // Drag items to the current cursor position VECTOR2D movement = ( evt->Position() - dragPosition ); - std::set::iterator it, it_end; - - // so move all the selected items - for( it = m_selection.begin(), it_end = m_selection.end(); it != it_end; ++it ) - (*it)->Move( wxPoint( movement.x, movement.y ) ); + m_state.Move( movement ); } else { @@ -112,28 +130,17 @@ int MOVE_TOOL::Main( TOOL_EVENT& aEvent ) std::set::iterator it; for( it = m_selection.begin(); it != m_selection.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 viewGroupAdd( *it, &m_items ); - - // 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( (*it)->Type() == PCB_MODULE_T ) - { - MODULE* module = static_cast( *it ); - - // Add everything that belongs to the module (besides the module itself) - for( D_PAD* pad = module->Pads().GetFirst(); pad; pad = pad->Next() ) - viewGroupAdd( pad, &m_items ); - - for( BOARD_ITEM* drawing = module->GraphicalItems().GetFirst(); drawing; - drawing = drawing->Next() ) - viewGroupAdd( drawing, &m_items ); - - viewGroupAdd( &module->Reference(), &m_items ); - viewGroupAdd( &module->Value(), &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; } @@ -144,25 +151,21 @@ int MOVE_TOOL::Main( TOOL_EVENT& aEvent ) break; // Finish } - // Clean-up after movement - std::deque::iterator it, it_end; + // Restore visibility of the original items + vgSetVisibility( &m_items, true ); + + // Movement has to be rollbacked, so restore the previous state of items if( restore ) { - // Movement has to be rollbacked, so restore the previous state of items - for( it = m_itemsState.begin(), it_end = m_itemsState.end(); it != it_end; ++it ) - it->Restore(); + vgUpdate( &m_items, VIEW_ITEM::APPEARANCE ); + m_state.RestoreAll(); } else { - // Apply changes - for( it = m_itemsState.begin(), it_end = m_itemsState.end(); it != it_end; ++it ) - { - it->RestoreVisibility(); - it->item->ViewUpdate( VIEW_ITEM::GEOMETRY ); - } + vgUpdate( &m_items, m_state.GetUpdateFlag() ); + m_state.Apply(); } - m_itemsState.clear(); m_items.Clear(); view->Remove( &m_items ); controls->ShowCursor( false ); @@ -173,17 +176,43 @@ int MOVE_TOOL::Main( TOOL_EVENT& aEvent ) } -void MOVE_TOOL::viewGroupAdd( BOARD_ITEM* aItem, KiGfx::VIEW_GROUP* aGroup ) +void MOVE_TOOL::viewGroupAdd( BOARD_ITEM* aItem, VIEW_GROUP* aGroup ) { - // Save the state of the selected items, in case it has to be restored - ITEM_STATE state; - state.Save( aItem ); - m_itemsState.push_back( state ); + // 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( aItem ); + + // Add everything that belongs to the module (besides the module itself) + for( D_PAD* pad = module->Pads().GetFirst(); pad; pad = pad->Next() ) + viewGroupAdd( pad, &m_items ); + + for( BOARD_ITEM* drawing = module->GraphicalItems().GetFirst(); drawing; + drawing = drawing->Next() ) + viewGroupAdd( drawing, &m_items ); + + viewGroupAdd( &module->Reference(), &m_items ); + viewGroupAdd( &module->Value(), &m_items ); + } // Add items to the VIEW_GROUP, so they will be displayed on the overlay // while dragging aGroup->Add( aItem ); - - // Set the original item as invisible - aItem->ViewSetVisible( false ); +} + + +void MOVE_TOOL::vgSetVisibility( VIEW_GROUP* aGroup, bool aVisible ) const +{ + std::set::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::const_iterator it, it_end; + for( it = aGroup->Begin(), it_end = aGroup->End(); it != it_end; ++it ) + (*it)->ViewUpdate( aFlags ); } diff --git a/pcbnew/tools/move_tool.h b/pcbnew/tools/move_tool.h index 2a3c4f7981..400af0d077 100644 --- a/pcbnew/tools/move_tool.h +++ b/pcbnew/tools/move_tool.h @@ -2,7 +2,7 @@ * This program source code file is part of KiCad, a free EDA CAD application. * * Copyright (C) 2013 CERN - * @author @author Maciej Suminski + * @author Maciej Suminski * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License @@ -27,6 +27,7 @@ #include #include +#include #include class BOARD_ITEM; @@ -40,7 +41,8 @@ class VIEW_GROUP; /** * Class MOVE_TOOL * - * Our sample move tool. Allows to move items selected by pcbnew.InteractiveSelection. + * Our sample move tool. Allows to move, rotate and flip items selected by + * pcbnew.InteractiveSelection tool. */ class MOVE_TOOL : public TOOL_INTERACTIVE @@ -67,55 +69,32 @@ private: /// Adds an item to the VIEW_GROUP that holds all moved items and displays them on the overlay void viewGroupAdd( BOARD_ITEM* aItem, KiGfx::VIEW_GROUP* aGroup ); - /// Structure for (re)storing BOARD_ITEM state - typedef struct - { - BOARD_ITEM* item; /// Pointer to the item - VECTOR2D position; /// Original position of the item - bool visible; /// Original visibility flag + /// Changes visibility settings for items stored in a VIEW_GROUP + void vgSetVisibility( KiGfx::VIEW_GROUP* aGroup, bool aVisible ) const; - void Save( BOARD_ITEM* aItem ) - { - wxPoint pos = aItem->GetPosition(); + /// Updates items stored in a VIEW_GROUP with selected update flag + void vgUpdate( KiGfx::VIEW_GROUP* aGroup, KiGfx::VIEW_ITEM::ViewUpdateFlags aFlags ) const; - item = aItem; - position.x = pos.x; - position.y = pos.y; - visible = aItem->ViewIsVisible(); - } - - void RestorePosition() - { - wxPoint curPosition = item->GetPosition(); - item->Move( wxPoint( position.x - curPosition.x, position.y - curPosition.y ) ); - } - - void RestoreVisibility() - { - item->ViewSetVisible( visible ); - } - - void Restore() - { - RestorePosition(); - RestoreVisibility(); - } - } ITEM_STATE; + /// 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; - /// Stores the initial state of moved items (so it is possible to rollback changes) - std::deque m_itemsState; - - /// Set of selected items (obtained from pcbnew. + /// Set of selected items (obtained from pcbnew.InteractiveSelection tool) std::set m_selection; /// VIEW_GROUP that helds currently moved items KiGfx::VIEW_GROUP m_items; - /// Register hotkey fot activation of the move tool + /// Register hotkey for activation of the move tool TOOL_ACTION m_activate; + + /// Register hotkey for rotation of selected objects + TOOL_ACTION m_rotate; + + /// Register hotkey for flipping of selected objects + TOOL_ACTION m_flip; }; #endif