view.cpp 24.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 PROFILE
38
#include <profile.h>
39
#endif /* PROFILE  */
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
    m_dynamic( aIsDynamic )
49
{
Maciej Suminski's avatar
Maciej Suminski committed
50
    m_needsUpdate.reserve( 32768 );
51

52
    // Redraw everything at the beginning
Maciej Suminski's avatar
Maciej Suminski committed
53
    MarkDirty();
54 55 56 57 58 59 60

    // 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 );
61 62 63 64 65
}


VIEW::~VIEW()
{
Maciej Suminski's avatar
Maciej Suminski committed
66
    BOOST_FOREACH( LAYER_MAP::value_type& l, m_layers )
67 68 69 70
        delete l.second.items;
}


71 72 73 74
void VIEW::AddLayer( int aLayer, bool aDisplayOnly )
{
    if( m_layers.find( aLayer ) == m_layers.end() )
    {
75 76 77
        m_layers[aLayer]                = VIEW_LAYER();
        m_layers[aLayer].id             = aLayer;
        m_layers[aLayer].items          = new VIEW_RTREE();
78
        m_layers[aLayer].renderingOrder = aLayer;
Maciej Suminski's avatar
Maciej Suminski committed
79
        m_layers[aLayer].visible        = true;
80
        m_layers[aLayer].displayOnly    = aDisplayOnly;
81
        m_layers[aLayer].target         = TARGET_CACHED;
82 83 84 85 86 87 88 89 90 91 92
    }

    sortLayers();
}


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

    aItem->ViewGetLayers( layers, layers_count );
93
    aItem->saveLayers( layers, layers_count );
94

95
    for( int i = 0; i < layers_count; ++i )
96
    {
97 98
        VIEW_LAYER& l = m_layers[layers[i]];
        l.items->Insert( aItem );
99
        MarkTargetDirty( l.target );
100 101 102 103
    }

    if( m_dynamic )
        aItem->viewAssign( this );
104 105 106

    if( aItem->viewRequiredUpdate() != VIEW_ITEM::NONE )
        MarkForUpdate( aItem );
107 108 109 110 111 112 113 114
}


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

115 116
    if( aItem->viewRequiredUpdate() != VIEW_ITEM::NONE )    // prevent from updating a removed item
    {
Maciej Suminski's avatar
Maciej Suminski committed
117 118
        std::vector<VIEW_ITEM*>::iterator item = std::find( m_needsUpdate.begin(),
                                                            m_needsUpdate.end(), aItem );
119 120 121 122 123

        if( item != m_needsUpdate.end() )
            m_needsUpdate.erase( item );
    }

124 125 126 127
    int layers[VIEW::VIEW_MAX_LAYERS], layers_count;
    aItem->getLayers( layers, layers_count );

    for( int i = 0; i < layers_count; ++i )
128
    {
129 130
        VIEW_LAYER& l = m_layers[layers[i]];
        l.items->Remove( aItem );
131 132 133 134
        MarkTargetDirty( l.target );

        // Clear the GAL cache
        int prevGroup = aItem->getGroup( layers[i] );
135

136 137
        if( prevGroup >= 0 )
            m_gal->DeleteGroup( prevGroup );
138
    }
139 140

    aItem->deleteGroups();
141 142 143
}


144 145 146 147 148 149 150 151 152 153 154 155
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 );
}


156
// stupid C++... python lambda would do this in one line
157 158 159 160 161 162 163 164 165 166
template <class Container>
struct queryVisitor
{
    typedef typename Container::value_type item_type;

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

167
    bool operator()( VIEW_ITEM* aItem )
168 169
    {
        if( aItem->ViewIsVisible() )
Maciej Suminski's avatar
Maciej Suminski committed
170
            m_cont.push_back( VIEW::LAYER_ITEM_PAIR( aItem, m_layer ) );
171 172

        return true;
173 174 175 176 177 178 179
    }

    Container&  m_cont;
    int         m_layer;
};


