view.cpp 23.3 KB
Newer Older
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30
/*
 * This program source code file is part of KiCad, a free EDA CAD application.
 *
 * Copyright (C) 2013 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 <base_struct.h>
#include <layers_id_colors_and_visibility.h>

#include <view/view.h>
31
#include <view/view_group.h>
32 33 34 35 36
#include <view/view_rtree.h>
#include <gal/definitions.h>
#include <gal/graphics_abstraction_layer.h>
#include <painter.h>

37
#ifdef __WXDEBUG__
38
#include <profile.h>
39
#endif /* __WXDEBUG__ */
40

41
using namespace KIGFX;
42

43
VIEW::VIEW( bool aIsDynamic ) :
44
    m_enableOrderModifier( true ),
45 46 47
    m_scale( 1.0 ),
    m_painter( NULL ),
    m_gal( NULL ),
48 49
    m_dynamic( aIsDynamic ),
    m_scaleLimits( 15000.0, 1.0 )
50
{
51 52
    m_panBoundary.SetMaximum();

53 54
    // Redraw everything at the beginning
    for( int i = 0; i < TARGETS_NUMBER; ++i )
55
        MarkTargetDirty( i );
56 57 58 59 60 61 62 63 64

    // View uses layers to display EDA_ITEMs (item may be displayed on several layers, for example
    // pad may be shown on pad, pad hole and solder paste layers). There are usual copper layers
    // (eg. F.Cu, B.Cu, internal and so on) and layers for displaying objects such as texts,
    // silkscreen, pads, vias, etc.
    for( int i = 0; i < VIEW_MAX_LAYERS; i++ )
    {
        AddLayer( i );
    }
65 66 67 68 69
}


VIEW::~VIEW()
{
Maciej Suminski's avatar
Maciej Suminski committed
70
    BOOST_FOREACH( LAYER_MAP::value_type& l, m_layers )
71 72 73 74 75 76
    {
        delete l.second.items;
    }
}


77 78 79 80
void VIEW::AddLayer( int aLayer, bool aDisplayOnly )
{
    if( m_layers.find( aLayer ) == m_layers.end() )
    {
81 82 83
        m_layers[aLayer]                = VIEW_LAYER();
        m_layers[aLayer].id             = aLayer;
        m_layers[aLayer].items          = new VIEW_RTREE();
84 85 86
        m_layers[aLayer].renderingOrder = aLayer;
        m_layers[aLayer].enabled        = true;
        m_layers[aLayer].displayOnly    = aDisplayOnly;
87
        m_layers[aLayer].target         = TARGET_CACHED;
88 89 90 91 92 93 94 95 96 97 98
    }

    sortLayers();
}


void VIEW::Add( VIEW_ITEM* aItem )
{
    int layers[VIEW_MAX_LAYERS], layers_count;

    aItem->ViewGetLayers( layers, layers_count );
99
    aItem->saveLayers( layers, layers_count );
100 101 102

    for( int i = 0; i < layers_count; i++ )
    {
103 104
        VIEW_LAYER& l = m_layers[layers[i]];
        l.items->Insert( aItem );
105
        MarkTargetDirty( l.target );
106 107 108 109 110 111 112 113 114 115 116 117
    }

    if( m_dynamic )
        aItem->viewAssign( this );
}


void VIEW::Remove( VIEW_ITEM* aItem )
{
    if( m_dynamic )
        aItem->m_view = NULL;

118 119 120 121
    int layers[VIEW::VIEW_MAX_LAYERS], layers_count;
    aItem->getLayers( layers, layers_count );

    for( int i = 0; i < layers_count; ++i )
122
    {
123 124
        VIEW_LAYER& l = m_layers[layers[i]];
        l.items->Remove( aItem );
125 126 127 128
    }
}


