1 /*
2  * This program source code file is part of KiCad, a free EDA CAD application.
3  *
4  * Copyright (C) 2013-2017 CERN
5  * Copyright (C) 2021 KiCad Developers, see AUTHORS.txt for contributors.
6  *
7  * @author Tomasz Wlostowski <tomasz.wlostowski@cern.ch>
8  * @author Maciej Suminski <maciej.suminski@cern.ch>
9  *
10  * This program is free software; you can redistribute it and/or
11  * modify it under the terms of the GNU General Public License
12  * as published by the Free Software Foundation; either version 2
13  * of the License, or (at your option) any later version.
14  *
15  * This program is distributed in the hope that it will be useful,
16  * but WITHOUT ANY WARRANTY; without even the implied warranty of
17  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
18  * GNU General Public License for more details.
19  *
20  * You should have received a copy of the GNU General Public License
21  * along with this program; if not, you may find one here:
22  * http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
23  * or you may search the http://www.gnu.org website for the version 2 license,
24  * or you may write to the Free Software Foundation, Inc.,
25  * 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA
26  */
27 
28 
29 #include <eda_item.h>
30 #include <layer_ids.h>
31 #include <trace_helpers.h>
32 
33 #include <view/view.h>
34 #include <view/view_group.h>
35 #include <view/view_item.h>
36 #include <view/view_rtree.h>
37 #include <view/view_overlay.h>
38 
39 #include <gal/definitions.h>
40 #include <gal/graphics_abstraction_layer.h>
41 #include <painter.h>
42 
43 #include <profile.h>
44 
45 #ifdef KICAD_GAL_PROFILE
46 #include <wx/log.h>
47 #endif
48 
49 namespace KIGFX {
50 
51 class VIEW;
52 
53 class VIEW_ITEM_DATA
54 {
55 public:
VIEW_ITEM_DATA()56     VIEW_ITEM_DATA() :
57         m_view( nullptr ),
58         m_flags( KIGFX::VISIBLE ),
59         m_requiredUpdate( KIGFX::NONE ),
60         m_drawPriority( 0 ),
61         m_groups( nullptr ),
62         m_groupsSize( 0 ) {}
63 
~VIEW_ITEM_DATA()64     ~VIEW_ITEM_DATA()
65     {
66         deleteGroups();
67     }
68 
GetFlags() const69     int GetFlags() const
70     {
71         return m_flags;
72     }
73 
74 private:
75     friend class VIEW;
76 
77     /**
78      * Return layer numbers used by the item.
79      *
80      * @param aLayers[]: output layer index array
81      * @param aCount: number of layer indices in aLayers[]
82      */
getLayers(int * aLayers,int & aCount) const83     void getLayers( int* aLayers, int& aCount ) const
84     {
85         int* layersPtr = aLayers;
86 
87         for( int layer : m_layers )
88             *layersPtr++ = layer;
89 
90         aCount = m_layers.size();
91     }
92 
93     /**
94      * Return number of the group id for the given layer, or -1 in case it was not cached before.
95      *
96      * @param aLayer is the layer number for which group id is queried.
97      * @return group id or -1 in case there is no group id (ie. item is not cached).
98      */
getGroup(int aLayer) const99     int getGroup( int aLayer ) const
100     {
101         for( int i = 0; i < m_groupsSize; ++i )
102         {
103             if( m_groups[i].first == aLayer )
104                 return m_groups[i].second;
105         }
106 
107         return -1;
108     }
109 
110     /**
111      * Set a group id for the item and the layer combination.
112      *
113      * @param aLayer is the layer number.
114      * @param aGroup is the group id.
115      */
setGroup(int aLayer,int aGroup)116     void setGroup( int aLayer, int aGroup )
117     {
118         // Look if there is already an entry for the layer
119         for( int i = 0; i < m_groupsSize; ++i )
120         {
121             if( m_groups[i].first == aLayer )
122             {
123                 m_groups[i].second = aGroup;
124                 return;
125             }
126         }
127 
128         // If there was no entry for the given layer - create one
129         std::pair<int, int>* newGroups = new std::pair<int, int>[m_groupsSize + 1];
130 
131         if( m_groupsSize > 0 )
132         {
133             std::copy( m_groups, m_groups + m_groupsSize, newGroups );
134             delete[] m_groups;
135         }
136 
137         m_groups = newGroups;
138         newGroups[m_groupsSize++] = { aLayer, aGroup };
139     }
140 
141 
142     /**
143      * Remove all of the stored group ids. Forces recaching of the item.
144      */
deleteGroups()145     void deleteGroups()
146     {
147         delete[] m_groups;
148         m_groups = nullptr;
149         m_groupsSize = 0;
150     }
151 
152 
153     /**
154      * Return information if the item uses at least one group id (ie. if it is cached at all).
155      *
156      * @returns true in case it is cached at least for one layer.
157      */
storesGroups() const158     inline bool storesGroups() const
159     {
160         return m_groupsSize > 0;
161     }
162 
163 
164     /**
165      * Reorder the stored groups (to facilitate reordering of layers).
166      *
167      * @see VIEW::ReorderLayerData
168      *
169      * @param aReorderMap is the mapping of old to new layer ids
170      */
reorderGroups(std::unordered_map<int,int> aReorderMap)171     void reorderGroups( std::unordered_map<int, int> aReorderMap )
172     {
173         for( int i = 0; i < m_groupsSize; ++i )
174         {
175             int orig_layer = m_groups[i].first;
176             int new_layer = orig_layer;
177 
178             try
179             {
180                 new_layer = aReorderMap.at( orig_layer );
181             }
182             catch( const std::out_of_range& )
183             {}
184 
185             m_groups[i].first = new_layer;
186         }
187     }
188 
189     /**
190      * Save layers used by the item.
191      *
192      * @param aLayers is an array containing layer numbers to be saved.
193      * @param aCount is the size of the array.
194      */
saveLayers(int * aLayers,int aCount)195     void saveLayers( int* aLayers, int aCount )
196     {
197         m_layers.clear();
198 
199         for( int i = 0; i < aCount; ++i )
200         {
201             // this fires on some eagle board after EAGLE_PLUGIN::Load()
202             wxASSERT( unsigned( aLayers[i] ) <= unsigned( VIEW::VIEW_MAX_LAYERS ) );
203 
204             m_layers.push_back( aLayers[i] );
205         }
206     }
207 
208     /**
209      * Return current update flag for an item.
210      */
requiredUpdate() const211     int requiredUpdate() const
212     {
213         return m_requiredUpdate;
214     }
215 
216     /**
217      * Mark an item as already updated, so it is not going to be redrawn.
218      */
clearUpdateFlags()219     void clearUpdateFlags()
220     {
221         m_requiredUpdate = NONE;
222     }
223 
224     /**
225      * Return if the item should be drawn or not.
226      */
isRenderable() const227     bool isRenderable() const
228     {
229         return m_flags == VISIBLE;
230     }
231 
232     VIEW*                m_view;             ///< Current dynamic view the item is assigned to.
233     int                  m_flags;            ///< Visibility flags
234     int                  m_requiredUpdate;   ///< Flag required for updating
235     int                  m_drawPriority;     ///< Order to draw this item in a layer, lowest first
236 
237     std::pair<int, int>* m_groups;           ///< layer_number:group_id pairs for each layer the
238                                              ///< item occupies.
239     int                  m_groupsSize;
240 
241     std::vector<int>     m_layers;           /// Stores layer numbers used by the item.
242 };
243 
244 
OnDestroy(VIEW_ITEM * aItem)245 void VIEW::OnDestroy( VIEW_ITEM* aItem )
246 {
247     VIEW_ITEM_DATA* data = aItem->viewPrivData();
248 
249     if( !data )
250         return;
251 
252     if( data->m_view )
253         data->m_view->VIEW::Remove( aItem );
254 
255     delete data;
256     aItem->ClearViewPrivData();
257 }
258 
259 
VIEW(bool aIsDynamic)260 VIEW::VIEW( bool aIsDynamic ) :
261     m_enableOrderModifier( true ),
262     m_scale( 4.0 ),
263     m_minScale( 0.2 ), m_maxScale( 50000.0 ),
264     m_mirrorX( false ), m_mirrorY( false ),
265     m_painter( nullptr ),
266     m_gal( nullptr ),
267     m_dynamic( aIsDynamic ),
268     m_useDrawPriority( false ),
269     m_nextDrawPriority( 0 ),
270     m_reverseDrawOrder( false )
271 {
272     // Set m_boundary to define the max area size. The default area size
273     // is defined here as the max value of a int.
274     // this is a default value acceptable for Pcbnew and Gerbview, but too large for Eeschema.
275     // So in eeschema a call to SetBoundary() with a smaller value will be needed.
276     typedef std::numeric_limits<int> coord_limits;
277     double pos = coord_limits::lowest() / 2 + coord_limits::epsilon();
278     double size = coord_limits::max() - coord_limits::epsilon();
279     m_boundary.SetOrigin( pos, pos );
280     m_boundary.SetSize( size, size );
281 
282     m_allItems.reset( new std::vector<VIEW_ITEM*> );
283     m_allItems->reserve( 32768 );
284 
285     // Redraw everything at the beginning
286     MarkDirty();
287 
288     m_layers.reserve( VIEW_MAX_LAYERS );
289 
290     // View uses layers to display EDA_ITEMs (item may be displayed on several layers, for example
291     // pad may be shown on pad, pad hole and solder paste layers). There are usual copper layers
292     // (eg. F.Cu, B.Cu, internal and so on) and layers for displaying objects such as texts,
293     // silkscreen, pads, vias, etc.
294     for( int ii = 0; ii < VIEW_MAX_LAYERS; ++ii )
295     {
296         m_layers.emplace_back();
297         m_layers[ii].items          = std::make_shared<VIEW_RTREE>();
298         m_layers[ii].id             = ii;
299         m_layers[ii].renderingOrder = ii;
300         m_layers[ii].visible        = true;
301         m_layers[ii].displayOnly    = false;
302         m_layers[ii].diffLayer      = false;
303         m_layers[ii].hasNegatives   = false;
304         m_layers[ii].target         = TARGET_CACHED;
305     }
306 
307     sortLayers();
308 
309     m_preview.reset( new KIGFX::VIEW_GROUP() );
310     Add( m_preview.get() );
311 }
312 
313 
~VIEW()314 VIEW::~VIEW()
315 {
316     Remove( m_preview.get() );
317 }
318 
319 
Add(VIEW_ITEM * aItem,int aDrawPriority)320 void VIEW::Add( VIEW_ITEM* aItem, int aDrawPriority )
321 {
322     int layers[VIEW_MAX_LAYERS], layers_count;
323 
324     if( aDrawPriority < 0 )
325         aDrawPriority = m_nextDrawPriority++;
326 
327     if( !aItem->m_viewPrivData )
328         aItem->m_viewPrivData = new VIEW_ITEM_DATA;
329 
330     aItem->m_viewPrivData->m_view = this;
331     aItem->m_viewPrivData->m_drawPriority = aDrawPriority;
332 
333     aItem->ViewGetLayers( layers, layers_count );
334     aItem->viewPrivData()->saveLayers( layers, layers_count );
335 
336     m_allItems->push_back( aItem );
337 
338     for( int i = 0; i < layers_count; ++i )
339     {
340         VIEW_LAYER& l = m_layers[layers[i]];
341         l.items->Insert( aItem );
342         MarkTargetDirty( l.target );
343     }
344 
345     SetVisible( aItem, true );
346     Update( aItem, KIGFX::INITIAL_ADD );
347 }
348 
349 
Remove(VIEW_ITEM * aItem)350 void VIEW::Remove( VIEW_ITEM* aItem )
351 {
352     if( !aItem )
353         return;
354 
355     auto viewData = aItem->viewPrivData();
356 
357     if( !viewData )
358         return;
359 
360     wxCHECK( viewData->m_view == this, /*void*/ );
361     auto item = std::find( m_allItems->begin(), m_allItems->end(), aItem );
362 
363     if( item != m_allItems->end() )
364     {
365         m_allItems->erase( item );
366         viewData->clearUpdateFlags();
367     }
368 
369     int layers[VIEW::VIEW_MAX_LAYERS], layers_count;
370     viewData->getLayers( layers, layers_count );
371 
372     for( int i = 0; i < layers_count; ++i )
373     {
374         VIEW_LAYER& l = m_layers[layers[i]];
375         l.items->Remove( aItem );
376         MarkTargetDirty( l.target );
377 
378         // Clear the GAL cache
379         int prevGroup = viewData->getGroup( layers[i] );
380 
381         if( prevGroup >= 0 )
382             m_gal->DeleteGroup( prevGroup );
383     }
384 
385     viewData->deleteGroups();
386     viewData->m_view = nullptr;
387 }
388 
389 
SetRequired(int aLayerId,int aRequiredId,bool aRequired)390 void VIEW::SetRequired( int aLayerId, int aRequiredId, bool aRequired )
391 {
392     wxCHECK( (unsigned) aLayerId < m_layers.size(), /*void*/ );
393     wxCHECK( (unsigned) aRequiredId < m_layers.size(), /*void*/ );
394 
395     if( aRequired )
396         m_layers[aLayerId].requiredLayers.insert( aRequiredId );
397     else
398         m_layers[aLayerId].requiredLayers.erase( aRequired );
399 }
400 
401 
402 // stupid C++... python lambda would do this in one line
403 template <class CONTAINER>
404 struct QUERY_VISITOR
405 {
406     typedef typename CONTAINER::value_type item_type;
407 
QUERY_VISITORKIGFX::QUERY_VISITOR408     QUERY_VISITOR( CONTAINER& aCont, int aLayer ) :
409         m_cont( aCont ), m_layer( aLayer )
410     {
411     }
412 
operator ()KIGFX::QUERY_VISITOR413     bool operator()( VIEW_ITEM* aItem )
414     {
415         if( aItem->viewPrivData()->GetFlags() & VISIBLE )
416             m_cont.push_back( VIEW::LAYER_ITEM_PAIR( aItem, m_layer ) );
417 
418         return true;
419     }
420 
421     CONTAINER&  m_cont;
422     int         m_layer;
423 };
424 
425 
Query(const BOX2I & aRect,std::vector<LAYER_ITEM_PAIR> & aResult) const426 int VIEW::Query( const BOX2I& aRect, std::vector<LAYER_ITEM_PAIR>& aResult ) const
427 {
428     if( m_orderedLayers.empty() )
429         return 0;
430 
431     std::vector<VIEW_LAYER*>::const_reverse_iterator i;
432 
433     // execute queries in reverse direction, so that items that are on the top of
434     // the rendering stack are returned first.
435     for( i = m_orderedLayers.rbegin(); i != m_orderedLayers.rend(); ++i )
436     {
437         // ignore layers that do not contain actual items (i.e. the selection box, menus, floats)
438         if( ( *i )->displayOnly || !( *i )->visible )
439             continue;
440 
441         QUERY_VISITOR<std::vector<LAYER_ITEM_PAIR> > visitor( aResult, ( *i )->id );
442         ( *i )->items->Query( aRect, visitor );
443     }
444 
445     return aResult.size();
446 }
447 
448 
ToWorld(const VECTOR2D & aCoord,bool aAbsolute) const449 VECTOR2D VIEW::ToWorld( const VECTOR2D& aCoord, bool aAbsolute ) const
450 {
451     const MATRIX3x3D& matrix = m_gal->GetScreenWorldMatrix();
452 
453     if( aAbsolute )
454         return VECTOR2D( matrix * aCoord );
455     else
456         return VECTOR2D( matrix.GetScale().x * aCoord.x, matrix.GetScale().y * aCoord.y );
457 }
458 
459 
ToWorld(double aSize) const460 double VIEW::ToWorld( double aSize ) const
461 {
462     const MATRIX3x3D& matrix = m_gal->GetScreenWorldMatrix();
463 
464     return fabs( matrix.GetScale().x * aSize );
465 }
466 
467 
ToScreen(const VECTOR2D & aCoord,bool aAbsolute) const468 VECTOR2D VIEW::ToScreen( const VECTOR2D& aCoord, bool aAbsolute ) const
469 {
470     const MATRIX3x3D& matrix = m_gal->GetWorldScreenMatrix();
471 
472     if( aAbsolute )
473         return VECTOR2D( matrix * aCoord );
474     else
475         return VECTOR2D( matrix.GetScale().x * aCoord.x, matrix.GetScale().y * aCoord.y );
476 }
477 
478 
ToScreen(double aSize) const479 double VIEW::ToScreen( double aSize ) const
480 {
481     const MATRIX3x3D& matrix = m_gal->GetWorldScreenMatrix();
482 
483     return matrix.GetScale().x * aSize;
484 }
485 
486 
CopySettings(const VIEW * aOtherView)487 void VIEW::CopySettings( const VIEW* aOtherView )
488 {
489     wxASSERT_MSG( false, wxT( "This is not implemented" ) );
490 }
491 
492 
SetGAL(GAL * aGal)493 void VIEW::SetGAL( GAL* aGal )
494 {
495     bool recacheGroups = ( m_gal != nullptr );    // recache groups only if GAL is reassigned
496     m_gal = aGal;
497 
498     // clear group numbers, so everything is going to be recached
499     if( recacheGroups )
500         clearGroupCache();
501 
502     // every target has to be refreshed
503     MarkDirty();
504 
505     // force the new GAL to display the current viewport.
506     SetCenter( m_center );
507     SetScale( m_scale );
508     SetMirror( m_mirrorX, m_mirrorY );
509 }
510 
511 
GetViewport() const512 BOX2D VIEW::GetViewport() const
513 {
514     BOX2D    rect;
515     VECTOR2D screenSize = m_gal->GetScreenPixelSize();
516 
517     rect.SetOrigin( ToWorld( VECTOR2D( 0, 0 ) ) );
518     rect.SetEnd( ToWorld( screenSize ) );
519 
520     return rect.Normalize();
521 }
522 
523 
SetViewport(const BOX2D & aViewport)524 void VIEW::SetViewport( const BOX2D& aViewport )
525 {
526     VECTOR2D ssize = ToWorld( m_gal->GetScreenPixelSize(), false );
527 
528     wxCHECK( ssize.x > 0 && ssize.y > 0, /*void*/ );
529 
530     VECTOR2D centre = aViewport.Centre();
531     VECTOR2D vsize  = aViewport.GetSize();
532     double   zoom   = 1.0 / std::max( fabs( vsize.x / ssize.x ), fabs( vsize.y / ssize.y ) );
533 
534     SetCenter( centre );
535     SetScale( GetScale() * zoom );
536 }
537 
538 
SetMirror(bool aMirrorX,bool aMirrorY)539 void VIEW::SetMirror( bool aMirrorX, bool aMirrorY )
540 {
541     wxASSERT_MSG( !aMirrorY, _( "Mirroring for Y axis is not supported yet" ) );
542 
543     m_mirrorX = aMirrorX;
544     m_mirrorY = aMirrorY;
545     m_gal->SetFlip( aMirrorX, aMirrorY );
546 
547     // Redraw everything
548     MarkDirty();
549 }
550 
551 
SetScale(double aScale,VECTOR2D aAnchor)552 void VIEW::SetScale( double aScale, VECTOR2D aAnchor )
553 {
554     if( aAnchor == VECTOR2D( 0, 0 ) )
555         aAnchor = m_center;
556 
557     VECTOR2D a = ToScreen( aAnchor );
558 
559     if( aScale < m_minScale )
560         m_scale = m_minScale;
561     else if( aScale > m_maxScale )
562         m_scale = m_maxScale;
563     else
564         m_scale = aScale;
565 
566     m_gal->SetZoomFactor( m_scale );
567     m_gal->ComputeWorldScreenMatrix();
568 
569     VECTOR2D delta = ToWorld( a ) - aAnchor;
570 
571     SetCenter( m_center - delta );
572 
573     // Redraw everything after the viewport has changed
574     MarkDirty();
575 }
576 
577 
SetCenter(const VECTOR2D & aCenter)578 void VIEW::SetCenter( const VECTOR2D& aCenter )
579 {
580     m_center = aCenter;
581 
582     if( !m_boundary.Contains( aCenter ) )
583     {
584         if( m_center.x < m_boundary.GetLeft() )
585             m_center.x = m_boundary.GetLeft();
586         else if( aCenter.x > m_boundary.GetRight() )
587             m_center.x = m_boundary.GetRight();
588 
589         if( m_center.y < m_boundary.GetTop() )
590             m_center.y = m_boundary.GetTop();
591         else if( m_center.y > m_boundary.GetBottom() )
592             m_center.y = m_boundary.GetBottom();
593     }
594 
595     m_gal->SetLookAtPoint( m_center );
596     m_gal->ComputeWorldScreenMatrix();
597 
598     // Redraw everything after the viewport has changed
599     MarkDirty();
600 }
601 
602 
SetCenter(const VECTOR2D & aCenter,const std::vector<BOX2D> & obscuringScreenRects)603 void VIEW::SetCenter( const VECTOR2D& aCenter, const std::vector<BOX2D>& obscuringScreenRects )
604 {
605     if( obscuringScreenRects.empty() )
606         return SetCenter( aCenter );
607 
608     BOX2D          screenRect( { 0, 0 }, m_gal->GetScreenPixelSize() );
609     SHAPE_POLY_SET unobscuredPoly( screenRect );
610     VECTOR2D       unobscuredCenter = screenRect.Centre();
611 
612     for( const BOX2D& obscuringScreenRect : obscuringScreenRects )
613     {
614         SHAPE_POLY_SET obscuringPoly( obscuringScreenRect );
615         unobscuredPoly.BooleanSubtract( obscuringPoly, SHAPE_POLY_SET::PM_FAST );
616     }
617 
618     /*
619      * Perform a step-wise deflate to find the center of the largest unobscured area
620      */
621 
622     BOX2I bbox = unobscuredPoly.BBox();
623     int   step = std::min( bbox.GetWidth(), bbox.GetHeight() ) / 10;
624 
625     while( !unobscuredPoly.IsEmpty() )
626     {
627         unobscuredCenter = (wxPoint) unobscuredPoly.BBox().Centre();
628         unobscuredPoly.Deflate( step, 4 );
629     }
630 
631     SetCenter( aCenter - ToWorld( unobscuredCenter - screenRect.Centre(), false ) );
632 }
633 
634 
SetLayerOrder(int aLayer,int aRenderingOrder)635 void VIEW::SetLayerOrder( int aLayer, int aRenderingOrder )
636 {
637     m_layers[aLayer].renderingOrder = aRenderingOrder;
638 
639     sortLayers();
640 }
641 
642 
GetLayerOrder(int aLayer) const643 int VIEW::GetLayerOrder( int aLayer ) const
644 {
645     return m_layers.at( aLayer ).renderingOrder;
646 }
647 
648 
SortLayers(int aLayers[],int & aCount) const649 void VIEW::SortLayers( int aLayers[], int& aCount ) const
650 {
651     int maxLay, maxOrd, maxIdx;
652 
653     for( int i = 0; i < aCount; ++i )
654     {
655         maxLay = aLayers[i];
656         maxOrd = GetLayerOrder( maxLay );
657         maxIdx = i;
658 
659         // Look for the max element in the range (j..aCount)
660         for( int j = i; j < aCount; ++j )
661         {
662             if( maxOrd < GetLayerOrder( aLayers[j] ) )
663             {
664                 maxLay = aLayers[j];
665                 maxOrd = GetLayerOrder( maxLay );
666                 maxIdx = j;
667             }
668         }
669 
670         // Swap elements
671         aLayers[maxIdx] = aLayers[i];
672         aLayers[i] = maxLay;
673     }
674 }
675 
676 
ReorderLayerData(std::unordered_map<int,int> aReorderMap)677 void VIEW::ReorderLayerData( std::unordered_map<int, int> aReorderMap )
678 {
679     std::vector<VIEW_LAYER> new_map;
680     new_map.reserve( m_layers.size() );
681 
682     for( int ii = 0; ii < VIEW_MAX_LAYERS; ++ii )
683         new_map.emplace_back();
684 
685     for( const VIEW_LAYER& layer : m_layers )
686     {
687         int orig_idx = layer.id;
688         int new_idx = orig_idx;
689 
690         if( aReorderMap.count( orig_idx ) )
691             new_idx = aReorderMap.at( orig_idx );
692 
693         new_map[new_idx] = layer;
694         new_map[new_idx].id = new_idx;
695     }
696 
697     m_layers = new_map;
698 
699     for( VIEW_ITEM* item : *m_allItems )
700     {
701         VIEW_ITEM_DATA* viewData = item->viewPrivData();
702 
703         if( !viewData )
704             continue;
705 
706         int layers[VIEW::VIEW_MAX_LAYERS], layers_count;
707 
708         item->ViewGetLayers( layers, layers_count );
709         viewData->saveLayers( layers, layers_count );
710 
711         viewData->reorderGroups( aReorderMap );
712 
713         viewData->m_requiredUpdate |= COLOR;
714     }
715 
716     UpdateItems();
717 }
718 
719 
720 struct VIEW::UPDATE_COLOR_VISITOR
721 {
UPDATE_COLOR_VISITORKIGFX::VIEW::UPDATE_COLOR_VISITOR722     UPDATE_COLOR_VISITOR( int aLayer, PAINTER* aPainter, GAL* aGal ) :
723         layer( aLayer ),
724         painter( aPainter ),
725         gal( aGal )
726     {
727     }
728 
operator ()KIGFX::VIEW::UPDATE_COLOR_VISITOR729     bool operator()( VIEW_ITEM* aItem )
730     {
731         // Obtain the color that should be used for coloring the item
732         const COLOR4D color = painter->GetSettings()->GetColor( aItem, layer );
733         int           group = aItem->viewPrivData()->getGroup( layer );
734 
735         if( group >= 0 )
736             gal->ChangeGroupColor( group, color );
737 
738         return true;
739     }
740 
741     int layer;
742     PAINTER* painter;
743     GAL* gal;
744 };
745 
746 
UpdateLayerColor(int aLayer)747 void VIEW::UpdateLayerColor( int aLayer )
748 {
749     // There is no point in updating non-cached layers
750     if( !IsCached( aLayer ) )
751         return;
752 
753     BOX2I r;
754 
755     r.SetMaximum();
756 
757     if( m_gal->IsVisible() )
758     {
759         GAL_UPDATE_CONTEXT ctx( m_gal );
760 
761         UPDATE_COLOR_VISITOR visitor( aLayer, m_painter, m_gal );
762         m_layers[aLayer].items->Query( r, visitor );
763         MarkTargetDirty( m_layers[aLayer].target );
764     }
765 }
766 
767 
UpdateAllLayersColor()768 void VIEW::UpdateAllLayersColor()
769 {
770     if( m_gal->IsVisible() )
771     {
772         GAL_UPDATE_CONTEXT ctx( m_gal );
773 
774         for( VIEW_ITEM* item : *m_allItems )
775         {
776             VIEW_ITEM_DATA* viewData = item->viewPrivData();
777 
778             if( !viewData )
779                 continue;
780 
781             int layers[VIEW::VIEW_MAX_LAYERS], layers_count;
782             viewData->getLayers( layers, layers_count );
783 
784             for( int i = 0; i < layers_count; ++i )
785             {
786                 const COLOR4D color = m_painter->GetSettings()->GetColor( item, layers[i] );
787                 int           group = viewData->getGroup( layers[i] );
788 
789                 if( group >= 0 )
790                     m_gal->ChangeGroupColor( group, color );
791             }
792         }
793     }
794 
795     MarkDirty();
796 }
797 
798 
799 struct VIEW::UPDATE_DEPTH_VISITOR
800 {
UPDATE_DEPTH_VISITORKIGFX::VIEW::UPDATE_DEPTH_VISITOR801     UPDATE_DEPTH_VISITOR( int aLayer, int aDepth, GAL* aGal ) :
802         layer( aLayer ),
803         depth( aDepth ),
804         gal( aGal )
805     {
806     }
807 
operator ()KIGFX::VIEW::UPDATE_DEPTH_VISITOR808     bool operator()( VIEW_ITEM* aItem )
809     {
810         int group = aItem->viewPrivData()->getGroup( layer );
811 
812         if( group >= 0 )
813             gal->ChangeGroupDepth( group, depth );
814 
815         return true;
816     }
817 
818     int layer, depth;
819     GAL* gal;
820 };
821 
822 
GetTopLayer() const823 int VIEW::GetTopLayer() const
824 {
825     if( m_topLayers.size() == 0 )
826         return 0;
827 
828     return *m_topLayers.begin();
829 }
830 
831 
SetTopLayer(int aLayer,bool aEnabled)832 void VIEW::SetTopLayer( int aLayer, bool aEnabled )
833 {
834     if( aEnabled )
835     {
836         if( m_topLayers.count( aLayer ) == 1 )
837             return;
838 
839         m_topLayers.insert( aLayer );
840 
841         // Move the layer closer to front
842         if( m_enableOrderModifier )
843             m_layers[aLayer].renderingOrder += TOP_LAYER_MODIFIER;
844     }
845     else
846     {
847         if( m_topLayers.count( aLayer ) == 0 )
848             return;
849 
850         m_topLayers.erase( aLayer );
851 
852         // Restore the previous rendering order
853         if( m_enableOrderModifier )
854             m_layers[aLayer].renderingOrder -= TOP_LAYER_MODIFIER;
855     }
856 }
857 
858 
EnableTopLayer(bool aEnable)859 void VIEW::EnableTopLayer( bool aEnable )
860 {
861     if( aEnable == m_enableOrderModifier )
862         return;
863 
864     m_enableOrderModifier = aEnable;
865 
866     std::set<unsigned int>::iterator it;
867 
868     if( aEnable )
869     {
870         for( it = m_topLayers.begin(); it != m_topLayers.end(); ++it )
871             m_layers[*it].renderingOrder += TOP_LAYER_MODIFIER;
872     }
873     else
874     {
875         for( it = m_topLayers.begin(); it != m_topLayers.end(); ++it )
876             m_layers[*it].renderingOrder -= TOP_LAYER_MODIFIER;
877     }
878 
879     UpdateAllLayersOrder();
880     UpdateAllLayersColor();
881 }
882 
883 
ClearTopLayers()884 void VIEW::ClearTopLayers()
885 {
886     std::set<unsigned int>::iterator it;
887 
888     if( m_enableOrderModifier )
889     {
890         // Restore the previous rendering order for layers that were marked as top
891         for( it = m_topLayers.begin(); it != m_topLayers.end(); ++it )
892             m_layers[*it].renderingOrder -= TOP_LAYER_MODIFIER;
893     }
894 
895     m_topLayers.clear();
896 }
897 
898 
UpdateAllLayersOrder()899 void VIEW::UpdateAllLayersOrder()
900 {
901     sortLayers();
902 
903     if( m_gal->IsVisible() )
904     {
905         GAL_UPDATE_CONTEXT ctx( m_gal );
906 
907         for( VIEW_ITEM* item : *m_allItems )
908         {
909             VIEW_ITEM_DATA* viewData = item->viewPrivData();
910 
911             if( !viewData )
912                 continue;
913 
914             int layers[VIEW::VIEW_MAX_LAYERS], layers_count;
915             viewData->getLayers( layers, layers_count );
916 
917             for( int i = 0; i < layers_count; ++i )
918             {
919                 int group = viewData->getGroup( layers[i] );
920 
921                 if( group >= 0 )
922                     m_gal->ChangeGroupDepth( group, m_layers[layers[i]].renderingOrder );
923             }
924         }
925     }
926 
927     MarkDirty();
928 }
929 
930 
931 struct VIEW::DRAW_ITEM_VISITOR
932 {
DRAW_ITEM_VISITORKIGFX::VIEW::DRAW_ITEM_VISITOR933     DRAW_ITEM_VISITOR( VIEW* aView, int aLayer, bool aUseDrawPriority, bool aReverseDrawOrder ) :
934         view( aView ),
935         layer( aLayer ),
936         useDrawPriority( aUseDrawPriority ),
937         reverseDrawOrder( aReverseDrawOrder )
938     {
939     }
940 
operator ()KIGFX::VIEW::DRAW_ITEM_VISITOR941     bool operator()( VIEW_ITEM* aItem )
942     {
943         wxCHECK( aItem->viewPrivData(), false );
944 
945         // Conditions that have to be fulfilled for an item to be drawn
946         bool drawCondition = aItem->viewPrivData()->isRenderable()
947                                     && aItem->ViewGetLOD( layer, view ) < view->m_scale;
948         if( !drawCondition )
949             return true;
950 
951         if( useDrawPriority )
952             drawItems.push_back( aItem );
953         else
954             view->draw( aItem, layer );
955 
956         return true;
957     }
958 
deferredDrawKIGFX::VIEW::DRAW_ITEM_VISITOR959     void deferredDraw()
960     {
961         if( reverseDrawOrder )
962         {
963             std::sort( drawItems.begin(), drawItems.end(),
964                        []( VIEW_ITEM* a, VIEW_ITEM* b ) -> bool
965                        {
966                            return b->viewPrivData()->m_drawPriority < a->viewPrivData()->m_drawPriority;
967                        });
968         }
969         else
970         {
971             std::sort( drawItems.begin(), drawItems.end(),
972                        []( VIEW_ITEM* a, VIEW_ITEM* b ) -> bool
973                        {
974                            return a->viewPrivData()->m_drawPriority < b->viewPrivData()->m_drawPriority;
975                        });
976         }
977 
978         for( VIEW_ITEM* item : drawItems )
979             view->draw( item, layer );
980     }
981 
982     VIEW* view;
983     int layer, layers[VIEW_MAX_LAYERS];
984     bool useDrawPriority, reverseDrawOrder;
985     std::vector<VIEW_ITEM*> drawItems;
986 };
987 
988 
redrawRect(const BOX2I & aRect)989 void VIEW::redrawRect( const BOX2I& aRect )
990 {
991     for( VIEW_LAYER* l : m_orderedLayers )
992     {
993         if( l->visible && IsTargetDirty( l->target ) && areRequiredLayersEnabled( l->id ) )
994         {
995             DRAW_ITEM_VISITOR drawFunc( this, l->id, m_useDrawPriority, m_reverseDrawOrder );
996 
997             m_gal->SetTarget( l->target );
998             m_gal->SetLayerDepth( l->renderingOrder );
999 
1000             // Differential layer also work for the negatives, since both special layer types
1001             // will composite on separate layers (at least in Cairo)
1002             if( l->diffLayer )
1003                 m_gal->StartDiffLayer();
1004             else if( l->hasNegatives )
1005                 m_gal->StartNegativesLayer();
1006 
1007 
1008             l->items->Query( aRect, drawFunc );
1009 
1010             if( m_useDrawPriority )
1011                 drawFunc.deferredDraw();
1012 
1013             if( l->diffLayer )
1014                 m_gal->EndDiffLayer();
1015             else if( l->hasNegatives )
1016                 m_gal->EndNegativesLayer();
1017         }
1018     }
1019 }
1020 
1021 
draw(VIEW_ITEM * aItem,int aLayer,bool aImmediate)1022 void VIEW::draw( VIEW_ITEM* aItem, int aLayer, bool aImmediate )
1023 {
1024     VIEW_ITEM_DATA* viewData = aItem->viewPrivData();
1025 
1026     if( !viewData )
1027         return;
1028 
1029     if( IsCached( aLayer ) && !aImmediate )
1030     {
1031         // Draw using cached information or create one
1032         int group = viewData->getGroup( aLayer );
1033 
1034         if( group >= 0 )
1035             m_gal->DrawGroup( group );
1036         else
1037             Update( aItem );
1038     }
1039     else
1040     {
1041         // Immediate mode
1042         if( !m_painter->Draw( aItem, aLayer ) )
1043             aItem->ViewDraw( aLayer, this );  // Alternative drawing method
1044     }
1045 }
1046 
1047 
draw(VIEW_ITEM * aItem,bool aImmediate)1048 void VIEW::draw( VIEW_ITEM* aItem, bool aImmediate )
1049 {
1050     int layers[VIEW_MAX_LAYERS], layers_count;
1051 
1052     aItem->ViewGetLayers( layers, layers_count );
1053 
1054     // Sorting is needed for drawing order dependent GALs (like Cairo)
1055     SortLayers( layers, layers_count );
1056 
1057     for( int i = 0; i < layers_count; ++i )
1058     {
1059         m_gal->SetLayerDepth( m_layers.at( layers[i] ).renderingOrder );
1060         draw( aItem, layers[i], aImmediate );
1061     }
1062 }
1063 
1064 
draw(VIEW_GROUP * aGroup,bool aImmediate)1065 void VIEW::draw( VIEW_GROUP* aGroup, bool aImmediate )
1066 {
1067     for( unsigned int i = 0; i < aGroup->GetSize(); i++)
1068         draw( aGroup->GetItem(i), aImmediate );
1069 }
1070 
1071 
1072 struct VIEW::RECACHE_ITEM_VISITOR
1073 {
RECACHE_ITEM_VISITORKIGFX::VIEW::RECACHE_ITEM_VISITOR1074     RECACHE_ITEM_VISITOR( VIEW* aView, GAL* aGal, int aLayer ) :
1075         view( aView ),
1076         gal( aGal ),
1077         layer( aLayer )
1078     {
1079     }
1080 
operator ()KIGFX::VIEW::RECACHE_ITEM_VISITOR1081     bool operator()( VIEW_ITEM* aItem )
1082     {
1083         VIEW_ITEM_DATA* viewData = aItem->viewPrivData();
1084 
1085         if( !viewData )
1086             return false;
1087 
1088         // Remove previously cached group
1089         int group = viewData->getGroup( layer );
1090 
1091         if( group >= 0 )
1092             gal->DeleteGroup( group );
1093 
1094         viewData->setGroup( layer, -1 );
1095         view->Update( aItem );
1096 
1097         return true;
1098     }
1099 
1100     VIEW* view;
1101     GAL* gal;
1102     int layer;
1103 };
1104 
1105 
Clear()1106 void VIEW::Clear()
1107 {
1108     BOX2I r;
1109     r.SetMaximum();
1110     m_allItems->clear();
1111 
1112     for( VIEW_LAYER& layer : m_layers )
1113         layer.items->RemoveAll();
1114 
1115     m_nextDrawPriority = 0;
1116 
1117     m_gal->ClearCache();
1118 }
1119 
1120 
ClearTargets()1121 void VIEW::ClearTargets()
1122 {
1123     if( IsTargetDirty( TARGET_CACHED ) || IsTargetDirty( TARGET_NONCACHED ) )
1124     {
1125         // TARGET_CACHED and TARGET_NONCACHED have to be redrawn together, as they contain
1126         // layers that rely on each other (eg. netnames are noncached, but tracks - are cached)
1127         m_gal->ClearTarget( TARGET_NONCACHED );
1128         m_gal->ClearTarget( TARGET_CACHED );
1129 
1130         MarkDirty();
1131     }
1132 
1133     if( IsTargetDirty( TARGET_OVERLAY ) )
1134     {
1135         m_gal->ClearTarget( TARGET_OVERLAY );
1136     }
1137 }
1138 
1139 
Redraw()1140 void VIEW::Redraw()
1141 {
1142 #ifdef KICAD_GAL_PROFILE
1143     PROF_COUNTER totalRealTime;
1144 #endif /* KICAD_GAL_PROFILE */
1145 
1146     VECTOR2D screenSize = m_gal->GetScreenPixelSize();
1147     BOX2D    rect( ToWorld( VECTOR2D( 0, 0 ) ),
1148                    ToWorld( screenSize ) - ToWorld( VECTOR2D( 0, 0 ) ) );
1149 
1150     rect.Normalize();
1151     BOX2I recti( rect.GetPosition(), rect.GetSize() );
1152 
1153     // The view rtree uses integer positions.  Large screens can overflow this size so in
1154     // this case, simply set the rectangle to the full rtree.
1155     if( rect.GetWidth() > std::numeric_limits<int>::max()
1156             || rect.GetHeight() > std::numeric_limits<int>::max() )
1157     {
1158         recti.SetMaximum();
1159     }
1160 
1161     redrawRect( recti );
1162 
1163     // All targets were redrawn, so nothing is dirty
1164     MarkClean();
1165 
1166 #ifdef KICAD_GAL_PROFILE
1167     totalRealTime.Stop();
1168     wxLogTrace( traceGalProfile, "VIEW::Redraw(): %.1f ms", totalRealTime.msecs() );
1169 #endif /* KICAD_GAL_PROFILE */
1170 }
1171 
1172 
GetScreenPixelSize() const1173 const VECTOR2I& VIEW::GetScreenPixelSize() const
1174 {
1175     return m_gal->GetScreenPixelSize();
1176 }
1177 
1178 
1179 struct VIEW::CLEAR_LAYER_CACHE_VISITOR
1180 {
CLEAR_LAYER_CACHE_VISITORKIGFX::VIEW::CLEAR_LAYER_CACHE_VISITOR1181     CLEAR_LAYER_CACHE_VISITOR( VIEW* aView ) :
1182         view( aView )
1183     {
1184     }
1185 
operator ()KIGFX::VIEW::CLEAR_LAYER_CACHE_VISITOR1186     bool operator()( VIEW_ITEM* aItem )
1187     {
1188         aItem->viewPrivData()->deleteGroups();
1189 
1190         return true;
1191     }
1192 
1193     VIEW* view;
1194 };
1195 
1196 
clearGroupCache()1197 void VIEW::clearGroupCache()
1198 {
1199     BOX2I r;
1200 
1201     r.SetMaximum();
1202     CLEAR_LAYER_CACHE_VISITOR visitor( this );
1203 
1204     for( VIEW_LAYER& layer : m_layers )
1205         layer.items->Query( r, visitor );
1206 }
1207 
1208 
invalidateItem(VIEW_ITEM * aItem,int aUpdateFlags)1209 void VIEW::invalidateItem( VIEW_ITEM* aItem, int aUpdateFlags )
1210 {
1211     if( aUpdateFlags & INITIAL_ADD )
1212     {
1213         // Don't update layers or bbox, since it was done in VIEW::Add()
1214         // Now that we have initialized, set flags to ALL for the code below
1215         aUpdateFlags = ALL;
1216     }
1217     else
1218     {
1219         // updateLayers updates geometry too, so we do not have to update both of them at the
1220         // same time
1221         if( aUpdateFlags & LAYERS )
1222             updateLayers( aItem );
1223         else if( aUpdateFlags & GEOMETRY )
1224             updateBbox( aItem );
1225     }
1226 
1227     int layers[VIEW_MAX_LAYERS], layers_count;
1228     aItem->ViewGetLayers( layers, layers_count );
1229 
1230     // Iterate through layers used by the item and recache it immediately
1231     for( int i = 0; i < layers_count; ++i )
1232     {
1233         int layerId = layers[i];
1234 
1235         if( IsCached( layerId ) )
1236         {
1237             if( aUpdateFlags & ( GEOMETRY | LAYERS | REPAINT ) )
1238                 updateItemGeometry( aItem, layerId );
1239             else if( aUpdateFlags & COLOR )
1240                 updateItemColor( aItem, layerId );
1241         }
1242 
1243         // Mark those layers as dirty, so the VIEW will be refreshed
1244         MarkTargetDirty( m_layers[layerId].target );
1245     }
1246 
1247     aItem->viewPrivData()->clearUpdateFlags();
1248 }
1249 
1250 
sortLayers()1251 void VIEW::sortLayers()
1252 {
1253     int n = 0;
1254 
1255     m_orderedLayers.resize( m_layers.size() );
1256 
1257     for( VIEW_LAYER& layer : m_layers )
1258         m_orderedLayers[n++] = &layer;
1259 
1260     sort( m_orderedLayers.begin(), m_orderedLayers.end(), compareRenderingOrder );
1261 
1262     MarkDirty();
1263 }
1264 
1265 
updateItemColor(VIEW_ITEM * aItem,int aLayer)1266 void VIEW::updateItemColor( VIEW_ITEM* aItem, int aLayer )
1267 {
1268     VIEW_ITEM_DATA* viewData = aItem->viewPrivData();
1269     wxCHECK( (unsigned) aLayer < m_layers.size(), /*void*/ );
1270     wxCHECK( IsCached( aLayer ), /*void*/ );
1271 
1272     if( !viewData )
1273         return;
1274 
1275     // Obtain the color that should be used for coloring the item on the specific layerId
1276     const COLOR4D color = m_painter->GetSettings()->GetColor( aItem, aLayer );
1277     int group = viewData->getGroup( aLayer );
1278 
1279     // Change the color, only if it has group assigned
1280     if( group >= 0 )
1281         m_gal->ChangeGroupColor( group, color );
1282 }
1283 
1284 
updateItemGeometry(VIEW_ITEM * aItem,int aLayer)1285 void VIEW::updateItemGeometry( VIEW_ITEM* aItem, int aLayer )
1286 {
1287     VIEW_ITEM_DATA* viewData = aItem->viewPrivData();
1288     wxCHECK( (unsigned) aLayer < m_layers.size(), /*void*/ );
1289     wxCHECK( IsCached( aLayer ), /*void*/ );
1290 
1291     if( !viewData )
1292         return;
1293 
1294     VIEW_LAYER& l = m_layers.at( aLayer );
1295 
1296     m_gal->SetTarget( l.target );
1297     m_gal->SetLayerDepth( l.renderingOrder );
1298 
1299     // Redraw the item from scratch
1300     int group = viewData->getGroup( aLayer );
1301 
1302     if( group >= 0 )
1303         m_gal->DeleteGroup( group );
1304 
1305     group = m_gal->BeginGroup();
1306     viewData->setGroup( aLayer, group );
1307 
1308     if( !m_painter->Draw( static_cast<EDA_ITEM*>( aItem ), aLayer ) )
1309         aItem->ViewDraw( aLayer, this ); // Alternative drawing method
1310 
1311     m_gal->EndGroup();
1312 }
1313 
1314 
updateBbox(VIEW_ITEM * aItem)1315 void VIEW::updateBbox( VIEW_ITEM* aItem )
1316 {
1317     int layers[VIEW_MAX_LAYERS], layers_count;
1318 
1319     aItem->ViewGetLayers( layers, layers_count );
1320 
1321     for( int i = 0; i < layers_count; ++i )
1322     {
1323         VIEW_LAYER& l = m_layers[layers[i]];
1324         l.items->Remove( aItem );
1325         l.items->Insert( aItem );
1326         MarkTargetDirty( l.target );
1327     }
1328 }
1329 
1330 
updateLayers(VIEW_ITEM * aItem)1331 void VIEW::updateLayers( VIEW_ITEM* aItem )
1332 {
1333     VIEW_ITEM_DATA* viewData = aItem->viewPrivData();
1334     int             layers[VIEW_MAX_LAYERS], layers_count;
1335 
1336     if( !viewData )
1337         return;
1338 
1339     // Remove the item from previous layer set
1340     viewData->getLayers( layers, layers_count );
1341 
1342     for( int i = 0; i < layers_count; ++i )
1343     {
1344         VIEW_LAYER& l = m_layers[layers[i]];
1345         l.items->Remove( aItem );
1346         MarkTargetDirty( l.target );
1347 
1348         if( IsCached( l.id ) )
1349         {
1350             // Redraw the item from scratch
1351             int prevGroup = viewData->getGroup( layers[i] );
1352 
1353             if( prevGroup >= 0 )
1354             {
1355                 m_gal->DeleteGroup( prevGroup );
1356                 viewData->setGroup( l.id, -1 );
1357             }
1358         }
1359     }
1360 
1361     // Add the item to new layer set
1362     aItem->ViewGetLayers( layers, layers_count );
1363     viewData->saveLayers( layers, layers_count );
1364 
1365     for( int i = 0; i < layers_count; i++ )
1366     {
1367         VIEW_LAYER& l = m_layers[layers[i]];
1368         l.items->Insert( aItem );
1369         MarkTargetDirty( l.target );
1370     }
1371 }
1372 
1373 
areRequiredLayersEnabled(int aLayerId) const1374 bool VIEW::areRequiredLayersEnabled( int aLayerId ) const
1375 {
1376     wxCHECK( (unsigned) aLayerId < m_layers.size(), false );
1377 
1378     std::set<int>::const_iterator it, it_end;
1379 
1380     for( int layer : m_layers.at( aLayerId ).requiredLayers )
1381     {
1382         // That is enough if just one layer is not enabled
1383         if( !m_layers.at( layer ).visible || !areRequiredLayersEnabled( layer ) )
1384             return false;
1385     }
1386 
1387     return true;
1388 }
1389 
1390 
RecacheAllItems()1391 void VIEW::RecacheAllItems()
1392 {
1393     BOX2I r;
1394 
1395     r.SetMaximum();
1396 
1397     for( const VIEW_LAYER& l : m_layers )
1398     {
1399         if( IsCached( l.id ) )
1400         {
1401             RECACHE_ITEM_VISITOR visitor( this, m_gal, l.id );
1402             l.items->Query( r, visitor );
1403         }
1404     }
1405 }
1406 
1407 
UpdateItems()1408 void VIEW::UpdateItems()
1409 {
1410     if( !m_gal->IsVisible() )
1411         return;
1412 
1413     unsigned int cntGeomUpdate = 0;
1414     unsigned int cntAnyUpdate = 0;
1415 
1416     for( VIEW_ITEM* item : *m_allItems )
1417     {
1418         auto vpd = item->viewPrivData();
1419 
1420         if( !vpd )
1421             continue;
1422 
1423         if( vpd->m_requiredUpdate & ( GEOMETRY | LAYERS ) )
1424         {
1425             cntGeomUpdate++;
1426         }
1427         if( vpd->m_requiredUpdate != NONE )
1428         {
1429             cntAnyUpdate++;
1430         }
1431     }
1432 
1433     unsigned int cntTotal = m_allItems->size();
1434 
1435     double ratio = (double) cntGeomUpdate / (double) cntTotal;
1436 
1437     // Optimization to improve view update time. If a lot of items (say, 30%) have their
1438     // bboxes/geometry changed it's way faster (around 10 times) to rebuild the R-Trees
1439     // from scratch rather than update the bbox of each changed item. Pcbnew does multiple
1440     // full geometry updates during file load, this can save a solid 30 seconds on load time
1441     // for larger designs...
1442 
1443     if( ratio > 0.3 )
1444     {
1445         auto allItems = *m_allItems;
1446         int  layers[VIEW_MAX_LAYERS], layers_count;
1447 
1448         // kill all Rtrees
1449         for( VIEW_LAYER& layer : m_layers )
1450             layer.items->RemoveAll();
1451 
1452         // and re-insert items from scratch
1453         for( VIEW_ITEM* item : allItems )
1454         {
1455             item->ViewGetLayers( layers, layers_count );
1456             item->viewPrivData()->saveLayers( layers, layers_count );
1457 
1458             for( int i = 0; i < layers_count; ++i )
1459             {
1460                 VIEW_LAYER& l = m_layers[layers[i]];
1461                 l.items->Insert( item );
1462                 MarkTargetDirty( l.target );
1463             }
1464 
1465             item->viewPrivData()->m_requiredUpdate &= ~( LAYERS | GEOMETRY );
1466         }
1467     }
1468 
1469     if( cntAnyUpdate )
1470     {
1471         GAL_UPDATE_CONTEXT ctx( m_gal );
1472 
1473         for( VIEW_ITEM* item : *m_allItems.get() )
1474         {
1475             if( item->viewPrivData() && item->viewPrivData()->m_requiredUpdate != NONE )
1476             {
1477                 invalidateItem( item, item->viewPrivData()->m_requiredUpdate );
1478                 item->viewPrivData()->m_requiredUpdate = NONE;
1479             }
1480         }
1481     }
1482 
1483     KI_TRACE( traceGalProfile, "View update: total items %u, geom %u updates %u\n", cntTotal,
1484               cntGeomUpdate, cntAnyUpdate );
1485 }
1486 
1487 
UpdateAllItems(int aUpdateFlags)1488 void VIEW::UpdateAllItems( int aUpdateFlags )
1489 {
1490     for( VIEW_ITEM* item : *m_allItems )
1491     {
1492         if( item->viewPrivData() )
1493             item->viewPrivData()->m_requiredUpdate |= aUpdateFlags;
1494     }
1495 }
1496 
1497 
UpdateAllItemsConditionally(int aUpdateFlags,std::function<bool (VIEW_ITEM *)> aCondition)1498 void VIEW::UpdateAllItemsConditionally( int aUpdateFlags,
1499                                         std::function<bool( VIEW_ITEM* )> aCondition )
1500 {
1501     for( VIEW_ITEM* item : *m_allItems )
1502     {
1503         if( aCondition( item ) )
1504         {
1505             if( item->viewPrivData() )
1506                 item->viewPrivData()->m_requiredUpdate |= aUpdateFlags;
1507         }
1508     }
1509 }
1510 
1511 
DataReference() const1512 std::unique_ptr<VIEW> VIEW::DataReference() const
1513 {
1514     std::unique_ptr<VIEW> ret = std::make_unique<VIEW>();
1515     ret->m_allItems = m_allItems;
1516     ret->m_layers = m_layers;
1517     ret->sortLayers();
1518     return ret;
1519 }
1520 
1521 
SetVisible(VIEW_ITEM * aItem,bool aIsVisible)1522 void VIEW::SetVisible( VIEW_ITEM* aItem, bool aIsVisible )
1523 {
1524     VIEW_ITEM_DATA* viewData = aItem->viewPrivData();
1525 
1526     if( !viewData )
1527         return;
1528 
1529     bool cur_visible = viewData->m_flags & VISIBLE;
1530 
1531     if( cur_visible != aIsVisible )
1532     {
1533         if( aIsVisible )
1534             viewData->m_flags |= VISIBLE;
1535         else
1536             viewData->m_flags &= ~VISIBLE;
1537 
1538         Update( aItem, APPEARANCE | COLOR );
1539     }
1540 }
1541 
1542 
Hide(VIEW_ITEM * aItem,bool aHide)1543 void VIEW::Hide( VIEW_ITEM* aItem, bool aHide )
1544 {
1545     VIEW_ITEM_DATA* viewData = aItem->viewPrivData();
1546 
1547     if( !viewData )
1548         return;
1549 
1550     if( !( viewData->m_flags & VISIBLE ) )
1551         return;
1552 
1553     if( aHide )
1554         viewData->m_flags |= HIDDEN;
1555     else
1556         viewData->m_flags &= ~HIDDEN;
1557 
1558     Update( aItem, APPEARANCE );
1559 }
1560 
1561 
IsVisible(const VIEW_ITEM * aItem) const1562 bool VIEW::IsVisible( const VIEW_ITEM* aItem ) const
1563 {
1564     const VIEW_ITEM_DATA* viewData = aItem->viewPrivData();
1565 
1566     return viewData && ( viewData->m_flags & VISIBLE );
1567 }
1568 
1569 
Update(const VIEW_ITEM * aItem) const1570 void VIEW::Update( const VIEW_ITEM* aItem ) const
1571 {
1572     Update( aItem, ALL );
1573 }
1574 
1575 
Update(const VIEW_ITEM * aItem,int aUpdateFlags) const1576 void VIEW::Update( const VIEW_ITEM* aItem, int aUpdateFlags ) const
1577 {
1578     VIEW_ITEM_DATA* viewData = aItem->viewPrivData();
1579 
1580     if( !viewData )
1581         return;
1582 
1583     assert( aUpdateFlags != NONE );
1584 
1585     viewData->m_requiredUpdate |= aUpdateFlags;
1586 }
1587 
1588 
MakeOverlay()1589 std::shared_ptr<VIEW_OVERLAY> VIEW::MakeOverlay()
1590 {
1591     std::shared_ptr<VIEW_OVERLAY> overlay( new VIEW_OVERLAY );
1592 
1593     Add( overlay.get() );
1594     return overlay;
1595 }
1596 
1597 
ClearPreview()1598 void VIEW::ClearPreview()
1599 {
1600     if( !m_preview )
1601         return;
1602 
1603     m_preview->Clear();
1604 
1605     for( EDA_ITEM *item : m_ownedItems )
1606         delete item;
1607 
1608     m_ownedItems.clear();
1609     Update( m_preview.get() );
1610 }
1611 
1612 
InitPreview()1613 void VIEW::InitPreview()
1614 {
1615    m_preview.reset( new KIGFX::VIEW_GROUP() );
1616    Add( m_preview.get() );
1617 }
1618 
1619 
AddToPreview(EDA_ITEM * aItem,bool aTakeOwnership)1620 void VIEW::AddToPreview( EDA_ITEM* aItem, bool aTakeOwnership )
1621 {
1622    Hide( aItem, false );
1623    m_preview->Add( aItem );
1624 
1625    if( aTakeOwnership )
1626        m_ownedItems.push_back( aItem );
1627 
1628    SetVisible( m_preview.get(), true );
1629    Hide( m_preview.get(), false );
1630    Update( m_preview.get() );
1631 }
1632 
1633 
ShowPreview(bool aShow)1634 void VIEW::ShowPreview( bool aShow )
1635 {
1636    SetVisible( m_preview.get(), aShow );
1637 }
1638 
1639 
1640 const int VIEW::TOP_LAYER_MODIFIER = -VIEW_MAX_LAYERS;
1641 
1642 } // namespace KIGFX
1643