Maciej Suminski's avatar
Maciej Suminski committed
180
int VIEW::Query( const BOX2I& aRect, std::vector<LAYER_ITEM_PAIR>& aResult ) const
181 182 183 184
{
    if( m_orderedLayers.empty() )
        return 0;

Maciej Suminski's avatar
Maciej Suminski committed
185
    std::vector<VIEW_LAYER*>::const_reverse_iterator i;
186 187 188 189 190 191 192 193 194

    // 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
195
        queryVisitor<std::vector<LAYER_ITEM_PAIR> > visitor( aResult, ( *i )->id );
196 197 198 199 200 201 202 203 204
        ( *i )->items->Query( aRect, visitor );
    }

    return aResult.size();
}


VECTOR2D VIEW::ToWorld( const VECTOR2D& aCoord, bool aAbsolute ) const
{
205
    const MATRIX3x3D& matrix = m_gal->GetScreenWorldMatrix();
206 207 208 209 210 211 212 213

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


214 215 216 217 218 219 220 221
double VIEW::ToWorld( double aSize ) const
{
    const MATRIX3x3D& matrix = m_gal->GetScreenWorldMatrix();

    return matrix.GetScale().x * aSize;
}


222 223
VECTOR2D VIEW::ToScreen( const VECTOR2D& aCoord, bool aAbsolute ) const
{
224
    const MATRIX3x3D& matrix = m_gal->GetWorldScreenMatrix();
225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242

    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 )
{
243
    wxASSERT_MSG( false, wxT( "This is not implemented" ) );
244 245 246 247 248 249 250
}


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

251
    // clear group numbers, so everything is going to be recached
252
    clearGroupCache();
253

254
    // every target has to be refreshed
255
    MarkDirty();
256

257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274
    // force the new GAL to display the current viewport.
    SetCenter( m_center );
    SetScale( m_scale );
}


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

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

    return rect.Normalize();
}


275
void VIEW::SetViewport( const BOX2D& aViewport )
276 277
{
    VECTOR2D ssize  = ToWorld( m_gal->GetScreenPixelSize(), false );
278 279 280

    wxASSERT( ssize.x > 0 && ssize.y > 0 );

281 282
    VECTOR2D centre = aViewport.Centre();
    VECTOR2D vsize  = aViewport.GetSize();
283
    double   zoom   = 1.0 / std::max( fabs( vsize.x / ssize.x ), fabs( vsize.y / ssize.y ) );
284 285 286 287 288 289 290 291

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


void VIEW::SetMirror( bool aMirrorX, bool aMirrorY )
{
292
    m_gal->SetFlip( aMirrorX, aMirrorY );
293 294 295 296 297 298 299 300 301 302 303 304 305 306
}


void VIEW::SetScale( double aScale, const VECTOR2D& aAnchor )
{
    VECTOR2D a = ToScreen( aAnchor );

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

    VECTOR2D delta = ToWorld( a ) - aAnchor;

    SetCenter( m_center - delta );
    m_scale = aScale;
307 308

    // Redraw everything after the viewport has changed
309
    MarkDirty();
310 311 312 313 314 315
}


void VIEW::SetCenter( const VECTOR2D& aCenter )
{
    m_center = aCenter;
316

317 318
    m_gal->SetLookAtPoint( m_center );
    m_gal->ComputeWorldScreenMatrix();
319 320

    // Redraw everything after the viewport has changed
321
    MarkDirty();
322 323 324
}


325
void VIEW::SetLayerOrder( int aLayer, int aRenderingOrder )
326
{
327
    m_layers[aLayer].renderingOrder = aRenderingOrder;
328

329 330
    sortLayers();
}
331

332

333 334
int VIEW::GetLayerOrder( int aLayer ) const
{
335
    return m_layers.at( aLayer ).renderingOrder;
336 337 338
}


339
void VIEW::SortLayers( int aLayers[], int& aCount ) const
340
{
341
    int maxLay, maxOrd, maxIdx;
342

343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363
    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;
    }
364 365 366
}