129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144
void VIEW::SetRequired( int aLayerId, int aRequiredId, bool aRequired )
{
    wxASSERT( (unsigned) aLayerId < m_layers.size() );
    wxASSERT( (unsigned) aRequiredId < m_layers.size() );

    if( aRequired )
    {
        m_layers[aLayerId].requiredLayers.insert( aRequiredId );
    }
    else
    {
        m_layers[aLayerId].requiredLayers.erase( aRequired );
    }
}


145 146 147 148 149 150 151 152 153 154 155 156 157 158
// stupid C++... python lamda would do this in one line
template <class Container>
struct queryVisitor
{
    typedef typename Container::value_type item_type;

    queryVisitor( Container& aCont, int aLayer ) :
        m_cont( aCont ), m_layer( aLayer )
    {
    }

    void operator()( VIEW_ITEM* aItem )
    {
        if( aItem->ViewIsVisible() )
Maciej Suminski's avatar
Maciej Suminski committed
159
            m_cont.push_back( VIEW::LAYER_ITEM_PAIR( aItem, m_layer ) );
160 161 162 163 164 165 166
    }

    Container&  m_cont;
    int         m_layer;
};


Maciej Suminski's avatar
Maciej Suminski committed
167
int VIEW::Query( const BOX2I& aRect, std::vector<LAYER_ITEM_PAIR>& aResult )
168 169 170 171 172 173 174 175 176 177 178 179 180 181
{
    if( m_orderedLayers.empty() )
        return 0;

    std::vector<VIEW_LAYER*>::reverse_iterator i;

    // execute queries in reverse direction, so that items that are on the top of
    // the rendering stack are returned first.
    for( i = m_orderedLayers.rbegin(); i != m_orderedLayers.rend(); ++i )
    {
        // ignore layers that do not contain actual items (i.e. the selection box, menus, floats)
        if( ( *i )->displayOnly )
            continue;

Maciej Suminski's avatar
Maciej Suminski committed
182
        queryVisitor<std::vector<LAYER_ITEM_PAIR> > visitor( aResult, ( *i )->id );
183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229
        ( *i )->items->Query( aRect, visitor );
    }

    return aResult.size();
}


VECTOR2D VIEW::ToWorld( const VECTOR2D& aCoord, bool aAbsolute ) const
{
    MATRIX3x3D matrix = m_gal->GetWorldScreenMatrix().Inverse();

    if( aAbsolute )
    {
        return VECTOR2D( matrix * aCoord );
    }
    else
    {
        return VECTOR2D( matrix.GetScale().x * aCoord.x, matrix.GetScale().y * aCoord.y );
    }
}


VECTOR2D VIEW::ToScreen( const VECTOR2D& aCoord, bool aAbsolute ) const
{
    MATRIX3x3D matrix = m_gal->GetWorldScreenMatrix();

    if( aAbsolute )
    {
        return VECTOR2D( matrix * aCoord );
    }
    else
    {
        return VECTOR2D( matrix.GetScale().x * aCoord.x, matrix.GetScale().y * aCoord.y );
    }
}


double VIEW::ToScreen( double aCoord, bool aAbsolute ) const
{
    VECTOR2D t( aCoord, 0 );

    return ToScreen( t, aAbsolute ).x;
}


void VIEW::CopySettings( const VIEW* aOtherView )
{
230
    wxASSERT_MSG( false, wxT( "This is not implemented" ) );
231 232 233 234 235 236 237
}


void VIEW::SetGAL( GAL* aGal )
{
    m_gal = aGal;

238
    // clear group numbers, so everything is going to be recached
239
    clearGroupCache();
240

241
    // every target has to be refreshed
242 243 244
    MarkTargetDirty( TARGET_CACHED );
    MarkTargetDirty( TARGET_NONCACHED );
    MarkTargetDirty( TARGET_OVERLAY );
245

246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283
    // force the new GAL to display the current viewport.
    SetCenter( m_center );
    SetScale( m_scale );
}


