Commit 5adba827 authored by Maciej Suminski's avatar Maciej Suminski
Browse files

Added VIEW_GROUP for grouping items to be displayed on a single layer.

parent 61ba40aa
Loading
Loading
Loading
Loading
+1 −0
Original line number Diff line number Diff line
@@ -152,6 +152,7 @@ set(COMMON_SRCS
	${COMMON_SRCS}
	view/view.cpp
	view/view_item.cpp
	view/view_group.cpp

	system/fcontext.s
	
+2 −3
Original line number Diff line number Diff line
@@ -88,7 +88,6 @@ EDA_DRAW_PANEL_GAL::EDA_DRAW_PANEL_GAL( wxWindow* aParentWindow, wxWindowID aWin
    Connect( wxEVT_SIZE, wxSizeEventHandler( EDA_DRAW_PANEL_GAL::onSize ), NULL, this );

    /* Generic events for the Tool Dispatcher */

	Connect( wxEVT_MOTION, wxEventHandler( EDA_DRAW_PANEL_GAL::onEvent ), NULL, this );
	Connect( wxEVT_LEFT_UP, wxEventHandler( EDA_DRAW_PANEL_GAL::onEvent ), NULL, this );
	Connect( wxEVT_LEFT_DOWN, wxEventHandler( EDA_DRAW_PANEL_GAL::onEvent ), NULL, this );
@@ -127,8 +126,8 @@ void EDA_DRAW_PANEL_GAL::onPaint( wxPaintEvent& WXUNUSED( aEvent ) )
void EDA_DRAW_PANEL_GAL::onSize( wxSizeEvent& aEvent )
{
    m_gal->ResizeScreen( aEvent.GetSize().x, aEvent.GetSize().y );
    m_view->SetTargetDirty( KiGfx::TARGET_CACHED );
    m_view->SetTargetDirty( KiGfx::TARGET_NONCACHED );
    m_view->MarkTargetDirty( KiGfx::TARGET_CACHED );
    m_view->MarkTargetDirty( KiGfx::TARGET_NONCACHED );
}


+135 −80
Original line number Diff line number Diff line
@@ -28,6 +28,7 @@
#include <layers_id_colors_and_visibility.h>

#include <view/view.h>
#include <view/view_group.h>
#include <view/view_rtree.h>
#include <gal/definitions.h>
#include <gal/graphics_abstraction_layer.h>
@@ -48,7 +49,7 @@ VIEW::VIEW( bool aIsDynamic ) :
{
    // Redraw everything at the beginning
    for( int i = 0; i < TARGETS_NUMBER; ++i )
        SetTargetDirty( i );
        MarkTargetDirty( i );
}


@@ -111,53 +112,6 @@ void VIEW::Remove( VIEW_ITEM* aItem )
}


void VIEW::Draw( VIEW_ITEM* aItem, int aLayer ) const
{
    if( isCached( aLayer ) )
    {
        // Draw using cached information or create one
        int group = aItem->getGroup( aLayer );

        if( group >= 0 )
        {
            m_gal->DrawGroup( group );
        }
        else
        {
            group = m_gal->BeginGroup();
            aItem->setGroup( aLayer, group );
            if( !m_painter->Draw( aItem, aLayer ) )
                aItem->ViewDraw( aLayer, m_gal, BOX2I() ); // Alternative drawing method
            m_gal->EndGroup();
        }
    }
    else
    {
        // Immediate mode
        if( !m_painter->Draw( aItem, aLayer ) )
            aItem->ViewDraw( aLayer, m_gal, BOX2I() );  // Alternative drawing method
    }

    // Draws a bright contour around the item
    if( static_cast<const EDA_ITEM*>( aItem )->IsBrightened() )
    {
        m_painter->DrawBrightened( aItem );
    }
}


void VIEW::Draw( VIEW_ITEM* aItem ) const
{
    int layers[VIEW_MAX_LAYERS], layers_count;
    aItem->ViewGetLayers( layers, layers_count );

    for( int i = 0; i < layers_count; ++i )
    {
        Draw( aItem, layers[i] );
    }
}


void VIEW::SetRequired( int aLayerId, int aRequiredId, bool aRequired )
{
    wxASSERT( (unsigned) aLayerId < m_layers.size() );
@@ -271,9 +225,9 @@ void VIEW::SetGAL( GAL* aGal )
    clearGroupCache();

    // every target has to be refreshed
    SetTargetDirty( TARGET_CACHED );
    SetTargetDirty( TARGET_NONCACHED );
    SetTargetDirty( TARGET_OVERLAY );
    MarkTargetDirty( TARGET_CACHED );
    MarkTargetDirty( TARGET_NONCACHED );
    MarkTargetDirty( TARGET_OVERLAY );

    // force the new GAL to display the current viewport.
    SetCenter( m_center );
@@ -336,8 +290,8 @@ void VIEW::SetScale( double aScale, const VECTOR2D& aAnchor )
    m_scale = aScale;

    // Redraw everything after the viewport has changed
    SetTargetDirty( TARGET_CACHED );
    SetTargetDirty( TARGET_NONCACHED );
    MarkTargetDirty( TARGET_CACHED );
    MarkTargetDirty( TARGET_NONCACHED );
}


@@ -348,31 +302,50 @@ void VIEW::SetCenter( const VECTOR2D& aCenter )
    m_gal->ComputeWorldScreenMatrix();

    // Redraw everything after the viewport has changed
    SetTargetDirty( TARGET_CACHED );
    SetTargetDirty( TARGET_NONCACHED );
    MarkTargetDirty( TARGET_CACHED );
    MarkTargetDirty( TARGET_NONCACHED );
}