367 368 369
struct VIEW::updateItemsColor
{
    updateItemsColor( int aLayer, PAINTER* aPainter, GAL* aGal ) :
370
        layer( aLayer ), painter( aPainter ), gal( aGal )
371 372 373
    {
    }

374
    bool operator()( VIEW_ITEM* aItem )
375 376
    {
        // Obtain the color that should be used for coloring the item
377
        const COLOR4D color = painter->GetSettings()->GetColor( aItem, layer );
378 379
        int group = aItem->getGroup( layer );

380
        if( group >= 0 )
381
            gal->ChangeGroupColor( group, color );
382 383

        return true;
384 385 386 387 388 389 390 391 392 393
    }

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


void VIEW::UpdateLayerColor( int aLayer )
{
394
    // There is no point in updating non-cached layers
395
    if( !IsCached( aLayer ) )
396 397
        return;

398 399 400 401 402 403
    BOX2I r;

    r.SetMaximum();

    updateItemsColor visitor( aLayer, m_painter, m_gal );
    m_layers[aLayer].items->Query( r, visitor );
404
    MarkTargetDirty( m_layers[aLayer].target );
405 406 407 408 409 410 411 412 413
}


void VIEW::UpdateAllLayersColor()
{
    BOX2I r;

    r.SetMaximum();

Maciej Suminski's avatar
Maciej Suminski committed
414
    for( LAYER_MAP_ITER i = m_layers.begin(); i != m_layers.end(); ++i )
415 416 417
    {
        VIEW_LAYER* l = &( ( *i ).second );

418
        // There is no point in updating non-cached layers
419
        if( !IsCached( l->id ) )
420 421 422
            continue;

        updateItemsColor visitor( l->id, m_painter, m_gal );
423 424
        l->items->Query( r, visitor );
    }
425 426

    MarkDirty();
427 428 429
}


430 431 432 433 434 435 436
struct VIEW::changeItemsDepth
{
    changeItemsDepth( int aLayer, int aDepth, GAL* aGal ) :
        layer( aLayer ), depth( aDepth ), gal( aGal )
    {
    }

437
    bool operator()( VIEW_ITEM* aItem )
438 439 440 441 442
    {
        int group = aItem->getGroup( layer );

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

        return true;
445 446 447 448 449 450 451 452 453
    }