void VIEW::SetPainter( PAINTER* aPainter )
{
    m_painter = aPainter;
}


BOX2D VIEW::GetViewport() const
{
    BOX2D    rect;
    VECTOR2D screenSize = m_gal->GetScreenPixelSize();

    rect.SetOrigin( ToWorld( VECTOR2D( 0, 0 ) ) );
    rect.SetEnd( ToWorld( screenSize ) );

    return rect.Normalize();
}


void VIEW::SetViewport( const BOX2D& aViewport, bool aKeepAspect )
{
    VECTOR2D ssize  = ToWorld( m_gal->GetScreenPixelSize(), false );
    VECTOR2D centre = aViewport.Centre();
    VECTOR2D vsize  = aViewport.GetSize();
    double   zoom   = 1.0 / std::min( fabs( vsize.x / ssize.x ), fabs( vsize.y / ssize.y ) );

    SetCenter( centre );
    SetScale( GetScale() * zoom );
}


void VIEW::SetMirror( bool aMirrorX, bool aMirrorY )
{
284
    m_gal->SetFlip( aMirrorX, aMirrorY );
285 286 287 288 289 290 291 292 293 294 295
}


void VIEW::SetScale( double aScale )
{
    SetScale( aScale, m_center );
}


void VIEW::SetScale( double aScale, const VECTOR2D& aAnchor )
{
296 297 298 299 300
    if( aScale > m_scaleLimits.x )
        aScale = m_scaleLimits.x;
    else if( aScale < m_scaleLimits.y )
        aScale = m_scaleLimits.y;

301 302 303 304 305 306 307 308 309
    VECTOR2D a = ToScreen( aAnchor );

    m_gal->SetZoomFactor( aScale );
    m_gal->ComputeWorldScreenMatrix();

    VECTOR2D delta = ToWorld( a ) - aAnchor;

    SetCenter( m_center - delta );
    m_scale = aScale;
310 311

    // Redraw everything after the viewport has changed
312
    MarkTargetDirty( TARGET_CACHED );
313 314 315 316 317 318
}


void VIEW::SetCenter( const VECTOR2D& aCenter )
{
    m_center = aCenter;
319 320 321 322 323 324 325 326 327 328 329 330 331 332

    if( !m_panBoundary.Contains( aCenter ) )
    {
        if( aCenter.x < m_panBoundary.GetLeft() )
            m_center.x = m_panBoundary.GetLeft();
        else if( aCenter.x > m_panBoundary.GetRight() )
            m_center.x = m_panBoundary.GetRight();

        if( aCenter.y < m_panBoundary.GetTop() )
            m_center.y = m_panBoundary.GetTop();
        else if( aCenter.y > m_panBoundary.GetBottom() )
            m_center.y = m_panBoundary.GetBottom();
    }

333 334
    m_gal->SetLookAtPoint( m_center );
    m_gal->ComputeWorldScreenMatrix();
335 336

    // Redraw everything after the viewport has changed
337
    MarkTargetDirty( TARGET_CACHED );
338 339 340
}


341
void VIEW::SetLayerOrder( int aLayer, int aRenderingOrder )
342
{
343
    m_layers[aLayer].renderingOrder = aRenderingOrder;
344

345 346
    sortLayers();
}
347

348

349 350
int VIEW::GetLayerOrder( int aLayer ) const
{
351
    return m_layers.at( aLayer ).renderingOrder;
352 353 354
}


355
void VIEW::SortLayers( int aLayers[], int& aCount ) const
356
{
357
    int maxLay, maxOrd, maxIdx;
358

359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379
    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;
    }
380 381 382
}


383 384 385
struct VIEW::updateItemsColor
{
    updateItemsColor( int aLayer, PAINTER* aPainter, GAL* aGal ) :
386
        layer( aLayer ), painter( aPainter ), gal( aGal )
387 388 389 390 391 392
    {
    }

