KiCad PCB EDA Suite
Loading...
Searching...
No Matches
view.cpp
Go to the documentation of this file.
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 The KiCad Developers, see AUTHORS.txt for contributors.
6 *
7 * @author Tomasz Wlostowski <[email protected]>
8 * @author Maciej Suminski <[email protected]>
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 <layer_ids.h>
30#include <trace_helpers.h>
31
32#include <view/view.h>
33#include <view/view_group.h>
34#include <view/view_item.h>
35#include <view/view_rtree.h>
36#include <view/view_overlay.h>
37
38#include <gal/definitions.h>
40#include <gal/painter.h>
41#include <algorithm>
42
43#include <core/profile.h>
44
45#ifdef KICAD_GAL_PROFILE
46#include <wx/log.h>
47#endif
48
49namespace KIGFX {
50
51class VIEW;
52
54{
55public:
57 m_view( nullptr ),
60 m_drawPriority( 0 ),
61 m_cachedIndex( -1 ),
62 m_groups( nullptr ),
63 m_groupsSize( 0 ) {}
64
66 {
68 }
69
70 int GetFlags() const
71 {
72 return m_flags;
73 }
74
75private:
76 friend class VIEW;
77
84 int getGroup( int aLayer ) const
85 {
86 for( int i = 0; i < m_groupsSize; ++i )
87 {
88 if( m_groups[i].first == aLayer )
89 return m_groups[i].second;
90 }
91
92 return -1;
93 }
94
101 void setGroup( int aLayer, int aGroup )
102 {
103 // Look if there is already an entry for the layer
104 for( int i = 0; i < m_groupsSize; ++i )
105 {
106 if( m_groups[i].first == aLayer )
107 {
108 m_groups[i].second = aGroup;
109 return;
110 }
111 }
112
113 // If there was no entry for the given layer - create one
114 std::pair<int, int>* newGroups = new std::pair<int, int>[m_groupsSize + 1];
115
116 if( m_groupsSize > 0 )
117 {
118 std::copy( m_groups, m_groups + m_groupsSize, newGroups );
119 delete[] m_groups;
120 }
121
122 m_groups = newGroups;
123 newGroups[m_groupsSize++] = { aLayer, aGroup };
124 }
125
126
131 {
132 delete[] m_groups;
133 m_groups = nullptr;
134 m_groupsSize = 0;
135 }
136
142 inline bool storesGroups() const
143 {
144 return m_groupsSize > 0;
145 }
146
154 void reorderGroups( std::unordered_map<int, int> aReorderMap )
155 {
156 for( int i = 0; i < m_groupsSize; ++i )
157 {
158 int orig_layer = m_groups[i].first;
159 int new_layer = orig_layer;
160
161 if( aReorderMap.count( orig_layer ) )
162 new_layer = aReorderMap.at( orig_layer );
163
164 m_groups[i].first = new_layer;
165 }
166 }
167
174 void saveLayers( const std::vector<int>& aLayers )
175 {
176 m_layers.clear();
177
178 for( int layer : aLayers )
179 {
180 wxCHECK2_MSG( layer >= 0 && layer < VIEW::VIEW_MAX_LAYERS, continue,
181 wxString::Format( wxT( "Invalid layer number: %d" ), layer ) );
182 m_layers.push_back( layer );
183 }
184 }
185
189 int requiredUpdate() const
190 {
191 return m_requiredUpdate;
192 }
193
198 {
200 }
201
205 bool isRenderable() const
206 {
207 return m_flags == VISIBLE;
208 }
209
215
216 std::pair<int, int>* m_groups;
219
220 std::vector<int> m_layers;
221
223};
224
225
227{
228 if( aItem->m_viewPrivData )
229 {
230 if( aItem->m_viewPrivData->m_view )
231 aItem->m_viewPrivData->m_view->VIEW::Remove( aItem );
232
233 delete aItem->m_viewPrivData;
234 aItem->m_viewPrivData = nullptr;
235 }
236}
237
238
240 m_enableOrderModifier( true ),
241 m_scale( 4.0 ),
242 m_minScale( 0.2 ), m_maxScale( 50000.0 ),
243 m_mirrorX( false ), m_mirrorY( false ),
244 m_painter( nullptr ),
245 m_gal( nullptr ),
246 m_useDrawPriority( false ),
248 m_reverseDrawOrder( false )
249{
250 // Set m_boundary to define the max area size. The default area size
251 // is defined here as the max value of a int.
252 // this is a default value acceptable for Pcbnew and Gerbview, but too large for Eeschema.
253 // So in eeschema a call to SetBoundary() with a smaller value will be needed.
254 typedef std::numeric_limits<int> coord_limits;
255 double pos = coord_limits::lowest() / 2 + coord_limits::epsilon();
256 double size = coord_limits::max() - coord_limits::epsilon();
257 m_boundary.SetOrigin( pos, pos );
258 m_boundary.SetSize( size, size );
259
260 m_allItems.reset( new std::vector<VIEW_ITEM*> );
261 m_allItems->reserve( 32768 );
262
263 // Redraw everything at the beginning
264 MarkDirty();
265
266 // View uses layers to display EDA_ITEMs (item may be displayed on several layers, for example
267 // pad may be shown on pad, pad hole and solder paste layers). There are usual copper layers
268 // (eg. F.Cu, B.Cu, internal and so on) and layers for displaying objects such as texts,
269 // silkscreen, pads, vias, etc.
270 for( int ii = 0; ii < VIEW_MAX_LAYERS; ++ii )
271 {
272 auto [it, _] = m_layers.emplace( ii, VIEW_LAYER() );
273 VIEW_LAYER& l = it->second;
274
275 l.items = std::make_shared<VIEW_RTREE>();
276 l.id = ii;
277 l.renderingOrder = ii;
278 l.visible = true;
279 l.displayOnly = false;
280 l.diffLayer = false;
281 l.hasNegatives = false;
283 }
284
286
287 m_preview.reset( new KIGFX::VIEW_GROUP() );
288 Add( m_preview.get() );
289}
290
291
293{
294 Remove( m_preview.get() );
295}
296
297
298void VIEW::Add( VIEW_ITEM* aItem, int aDrawPriority )
299{
300 if( aDrawPriority < 0 )
301 aDrawPriority = m_nextDrawPriority++;
302
303 if( !aItem->m_viewPrivData )
304 aItem->m_viewPrivData = new VIEW_ITEM_DATA;
305
306 wxASSERT_MSG( aItem->m_viewPrivData->m_view == nullptr || aItem->m_viewPrivData->m_view == this,
307 wxS( "Already in a different view!" ) );
308
309 aItem->m_viewPrivData->m_view = this;
310 aItem->m_viewPrivData->m_drawPriority = aDrawPriority;
311 const BOX2I bbox = aItem->ViewBBox();
312 aItem->m_viewPrivData->m_bbox = bbox;
313 aItem->m_viewPrivData->m_cachedIndex = m_allItems->size();
314
315 std::vector<int> layers = aItem->ViewGetLayers();
316
317 std::erase_if( layers, []( int layer )
318 {
319 return layer < 0 || layer >= VIEW_MAX_LAYERS;
320 } );
321
322 if( layers.empty() )
323 return;
324
325 aItem->viewPrivData()->saveLayers( layers );
326
327 m_allItems->push_back( aItem );
328
329 for( int layer : layers )
330 {
331 VIEW_LAYER& l = m_layers[layer];
332 l.items->Insert( aItem, bbox );
334 }
335
336 SetVisible( aItem, true );
337 Update( aItem, KIGFX::INITIAL_ADD );
338}
339
340
342{
343 static int s_gcCounter = 0;
344
345 if( aItem && aItem->m_viewPrivData )
346 {
347 wxCHECK_MSG( aItem->m_viewPrivData->m_view == nullptr || aItem->m_viewPrivData->m_view == this, /*void*/,
348 aItem->GetClass() );
349
350 std::vector<VIEW_ITEM*>::iterator item = m_allItems->end();
351 int cachedIndex = aItem->m_viewPrivData->m_cachedIndex;
352
353 if( cachedIndex >= 0
354 && cachedIndex < static_cast<ssize_t>( m_allItems->size() )
355 && ( *m_allItems )[cachedIndex] == aItem )
356 {
357 item = m_allItems->begin() + cachedIndex;
358 }
359 else
360 {
361 item = std::find( m_allItems->begin(), m_allItems->end(), aItem );
362 }
363
364 if( item != m_allItems->end() )
365 {
366 *item = nullptr;
368
369 s_gcCounter++;
370
371 if( s_gcCounter > 4096 )
372 {
373 // Perform defragmentation
374 std::erase_if( *m_allItems,
375 []( VIEW_ITEM* it )
376 {
377 return it == nullptr;
378 } );
379
380 // Update cached indices
381 for( size_t idx = 0; idx < m_allItems->size(); idx++ )
382 ( *m_allItems )[idx]->m_viewPrivData->m_cachedIndex = idx;
383
384 s_gcCounter = 0;
385 }
386 }
387
388 const BOX2I* bbox = &aItem->m_viewPrivData->m_bbox;
389
390 for( int layer : aItem->m_viewPrivData->m_layers )
391 {
392 VIEW_LAYER& l = m_layers[layer];
393 l.items->Remove( aItem, bbox );
395
396 // Clear the GAL cache
397 int prevGroup = aItem->m_viewPrivData->getGroup( layer );
398
399 if( prevGroup >= 0 )
400 m_gal->DeleteGroup( prevGroup );
401 }
402
404 aItem->m_viewPrivData->m_view = nullptr;
405 }
406}
407
408
409void VIEW::SetRequired( int aLayerId, int aRequiredId, bool aRequired )
410{
411 wxCHECK( (unsigned) aLayerId < m_layers.size(), /*void*/ );
412 wxCHECK( (unsigned) aRequiredId < m_layers.size(), /*void*/ );
413
414 if( aRequired )
415 m_layers[aLayerId].requiredLayers.insert( aRequiredId );
416 else
417 m_layers[aLayerId].requiredLayers.erase( aRequired );
418}
419
420
421int VIEW::Query( const BOX2I& aRect, std::vector<LAYER_ITEM_PAIR>& aResult ) const
422{
423 if( m_orderedLayers.empty() )
424 return 0;
425
426 int layer = UNDEFINED_LAYER;
427 auto visitor =
428 [&]( VIEW_ITEM* item ) -> bool
429 {
430 aResult.push_back( VIEW::LAYER_ITEM_PAIR( item, layer ) );
431 return true;
432 };
433
434 std::vector<VIEW_LAYER*>::const_reverse_iterator i;
435
436 // execute queries in reverse direction, so that items that are on the top of
437 // the rendering stack are returned first.
438 for( i = m_orderedLayers.rbegin(); i != m_orderedLayers.rend(); ++i )
439 {
440 // ignore layers that do not contain actual items (i.e. the selection box, menus, floats)
441 if( ( *i )->displayOnly || !( *i )->visible )
442 continue;
443
444 layer = ( *i )->id;
445 ( *i )->items->Query( aRect, visitor );
446 }
447
448 return aResult.size();
449}
450
451
452void VIEW::Query( const BOX2I& aRect, const std::function<bool( VIEW_ITEM* )>& aFunc ) const
453{
454 if( m_orderedLayers.empty() )
455 return;
456
457 for( const auto& i : m_orderedLayers )
458 {
459 // ignore layers that do not contain actual items (i.e. the selection box, menus, floats)
460 if( i->displayOnly || !i->visible )
461 continue;
462
463 i->items->Query( aRect, aFunc );
464 }
465}
466
467
468VECTOR2D VIEW::ToWorld( const VECTOR2D& aCoord, bool aAbsolute ) const
469{
470 const MATRIX3x3D& matrix = m_gal->GetScreenWorldMatrix();
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
479double VIEW::ToWorld( double aSize ) const
480{
481 const MATRIX3x3D& matrix = m_gal->GetScreenWorldMatrix();
482
483 return fabs( matrix.GetScale().x * aSize );
484}
485
486
487VECTOR2D VIEW::ToScreen( const VECTOR2D& aCoord, bool aAbsolute ) const
488{
489 const MATRIX3x3D& matrix = m_gal->GetWorldScreenMatrix();
490
491 if( aAbsolute )
492 return VECTOR2D( matrix * aCoord );
493 else
494 return VECTOR2D( matrix.GetScale().x * aCoord.x, matrix.GetScale().y * aCoord.y );
495}
496
497
498double VIEW::ToScreen( double aSize ) const
499{
500 const MATRIX3x3D& matrix = m_gal->GetWorldScreenMatrix();
501
502 return matrix.GetScale().x * aSize;
503}
504
505
506void VIEW::CopySettings( const VIEW* aOtherView )
507{
508 wxASSERT_MSG( false, wxT( "This is not implemented" ) );
509}
510
511
512void VIEW::SetGAL( GAL* aGal )
513{
514 bool recacheGroups = ( m_gal != nullptr ); // recache groups only if GAL is reassigned
515 m_gal = aGal;
516
517 // clear group numbers, so everything is going to be recached
518 if( recacheGroups )
520
521 // every target has to be refreshed
522 MarkDirty();
523
524 // force the new GAL to display the current viewport.
526 SetScale( m_scale );
528}
529
530
532{
533 BOX2D rect;
534 VECTOR2D screenSize = m_gal->GetScreenPixelSize();
535
536 rect.SetOrigin( ToWorld( VECTOR2D( 0, 0 ) ) );
537 rect.SetEnd( ToWorld( screenSize ) );
538
539 return rect.Normalize();
540}
541
542
543void VIEW::SetViewport( const BOX2D& aViewport )
544{
545 VECTOR2D ssize = ToWorld( m_gal->GetScreenPixelSize(), false );
546
547 wxCHECK( fabs(ssize.x) > 0 && fabs(ssize.y) > 0, /*void*/ );
548
549 VECTOR2D centre = aViewport.Centre();
550 VECTOR2D vsize = aViewport.GetSize();
551 double zoom = 1.0 / std::max( fabs( vsize.x / ssize.x ), fabs( vsize.y / ssize.y ) );
552
553 SetCenter( centre );
554 SetScale( GetScale() * zoom );
555}
556
557
558void VIEW::SetMirror( bool aMirrorX, bool aMirrorY )
559{
560 wxASSERT_MSG( !aMirrorY, _( "Mirroring for Y axis is not supported yet" ) );
561
562 m_mirrorX = aMirrorX;
563 m_mirrorY = aMirrorY;
564 m_gal->SetFlip( aMirrorX, aMirrorY );
565
566 // Redraw everything
567 MarkDirty();
568}
569
570
571void VIEW::SetScale( double aScale, VECTOR2D aAnchor )
572{
573 if( aAnchor == VECTOR2D( 0, 0 ) )
574 aAnchor = m_center;
575
576 VECTOR2D a = ToScreen( aAnchor );
577
578 if( aScale < m_minScale )
580 else if( aScale > m_maxScale )
582 else
583 m_scale = aScale;
584
585 m_gal->SetZoomFactor( m_scale );
586 m_gal->ComputeWorldScreenMatrix();
587
588 VECTOR2D delta = ToWorld( a ) - aAnchor;
589
591
592 // Redraw everything after the viewport has changed
593 MarkDirty();
594}
595
596
597void VIEW::SetCenter( const VECTOR2D& aCenter )
598{
599 m_center = aCenter;
600
601 if( !m_boundary.Contains( aCenter ) )
602 {
603 if( m_center.x < m_boundary.GetLeft() )
604 m_center.x = m_boundary.GetLeft();
605 else if( aCenter.x > m_boundary.GetRight() )
606 m_center.x = m_boundary.GetRight();
607
608 if( m_center.y < m_boundary.GetTop() )
609 m_center.y = m_boundary.GetTop();
610 else if( m_center.y > m_boundary.GetBottom() )
611 m_center.y = m_boundary.GetBottom();
612 }
613
614 m_gal->SetLookAtPoint( m_center );
615 m_gal->ComputeWorldScreenMatrix();
616
617 // Redraw everything after the viewport has changed
618 MarkDirty();
619}
620
621
622void VIEW::SetCenter( const VECTOR2D& aCenter, const std::vector<BOX2D>& obscuringScreenRects )
623{
624 if( obscuringScreenRects.empty() )
625 return SetCenter( aCenter );
626
627 BOX2D screenRect( { 0, 0 }, m_gal->GetScreenPixelSize() );
628 SHAPE_POLY_SET unobscuredPoly( screenRect );
629 VECTOR2D unobscuredCenter = screenRect.Centre();
630
631 for( const BOX2D& obscuringScreenRect : obscuringScreenRects )
632 {
633 SHAPE_POLY_SET obscuringPoly( obscuringScreenRect );
634 unobscuredPoly.BooleanSubtract( obscuringPoly );
635 }
636
637 /*
638 * Perform a step-wise deflate to find the center of the largest unobscured area
639 */
640
641 BOX2I bbox = unobscuredPoly.BBox();
642 int step = std::min( bbox.GetWidth(), bbox.GetHeight() ) / 10;
643
644 if( step < 20 )
645 step = 20;
646
647 while( !unobscuredPoly.IsEmpty() )
648 {
649 unobscuredCenter = unobscuredPoly.BBox().Centre();
651 }
652
653 SetCenter( aCenter - ToWorld( unobscuredCenter - screenRect.Centre(), false ) );
654}
655
656
657void VIEW::SetLayerOrder( int aLayer, int aRenderingOrder )
658{
659 m_layers[aLayer].renderingOrder = aRenderingOrder;
660
662}
663
664
665int VIEW::GetLayerOrder( int aLayer ) const
666{
667 return m_layers.at( aLayer ).renderingOrder;
668}
669
670
671void VIEW::SortLayers( std::vector<int>& aLayers ) const
672{
673 std::sort( aLayers.begin(), aLayers.end(),
674 [this]( int a, int b )
675 {
676 return GetLayerOrder( a ) > GetLayerOrder( b );
677 } );
678}
679
680
681void VIEW::ReorderLayerData( std::unordered_map<int, int> aReorderMap )
682{
683 std::map<int,VIEW_LAYER> new_map;
684
685 for( auto& [_, layer] : m_layers )
686 {
687 auto reorder_it = aReorderMap.find( layer.id );
688
689 // If the layer is not in the reorder map or if it is mapped to itself,
690 // just copy the layer to the new map.
691 if( reorder_it == aReorderMap.end() || reorder_it->second == layer.id )
692 {
693 new_map.emplace( layer.id, layer );
694 continue;
695 }
696
697 auto [new_it,__] = new_map.emplace( reorder_it->second, layer );
698 new_it->second.id = reorder_it->second;
699 }
700
701 // Transfer reordered data (using the copy assignment operator ):
702 m_layers = new_map;
703
705
706 for( VIEW_ITEM* item : *m_allItems )
707 {
708 if( !item )
709 continue;
710
711 VIEW_ITEM_DATA* viewData = item->viewPrivData();
712
713 if( !viewData )
714 continue;
715
716 std::vector<int> layers = item->ViewGetLayers();
717 viewData->saveLayers( layers );
718
719 viewData->reorderGroups( aReorderMap );
720
721 viewData->m_requiredUpdate |= COLOR;
722 }
723
724 UpdateItems();
725}
726
727
729{
730 UPDATE_COLOR_VISITOR( int aLayer, PAINTER* aPainter, GAL* aGal ) :
731 layer( aLayer ),
732 painter( aPainter ),
733 gal( aGal )
734 {
735 }
736
737 bool operator()( VIEW_ITEM* aItem )
738 {
739 // Obtain the color that should be used for coloring the item
740 const COLOR4D color = painter->GetSettings()->GetColor( aItem, layer );
741 int group = aItem->viewPrivData()->getGroup( layer );
742
743 if( group >= 0 )
744 gal->ChangeGroupColor( group, color );
745
746 return true;
747 }
748
749 int layer;
752};
753
754
755void VIEW::UpdateLayerColor( int aLayer )
756{
757 // There is no point in updating non-cached layers
758 if( !IsCached( aLayer ) )
759 return;
760
761 BOX2I r;
762
763 r.SetMaximum();
764
765 if( m_gal->IsVisible() )
766 {
768
769 UPDATE_COLOR_VISITOR visitor( aLayer, m_painter, m_gal );
770 m_layers[aLayer].items->Query( r, visitor );
771 MarkTargetDirty( m_layers[aLayer].target );
772 }
773}
774
775
777{
778 if( m_gal->IsVisible() )
779 {
781
782 for( VIEW_ITEM* item : *m_allItems )
783 {
784 if( !item )
785 continue;
786
787 VIEW_ITEM_DATA* viewData = item->viewPrivData();
788
789 if( !viewData )
790 continue;
791
792 for( int layer : viewData->m_layers )
793 {
794 const COLOR4D color = m_painter->GetSettings()->GetColor( item, layer );
795 int group = viewData->getGroup( layer );
796
797 if( group >= 0 )
798 m_gal->ChangeGroupColor( group, color );
799 }
800 }
801 }
802
803 MarkDirty();
804}
805
806
808{
809 UPDATE_DEPTH_VISITOR( int aLayer, int aDepth, GAL* aGal ) :
810 layer( aLayer ),
811 depth( aDepth ),
812 gal( aGal )
813 {
814 }
815
816 bool operator()( VIEW_ITEM* aItem )
817 {
818 int group = aItem->viewPrivData()->getGroup( layer );
819
820 if( group >= 0 )
821 gal->ChangeGroupDepth( group, depth );
822
823 return true;
824 }
825
828};
829
830
832{
833 if( m_topLayers.size() == 0 )
834 return 0;
835
836 return *m_topLayers.begin();
837}
838
839
840void VIEW::SetTopLayer( int aLayer, bool aEnabled )
841{
842 if( aEnabled )
843 {
844 if( m_topLayers.count( aLayer ) == 1 )
845 return;
846
847 m_topLayers.insert( aLayer );
848
849 // Move the layer closer to front
851 m_layers[aLayer].renderingOrder += TOP_LAYER_MODIFIER;
852 }
853 else
854 {
855 if( m_topLayers.count( aLayer ) == 0 )
856 return;
857
858 m_topLayers.erase( aLayer );
859
860 // Restore the previous rendering order
862 m_layers[aLayer].renderingOrder -= TOP_LAYER_MODIFIER;
863 }
864}
865
866
867void VIEW::EnableTopLayer( bool aEnable )
868{
869 if( aEnable == m_enableOrderModifier )
870 return;
871
872 m_enableOrderModifier = aEnable;
873
874 std::set<unsigned int>::iterator it;
875
876 if( aEnable )
877 {
878 for( it = m_topLayers.begin(); it != m_topLayers.end(); ++it )
879 m_layers[*it].renderingOrder += TOP_LAYER_MODIFIER;
880 }
881 else
882 {
883 for( it = m_topLayers.begin(); it != m_topLayers.end(); ++it )
884 m_layers[*it].renderingOrder -= TOP_LAYER_MODIFIER;
885 }
886
889}
890
891
893{
894 std::set<unsigned int>::iterator it;
895
897 {
898 // Restore the previous rendering order for layers that were marked as top
899 for( it = m_topLayers.begin(); it != m_topLayers.end(); ++it )
900 m_layers[*it].renderingOrder -= TOP_LAYER_MODIFIER;
901 }
902
903 m_topLayers.clear();
904}
905
906
908{
910
911 if( m_gal->IsVisible() )
912 {
914
915 for( VIEW_ITEM* item : *m_allItems )
916 {
917 if( !item )
918 continue;
919
920 VIEW_ITEM_DATA* viewData = item->viewPrivData();
921
922 if( !viewData )
923 continue;
924
925 for( int layer : viewData->m_layers )
926 {
927 int group = viewData->getGroup( layer );
928
929 if( group >= 0 )
930 m_gal->ChangeGroupDepth( group, m_layers[layer].renderingOrder );
931 }
932 }
933 }
934
935 MarkDirty();
936}
937
938
940{
941 DRAW_ITEM_VISITOR( VIEW* aView, int aLayer, bool aUseDrawPriority, bool aReverseDrawOrder ) :
942 view( aView ),
943 layer( aLayer ),
944 useDrawPriority( aUseDrawPriority ),
945 reverseDrawOrder( aReverseDrawOrder ),
946 drawForcedTransparent( false ),
948 {
949 }
950
951 bool operator()( VIEW_ITEM* aItem )
952 {
953 wxCHECK( aItem->viewPrivData(), false );
954
956 {
958 return true;
959 }
960
961 const double itemLOD = aItem->ViewGetLOD( layer, view );
962
963 // Conditions that have to be fulfilled for an item to be drawn
964 bool drawCondition = aItem->viewPrivData()->isRenderable() && itemLOD < view->m_scale;
965
966 if( !drawCondition )
967 return true;
968
969 if( useDrawPriority )
970 drawItems.push_back( aItem );
971 else
972 view->draw( aItem, layer );
973
974 return true;
975 }
976
978 {
979 if( reverseDrawOrder )
980 {
981 std::sort( drawItems.begin(), drawItems.end(),
982 []( VIEW_ITEM* a, VIEW_ITEM* b ) -> bool
983 {
984 return b->viewPrivData()->m_drawPriority
985 < a->viewPrivData()->m_drawPriority;
986 } );
987 }
988 else
989 {
990 std::sort( drawItems.begin(), drawItems.end(),
991 []( VIEW_ITEM* a, VIEW_ITEM* b ) -> bool
992 {
993 return a->viewPrivData()->m_drawPriority
994 < b->viewPrivData()->m_drawPriority;
995 } );
996 }
997
998 for( VIEW_ITEM* item : drawItems )
999 view->draw( item, layer );
1000 }
1001
1005 std::vector<VIEW_ITEM*> drawItems;
1008};
1009
1010
1011void VIEW::redrawRect( const BOX2I& aRect )
1012{
1013 for( VIEW_LAYER* l : m_orderedLayers )
1014 {
1015 if( l->visible && IsTargetDirty( l->target ) && areRequiredLayersEnabled( l->id ) )
1016 {
1017 DRAW_ITEM_VISITOR drawFunc( this, l->id, m_useDrawPriority, m_reverseDrawOrder );
1018
1019 m_gal->SetTarget( l->target );
1020 m_gal->SetLayerDepth( l->renderingOrder );
1021
1022 // Differential layer also work for the negatives, since both special layer types
1023 // will composite on separate layers (at least in Cairo)
1024 if( l->diffLayer )
1025 m_gal->StartDiffLayer();
1026 else if( l->hasNegatives )
1027 m_gal->StartNegativesLayer();
1028
1029 l->items->Query( aRect, drawFunc );
1030
1031 if( m_useDrawPriority )
1032 drawFunc.deferredDraw();
1033
1034 if( l->diffLayer )
1035 m_gal->EndDiffLayer();
1036 else if( l->hasNegatives )
1037 m_gal->EndNegativesLayer();
1038
1039 if( drawFunc.foundForcedTransparent )
1040 {
1041 drawFunc.drawForcedTransparent = true;
1042
1043 m_gal->SetTarget( TARGET_NONCACHED );
1044 m_gal->EnableDepthTest( true );
1045 m_gal->SetLayerDepth( l->renderingOrder );
1046
1047 l->items->Query( aRect, drawFunc );
1048 }
1049 }
1050 }
1051}
1052
1053
1054void VIEW::draw( VIEW_ITEM* aItem, int aLayer, bool aImmediate )
1055{
1056 VIEW_ITEM_DATA* viewData = aItem->viewPrivData();
1057
1058 if( !viewData )
1059 return;
1060
1061 if( IsCached( aLayer ) && !aImmediate )
1062 {
1063 // Draw using cached information or create one
1064 int group = viewData->getGroup( aLayer );
1065
1066 if( group >= 0 )
1067 m_gal->DrawGroup( group );
1068 else
1069 Update( aItem );
1070 }
1071 else
1072 {
1073 // Immediate mode
1074 if( !m_painter->Draw( aItem, aLayer ) )
1075 aItem->ViewDraw( aLayer, this ); // Alternative drawing method
1076 }
1077}
1078
1079
1080void VIEW::draw( VIEW_ITEM* aItem, bool aImmediate )
1081{
1082 std::vector<int> layers = aItem->ViewGetLayers();
1083
1084 // Sorting is needed for drawing order dependent GALs (like Cairo)
1085 if( !m_gal || !m_gal->IsOpenGlEngine())
1086 SortLayers( layers );
1087
1088 for( int layer : layers )
1089 {
1090 auto it = m_layers.find( layer );
1091
1092 if( it == m_layers.end() )
1093 continue;
1094
1095 if( m_gal )
1096 m_gal->SetLayerDepth( it->second.renderingOrder );
1097
1098 draw( aItem, layer, aImmediate );
1099 }
1100}
1101
1102
1103void VIEW::draw( VIEW_GROUP* aGroup, bool aImmediate )
1104{
1105 for( unsigned int i = 0; i < aGroup->GetSize(); i++ )
1106 draw( aGroup->GetItem(i), aImmediate );
1107}
1108
1109
1111{
1112 RECACHE_ITEM_VISITOR( VIEW* aView, GAL* aGal, int aLayer ) :
1113 view( aView ),
1114 gal( aGal ),
1115 layer( aLayer )
1116 {
1117 }
1118
1119 bool operator()( VIEW_ITEM* aItem )
1120 {
1121 VIEW_ITEM_DATA* viewData = aItem->viewPrivData();
1122
1123 if( !viewData )
1124 return false;
1125
1126 // Remove previously cached group
1127 int group = viewData->getGroup( layer );
1128
1129 if( group >= 0 )
1130 gal->DeleteGroup( group );
1131
1132 viewData->setGroup( layer, -1 );
1133 view->Update( aItem );
1134
1135 return true;
1136 }
1137
1141};
1142
1143
1145{
1146 BOX2I r;
1147 r.SetMaximum();
1148
1149 // Invalidate viewPrivData for all items before clearing. This ensures that items
1150 // which persist outside the view (like selection groups) won't have stale references
1151 // to this view, which could cause issues if they're later removed and re-added.
1152 for( VIEW_ITEM* item : *m_allItems )
1153 {
1154 if( item && item->m_viewPrivData )
1155 item->m_viewPrivData->m_view = nullptr;
1156 }
1157
1158 m_allItems->clear();
1159
1160 for( auto& [_, layer] : m_layers )
1161 layer.items->RemoveAll();
1162
1164
1165 m_gal->ClearCache();
1166}
1167
1168
1170{
1172 {
1173 // TARGET_CACHED and TARGET_NONCACHED have to be redrawn together, as they contain
1174 // layers that rely on each other (eg. netnames are noncached, but tracks - are cached)
1175 m_gal->ClearTarget( TARGET_NONCACHED );
1176 m_gal->ClearTarget( TARGET_CACHED );
1177
1178 MarkDirty();
1179 }
1180
1182 {
1183 m_gal->ClearTarget( TARGET_OVERLAY );
1184 }
1185}
1186
1187
1189{
1190#ifdef KICAD_GAL_PROFILE
1191 PROF_TIMER totalRealTime;
1192#endif /* KICAD_GAL_PROFILE */
1193
1194 VECTOR2D screenSize = m_gal->GetScreenPixelSize();
1195 BOX2D rect( ToWorld( VECTOR2D( 0, 0 ) ),
1196 ToWorld( screenSize ) - ToWorld( VECTOR2D( 0, 0 ) ) );
1197
1198 rect.Normalize();
1199 BOX2I recti = BOX2ISafe( rect );
1200
1201 redrawRect( recti );
1202
1203 // All targets were redrawn, so nothing is dirty
1204 MarkClean();
1205
1206#ifdef KICAD_GAL_PROFILE
1207 totalRealTime.Stop();
1208 wxLogTrace( traceGalProfile, wxS( "VIEW::Redraw(): %.1f ms" ), totalRealTime.msecs() );
1209#endif /* KICAD_GAL_PROFILE */
1210}
1211
1212
1214{
1215 return m_gal->GetScreenPixelSize();
1216}
1217
1218
1220{
1222 view( aView )
1223 {
1224 }
1225
1226 bool operator()( VIEW_ITEM* aItem )
1227 {
1228 aItem->viewPrivData()->deleteGroups();
1229
1230 return true;
1231 }
1232
1234};
1235
1236
1238{
1239 BOX2I r;
1240
1241 r.SetMaximum();
1242 CLEAR_LAYER_CACHE_VISITOR visitor( this );
1243
1244 for( auto& [_, layer] : m_layers )
1245 layer.items->Query( r, visitor );
1246}
1247
1248
1249void VIEW::invalidateItem( VIEW_ITEM* aItem, int aUpdateFlags )
1250{
1251 if( aUpdateFlags & INITIAL_ADD )
1252 {
1253 // Don't update layers or bbox, since it was done in VIEW::Add()
1254 // Now that we have initialized, set flags to ALL for the code below
1255 aUpdateFlags = ALL;
1256 }
1257 else
1258 {
1259 // updateLayers updates geometry too, so we do not have to update both of them at the
1260 // same time
1261 if( aUpdateFlags & LAYERS )
1262 updateLayers( aItem );
1263 else if( aUpdateFlags & GEOMETRY )
1264 updateBbox( aItem );
1265 }
1266
1267 std::vector<int> layers = aItem->ViewGetLayers();
1268
1269 // Iterate through layers used by the item and recache it immediately
1270 for( int layer : layers )
1271 {
1272 if( IsCached( layer ) )
1273 {
1274 if( aUpdateFlags & ( GEOMETRY | LAYERS | REPAINT ) )
1275 updateItemGeometry( aItem, layer );
1276 else if( aUpdateFlags & COLOR )
1277 updateItemColor( aItem, layer );
1278 }
1279
1280 // Mark those layers as dirty, so the VIEW will be refreshed
1281 MarkTargetDirty( m_layers[layer].target );
1282 }
1283
1284 aItem->viewPrivData()->clearUpdateFlags();
1285}
1286
1287
1289{
1290 int n = 0;
1291
1292 m_orderedLayers.resize( m_layers.size() );
1293
1294 for( auto& [layer_id, layer] : m_layers )
1295 m_orderedLayers[n++] = &layer;
1296
1298
1299 MarkDirty();
1300}
1301
1302
1303void VIEW::updateItemColor( VIEW_ITEM* aItem, int aLayer )
1304{
1305 VIEW_ITEM_DATA* viewData = aItem->viewPrivData();
1306 wxCHECK( IsCached( aLayer ), /*void*/ ); // This will check if the layer exists
1307
1308 if( !viewData )
1309 return;
1310
1311 // Obtain the color that should be used for coloring the item on the specific layerId
1312 const COLOR4D color = m_painter->GetSettings()->GetColor( aItem, aLayer );
1313 int group = viewData->getGroup( aLayer );
1314
1315 // Change the color, only if it has group assigned
1316 if( group >= 0 )
1317 m_gal->ChangeGroupColor( group, color );
1318}
1319
1320
1321void VIEW::updateItemGeometry( VIEW_ITEM* aItem, int aLayer )
1322{
1323 VIEW_ITEM_DATA* viewData = aItem->viewPrivData();
1324
1325 if( !viewData )
1326 return;
1327
1328 auto it = m_layers.find( aLayer );
1329
1330 if( it == m_layers.end() )
1331 return;
1332
1333 VIEW_LAYER& l = it->second;
1334
1335 // Save the extra map lookup in IsCached by open coding here
1336 if( l.target != TARGET_CACHED )
1337 return;
1338
1339 m_gal->SetTarget( l.target );
1340 m_gal->SetLayerDepth( l.renderingOrder );
1341
1342 // Redraw the item from scratch
1343 int group = viewData->getGroup( aLayer );
1344
1345 if( group >= 0 )
1346 m_gal->DeleteGroup( group );
1347
1348 group = m_gal->BeginGroup();
1349 viewData->setGroup( aLayer, group );
1350
1351 if( !m_painter->Draw( aItem, aLayer ) )
1352 aItem->ViewDraw( aLayer, this ); // Alternative drawing method
1353
1354 m_gal->EndGroup();
1355}
1356
1357
1359{
1360 std::vector<int> layers = aItem->ViewGetLayers();
1361
1362 wxASSERT( aItem->m_viewPrivData ); //must have a viewPrivData
1363
1364 const BOX2I new_bbox = aItem->ViewBBox();
1365 const BOX2I* old_bbox = &aItem->m_viewPrivData->m_bbox;
1366 aItem->m_viewPrivData->m_bbox = new_bbox;
1367
1368 for( int layer : layers )
1369 {
1370 auto it = m_layers.find( layer );
1371
1372 if( it == m_layers.end() )
1373 continue;
1374
1375 VIEW_LAYER& l = it->second;
1376 l.items->Remove( aItem, old_bbox );
1377 l.items->Insert( aItem, new_bbox );
1379 }
1380}
1381
1382
1384{
1385 VIEW_ITEM_DATA* viewData = aItem->viewPrivData();
1386
1387 if( !viewData )
1388 return;
1389
1390 // Remove the item from previous layer set
1391 const BOX2I* old_bbox = &aItem->m_viewPrivData->m_bbox;
1392
1393 for( int layer : aItem->m_viewPrivData->m_layers )
1394 {
1395 auto it = m_layers.find( layer );
1396
1397 if( it == m_layers.end() )
1398 continue;
1399
1400 VIEW_LAYER& l = it->second;
1401 l.items->Remove( aItem, old_bbox );
1403
1404 if( IsCached( l.id ) )
1405 {
1406 // Redraw the item from scratch
1407 int prevGroup = viewData->getGroup( layer );
1408
1409 if( prevGroup >= 0 )
1410 {
1411 m_gal->DeleteGroup( prevGroup );
1412 viewData->setGroup( l.id, -1 );
1413 }
1414 }
1415 }
1416
1417 const BOX2I new_bbox = aItem->ViewBBox();
1418 aItem->m_viewPrivData->m_bbox = new_bbox;
1419
1420 // Add the item to new layer set
1421 std::vector<int> layers = aItem->ViewGetLayers();
1422 viewData->saveLayers( layers );
1423
1424 for( int layer : layers )
1425 {
1426 auto it = m_layers.find( layer );
1427
1428 if( it == m_layers.end() )
1429 continue;
1430
1431 VIEW_LAYER& l = it->second;
1432 l.items->Insert( aItem, new_bbox );
1434 }
1435}
1436
1437
1438bool VIEW::areRequiredLayersEnabled( int aLayerId ) const
1439{
1440 auto it = m_layers.find( aLayerId );
1441
1442 if( it == m_layers.end() )
1443 return false;
1444
1445 for( int layer : it->second.requiredLayers )
1446 {
1447 // That is enough if just one layer is not enabled
1448
1449 auto it2 = m_layers.find( layer );
1450
1451 if( it2 == m_layers.end() || !it2->second.visible )
1452 return false;
1453
1454 if( !areRequiredLayersEnabled( layer ) )
1455 return false;
1456 }
1457
1458 return true;
1459}
1460
1461
1463{
1464 BOX2I r;
1465
1466 r.SetMaximum();
1467
1468 for( const auto& [_, l] : m_layers )
1469 {
1470 if( IsCached( l.id ) )
1471 {
1472 RECACHE_ITEM_VISITOR visitor( this, m_gal, l.id );
1473 l.items->Query( r, visitor );
1474 }
1475 }
1476}
1477
1478
1480{
1481 if( !m_gal->IsVisible() || !m_gal->IsInitialized() )
1482 return;
1483
1484 unsigned int cntGeomUpdate = 0;
1485 bool anyUpdated = false;
1486
1487 for( VIEW_ITEM* item : *m_allItems )
1488 {
1489 if( !item )
1490 continue;
1491
1492 auto vpd = item->viewPrivData();
1493
1494 if( !vpd )
1495 continue;
1496
1497 if( vpd->m_requiredUpdate != NONE )
1498 {
1499 anyUpdated = true;
1500
1501 if( vpd->m_requiredUpdate & ( GEOMETRY | LAYERS ) )
1502 {
1503 cntGeomUpdate++;
1504 }
1505 }
1506 }
1507
1508 unsigned int cntTotal = m_allItems->size();
1509
1510 double ratio = (double) cntGeomUpdate / (double) cntTotal;
1511
1512 // Optimization to improve view update time. If a lot of items (say, 30%) have their
1513 // bboxes/geometry changed it's way faster (around 10 times) to rebuild the R-Trees
1514 // from scratch rather than update the bbox of each changed item. Pcbnew does multiple
1515 // full geometry updates during file load, this can save a solid 30 seconds on load time
1516 // for larger designs...
1517
1518 if( ratio > 0.3 )
1519 {
1520 auto allItems = *m_allItems;
1521
1522 // kill all Rtrees
1523 for( auto& [_, layer] : m_layers )
1524 layer.items->RemoveAll();
1525
1526 // and re-insert items from scratch
1527 for( VIEW_ITEM* item : allItems )
1528 {
1529 if( !item )
1530 continue;
1531
1532 const BOX2I bbox = item->ViewBBox();
1533 item->m_viewPrivData->m_bbox = bbox;
1534
1535 std::vector<int> layers = item->ViewGetLayers();
1536 item->viewPrivData()->saveLayers( layers );
1537
1538 for( int layer : layers )
1539 {
1540 auto it = m_layers.find( layer );
1541
1542 wxCHECK2_MSG( it != m_layers.end(), continue, wxS( "Invalid layer" ) );
1543
1544 VIEW_LAYER& l = it->second;
1545 l.items->Insert( item, bbox );
1547 }
1548
1549 item->viewPrivData()->m_requiredUpdate &= ~( LAYERS | GEOMETRY );
1550 }
1551 }
1552
1553 if( anyUpdated )
1554 {
1556
1557 for( VIEW_ITEM* item : *m_allItems.get() )
1558 {
1559 if( item && item->viewPrivData() && item->viewPrivData()->m_requiredUpdate != NONE )
1560 {
1561 invalidateItem( item, item->viewPrivData()->m_requiredUpdate );
1562 item->viewPrivData()->m_requiredUpdate = NONE;
1563 }
1564 }
1565 }
1566
1567 KI_TRACE( traceGalProfile, wxS( "View update: total items %u, geom %u anyUpdated %u\n" ),
1568 cntTotal, cntGeomUpdate, (unsigned) anyUpdated );
1569}
1570
1571
1572void VIEW::UpdateAllItems( int aUpdateFlags )
1573{
1574 for( VIEW_ITEM* item : *m_allItems )
1575 {
1576 if( item && item->viewPrivData() )
1577 item->viewPrivData()->m_requiredUpdate |= aUpdateFlags;
1578 }
1579}
1580
1581
1583 std::function<bool( VIEW_ITEM* )> aCondition )
1584{
1585 for( VIEW_ITEM* item : *m_allItems )
1586 {
1587 if( !item )
1588 continue;
1589
1590 if( aCondition( item ) )
1591 {
1592 if( item->viewPrivData() )
1593 item->viewPrivData()->m_requiredUpdate |= aUpdateFlags;
1594 }
1595 }
1596}
1597
1598
1599void VIEW::UpdateAllItemsConditionally( std::function<int( VIEW_ITEM* )> aItemFlagsProvider )
1600{
1601 for( VIEW_ITEM* item : *m_allItems )
1602 {
1603 if( !item )
1604 continue;
1605
1606 if( item->viewPrivData() )
1607 item->viewPrivData()->m_requiredUpdate |= aItemFlagsProvider( item );
1608 }
1609}
1610
1611
1612
1613std::unique_ptr<VIEW> VIEW::DataReference() const
1614{
1615 std::unique_ptr<VIEW> ret = std::make_unique<VIEW>();
1616 ret->m_allItems = m_allItems;
1617 ret->m_layers = m_layers;
1618 ret->sortOrderedLayers();
1619 return ret;
1620}
1621
1622
1623void VIEW::SetVisible( VIEW_ITEM* aItem, bool aIsVisible )
1624{
1625 VIEW_ITEM_DATA* viewData = aItem->viewPrivData();
1626
1627 if( !viewData )
1628 return;
1629
1630 bool cur_visible = viewData->m_flags & VISIBLE;
1631
1632 if( cur_visible != aIsVisible )
1633 {
1634 if( aIsVisible )
1635 viewData->m_flags |= VISIBLE;
1636 else
1637 viewData->m_flags &= ~VISIBLE;
1638
1639 Update( aItem, APPEARANCE | COLOR );
1640 }
1641}
1642
1643
1644void VIEW::Hide( VIEW_ITEM* aItem, bool aHide, bool aHideOverlay )
1645{
1646 VIEW_ITEM_DATA* viewData = aItem->viewPrivData();
1647
1648 if( !viewData )
1649 return;
1650
1651 if( !( viewData->m_flags & VISIBLE ) )
1652 return;
1653
1654 if( aHideOverlay )
1655 viewData->m_flags |= OVERLAY_HIDDEN;
1656
1657 if( aHide )
1658 viewData->m_flags |= HIDDEN;
1659 else
1660 viewData->m_flags &= ~( HIDDEN | OVERLAY_HIDDEN );
1661
1662 Update( aItem, APPEARANCE );
1663}
1664
1665
1666bool VIEW::IsVisible( const VIEW_ITEM* aItem ) const
1667{
1668 const VIEW_ITEM_DATA* viewData = aItem->viewPrivData();
1669
1670 return viewData && ( viewData->m_flags & VISIBLE );
1671}
1672
1673
1674bool VIEW::IsHiddenOnOverlay( const VIEW_ITEM* aItem ) const
1675{
1676 const VIEW_ITEM_DATA* viewData = aItem->viewPrivData();
1677
1678 return viewData && ( viewData->m_flags & OVERLAY_HIDDEN );
1679}
1680
1681
1682bool VIEW::HasItem( const VIEW_ITEM* aItem ) const
1683{
1684 const VIEW_ITEM_DATA* viewData = aItem->viewPrivData();
1685
1686 return viewData && viewData->m_view == this;
1687}
1688
1689
1690void VIEW::Update( const VIEW_ITEM* aItem ) const
1691{
1692 Update( aItem, ALL );
1693}
1694
1695
1696void VIEW::Update( const VIEW_ITEM* aItem, int aUpdateFlags ) const
1697{
1698 VIEW_ITEM_DATA* viewData = aItem->viewPrivData();
1699
1700 if( !viewData )
1701 return;
1702
1703 assert( aUpdateFlags != NONE );
1704
1705 viewData->m_requiredUpdate |= aUpdateFlags;
1706}
1707
1708
1709std::shared_ptr<VIEW_OVERLAY> VIEW::MakeOverlay()
1710{
1711 std::shared_ptr<VIEW_OVERLAY> overlay = std::make_shared<VIEW_OVERLAY>();
1712
1713 Add( overlay.get() );
1714 return overlay;
1715}
1716
1717
1719{
1720 if( !m_preview )
1721 return;
1722
1723 m_preview->Clear();
1724
1725 for( VIEW_ITEM* item : m_ownedItems )
1726 delete item;
1727
1728 m_ownedItems.clear();
1729 Update( m_preview.get() );
1730}
1731
1732
1734{
1735 m_preview.reset( new KIGFX::VIEW_GROUP() );
1736 Add( m_preview.get() );
1737}
1738
1739
1740void VIEW::AddToPreview( VIEW_ITEM* aItem, bool aTakeOwnership )
1741{
1742 Hide( aItem, false );
1743 m_preview->Add( aItem );
1744
1745 if( aTakeOwnership )
1746 m_ownedItems.push_back( aItem );
1747
1748 SetVisible( m_preview.get(), true );
1749 Hide( m_preview.get(), false );
1750 Update( m_preview.get() );
1751}
1752
1753
1754void VIEW::ShowPreview( bool aShow )
1755{
1756 SetVisible( m_preview.get(), aShow );
1757}
1758
1759
1760} // namespace KIGFX
constexpr int ARC_LOW_DEF
Definition base_units.h:128
constexpr BOX2I BOX2ISafe(const BOX2D &aInput)
Definition box2.h:929
BOX2< VECTOR2I > BOX2I
Definition box2.h:922
BOX2< VECTOR2D > BOX2D
Definition box2.h:923
constexpr void SetMaximum()
Definition box2.h:80
constexpr void SetOrigin(const Vec &pos)
Definition box2.h:237
constexpr BOX2< Vec > & Normalize()
Ensure that the height and width are positive.
Definition box2.h:146
constexpr size_type GetWidth() const
Definition box2.h:214
constexpr Vec Centre() const
Definition box2.h:97
constexpr size_type GetHeight() const
Definition box2.h:215
constexpr const SizeVec & GetSize() const
Definition box2.h:206
constexpr void SetEnd(coord_type x, coord_type y)
Definition box2.h:297
A color representation with 4 components: red, green, blue, alpha.
Definition color4d.h:105
Abstract interface for drawing on a 2D-surface.
Contains all the knowledge about how to draw graphical object onto any particular output device.
Definition painter.h:59
Extend VIEW_ITEM by possibility of grouping items into a single object.
Definition view_group.h:43
virtual unsigned int GetSize() const
Return the number of stored items.
virtual VIEW_ITEM * GetItem(unsigned int aIdx) const
bool storesGroups() const
Return information if the item uses at least one group id (ie.
Definition view.cpp:142
std::vector< int > m_layers
Definition view.cpp:220
int requiredUpdate() const
Return current update flag for an item.
Definition view.cpp:189
int m_requiredUpdate
Flag required for updating.
Definition view.cpp:212
int m_flags
Visibility flags.
Definition view.cpp:211
void reorderGroups(std::unordered_map< int, int > aReorderMap)
Reorder the stored groups (to facilitate reordering of layers).
Definition view.cpp:154
int m_cachedIndex
Cached index in m_allItems.
Definition view.cpp:214
void deleteGroups()
Remove all of the stored group ids.
Definition view.cpp:130
bool isRenderable() const
Return if the item should be drawn or not.
Definition view.cpp:205
int m_drawPriority
Order to draw this item in a layer, lowest first.
Definition view.cpp:213
friend class VIEW
Definition view.cpp:76
VIEW * m_view
Current dynamic view the item is assigned to.
Definition view.cpp:210
std::pair< int, int > * m_groups
layer_number:group_id pairs for each layer the item occupies.
Definition view.cpp:216
int getGroup(int aLayer) const
Return number of the group id for the given layer, or -1 in case it was not cached before.
Definition view.cpp:84
BOX2I m_bbox
Stores layer numbers used by the item.
Definition view.cpp:222
void setGroup(int aLayer, int aGroup)
Set a group id for the item and the layer combination.
Definition view.cpp:101
void saveLayers(const std::vector< int > &aLayers)
Save layers used by the item.
Definition view.cpp:174
int GetFlags() const
Definition view.cpp:70
void clearUpdateFlags()
Mark an item as already updated, so it is not going to be redrawn.
Definition view.cpp:197
virtual const BOX2I ViewBBox() const =0
Return the bounding box of the item covering all its layers.
double m_forcedTransparency
Additional transparency for diff'ing items.
Definition view_item.h:210
VIEW_ITEM_DATA * viewPrivData() const
Definition view_item.h:161
virtual void ViewDraw(int aLayer, VIEW *aView) const
Draw the parts of the object belonging to layer aLayer.
Definition view_item.h:127
virtual std::vector< int > ViewGetLayers() const =0
Return the all the layers within the VIEW the object is painted on.
virtual wxString GetClass() const =0
Return the class name.
virtual double ViewGetLOD(int aLayer, const VIEW *aView) const
Return the level of detail (LOD) of the item.
Definition view_item.h:155
VIEW_ITEM_DATA * m_viewPrivData
Definition view_item.h:209
Hold a (potentially large) number of VIEW_ITEMs and renders them on a graphics device provided by the...
Definition view.h:66
double GetScale() const
Definition view.h:276
void SetMirror(bool aMirrorX, bool aMirrorY)
Control the mirroring of the VIEW.
Definition view.cpp:558
void ShowPreview(bool aShow=true)
Definition view.cpp:1754
double m_maxScale
Definition view.h:882
BOX2D GetViewport() const
Return the current viewport visible area rectangle.
Definition view.cpp:531
void CopySettings(const VIEW *aOtherView)
Copy layers and visibility settings from another view.
Definition view.cpp:506
virtual void SetScale(double aScale, VECTOR2D aAnchor={ 0, 0 })
Set the scaling factor, zooming around a given anchor point.
Definition view.cpp:571
static constexpr int TOP_LAYER_MODIFIER
Rendering order modifier for layers that are marked as top layers.
Definition view.h:748
void draw(VIEW_ITEM *aItem, int aLayer, bool aImmediate=false)
Draw an item, but on a specified layers.
Definition view.cpp:1054
bool m_reverseDrawOrder
Flag to reverse the draw order when using draw priority.
Definition view.h:903
void UpdateAllLayersOrder()
Do everything that is needed to apply the rendering order of layers.
Definition view.cpp:907
void updateItemColor(VIEW_ITEM *aItem, int aLayer)
Update colors that are used for an item to be drawn.
Definition view.cpp:1303
void SetViewport(const BOX2D &aViewport)
Set the visible area of the VIEW.
Definition view.cpp:543
void SetRequired(int aLayerId, int aRequiredId, bool aRequired=true)
Mark the aRequiredId layer as required for the aLayerId layer.
Definition view.cpp:409
VECTOR2D ToScreen(const VECTOR2D &aCoord, bool aAbsolute=true) const
Convert a world space point/vector to a point/vector in screen space coordinates.
Definition view.cpp:487
static bool compareRenderingOrder(VIEW_LAYER *aI, VIEW_LAYER *aJ)
Determine rendering order of layers. Used in display order sorting function.
Definition view.h:843
int GetLayerOrder(int aLayer) const
Return rendering order of a particular layer.
Definition view.cpp:665
virtual void Add(VIEW_ITEM *aItem, int aDrawPriority=-1)
Add a VIEW_ITEM to the view.
Definition view.cpp:298
virtual void Remove(VIEW_ITEM *aItem)
Remove a VIEW_ITEM from the view.
Definition view.cpp:341
void ClearTargets()
Clear targets that are marked as dirty.
Definition view.cpp:1169
virtual void EnableTopLayer(bool aEnable)
Enable or disable display of the top layer.
Definition view.cpp:867
bool m_mirrorX
Definition view.h:884
void UpdateAllLayersColor()
Apply the new coloring scheme to all layers.
Definition view.cpp:776
bool m_mirrorY
Definition view.h:885
std::shared_ptr< std::vector< VIEW_ITEM * > > m_allItems
Flat list of all items.
Definition view.h:871
std::shared_ptr< VIEW_OVERLAY > MakeOverlay()
Definition view.cpp:1709
void SetGAL(GAL *aGal)
Assign a rendering device for the VIEW.
Definition view.cpp:512
int Query(const BOX2I &aRect, std::vector< LAYER_ITEM_PAIR > &aResult) const
Find all visible items that touch or are within the rectangle aRect.
Definition view.cpp:421
std::vector< VIEW_ITEM * > m_ownedItems
Definition view.h:859
virtual void Update(const VIEW_ITEM *aItem, int aUpdateFlags) const
For dynamic VIEWs, inform the associated VIEW that the graphical representation of this item has chan...
Definition view.cpp:1696
void invalidateItem(VIEW_ITEM *aItem, int aUpdateFlags)
Manage dirty flags & redraw queuing when updating an item.
Definition view.cpp:1249
const VECTOR2I & GetScreenPixelSize() const
Return the size of the our rendering area in pixels.
Definition view.cpp:1213
bool HasItem(const VIEW_ITEM *aItem) const
Indicates whether or not the given item has been added to the view.
Definition view.cpp:1682
virtual int GetTopLayer() const
Definition view.cpp:831
PAINTER * m_painter
PAINTER contains information how do draw items.
Definition view.h:888
virtual void Redraw()
Immediately redraws the whole view.
Definition view.cpp:1188
void Clear()
Remove all items from the view.
Definition view.cpp:1144
std::set< unsigned int > m_topLayers
The set of layers that are displayed on the top.
Definition view.h:874
bool m_enableOrderModifier
Whether to use rendering order modifier or not.
Definition view.h:862
VECTOR2D ToWorld(const VECTOR2D &aCoord, bool aAbsolute=true) const
Converts a screen space point/vector to a point/vector in world space coordinates.
Definition view.cpp:468
bool IsHiddenOnOverlay(const VIEW_ITEM *aItem) const
Definition view.cpp:1674
void ClearTopLayers()
Remove all layers from the on-the-top set (they are no longer displayed over the rest of layers).
Definition view.cpp:892
void InitPreview()
Definition view.cpp:1733
void ClearPreview()
Definition view.cpp:1718
void MarkClean()
Force redraw of view on the next rendering.
Definition view.h:668
void updateItemGeometry(VIEW_ITEM *aItem, int aLayer)
Update all information needed to draw an item.
Definition view.cpp:1321
static constexpr int VIEW_MAX_LAYERS
Maximum number of layers that may be shown.
Definition view.h:745
double m_minScale
Definition view.h:881
double m_scale
Definition view.h:879
void updateLayers(VIEW_ITEM *aItem)
Update set of layers that an item occupies.
Definition view.cpp:1383
void RecacheAllItems()
Rebuild GAL display lists.
Definition view.cpp:1462
bool areRequiredLayersEnabled(int aLayerId) const
Check if every layer required by the aLayerId layer is enabled.
Definition view.cpp:1438
bool IsTargetDirty(int aTarget) const
Return true if any of layers belonging to the target or the target itself should be redrawn.
Definition view.h:628
int m_nextDrawPriority
The next sequential drawing priority.
Definition view.h:900
void sortOrderedLayers()
Sort m_orderedLayers when layer rendering order has changed.
Definition view.cpp:1288
bool m_useDrawPriority
Flag to respect draw priority when drawing items.
Definition view.h:897
void UpdateItems()
Iterate through the list of items that asked for updating and updates them.
Definition view.cpp:1479
bool IsCached(int aLayer) const
Return true if the layer is cached.
Definition view.h:646
std::pair< VIEW_ITEM *, int > LAYER_ITEM_PAIR
Definition view.h:70
void SortLayers(std::vector< int > &aLayers) const
Change the order of given layer ids, so after sorting the order corresponds to layers rendering order...
Definition view.cpp:671
void UpdateAllItems(int aUpdateFlags)
Update all items in the view according to the given flags.
Definition view.cpp:1572
std::unique_ptr< KIGFX::VIEW_GROUP > m_preview
Definition view.h:858
static void OnDestroy(VIEW_ITEM *aItem)
Nasty hack, invoked by the destructor of VIEW_ITEM to auto-remove the item from the owning VIEW if th...
Definition view.cpp:226
virtual ~VIEW()
Definition view.cpp:292
GAL * m_gal
Interface to PAINTER that is used to draw items.
Definition view.h:891
std::map< int, VIEW_LAYER > m_layers
The set of possible displayed layers and its properties.
Definition view.h:865
std::unique_ptr< VIEW > DataReference() const
Return a new VIEW object that shares the same set of VIEW_ITEMs and LAYERs.
Definition view.cpp:1613
void Hide(VIEW_ITEM *aItem, bool aHide=true, bool aHideOverlay=false)
Temporarily hide the item in the view (e.g.
Definition view.cpp:1644
virtual void SetTopLayer(int aLayer, bool aEnabled=true)
Set given layer to be displayed on the top or sets back the default order of layers.
Definition view.cpp:840
void AddToPreview(VIEW_ITEM *aItem, bool aTakeOwnership=true)
Definition view.cpp:1740
void UpdateLayerColor(int aLayer)
Apply the new coloring scheme held by RENDER_SETTINGS in case that it has changed.
Definition view.cpp:755
void MarkDirty()
Force redraw of view on the next rendering.
Definition view.h:659
friend class VIEW_ITEM
Definition view.h:68
BOX2D m_boundary
Definition view.h:880
void SetCenter(const VECTOR2D &aCenter)
Set the center point of the VIEW (i.e.
Definition view.cpp:597
std::vector< VIEW_LAYER * > m_orderedLayers
Sorted list of pointers to members of m_layers.
Definition view.h:868
void clearGroupCache()
Clear cached GAL group numbers (ONLY numbers stored in VIEW_ITEMs, not group objects used by GAL).
Definition view.cpp:1237
VECTOR2D m_center
Center point of the VIEW (the point at which we are looking at).
Definition view.h:877
void SetLayerOrder(int aLayer, int aRenderingOrder)
Set rendering order of a particular layer.
Definition view.cpp:657
void MarkTargetDirty(int aTarget)
Set or clear target 'dirty' flag.
Definition view.h:639
void updateBbox(VIEW_ITEM *aItem)
Update bounding box of an item.
Definition view.cpp:1358
bool IsVisible(const VIEW_ITEM *aItem) const
Return information if the item is visible (or not).
Definition view.cpp:1666
void UpdateAllItemsConditionally(int aUpdateFlags, std::function< bool(VIEW_ITEM *)> aCondition)
Update items in the view according to the given flags and condition.
Definition view.cpp:1582
void SetVisible(VIEW_ITEM *aItem, bool aIsVisible=true)
Set the item visibility.
Definition view.cpp:1623
void ReorderLayerData(std::unordered_map< int, int > aReorderMap)
Remap the data between layer ids without invalidating that data.
Definition view.cpp:681
void redrawRect(const BOX2I &aRect)
Redraw contents within rectangle aRect.
Definition view.cpp:1011
VECTOR2< T > GetScale() const
Get the scale components of the matrix.
Definition matrix3x3.h:295
A small class to help profiling.
Definition profile.h:49
void Stop()
Save the time when this function was called, and set the counter stane to stop.
Definition profile.h:88
double msecs(bool aSinceLast=false)
Definition profile.h:149
Represent a set of closed polygons.
bool IsEmpty() const
Return true if the set is empty (no polygons at all)
void Deflate(int aAmount, CORNER_STRATEGY aCornerStrategy, int aMaxError)
void BooleanSubtract(const SHAPE_POLY_SET &b)
Perform boolean polyset difference.
const BOX2I BBox(int aClearance=0) const override
Compute a bounding box of the shape, with a margin of aClearance a collision.
@ ALLOW_ACUTE_CORNERS
just inflate the polygon. Acute angles create spikes
#define _(s)
const wxChar *const traceGalProfile
Flag to enable debug output of GAL performance profiling.
@ UNDEFINED_LAYER
Definition layer_ids.h:61
MATRIX3x3< double > MATRIX3x3D
Definition matrix3x3.h:473
The Cairo implementation of the graphics abstraction layer.
Definition eda_group.h:33
@ COLOR
Color has changed.
Definition view_item.h:54
@ INITIAL_ADD
Item is being added to the view.
Definition view_item.h:57
@ NONE
No updates are required.
Definition view_item.h:52
@ REPAINT
Item needs to be redrawn.
Definition view_item.h:58
@ APPEARANCE
Visibility flag has changed.
Definition view_item.h:53
@ GEOMETRY
Position or shape has changed.
Definition view_item.h:55
@ LAYERS
Layers have changed.
Definition view_item.h:56
@ ALL
All except INITIAL_ADD.
Definition view_item.h:59
@ TARGET_NONCACHED
Auxiliary rendering target (noncached)
Definition definitions.h:38
@ TARGET_CACHED
Main rendering target (cached)
Definition definitions.h:37
@ TARGET_OVERLAY
Items that may change while the view stays the same (noncached)
Definition definitions.h:39
@ HIDDEN
Item is temporarily hidden (usually in favor of a being drawn from an overlay, such as a SELECTION).
Definition view_item.h:70
@ OVERLAY_HIDDEN
Item is temporarily hidden from being drawn on an overlay.
Definition view_item.h:71
@ VISIBLE
Item is visible (in general)
Definition view_item.h:66
std::shared_ptr< PNS_LOG_VIEWER_OVERLAY > overlay
bool operator()(VIEW_ITEM *aItem)
Definition view.cpp:1226
bool operator()(VIEW_ITEM *aItem)
Definition view.cpp:951
DRAW_ITEM_VISITOR(VIEW *aView, int aLayer, bool aUseDrawPriority, bool aReverseDrawOrder)
Definition view.cpp:941
int layers[VIEW_MAX_LAYERS]
Definition view.cpp:1003
std::vector< VIEW_ITEM * > drawItems
Definition view.cpp:1005
bool operator()(VIEW_ITEM *aItem)
Definition view.cpp:1119
RECACHE_ITEM_VISITOR(VIEW *aView, GAL *aGal, int aLayer)
Definition view.cpp:1112
bool operator()(VIEW_ITEM *aItem)
Definition view.cpp:737
UPDATE_COLOR_VISITOR(int aLayer, PAINTER *aPainter, GAL *aGal)
Definition view.cpp:730
UPDATE_DEPTH_VISITOR(int aLayer, int aDepth, GAL *aGal)
Definition view.cpp:809
bool operator()(VIEW_ITEM *aItem)
Definition view.cpp:816
bool diffLayer
Layer should be drawn differentially over lower layers.
Definition view.h:757
int renderingOrder
Rendering order of this layer.
Definition view.h:762
bool hasNegatives
Layer should be drawn separately to not delete lower layers.
Definition view.h:760
bool visible
Is the layer to be rendered?
Definition view.h:753
bool displayOnly
Is the layer display only?
Definition view.h:754
std::shared_ptr< VIEW_RTREE > items
R-tree indexing all items on this layer.
Definition view.h:761
RENDER_TARGET target
Where the layer should be rendered.
Definition view.h:764
int id
Layer ID.
Definition view.h:763
int delta
wxLogTrace helper definitions.
#define KI_TRACE(aWhat,...)
VECTOR2< int32_t > VECTOR2I
Definition vector2d.h:695
VECTOR2< double > VECTOR2D
Definition vector2d.h:694