Commit 2ee85807 authored by Maciej Suminski's avatar Maciej Suminski
Browse files

Moved VIEW_GROUP creation to the selection tool. In this way selected items...

Moved VIEW_GROUP creation to the selection tool. In this way selected items are always drawn on overlay, not only when dragged.
parent 86000832
Loading
Loading
Loading
Loading
+10 −70
Original line number Diff line number Diff line
@@ -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 );

    VIEW_CONTROLS* controls = getViewControls();
    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<BOARD_ITEM*>::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<MODULE*>( 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<VIEW_ITEM*>::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<VIEW_ITEM*>::const_iterator it, it_end;
    for( it = aGroup->Begin(), it_end = aGroup->End(); it != it_end; ++it )
        (*it)->ViewUpdate( aFlags );
}
+0 −15
Original line number Diff line number Diff line
@@ -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<BOARD_ITEM*> m_selection;

    /// VIEW_GROUP that helds currently moved items
    KiGfx::VIEW_GROUP m_items;
};

#endif
+118 −19
Original line number Diff line number Diff line
@@ -36,6 +36,7 @@
#include <wxPcbStruct.h>
#include <collectors.h>
#include <view/view_controls.h>
#include <view/view_group.h>
#include <painter.h>

#include <tool/tool_event.h>
@@ -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_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<BOARD>( 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<BOARD_ITEM*>( *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<MODULE*>( 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<MODULE*>( 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<BOARD_ITEM*>::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
+24 −22
Original line number Diff line number Diff line
@@ -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<BOARD_ITEM*> 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<BOARD_ITEM*>& 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<BOARD_ITEM*> 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;