    void operator()( VIEW_ITEM* aItem )
    {
        // Obtain the color that should be used for coloring the item
393
        const COLOR4D color = painter->GetSettings()->GetColor( aItem, layer );
394 395
        int group = aItem->getGroup( layer );

396
        if( group >= 0 )
397
            gal->ChangeGroupColor( group, color );
398 399 400 401 402 403 404 405 406 407
    }

    int layer;
    PAINTER* painter;
    GAL* gal;
};


void VIEW::UpdateLayerColor( int aLayer )
{
408
    // There is no point in updating non-cached layers
409
    if( !IsCached( aLayer ) )
410 411
        return;

412 413 414 415 416 417 418 419 420 421 422 423 424 425 426
    BOX2I r;

    r.SetMaximum();

    updateItemsColor visitor( aLayer, m_painter, m_gal );
    m_layers[aLayer].items->Query( r, visitor );
}


void VIEW::UpdateAllLayersColor()
{
    BOX2I r;

    r.SetMaximum();

Maciej Suminski's avatar
Maciej Suminski committed
427
    for( LAYER_MAP_ITER i = m_layers.begin(); i != m_layers.end(); ++i )
428 429 430
    {
        VIEW_LAYER* l = &( ( *i ).second );

431
        // There is no point in updating non-cached layers
432
        if( !IsCached( l->id ) )
433 434 435
            continue;

        updateItemsColor visitor( l->id, m_painter, m_gal );
436 437
        l->items->Query( r, visitor );
    }
438 439

    MarkDirty();
440 441 442
}


443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464
struct VIEW::changeItemsDepth
{
    changeItemsDepth( int aLayer, int aDepth, GAL* aGal ) :
        layer( aLayer ), depth( aDepth ), gal( aGal )
    {
    }

    void operator()( VIEW_ITEM* aItem )
    {
        int group = aItem->getGroup( layer );

        if( group >= 0 )
            gal->ChangeGroupDepth( group, depth );
    }

    int layer, depth;
    GAL* gal;
};


void VIEW::ChangeLayerDepth( int aLayer, int aDepth )
{
465
    // There is no point in updating non-cached layers
466
    if( !IsCached( aLayer ) )
467 468
        return;

469 470 471 472 473 474 475 476
    BOX2I r;

    r.SetMaximum();

    changeItemsDepth visitor( aLayer, aDepth, m_gal );
    m_layers[aLayer].items->Query( r, visitor );
}

477 478

int VIEW::GetTopLayer() const
479 480 481 482 483 484 485
{
    if( m_topLayers.size() == 0 )
        return 0;

    return *m_topLayers.begin();
}

486

487
void VIEW::SetTopLayer( int aLayer, bool aEnabled )
488
{
489
    if( aEnabled )
490
    {
491 492
        if( m_topLayers.count( aLayer ) == 1 )
            return;
493

494 495 496 497 498 499 500
        m_topLayers.insert( aLayer );

        // Move the layer closer to front
        if( m_enableOrderModifier )
            m_layers[aLayer].renderingOrder += TOP_LAYER_MODIFIER;
    }
    else
501
    {
502 503
        if( m_topLayers.count( aLayer ) == 0 )
            return;
504

505
        m_topLayers.erase( aLayer );
506

507 508 509 510 511 512 513 514 515
        // Restore the previous rendering order
        if( m_enableOrderModifier )
            m_layers[aLayer].renderingOrder -= TOP_LAYER_MODIFIER;
    }
}


void VIEW::EnableTopLayer( bool aEnable )
{
516 517 518
    if( aEnable == m_enableOrderModifier )
        return;

519 520 521
    m_enableOrderModifier = aEnable;

    std::set<unsigned int>::iterator it;
522

523 524 525 526
    if( aEnable )
    {
        for( it = m_topLayers.begin(); it != m_topLayers.end(); ++it )
            m_layers[*it].renderingOrder += TOP_LAYER_MODIFIER;
527 528 529
    }
    else
    {
530 531
        for( it = m_topLayers.begin(); it != m_topLayers.end(); ++it )
            m_layers[*it].renderingOrder -= TOP_LAYER_MODIFIER;
532
    }
533 534 535

    UpdateAllLayersOrder();
    UpdateAllLayersColor();
536 537 538
}