    int layer, depth;
    GAL* gal;
};


void VIEW::ChangeLayerDepth( int aLayer, int aDepth )
{
454
    // There is no point in updating non-cached layers
455
    if( !IsCached( aLayer ) )
456 457
        return;

458 459 460 461 462 463
    BOX2I r;

    r.SetMaximum();

    changeItemsDepth visitor( aLayer, aDepth, m_gal );
    m_layers[aLayer].items->Query( r, visitor );
464
    MarkTargetDirty( m_layers[aLayer].target );
465 466
}

467 468

int VIEW::GetTopLayer() const
469 470 471 472 473 474 475
{
    if( m_topLayers.size() == 0 )
        return 0;

    return *m_topLayers.begin();
}

476

477
void VIEW::SetTopLayer( int aLayer, bool aEnabled )
478
{
479
    if( aEnabled )
480
    {
481 482
        if( m_topLayers.count( aLayer ) == 1 )
            return;
483

484 485 486 487 488 489 490
        m_topLayers.insert( aLayer );

        // Move the layer closer to front
        if( m_enableOrderModifier )
            m_layers[aLayer].renderingOrder += TOP_LAYER_MODIFIER;
    }
    else
491
    {
492 493
        if( m_topLayers.count( aLayer ) == 0 )
            return;
494

495
        m_topLayers.erase( aLayer );
496

497 498 499 500 501 502 503 504 505
        // Restore the previous rendering order
        if( m_enableOrderModifier )
            m_layers[aLayer].renderingOrder -= TOP_LAYER_MODIFIER;
    }
}


void VIEW::EnableTopLayer( bool aEnable )
{
506 507 508
    if( aEnable == m_enableOrderModifier )
        return;

509 510 511
    m_enableOrderModifier = aEnable;

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

513 514 515 516
    if( aEnable )
    {
        for( it = m_topLayers.begin(); it != m_topLayers.end(); ++it )
            m_layers[*it].renderingOrder += TOP_LAYER_MODIFIER;
517 518 519
    }
    else
    {
520 521
        for( it = m_topLayers.begin(); it != m_topLayers.end(); ++it )
            m_layers[*it].renderingOrder -= TOP_LAYER_MODIFIER;
522
    }
523 524 525

    UpdateAllLayersOrder();
    UpdateAllLayersColor();
526 527 528
}


529
void VIEW::ClearTopLayers()
530
{
531
    std::set<unsigned int>::iterator it;
532

533
    if( m_enableOrderModifier )
534
    {
535 536 537
        // 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;
538
    }
539 540 541 542 543 544 545

    m_topLayers.clear();
}


void VIEW::UpdateAllLayersOrder()
{
546
    sortLayers();
547

Maciej Suminski's avatar
Maciej Suminski committed
548
    BOOST_FOREACH( LAYER_MAP::value_type& l, m_layers )
549 550 551
    {
        ChangeLayerDepth( l.first, l.second.renderingOrder );
    }
552 553

    MarkDirty();
554 555 556
}


557 558
struct VIEW::drawItem
{
Maciej Suminski's avatar
Maciej Suminski committed
559 560
    drawItem( VIEW* aView, int aLayer ) :
        view( aView ), layer( aLayer )
561 562 563
    {
    }

564
    bool operator()( VIEW_ITEM* aItem )
565
    {
566 567
        // Conditions that have te be fulfilled for an item to be drawn
        bool drawCondition = aItem->ViewIsVisible() &&
Maciej Suminski's avatar
Maciej Suminski committed
568
                             aItem->ViewGetLOD( layer ) < view->m_scale;
569
        if( !drawCondition )
570
            return true;
571

Maciej Suminski's avatar
Maciej Suminski committed
572
        view->draw( aItem, layer );
573 574

        return true;
575 576
    }

577
    VIEW* view;
578
    int layer, layers[VIEW_MAX_LAYERS];
579 580
};

581

582 583 584 585
void VIEW::redrawRect( const BOX2I& aRect )
{
    BOOST_FOREACH( VIEW_LAYER* l, m_orderedLayers )
    {
Maciej Suminski's avatar
Maciej Suminski committed
586
        if( l->visible && IsTargetDirty( l->target ) && areRequiredLayersEnabled( l->id ) )
587
        {
Maciej Suminski's avatar
Maciej Suminski committed
588
            drawItem drawFunc( this, l->id );
589

590
            m_gal->SetTarget( l->target );
591
            m_gal->SetLayerDepth( l->renderingOrder );
592 593
            l->items->Query( aRect, drawFunc );
        }
594 595 596
    }
}

597

Maciej Suminski's avatar
Maciej Suminski committed
598
void VIEW::draw( VIEW_ITEM* aItem, int aLayer, bool aImmediate )
599
{
600
    if( IsCached( aLayer ) && !aImmediate )
601 602 603 604 605 606 607 608 609 610 611 612
    {
        // 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 );
613

614
            if( !m_painter->Draw( aItem, aLayer ) )
615
                aItem->ViewDraw( aLayer, m_gal ); // Alternative drawing method
616

617 618 619 620 621 622 623
            m_gal->EndGroup();
        }
    }
    else
    {
        // Immediate mode
        if( !m_painter->Draw( aItem, aLayer ) )
624
            aItem->ViewDraw( aLayer, m_gal );  // Alternative drawing method
625 626 627 628
    }
}