void VIEW::sortLayers()
void VIEW::SetLayerOrder( int aLayer, int aRenderingOrder )
{
    int n = 0;

    m_orderedLayers.resize( m_layers.size() );
    m_layers[aLayer].renderingOrder = aRenderingOrder;

    for( LayerMapIter i = m_layers.begin(); i != m_layers.end(); ++i )
        m_orderedLayers[n++] = &i->second;
    sortLayers();
}

    sort( m_orderedLayers.begin(), m_orderedLayers.end(), compareRenderingOrder );

    SetTargetDirty( TARGET_CACHED );
int VIEW::GetLayerOrder( int aLayer ) const
{
    return m_layers.at(aLayer).renderingOrder;
}


void VIEW::SetLayerOrder( int aLayer, int aRenderingOrder )
void VIEW::SortLayers( int aLayers[], int& aCount ) const
{
    m_layers[aLayer].renderingOrder = aRenderingOrder;
    int maxLay, maxOrd, maxIdx;

    sortLayers();
    for( int i = 0; i < aCount; ++i )
    {
        maxLay = aLayers[i];
        maxOrd = GetLayerOrder( maxLay );
        maxIdx = i;

        // Look for the max element in the range (j..aCount)
        for( int j = i; j < aCount; ++j )
        {
            if( maxOrd < GetLayerOrder( aLayers[j] ) )
            {
                maxLay = aLayers[j];
                maxOrd = GetLayerOrder( maxLay );
                maxIdx = j;
            }
        }

        // Swap elements
        aLayers[maxIdx] = aLayers[i];
        aLayers[i] = maxLay;
    }
}


@@ -559,7 +532,7 @@ struct VIEW::drawItem
        if( !drawCondition )
            return;

        view->Draw( aItem, currentLayer->id );
        view->draw( aItem, currentLayer->id );
    }

    const VIEW_LAYER* currentLayer;
@@ -585,13 +558,73 @@ void VIEW::redrawRect( const BOX2I& aRect )
}


void VIEW::draw( VIEW_ITEM* aItem, int aLayer, bool aImmediate ) const
{
    if( isCached( aLayer ) && !aImmediate )
    {
        // Draw using cached information or create one
        int group = aItem->getGroup( aLayer );

        if( group >= 0 )
        {
            m_gal->DrawGroup( group );
        }
        else
        {
            group = m_gal->BeginGroup();
            aItem->setGroup( aLayer, group );
            if( !m_painter->Draw( aItem, aLayer ) )
                aItem->ViewDraw( aLayer, m_gal, BOX2I() ); // Alternative drawing method
            m_gal->EndGroup();
        }
    }
    else
    {
        // Immediate mode
        if( !m_painter->Draw( aItem, aLayer ) )
            aItem->ViewDraw( aLayer, m_gal, BOX2I() );  // Alternative drawing method
    }

    // Draws a bright contour around the item
    if( static_cast<const EDA_ITEM*>( aItem )->IsBrightened() )
    {
        m_painter->DrawBrightened( aItem );
    }
}