539
void VIEW::ClearTopLayers()
540
{
541
    std::set<unsigned int>::iterator it;
542

543
    if( m_enableOrderModifier )
544
    {
545 546 547
        // Restore the previous rendering order for layers that were marked as top
        for( it = m_topLayers.begin(); it != m_topLayers.end(); ++it )
            m_layers[*it].renderingOrder -= TOP_LAYER_MODIFIER;
548
    }
549 550 551 552 553 554 555

    m_topLayers.clear();
}


void VIEW::UpdateAllLayersOrder()
{
556
    sortLayers();
557

Maciej Suminski's avatar
Maciej Suminski committed
558
    BOOST_FOREACH( LAYER_MAP::value_type& l, m_layers )
559 560 561
    {
        ChangeLayerDepth( l.first, l.second.renderingOrder );
    }
562 563

    MarkDirty();
564 565 566
}


567 568
struct VIEW::drawItem
{
569
    drawItem( VIEW* aView, const VIEW_LAYER* aCurrentLayer ) :
570
        currentLayer( aCurrentLayer ), view( aView )
571 572 573 574 575
    {
    }

    void operator()( VIEW_ITEM* aItem )
    {
576 577
        // Conditions that have te be fulfilled for an item to be drawn
        bool drawCondition = aItem->ViewIsVisible() &&
578
                             aItem->ViewGetLOD( currentLayer->id ) < view->m_scale;
579 580 581
        if( !drawCondition )
            return;

582
        view->draw( aItem, currentLayer->id );
583 584
    }

585 586
    const VIEW_LAYER* currentLayer;
    VIEW* view;
587
    int layersCount, layers[VIEW_MAX_LAYERS];
588 589
};

590

591 592 593 594
void VIEW::redrawRect( const BOX2I& aRect )
{
    BOOST_FOREACH( VIEW_LAYER* l, m_orderedLayers )
    {
595
        if( l->enabled && IsTargetDirty( l->target ) && areRequiredLayersEnabled( l->id ) )
596
        {
597
            drawItem drawFunc( this, l );
598

599
            m_gal->SetTarget( l->target );
600
            m_gal->SetLayerDepth( l->renderingOrder );
601 602
            l->items->Query( aRect, drawFunc );
        }
603 604 605
    }
}

606

607 608
void VIEW::draw( VIEW_ITEM* aItem, int aLayer, bool aImmediate ) const
{
609
    if( IsCached( aLayer ) && !aImmediate )
610 611 612 613 614 615 616 617 618 619 620 621
    {
        // 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 );
622

623
            if( !m_painter->Draw( aItem, aLayer ) )
624
                aItem->ViewDraw( aLayer, m_gal ); // Alternative drawing method
625

626 627 628 629 630 631 632
            m_gal->EndGroup();
        }
    }
    else
    {
        // Immediate mode
        if( !m_painter->Draw( aItem, aLayer ) )
633
            aItem->ViewDraw( aLayer, m_gal );  // Alternative drawing method
634 635 636 637 638 639 640
    }
}


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

642
    aItem->ViewGetLayers( layers, layers_count );
643
    // Sorting is needed for drawing order dependent GALs (like Cairo)
644 645 646 647
    SortLayers( layers, layers_count );

    for( int i = 0; i < layers_count; ++i )
    {
648
        m_gal->SetLayerDepth( m_layers.at( layers[i] ).renderingOrder );
649 650 651 652 653 654 655 656
        draw( aItem, layers[i], aImmediate );
    }
}