Maciej Suminski's avatar
Maciej Suminski committed
629
void VIEW::draw( VIEW_ITEM* aItem, bool aImmediate )
630 631
{
    int layers[VIEW_MAX_LAYERS], layers_count;
632

633
    aItem->ViewGetLayers( layers, layers_count );
Maciej Suminski's avatar
Maciej Suminski committed
634

635
    // Sorting is needed for drawing order dependent GALs (like Cairo)
636 637 638 639
    SortLayers( layers, layers_count );

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


Maciej Suminski's avatar
Maciej Suminski committed
646
void VIEW::draw( VIEW_GROUP* aGroup, bool aImmediate )
647 648
{
    std::set<VIEW_ITEM*>::const_iterator it;
649

650 651
    for( it = aGroup->Begin(); it != aGroup->End(); ++it )
        draw( *it, aImmediate );
652
}
653

654

655 656
struct VIEW::unlinkItem
{
657
    bool operator()( VIEW_ITEM* aItem )
658 659
    {
        aItem->m_view = NULL;
660 661

        return true;
662 663 664 665
    }
};


666
struct VIEW::recacheItem
667
{
668
    recacheItem( VIEW* aView, GAL* aGal, int aLayer, bool aImmediately ) :
669 670 671 672
        view( aView ), gal( aGal ), layer( aLayer ), immediately( aImmediately )
    {
    }

673
    bool operator()( VIEW_ITEM* aItem )
674
    {
675
        // Remove previously cached group
Maciej Suminski's avatar
Maciej Suminski committed
676
        int group = aItem->getGroup( layer );
677

Maciej Suminski's avatar
Maciej Suminski committed
678 679
        if( group >= 0 )
            gal->DeleteGroup( group );
680 681 682

        if( immediately )
        {
Maciej Suminski's avatar
Maciej Suminski committed
683
            group = gal->BeginGroup();
684
            aItem->setGroup( layer, group );
685

686
            if( !view->m_painter->Draw( aItem, layer ) )
687
                aItem->ViewDraw( layer, gal ); // Alternative drawing method
688

689 690
            gal->EndGroup();
        }
691 692
        else
        {
693
            aItem->ViewUpdate( VIEW_ITEM::ALL );
694 695
            aItem->setGroup( layer, -1 );
        }
696 697

        return true;
698
    }
699 700 701 702 703

    VIEW* view;
    GAL* gal;
    int layer;
    bool immediately;
704 705 706
};


707 708 709 710 711 712
void VIEW::Clear()
{
    BOX2I r;

    r.SetMaximum();

Maciej Suminski's avatar
Maciej Suminski committed
713
    for( LAYER_MAP_ITER i = m_layers.begin(); i != m_layers.end(); ++i )
714 715 716
    {
        VIEW_LAYER* l = &( ( *i ).second );
        unlinkItem v;
717

718 719 720 721
        if( m_dynamic )
            l->items->Query( r, v );

        l->items->RemoveAll();
722
    }
723

724
    m_gal->ClearCache();
725
    m_needsUpdate.clear();
726 727 728
}


729
void VIEW::ClearTargets()
730
{
731
    if( IsTargetDirty( TARGET_CACHED ) || IsTargetDirty( TARGET_NONCACHED ) )
732 733 734 735 736 737
    {
        // 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 );

738
        MarkDirty();
739
    }
740

741 742 743
    if( IsTargetDirty( TARGET_OVERLAY ) )
    {
        m_gal->ClearTarget( TARGET_OVERLAY );
744
    }
745
}
746

747 748 749

void VIEW::Redraw()
{
750 751 752 753 754
#ifdef PROFILE
    prof_counter totalRealTime;
    prof_start( &totalRealTime );
#endif /* PROFILE */

755 756 757 758
    VECTOR2D screenSize = m_gal->GetScreenPixelSize();
    BOX2I    rect( ToWorld( VECTOR2D( 0, 0 ) ),
                   ToWorld( screenSize ) - ToWorld( VECTOR2D( 0, 0 ) ) );
    rect.Normalize();
759

760
    redrawRect( rect );
761 762

    // All targets were redrawn, so nothing is dirty
Maciej Suminski's avatar
Maciej Suminski committed
763 764 765
    markTargetClean( TARGET_CACHED );
    markTargetClean( TARGET_NONCACHED );
    markTargetClean( TARGET_OVERLAY );
766 767 768 769 770 771

#ifdef PROFILE
    prof_end( &totalRealTime );

    wxLogDebug( wxT( "Redraw: %.1f ms" ), totalRealTime.msecs() );
#endif /* PROFILE */
772 773 774
}


775
const VECTOR2I& VIEW::GetScreenPixelSize() const
776 777 778 779 780
{
    return m_gal->GetScreenPixelSize();
}


781
struct VIEW::clearLayerCache
782
{
783
    clearLayerCache( VIEW* aView ) :
784 785 786 787
        view( aView )
    {
    }

788
    bool operator()( VIEW_ITEM* aItem )
789
    {
790
        aItem->deleteGroups();
791 792

        return true;
793 794 795 796 797 798 799 800 801 802 803
    }

    VIEW* view;
};


void VIEW::clearGroupCache()
{
    BOX2I r;

    r.SetMaximum();
804
    clearLayerCache visitor( this );
805

Maciej Suminski's avatar
Maciej Suminski committed
806
    for( LAYER_MAP_ITER i = m_layers.begin(); i != m_layers.end(); ++i )
807
    {
808
        VIEW_LAYER* l = &( ( *i ).second );
809
        l->items->Query( r, visitor );
810
    }
811
}
812 813


Maciej Suminski's avatar
Maciej Suminski committed
814
void VIEW::invalidateItem( VIEW_ITEM* aItem, int aUpdateFlags )
815
{
816 817 818 819
    // 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 )
820 821
        updateBbox( aItem );

822 823 824
    int layers[VIEW_MAX_LAYERS], layers_count;
    aItem->ViewGetLayers( layers, layers_count );

825
    // Iterate through layers used by the item and recache it immediately
Maciej Suminski's avatar
Maciej Suminski committed
826
    for( int i = 0; i < layers_count; ++i )
827
    {
828 829
        int layerId = layers[i];

Maciej Suminski's avatar
Maciej Suminski committed
830
        if( IsCached( layerId ) )
831
        {
Maciej Suminski's avatar
Maciej Suminski committed
832
            if( aUpdateFlags & ( VIEW_ITEM::GEOMETRY | VIEW_ITEM::LAYERS ) )
833
                updateItemGeometry( aItem, layerId );
Maciej Suminski's avatar
Maciej Suminski committed
834 835
            else if( aUpdateFlags & VIEW_ITEM::COLOR )
                updateItemColor( aItem, layerId );
836 837 838
        }

        // Mark those layers as dirty, so the VIEW will be refreshed
839
        MarkTargetDirty( m_layers[layerId].target );
840
    }
Maciej Suminski's avatar
Maciej Suminski committed
841 842

    aItem->clearUpdateFlags();
843 844 845
}


846 847 848 849 850 851
void VIEW::sortLayers()
{
    int n = 0;

    m_orderedLayers.resize( m_layers.size() );

Maciej Suminski's avatar
Maciej Suminski committed
852
    for( LAYER_MAP_ITER i = m_layers.begin(); i != m_layers.end(); ++i )
853 854 855 856
        m_orderedLayers[n++] = &i->second;

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

857
    MarkDirty();
858 859 860
}


861
void VIEW::updateItemColor( VIEW_ITEM* aItem, int aLayer )
862 863
{
    wxASSERT( (unsigned) aLayer < m_layers.size() );
Maciej Suminski's avatar
Maciej Suminski committed
864
    wxASSERT( IsCached( aLayer ) );
865 866

    // Obtain the color that should be used for coloring the item on the specific layerId
867
    const COLOR4D color = m_painter->GetSettings()->GetColor( aItem, aLayer );
868 869 870 871 872 873 874 875 876 877 878
    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() );
Maciej Suminski's avatar
Maciej Suminski committed
879 880
    wxASSERT( IsCached( aLayer ) );

881 882 883 884 885 886
    VIEW_LAYER& l = m_layers.at( aLayer );

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

    // Redraw the item from scratch
Maciej Suminski's avatar
Maciej Suminski committed
887
    int group = aItem->getGroup( aLayer );
888

Maciej Suminski's avatar
Maciej Suminski committed
889 890
    if( group >= 0 )
        m_gal->DeleteGroup( group );
891

Maciej Suminski's avatar
Maciej Suminski committed
892
    group = m_gal->BeginGroup();
893
    aItem->setGroup( aLayer, group );
894

895
    if( !m_painter->Draw( static_cast<EDA_ITEM*>( aItem ), aLayer ) )
896 897
        aItem->ViewDraw( aLayer, m_gal ); // Alternative drawing method

898 899 900 901
    m_gal->EndGroup();
}


