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