void VIEW::draw( VIEW_GROUP* aGroup, bool aImmediate ) const
{
    std::set<VIEW_ITEM*>::const_iterator it;
657

658 659 660 661 662 663 664
    for( it = aGroup->Begin(); it != aGroup->End(); ++it )
    {
        draw( *it, aImmediate );
    }
}


665
bool VIEW::IsDirty() const
666
{
667
    for( int i = 0; i < TARGETS_NUMBER; ++i )
668
    {
669
        if( IsTargetDirty( i ) )
670
            return true;
671 672
    }

673 674
    return false;
}
675

676

677 678 679 680 681 682 683 684 685
struct VIEW::unlinkItem
{
    void operator()( VIEW_ITEM* aItem )
    {
        aItem->m_view = NULL;
    }
};


686
struct VIEW::recacheItem
687
{
688
    recacheItem( VIEW* aView, GAL* aGal, int aLayer, bool aImmediately ) :
689 690 691 692
        view( aView ), gal( aGal ), layer( aLayer ), immediately( aImmediately )
    {
    }

693 694
    void operator()( VIEW_ITEM* aItem )
    {
695 696
        // Remove previously cached group
        int prevGroup = aItem->getGroup( layer );
697

698
        if( prevGroup >= 0 )
699 700 701 702 703
            gal->DeleteGroup( prevGroup );

        if( immediately )
        {
            int group = gal->BeginGroup();
704
            aItem->setGroup( layer, group );
705

706
            if( !view->m_painter->Draw( aItem, layer ) )
707
                aItem->ViewDraw( layer, gal ); // Alternative drawing method
708

709 710
            gal->EndGroup();
        }
711 712 713 714
        else
        {
            aItem->setGroup( layer, -1 );
        }
715
    }
716 717 718 719 720

    VIEW* view;
    GAL* gal;
    int layer;
    bool immediately;
721 722 723
};


724 725 726 727 728 729
void VIEW::Clear()
{
    BOX2I r;

    r.SetMaximum();

Maciej Suminski's avatar
Maciej Suminski committed
730
    for( LAYER_MAP_ITER i = m_layers.begin(); i != m_layers.end(); ++i )
731 732 733
    {
        VIEW_LAYER* l = &( ( *i ).second );
        unlinkItem v;
734

735 736 737 738
        if( m_dynamic )
            l->items->Query( r, v );

        l->items->RemoveAll();
739
    }
740

741
    m_gal->ClearCache();
742 743 744
}


745
void VIEW::ClearTargets()
746
{
747
    if( IsTargetDirty( TARGET_CACHED ) || IsTargetDirty( TARGET_NONCACHED ) )
748 749 750 751 752 753
    {
        // TARGET_CACHED and TARGET_NONCACHED have to be redrawn together, as they contain
        // layers that rely on each other (eg. netnames are noncached, but tracks - are cached)
        m_gal->ClearTarget( TARGET_NONCACHED );
        m_gal->ClearTarget( TARGET_CACHED );

754 755
        MarkTargetDirty( TARGET_NONCACHED );
        MarkTargetDirty( TARGET_CACHED );
756
        MarkTargetDirty( TARGET_OVERLAY );
757
    }
758

759 760 761
    if( IsTargetDirty( TARGET_OVERLAY ) )
    {
        m_gal->ClearTarget( TARGET_OVERLAY );
762
    }
763
}
764

765 766 767 768 769 770 771

void VIEW::Redraw()
{
    VECTOR2D screenSize = m_gal->GetScreenPixelSize();
    BOX2I    rect( ToWorld( VECTOR2D( 0, 0 ) ),
                   ToWorld( screenSize ) - ToWorld( VECTOR2D( 0, 0 ) ) );
    rect.Normalize();
772

773
    redrawRect( rect );
774 775

    // All targets were redrawn, so nothing is dirty
776 777 778
    clearTargetDirty( TARGET_CACHED );
    clearTargetDirty( TARGET_NONCACHED );
    clearTargetDirty( TARGET_OVERLAY );
779 780 781 782 783 784 785 786 787
}