void VIEW::draw( VIEW_ITEM* aItem, bool aImmediate ) const
{
    int layers[VIEW_MAX_LAYERS], layers_count;
    aItem->ViewGetLayers( layers, layers_count );
    SortLayers( layers, layers_count );

    for( int i = 0; i < layers_count; ++i )
    {
        m_gal->SetLayerDepth( m_layers.at( i ).renderingOrder );
        draw( aItem, layers[i], aImmediate );
    }
}


void VIEW::draw( VIEW_GROUP* aGroup, bool aImmediate ) const
{
    std::set<VIEW_ITEM*>::const_iterator it;
    for( it = aGroup->Begin(); it != aGroup->End(); ++it )
    {
        draw( *it, aImmediate );
    }
}


bool VIEW::IsDirty() const
{
    BOOST_FOREACH( VIEW_LAYER* l, m_orderedLayers )
    for( int i = 0; i < TARGETS_NUMBER; ++i )
    {
        if( l->isDirty )
        if( isTargetDirty( i ) )
            return true;
    }

    return false;
}

@@ -675,18 +708,22 @@ void VIEW::Redraw()
        m_gal->ClearTarget( TARGET_NONCACHED );
        m_gal->ClearTarget( TARGET_CACHED );

        SetTargetDirty( TARGET_NONCACHED );
        SetTargetDirty( TARGET_CACHED );
        MarkTargetDirty( TARGET_NONCACHED );
        MarkTargetDirty( TARGET_CACHED );

        m_gal->DrawGrid();
    }

    // Always refresh the overlay
    MarkTargetDirty( TARGET_OVERLAY );
    m_gal->ClearTarget( TARGET_OVERLAY );

    redrawRect( rect );

    // All targets were redrawn, so nothing is dirty
    SetTargetDirty( TARGET_CACHED, false );
    SetTargetDirty( TARGET_NONCACHED, false );
    clearTargetDirty( TARGET_CACHED );
    clearTargetDirty( TARGET_NONCACHED );
    clearTargetDirty( TARGET_OVERLAY );
}


@@ -752,7 +789,23 @@ void VIEW::invalidateItem( VIEW_ITEM* aItem, int aUpdateFlags )

        // Mark those layers as dirty, so the VIEW will be refreshed
        m_layers[layers[i]].isDirty = true;
        MarkTargetDirty( m_layers[layers[i]].target );   // TODO remove?
    }
}


void VIEW::sortLayers()
{
    int n = 0;

    m_orderedLayers.resize( m_layers.size() );

    for( LayerMapIter i = m_layers.begin(); i != m_layers.end(); ++i )
        m_orderedLayers[n++] = &i->second;

    sort( m_orderedLayers.begin(), m_orderedLayers.end(), compareRenderingOrder );

    MarkTargetDirty( TARGET_CACHED );
}


@@ -811,8 +864,6 @@ void VIEW::RecacheAllItems( bool aImmediately )
    r.SetMaximum();

#ifdef __WXDEBUG__
    wxLogDebug( wxT( "RecacheAllItems::immediately: %u" ), aImmediately );

    prof_counter totalRealTime;
    prof_start( &totalRealTime, false );
#endif /* __WXDEBUG__ */
@@ -834,7 +885,8 @@ void VIEW::RecacheAllItems( bool aImmediately )
#ifdef __WXDEBUG__
    prof_end( &totalRealTime );

    wxLogDebug( wxT( "RecacheAllItems::%.1f ms" ), (double) totalRealTime.value / 1000.0 );
    wxLogDebug( wxT( "RecacheAllItems::immediately: %u %.1f ms" ),
                aImmediately, (double) totalRealTime.value / 1000.0 );
#endif /* __WXDEBUG__ */
}

@@ -843,6 +895,10 @@ bool VIEW::isTargetDirty( int aTarget ) const
{
    wxASSERT( aTarget < TARGETS_NUMBER );

    // Check the target status
    if( m_dirtyTargets[aTarget] )
        return true;

    // Check if any of layers belonging to the target is dirty
    BOOST_FOREACH( VIEW_LAYER* l, m_orderedLayers )
    {
@@ -850,6 +906,5 @@ bool VIEW::isTargetDirty( int aTarget ) const
            return true;
    }

    // If no layer is dirty, just check the target status itself
    return m_dirtyTargets[aTarget];
    return false;
}
+145 −0
Original line number Diff line number Diff line
/*
 * This program source code file is part of KiCad, a free EDA CAD application.
 *
 * Copyright (C) 2013 CERN
 * @author Maciej Suminski <maciej.suminski@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
 *
 */