902 903 904
void VIEW::updateBbox( VIEW_ITEM* aItem )
{
    int layers[VIEW_MAX_LAYERS], layers_count;
905

906 907
    aItem->ViewGetLayers( layers, layers_count );

908
    for( int i = 0; i < layers_count; ++i )
909 910 911 912
    {
        VIEW_LAYER& l = m_layers[layers[i]];
        l.items->Remove( aItem );
        l.items->Insert( aItem );
913
        MarkTargetDirty( l.target );
914 915 916 917
    }
}


918 919 920 921 922 923
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 );
924

925
    for( int i = 0; i < layers_count; ++i )
926 927 928 929
    {
        VIEW_LAYER& l = m_layers[layers[i]];
        l.items->Remove( aItem );
        MarkTargetDirty( l.target );
930

Maciej Suminski's avatar
Maciej Suminski committed
931 932 933 934
        if( IsCached( l.id ) )
        {
            // Redraw the item from scratch
            int prevGroup = aItem->getGroup( layers[i] );
935

Maciej Suminski's avatar
Maciej Suminski committed
936 937 938 939 940 941
            if( prevGroup >= 0 )
            {
                m_gal->DeleteGroup( prevGroup );
                aItem->setGroup( l.id, -1 );
            }
        }
942 943 944 945 946
    }

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