VECTOR2D VIEW::GetScreenPixelSize() const
{
    return m_gal->GetScreenPixelSize();
}


788
struct VIEW::clearLayerCache
789
{
790
    clearLayerCache( VIEW* aView ) :
791 792 793 794 795 796
        view( aView )
    {
    }

    void operator()( VIEW_ITEM* aItem )
    {
797
        if( aItem->storesGroups() )
798
        {
799
            aItem->deleteGroups();
800 801 802 803 804 805 806 807 808 809 810 811
        }
    }

    VIEW* view;
};


void VIEW::clearGroupCache()
{
    BOX2I r;

    r.SetMaximum();
812
    clearLayerCache visitor( this );
813

Maciej Suminski's avatar
Maciej Suminski committed
814
    for( LAYER_MAP_ITER i = m_layers.begin(); i != m_layers.end(); ++i )
815
    {
816
        VIEW_LAYER* l = &( ( *i ).second );
817
        l->items->Query( r, visitor );
818
    }
819
}
820 821


822 823
void VIEW::invalidateItem( VIEW_ITEM* aItem, int aUpdateFlags )
{
824 825 826 827
    // updateLayers updates geometry too, so we do not have to update both of them at the same time
    if( aUpdateFlags & VIEW_ITEM::LAYERS )
        updateLayers( aItem );
    else if( aUpdateFlags & VIEW_ITEM::GEOMETRY )
828 829
        updateBbox( aItem );

830 831 832
    int layers[VIEW_MAX_LAYERS], layers_count;
    aItem->ViewGetLayers( layers, layers_count );

833 834 835
    // Iterate through layers used by the item and recache it immediately
    for( int i = 0; i < layers_count; i++ )
    {
836 837
        int layerId = layers[i];

838
        if( aUpdateFlags & ( VIEW_ITEM::GEOMETRY | VIEW_ITEM::LAYERS ) )
839
        {
840
            // Redraw
841 842
            if( IsCached( layerId ) )
                updateItemGeometry( aItem, layerId );
843 844 845 846
        }
        else if( aUpdateFlags & VIEW_ITEM::COLOR )
        {
            updateItemColor( aItem, layerId );
847 848 849
        }

        // Mark those layers as dirty, so the VIEW will be refreshed
850
        MarkTargetDirty( m_layers[layerId].target );
851 852 853 854
    }
}


855 856 857 858 859 860
void VIEW::sortLayers()
{
    int n = 0;

    m_orderedLayers.resize( m_layers.size() );

Maciej Suminski's avatar
Maciej Suminski committed
861
    for( LAYER_MAP_ITER i = m_layers.begin(); i != m_layers.end(); ++i )
862 863 864 865 866 867 868 869
        m_orderedLayers[n++] = &i->second;

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

    MarkTargetDirty( TARGET_CACHED );
}


870
void VIEW::updateItemColor( VIEW_ITEM* aItem, int aLayer )
871 872 873 874
{
    wxASSERT( (unsigned) aLayer < m_layers.size() );

    // Obtain the color that should be used for coloring the item on the specific layerId
875
    const COLOR4D color = m_painter->GetSettings()->GetColor( aItem, aLayer );
876 877 878 879 880 881 882 883 884 885 886 887 888 889 890 891 892
    int group = aItem->getGroup( aLayer );

    // Change the color, only if it has group assigned
    if( group >= 0 )
        m_gal->ChangeGroupColor( group, color );
}