/**
 * @file view_group.cpp
 * @brief VIEW_GROUP extends VIEW_ITEM by possibility of grouping items into a single object.
 * VIEW_GROUP does not take over ownership of the held items. The main purpose of this class is
 * to group items and draw them on a single layer (in particular the overlay).
 */

#include <set>
#include <algorithm>
#include <view/view_group.h>
#include <view/view.h>
#include <painter.h>
#include <gal/graphics_abstraction_layer.h>
#include <boost/foreach.hpp>
#include <layers_id_colors_and_visibility.h>

using namespace KiGfx;

VIEW_GROUP::VIEW_GROUP( VIEW* aView ) :
        m_layer( ITEM_GAL_LAYER( GP_OVERLAY ) )
{
    m_view = aView;
}


VIEW_GROUP::~VIEW_GROUP()
{
}


void VIEW_GROUP::Add( VIEW_ITEM* aItem )
{
    m_items.insert( aItem );
    updateBbox();
}


void VIEW_GROUP::Remove( VIEW_ITEM* aItem )
{
    m_items.erase( aItem );
    updateBbox();
}


void VIEW_GROUP::Clear()
{
    m_items.clear();
    updateBbox();
}


unsigned int VIEW_GROUP::GetSize() const
{
    return m_items.size();
}


const BOX2I VIEW_GROUP::ViewBBox() const
{
    BOX2I box;

    // Merge all bounding boxes, so the returned one contains all stored items
    BOOST_FOREACH( VIEW_ITEM* item, m_items )
    {
        box.Merge( item->ViewBBox() );
    }

    return box;
}


void VIEW_GROUP::ViewDraw( int aLayer, GAL* aGal, const BOX2I& aVisibleArea ) const
{
    PAINTER* painter = m_view->GetPainter();

    // Draw all items immediately (without caching)
    BOOST_FOREACH( VIEW_ITEM* item, m_items )
    {
        int layers[VIEW::VIEW_MAX_LAYERS], layers_count;
        item->ViewGetLayers( layers, layers_count );
        m_view->SortLayers( layers, layers_count );

        for( int i = 0; i < layers_count; i++ )
        {
            aGal->SetLayerDepth( m_view->GetLayerOrder( layers[i] ) );

            if( !painter->Draw( item, layers[i] ) )
                item->ViewDraw( layers[i], aGal, aVisibleArea );  // Alternative drawing method
        }

        /// m_view->Draw( item, true );
    }
}


void VIEW_GROUP::ViewGetLayers( int aLayers[], int& aCount ) const
{
    aLayers[0] = m_layer;
    aCount = 1;
}


void VIEW_GROUP::ViewUpdate( int aUpdateFlags, bool aForceImmediateRedraw )
{
    BOOST_FOREACH( VIEW_ITEM* item, m_items )
    {
        item->ViewUpdate( aUpdateFlags, aForceImmediateRedraw );
    }
}


void VIEW_GROUP::updateBbox()
{
    // Save the used VIEW, as it used nulled during Remove()
    VIEW* view = m_view;

    // Reinsert the group, so the bounding box can be updated
    view->Remove( this );
    view->Add( this );
}
+68 −25
Original line number Diff line number Diff line
@@ -37,6 +37,7 @@ namespace KiGfx
class PAINTER;
class GAL;
class VIEW_ITEM;
class VIEW_GROUP;
class VIEW_RTREE;

