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