void VIEW::updateItemGeometry( VIEW_ITEM* aItem, int aLayer )
{
    wxASSERT( (unsigned) aLayer < m_layers.size() );
    VIEW_LAYER& l = m_layers.at( aLayer );

    m_gal->SetTarget( l.target );
    m_gal->SetLayerDepth( l.renderingOrder );

    // Redraw the item from scratch
893
    int prevGroup = aItem->getGroup( aLayer );
894

895 896 897
    if( prevGroup >= 0 )
        m_gal->DeleteGroup( prevGroup );

898 899 900 901 902 903 904
    int group = m_gal->BeginGroup();
    aItem->setGroup( aLayer, group );
    m_painter->Draw( static_cast<EDA_ITEM*>( aItem ), aLayer );
    m_gal->EndGroup();
}


905 906 907
void VIEW::updateBbox( VIEW_ITEM* aItem )
{
    int layers[VIEW_MAX_LAYERS], layers_count;
908

909 910 911 912 913 914 915
    aItem->ViewGetLayers( layers, layers_count );

    for( int i = 0; i < layers_count; i++ )
    {
        VIEW_LAYER& l = m_layers[layers[i]];
        l.items->Remove( aItem );
        l.items->Insert( aItem );
916
        MarkTargetDirty( l.target );
917 918 919 920
    }
}


921 922 923 924 925 926
void VIEW::updateLayers( VIEW_ITEM* aItem )
{
    int layers[VIEW_MAX_LAYERS], layers_count;

    // Remove the item from previous layer set
    aItem->getLayers( layers, layers_count );
927

928 929 930 931 932 933 934 935 936 937
    for( int i = 0; i < layers_count; i++ )
    {
        VIEW_LAYER& l = m_layers[layers[i]];
        l.items->Remove( aItem );
        MarkTargetDirty( l.target );
    }

    // Add the item to new layer set
    aItem->ViewGetLayers( layers, layers_count );
    aItem->saveLayers( layers, layers_count );
938

939 940 941 942 943 944 945 946 947
    for( int i = 0; i < layers_count; i++ )
    {
        VIEW_LAYER& l = m_layers[layers[i]];
        l.items->Insert( aItem );
        MarkTargetDirty( l.target );
    }
}


948
bool VIEW::areRequiredLayersEnabled( int aLayerId ) const
949
{
950 951 952 953
    wxASSERT( (unsigned) aLayerId < m_layers.size() );

    std::set<int>::iterator it, it_end;

954
    for( it = m_layers.at( aLayerId ).requiredLayers.begin(),
955
         it_end = m_layers.at( aLayerId ).requiredLayers.end(); it != it_end; ++it )
956
    {
957 958
        // That is enough if just one layer is not enabled
        if( !m_layers.at( *it ).enabled )
959 960 961 962 963 964 965
            return false;
    }

    return true;
}


966
void VIEW::RecacheAllItems( bool aImmediately )
967 968 969 970 971
{
    BOX2I r;

    r.SetMaximum();

972 973 974 975 976
#ifdef __WXDEBUG__
    prof_counter totalRealTime;
    prof_start( &totalRealTime, false );
#endif /* __WXDEBUG__ */

Maciej Suminski's avatar
Maciej Suminski committed
977
    for( LAYER_MAP_ITER i = m_layers.begin(); i != m_layers.end(); ++i )
978
    {
979
        VIEW_LAYER* l = &( ( *i ).second );
980

981
        if( IsCached( l->id ) )
982
        {
983
            m_gal->SetTarget( l->target );
984
            m_gal->SetLayerDepth( l->renderingOrder );
985
            recacheItem visitor( this, m_gal, l->id, aImmediately );
986
            l->items->Query( r, visitor );
987
            MarkTargetDirty( l->target );
988
        }
989
    }
990 991 992 993

#ifdef __WXDEBUG__
    prof_end( &totalRealTime );

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


1000
bool VIEW::IsTargetDirty( int aTarget ) const
1001 1002 1003
{
    wxASSERT( aTarget < TARGETS_NUMBER );

1004 1005 1006 1007 1008
    // Check the target status
    if( m_dirtyTargets[aTarget] )
        return true;

    return false;
1009
}