/**
@@ -95,19 +96,6 @@ public:
     */
    int     Query( const BOX2I& aRect, std::vector<LayerItemPair>& aResult );

    /**
     * Function Draw()
     * Draws an item, but on a specified layers. It has to be marked that some of drawing settings
     * are based on the layer on which an item is drawn.
     */
    void   Draw( VIEW_ITEM* aItem, int aLayer ) const;

    /**
     * Function Draw()
     * Draws an item on all layers that the item uses.
     */
    void   Draw( VIEW_ITEM* aItem ) const;

    /**
     * Function SetRequired()
     * Marks the aRequiredId layer as required for the aLayerId layer. In order to display the
@@ -296,13 +284,30 @@ public:

    /**
     * Function SetLayerOrder()
     * Sets rendering order of a particular layer.
     * Sets rendering order of a particular layer. Lower values are rendered first.
     * @param aLayer: the layer
     * @param aRenderingOrder: arbitrary number denoting the rendering order.
     * Lower values are rendered first.
     */
    void    SetLayerOrder( int aLayer, int aRenderingOrder );

    /**
     * Function GetLayerOrder()
     * Returns rendering order of a particular layer. Lower values are rendered first.
     * @param aLayer: the layer
     * @return Rendering order of a particular layer.
     */
    int     GetLayerOrder( int aLayer ) const;

    /**
     * Function SortLayers()
     * Changes the order of given layer ids, so after sorting the order corresponds to layers
     * rendering order (descending, ie. order in which layers should be drawn - from the bottom to
     * the top).
     * @param aLayers stores id of layers to be sorted.
     * @param aCount stores the number of layers.
     */
    void    SortLayers( int aLayers[], int& aCount ) const;

    /**
     * Function UpdateLayerColor()
     * Applies the new coloring scheme held by RENDER_SETTINGS in case that it has changed.
@@ -393,19 +398,17 @@ public:
    bool    IsDirty() const;

    /**
     * Function SetTargetDirty()
     * Function MarkTargetDirty()
     * Sets or clears target 'dirty' flag.
     * @param aTarget is the target to set.
     * @param aState says if the flag should be set or cleared.
     */
    inline void SetTargetDirty( int aTarget, bool aState = true )
    inline void MarkTargetDirty( int aTarget )
    {
        wxASSERT( aTarget < TARGETS_NUMBER );

        m_dirtyTargets[aTarget] = aState;
        m_dirtyTargets[aTarget] = true;
    }


    static const int VIEW_MAX_LAYERS = 128;      ///* maximum number of layers that may be shown

private:
@@ -438,12 +441,49 @@ private:
    struct updateItemsColor;
    struct changeItemsDepth;

    ///* Whether to use rendering order modifier or not
    bool m_enableOrderModifier;

    ///* Redraws contents within rect aRect
    void redrawRect( const BOX2I& aRect );

    inline void clearTargetDirty( int aTarget )
    {
        wxASSERT( aTarget < TARGETS_NUMBER );

        m_dirtyTargets[aTarget] = false;
    }

    /**
     * Function draw()
     * Draws an item, but on a specified layers. It has to be marked that some of drawing settings
     * are based on the layer on which an item is drawn.
     *
     * @param aItem is the item to be drawn.
     * @param aLayer is the layer which should be drawn.
     * @param aImmediate dictates the way of drawing - it allows to force immediate drawing mode
     * for cached items.
     */
    void    draw( VIEW_ITEM* aItem, int aLayer, bool aImmediate = false ) const;

    /**
     * Function draw()
     * Draws an item on all layers that the item uses.
     *
     * @param aItem is the item to be drawn.
     * @param aImmediate dictates the way of drawing - it allows to force immediate drawing mode
     * for cached items.
     */
    void    draw( VIEW_ITEM* aItem, bool aImmediate = false ) const;

    /**
     * Function draw()
     * Draws a group of items on all layers that those items use.
     *
     * @param aItem is the group to be drawn.
     * @param aImmediate dictates the way of drawing - it allows to force immediate drawing mode
     * for cached items.
     */
    void    draw( VIEW_GROUP* aGroup, bool aImmediate = false ) const;


    ///* Manages dirty flags & redraw queueing when updating an item. Called internally
    ///  via VIEW_ITEM::ViewUpdate()
    void invalidateItem( VIEW_ITEM* aItem, int aUpdateFlags );
@@ -484,10 +524,13 @@ private:
     */
    bool isTargetDirty( int aTarget ) const;

    ///* Whether to use rendering order modifier or not
    bool m_enableOrderModifier;

    /// Contains set of possible displayed layers and its properties
    LayerMap    m_layers;

    /// Sorted list of pointers to members of m_layers.
    /// Sorted list of pointers to members of m_layers
    LayerOrder  m_orderedLayers;

    /// Stores set of layers that are displayed on the top
Loading