948 949 950 951 952 953 954 955 956
    for( int i = 0; i < layers_count; i++ )
    {
        VIEW_LAYER& l = m_layers[layers[i]];
        l.items->Insert( aItem );
        MarkTargetDirty( l.target );
    }
}


957
bool VIEW::areRequiredLayersEnabled( int aLayerId ) const
958
{
959 960 961 962
    wxASSERT( (unsigned) aLayerId < m_layers.size() );

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

963
    for( it = m_layers.at( aLayerId ).requiredLayers.begin(),
964
         it_end = m_layers.at( aLayerId ).requiredLayers.end(); it != it_end; ++it )
965
    {
966
        // That is enough if just one layer is not enabled
967
        if( !m_layers.at( *it ).visible || !areRequiredLayersEnabled( *it ) )
968 969 970 971 972 973 974
            return false;
    }

    return true;
}


975
void VIEW::RecacheAllItems( bool aImmediately )
976 977 978 979 980
{
    BOX2I r;

    r.SetMaximum();

981
#ifdef PROFILE
982
    prof_counter totalRealTime;
983
    prof_start( &totalRealTime );
984
#endif /* PROFILE */
985

Maciej Suminski's avatar
Maciej Suminski committed
986
    for( LAYER_MAP_ITER i = m_layers.begin(); i != m_layers.end(); ++i )
987
    {
988
        VIEW_LAYER* l = &( ( *i ).second );
989

990
        if( IsCached( l->id ) )
991
        {
992
            m_gal->SetTarget( l->target );
993
            m_gal->SetLayerDepth( l->renderingOrder );
994
            recacheItem visitor( this, m_gal, l->id, aImmediately );
995
            l->items->Query( r, visitor );
996
            MarkTargetDirty( l->target );
997
        }
998
    }
999

1000
#ifdef PROFILE
1001 1002
    prof_end( &totalRealTime );

1003
    wxLogDebug( wxT( "RecacheAllItems::immediately: %u %.1f ms" ),
1004
                aImmediately, totalRealTime.msecs() );
1005
#endif /* PROFILE */
1006
}
1007 1008


Maciej Suminski's avatar
Maciej Suminski committed
1009
void VIEW::UpdateItems()
1010
{
Maciej Suminski's avatar
Maciej Suminski committed
1011 1012 1013 1014
    // Update items that need this
    BOOST_FOREACH( VIEW_ITEM* item, m_needsUpdate )
    {
        assert( item->viewRequiredUpdate() != VIEW_ITEM::NONE );
1015

Maciej Suminski's avatar
Maciej Suminski committed
1016 1017
        invalidateItem( item, item->viewRequiredUpdate() );
    }
1018

Maciej Suminski's avatar
Maciej Suminski committed
1019
    m_needsUpdate.clear();
1020
}
1021 1022


1023 1024 1025 1026 1027 1028 1029 1030 1031 1032 1033 1034 1035 1036 1037 1038 1039 1040 1041
struct VIEW::extentsVisitor
{
    BOX2I extents;
    bool first;

    extentsVisitor()
    {
        first = true;
    }

    bool operator()( VIEW_ITEM* aItem )
    {
        if( first )
            extents = aItem->ViewBBox();
        else
            extents.Merge ( aItem->ViewBBox() );
        return false;
    }
};
1042 1043 1044 1045 1046 1047 1048 1049 1050 1051 1052 1053 1054 1055 1056


const BOX2I VIEW::CalculateExtents() 
{
    extentsVisitor v;
    BOX2I fullScene;
    fullScene.SetMaximum();

    BOOST_FOREACH( VIEW_LAYER* l, m_orderedLayers )
    {
        l->items->Query( fullScene, v );
    }
    
    return v.extents;
}