KiCad PCB EDA Suite
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 (C) 2021 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 <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>
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 
54 {
55 public:
57  m_view( nullptr ),
58  m_flags( KIGFX::VISIBLE ),
60  m_drawPriority( 0 ),
61  m_groups( nullptr ),
62  m_groupsSize( 0 ) {}
63 
65  {
66  deleteGroups();
67  }
68 
69  int GetFlags() const
70  {
71  return m_flags;
72  }
73 
74 private:
75  friend class VIEW;
76 
83  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 
99  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 
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 
146  {
147  delete[] m_groups;
148  m_groups = nullptr;
149  m_groupsSize = 0;
150  }
151 
152 
158  inline bool storesGroups() const
159  {
160  return m_groupsSize > 0;
161  }
162 
163 
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 
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 
211  int requiredUpdate() const
212  {
213  return m_requiredUpdate;
214  }
215 
220  {
222  }
223 
227  bool isRenderable() const
228  {
229  return m_flags == VISIBLE;
230  }
231 
233  int m_flags;
236 
237  std::pair<int, int>* m_groups;
238  int m_groupsSize;
240 
241  std::vector<int> m_layers;
242 };
243 
244 
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 
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 
315 {
316  Remove( m_preview.get() );
317 }
318 
319 
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 
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 
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>
405 {
406  typedef typename CONTAINER::value_type item_type;
407 
408  QUERY_VISITOR( CONTAINER& aCont, int aLayer ) :
409  m_cont( aCont ), m_layer( aLayer )
410  {
411  }
412 
413  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 
422  int m_layer;
423 };
424 
425 
426 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 
449 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 
460 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 
468 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 
479 double VIEW::ToScreen( double aSize ) const
480 {
481  const MATRIX3x3D& matrix = m_gal->GetWorldScreenMatrix();
482 
483  return matrix.GetScale().x * aSize;
484 }
485 
486 
487 void VIEW::CopySettings( const VIEW* aOtherView )
488 {
489  wxASSERT_MSG( false, wxT( "This is not implemented" ) );
490 }
491 
492 
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 );
509 }
510 
511 
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 
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 
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 
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 )
561  else if( aScale > m_maxScale )
563  else
564  m_scale = aScale;
565 
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 
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() )
586  else if( aCenter.x > m_boundary.GetRight() )
588 
589  if( m_center.y < m_boundary.GetTop() )
591  else if( m_center.y > m_boundary.GetBottom() )
593  }
594 
597 
598  // Redraw everything after the viewport has changed
599  MarkDirty();
600 }
601 
602 
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 
635 void VIEW::SetLayerOrder( int aLayer, int aRenderingOrder )
636 {
637  m_layers[aLayer].renderingOrder = aRenderingOrder;
638 
639  sortLayers();
640 }
641 
642 
643 int VIEW::GetLayerOrder( int aLayer ) const
644 {
645  return m_layers.at( aLayer ).renderingOrder;
646 }
647 
648 
649 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 
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( const VIEW_LAYER& layer : m_layers )
683  new_map.push_back( layer );
684 
685  for( auto& pair : aReorderMap )
686  {
687  new_map[pair.second] = m_layers[pair.first];
688  new_map[pair.second].id = pair.second;
689  }
690 
691  m_layers = new_map;
692 
693  for( VIEW_ITEM* item : *m_allItems )
694  {
695  VIEW_ITEM_DATA* viewData = item->viewPrivData();
696 
697  if( !viewData )
698  continue;
699 
700  int layers[VIEW::VIEW_MAX_LAYERS], layers_count;
701 
702  item->ViewGetLayers( layers, layers_count );
703  viewData->saveLayers( layers, layers_count );
704 
705  viewData->reorderGroups( aReorderMap );
706 
707  viewData->m_requiredUpdate |= COLOR;
708  }
709 
710  UpdateItems();
711 }
712 
713 
715 {
716  UPDATE_COLOR_VISITOR( int aLayer, PAINTER* aPainter, GAL* aGal ) :
717  layer( aLayer ),
718  painter( aPainter ),
719  gal( aGal )
720  {
721  }
722 
723  bool operator()( VIEW_ITEM* aItem )
724  {
725  // Obtain the color that should be used for coloring the item
726  const COLOR4D color = painter->GetSettings()->GetColor( aItem, layer );
727  int group = aItem->viewPrivData()->getGroup( layer );
728 
729  if( group >= 0 )
731 
732  return true;
733  }
734 
735  int layer;
738 };
739 
740 
741 void VIEW::UpdateLayerColor( int aLayer )
742 {
743  // There is no point in updating non-cached layers
744  if( !IsCached( aLayer ) )
745  return;
746 
747  BOX2I r;
748 
749  r.SetMaximum();
750 
751  if( m_gal->IsVisible() )
752  {
753  GAL_UPDATE_CONTEXT ctx( m_gal );
754 
755  UPDATE_COLOR_VISITOR visitor( aLayer, m_painter, m_gal );
756  m_layers[aLayer].items->Query( r, visitor );
757  MarkTargetDirty( m_layers[aLayer].target );
758  }
759 }
760 
761 
763 {
764  if( m_gal->IsVisible() )
765  {
766  GAL_UPDATE_CONTEXT ctx( m_gal );
767 
768  for( VIEW_ITEM* item : *m_allItems )
769  {
770  VIEW_ITEM_DATA* viewData = item->viewPrivData();
771 
772  if( !viewData )
773  continue;
774 
775  int layers[VIEW::VIEW_MAX_LAYERS], layers_count;
776  viewData->getLayers( layers, layers_count );
777 
778  for( int i = 0; i < layers_count; ++i )
779  {
780  const COLOR4D color = m_painter->GetSettings()->GetColor( item, layers[i] );
781  int group = viewData->getGroup( layers[i] );
782 
783  if( group >= 0 )
785  }
786  }
787  }
788 
789  MarkDirty();
790 }
791 
792 
794 {
795  UPDATE_DEPTH_VISITOR( int aLayer, int aDepth, GAL* aGal ) :
796  layer( aLayer ),
797  depth( aDepth ),
798  gal( aGal )
799  {
800  }
801 
802  bool operator()( VIEW_ITEM* aItem )
803  {
804  int group = aItem->viewPrivData()->getGroup( layer );
805 
806  if( group >= 0 )
808 
809  return true;
810  }
811 
812  int layer, depth;
814 };
815 
816 
817 int VIEW::GetTopLayer() const
818 {
819  if( m_topLayers.size() == 0 )
820  return 0;
821 
822  return *m_topLayers.begin();
823 }
824 
825 
826 void VIEW::SetTopLayer( int aLayer, bool aEnabled )
827 {
828  if( aEnabled )
829  {
830  if( m_topLayers.count( aLayer ) == 1 )
831  return;
832 
833  m_topLayers.insert( aLayer );
834 
835  // Move the layer closer to front
837  m_layers[aLayer].renderingOrder += TOP_LAYER_MODIFIER;
838  }
839  else
840  {
841  if( m_topLayers.count( aLayer ) == 0 )
842  return;
843 
844  m_topLayers.erase( aLayer );
845 
846  // Restore the previous rendering order
848  m_layers[aLayer].renderingOrder -= TOP_LAYER_MODIFIER;
849  }
850 }
851 
852 
853 void VIEW::EnableTopLayer( bool aEnable )
854 {
855  if( aEnable == m_enableOrderModifier )
856  return;
857 
858  m_enableOrderModifier = aEnable;
859 
860  std::set<unsigned int>::iterator it;
861 
862  if( aEnable )
863  {
864  for( it = m_topLayers.begin(); it != m_topLayers.end(); ++it )
865  m_layers[*it].renderingOrder += TOP_LAYER_MODIFIER;
866  }
867  else
868  {
869  for( it = m_topLayers.begin(); it != m_topLayers.end(); ++it )
870  m_layers[*it].renderingOrder -= TOP_LAYER_MODIFIER;
871  }
872 
875 }
876 
877 
879 {
880  std::set<unsigned int>::iterator it;
881 
883  {
884  // Restore the previous rendering order for layers that were marked as top
885  for( it = m_topLayers.begin(); it != m_topLayers.end(); ++it )
886  m_layers[*it].renderingOrder -= TOP_LAYER_MODIFIER;
887  }
888 
889  m_topLayers.clear();
890 }
891 
892 
894 {
895  sortLayers();
896 
897  if( m_gal->IsVisible() )
898  {
899  GAL_UPDATE_CONTEXT ctx( m_gal );
900 
901  for( VIEW_ITEM* item : *m_allItems )
902  {
903  VIEW_ITEM_DATA* viewData = item->viewPrivData();
904 
905  if( !viewData )
906  continue;
907 
908  int layers[VIEW::VIEW_MAX_LAYERS], layers_count;
909  viewData->getLayers( layers, layers_count );
910 
911  for( int i = 0; i < layers_count; ++i )
912  {
913  int group = viewData->getGroup( layers[i] );
914 
915  if( group >= 0 )
916  m_gal->ChangeGroupDepth( group, m_layers[layers[i]].renderingOrder );
917  }
918  }
919  }
920 
921  MarkDirty();
922 }
923 
924 
926 {
927  DRAW_ITEM_VISITOR( VIEW* aView, int aLayer, bool aUseDrawPriority, bool aReverseDrawOrder ) :
928  view( aView ),
929  layer( aLayer ),
930  useDrawPriority( aUseDrawPriority ),
931  reverseDrawOrder( aReverseDrawOrder )
932  {
933  }
934 
935  bool operator()( VIEW_ITEM* aItem )
936  {
937  wxCHECK( aItem->viewPrivData(), false );
938 
939  // Conditions that have to be fulfilled for an item to be drawn
940  bool drawCondition = aItem->viewPrivData()->isRenderable()
941  && aItem->ViewGetLOD( layer, view ) < view->m_scale;
942  if( !drawCondition )
943  return true;
944 
945  if( useDrawPriority )
946  drawItems.push_back( aItem );
947  else
948  view->draw( aItem, layer );
949 
950  return true;
951  }
952 
954  {
955  if( reverseDrawOrder )
956  {
957  std::sort( drawItems.begin(), drawItems.end(),
958  []( VIEW_ITEM* a, VIEW_ITEM* b ) -> bool
959  {
960  return b->viewPrivData()->m_drawPriority < a->viewPrivData()->m_drawPriority;
961  });
962  }
963  else
964  {
965  std::sort( drawItems.begin(), drawItems.end(),
966  []( VIEW_ITEM* a, VIEW_ITEM* b ) -> bool
967  {
968  return a->viewPrivData()->m_drawPriority < b->viewPrivData()->m_drawPriority;
969  });
970  }
971 
972  for( VIEW_ITEM* item : drawItems )
973  view->draw( item, layer );
974  }
975 
979  std::vector<VIEW_ITEM*> drawItems;
980 };
981 
982 
983 void VIEW::redrawRect( const BOX2I& aRect )
984 {
985  for( VIEW_LAYER* l : m_orderedLayers )
986  {
987  if( l->visible && IsTargetDirty( l->target ) && areRequiredLayersEnabled( l->id ) )
988  {
989  DRAW_ITEM_VISITOR drawFunc( this, l->id, m_useDrawPriority, m_reverseDrawOrder );
990 
991  m_gal->SetTarget( l->target );
992  m_gal->SetLayerDepth( l->renderingOrder );
993 
994  // Differential layer also work for the negatives, since both special layer types
995  // will composite on separate layers (at least in Cairo)
996  if( l->diffLayer )
998  else if( l->hasNegatives )
1000 
1001 
1002  l->items->Query( aRect, drawFunc );
1003 
1004  if( m_useDrawPriority )
1005  drawFunc.deferredDraw();
1006 
1007  if( l->diffLayer )
1008  m_gal->EndDiffLayer();
1009  else if( l->hasNegatives )
1011  }
1012  }
1013 }
1014 
1015 
1016 void VIEW::draw( VIEW_ITEM* aItem, int aLayer, bool aImmediate )
1017 {
1018  VIEW_ITEM_DATA* viewData = aItem->viewPrivData();
1019 
1020  if( !viewData )
1021  return;
1022 
1023  if( IsCached( aLayer ) && !aImmediate )
1024  {
1025  // Draw using cached information or create one
1026  int group = viewData->getGroup( aLayer );
1027 
1028  if( group >= 0 )
1029  m_gal->DrawGroup( group );
1030  else
1031  Update( aItem );
1032  }
1033  else
1034  {
1035  // Immediate mode
1036  if( !m_painter->Draw( aItem, aLayer ) )
1037  aItem->ViewDraw( aLayer, this ); // Alternative drawing method
1038  }
1039 }
1040 
1041 
1042 void VIEW::draw( VIEW_ITEM* aItem, bool aImmediate )
1043 {
1044  int layers[VIEW_MAX_LAYERS], layers_count;
1045 
1046  aItem->ViewGetLayers( layers, layers_count );
1047 
1048  // Sorting is needed for drawing order dependent GALs (like Cairo)
1049  SortLayers( layers, layers_count );
1050 
1051  for( int i = 0; i < layers_count; ++i )
1052  {
1053  m_gal->SetLayerDepth( m_layers.at( layers[i] ).renderingOrder );
1054  draw( aItem, layers[i], aImmediate );
1055  }
1056 }
1057 
1058 
1059 void VIEW::draw( VIEW_GROUP* aGroup, bool aImmediate )
1060 {
1061  for( unsigned int i = 0; i < aGroup->GetSize(); i++)
1062  draw( aGroup->GetItem(i), aImmediate );
1063 }
1064 
1065 
1067 {
1068  RECACHE_ITEM_VISITOR( VIEW* aView, GAL* aGal, int aLayer ) :
1069  view( aView ),
1070  gal( aGal ),
1071  layer( aLayer )
1072  {
1073  }
1074 
1075  bool operator()( VIEW_ITEM* aItem )
1076  {
1077  VIEW_ITEM_DATA* viewData = aItem->viewPrivData();
1078 
1079  if( !viewData )
1080  return false;
1081 
1082  // Remove previously cached group
1083  int group = viewData->getGroup( layer );
1084 
1085  if( group >= 0 )
1086  gal->DeleteGroup( group );
1087 
1088  viewData->setGroup( layer, -1 );
1089  view->Update( aItem );
1090 
1091  return true;
1092  }
1093 
1096  int layer;
1097 };
1098 
1099 
1101 {
1102  BOX2I r;
1103  r.SetMaximum();
1104  m_allItems->clear();
1105 
1106  for( VIEW_LAYER& layer : m_layers )
1107  layer.items->RemoveAll();
1108 
1109  m_nextDrawPriority = 0;
1110 
1111  m_gal->ClearCache();
1112 }
1113 
1114 
1116 {
1118  {
1119  // TARGET_CACHED and TARGET_NONCACHED have to be redrawn together, as they contain
1120  // layers that rely on each other (eg. netnames are noncached, but tracks - are cached)
1123 
1124  MarkDirty();
1125  }
1126 
1127  if( IsTargetDirty( TARGET_OVERLAY ) )
1128  {
1130  }
1131 }
1132 
1133 
1135 {
1136 #ifdef KICAD_GAL_PROFILE
1137  PROF_COUNTER totalRealTime;
1138 #endif /* KICAD_GAL_PROFILE */
1139 
1140  VECTOR2D screenSize = m_gal->GetScreenPixelSize();
1141  BOX2D rect( ToWorld( VECTOR2D( 0, 0 ) ),
1142  ToWorld( screenSize ) - ToWorld( VECTOR2D( 0, 0 ) ) );
1143 
1144  rect.Normalize();
1145  BOX2I recti( rect.GetPosition(), rect.GetSize() );
1146 
1147  // The view rtree uses integer positions. Large screens can overflow this size so in
1148  // this case, simply set the rectangle to the full rtree.
1149  if( rect.GetWidth() > std::numeric_limits<int>::max()
1150  || rect.GetHeight() > std::numeric_limits<int>::max() )
1151  {
1152  recti.SetMaximum();
1153  }
1154 
1155  redrawRect( recti );
1156 
1157  // All targets were redrawn, so nothing is dirty
1158  MarkClean();
1159 
1160 #ifdef KICAD_GAL_PROFILE
1161  totalRealTime.Stop();
1162  wxLogTrace( traceGalProfile, "VIEW::Redraw(): %.1f ms", totalRealTime.msecs() );
1163 #endif /* KICAD_GAL_PROFILE */
1164 }
1165 
1166 
1168 {
1169  return m_gal->GetScreenPixelSize();
1170 }
1171 
1172 
1174 {
1176  view( aView )
1177  {
1178  }
1179 
1180  bool operator()( VIEW_ITEM* aItem )
1181  {
1182  aItem->viewPrivData()->deleteGroups();
1183 
1184  return true;
1185  }
1186 
1188 };
1189 
1190 
1192 {
1193  BOX2I r;
1194 
1195  r.SetMaximum();
1196  CLEAR_LAYER_CACHE_VISITOR visitor( this );
1197 
1198  for( VIEW_LAYER& layer : m_layers )
1199  layer.items->Query( r, visitor );
1200 }
1201 
1202 
1203 void VIEW::invalidateItem( VIEW_ITEM* aItem, int aUpdateFlags )
1204 {
1205  if( aUpdateFlags & INITIAL_ADD )
1206  {
1207  // Don't update layers or bbox, since it was done in VIEW::Add()
1208  // Now that we have initialized, set flags to ALL for the code below
1209  aUpdateFlags = ALL;
1210  }
1211  else
1212  {
1213  // updateLayers updates geometry too, so we do not have to update both of them at the
1214  // same time
1215  if( aUpdateFlags & LAYERS )
1216  updateLayers( aItem );
1217  else if( aUpdateFlags & GEOMETRY )
1218  updateBbox( aItem );
1219  }
1220 
1221  int layers[VIEW_MAX_LAYERS], layers_count;
1222  aItem->ViewGetLayers( layers, layers_count );
1223 
1224  // Iterate through layers used by the item and recache it immediately
1225  for( int i = 0; i < layers_count; ++i )
1226  {
1227  int layerId = layers[i];
1228 
1229  if( IsCached( layerId ) )
1230  {
1231  if( aUpdateFlags & ( GEOMETRY | LAYERS | REPAINT ) )
1232  updateItemGeometry( aItem, layerId );
1233  else if( aUpdateFlags & COLOR )
1234  updateItemColor( aItem, layerId );
1235  }
1236 
1237  // Mark those layers as dirty, so the VIEW will be refreshed
1238  MarkTargetDirty( m_layers[layerId].target );
1239  }
1240 
1241  aItem->viewPrivData()->clearUpdateFlags();
1242 }
1243 
1244 
1246 {
1247  int n = 0;
1248 
1249  m_orderedLayers.resize( m_layers.size() );
1250 
1251  for( VIEW_LAYER& layer : m_layers )
1252  m_orderedLayers[n++] = &layer;
1253 
1254  sort( m_orderedLayers.begin(), m_orderedLayers.end(), compareRenderingOrder );
1255 
1256  MarkDirty();
1257 }
1258 
1259 
1260 void VIEW::updateItemColor( VIEW_ITEM* aItem, int aLayer )
1261 {
1262  VIEW_ITEM_DATA* viewData = aItem->viewPrivData();
1263  wxCHECK( (unsigned) aLayer < m_layers.size(), /*void*/ );
1264  wxCHECK( IsCached( aLayer ), /*void*/ );
1265 
1266  if( !viewData )
1267  return;
1268 
1269  // Obtain the color that should be used for coloring the item on the specific layerId
1270  const COLOR4D color = m_painter->GetSettings()->GetColor( aItem, aLayer );
1271  int group = viewData->getGroup( aLayer );
1272 
1273  // Change the color, only if it has group assigned
1274  if( group >= 0 )
1276 }
1277 
1278 
1279 void VIEW::updateItemGeometry( VIEW_ITEM* aItem, int aLayer )
1280 {
1281  VIEW_ITEM_DATA* viewData = aItem->viewPrivData();
1282  wxCHECK( (unsigned) aLayer < m_layers.size(), /*void*/ );
1283  wxCHECK( IsCached( aLayer ), /*void*/ );
1284 
1285  if( !viewData )
1286  return;
1287 
1288  VIEW_LAYER& l = m_layers.at( aLayer );
1289 
1290  m_gal->SetTarget( l.target );
1292 
1293  // Redraw the item from scratch
1294  int group = viewData->getGroup( aLayer );
1295 
1296  if( group >= 0 )
1297  m_gal->DeleteGroup( group );
1298 
1299  group = m_gal->BeginGroup();
1300  viewData->setGroup( aLayer, group );
1301 
1302  if( !m_painter->Draw( static_cast<EDA_ITEM*>( aItem ), aLayer ) )
1303  aItem->ViewDraw( aLayer, this ); // Alternative drawing method
1304 
1305  m_gal->EndGroup();
1306 }
1307 
1308 
1310 {
1311  int layers[VIEW_MAX_LAYERS], layers_count;
1312 
1313  aItem->ViewGetLayers( layers, layers_count );
1314 
1315  for( int i = 0; i < layers_count; ++i )
1316  {
1317  VIEW_LAYER& l = m_layers[layers[i]];
1318  l.items->Remove( aItem );
1319  l.items->Insert( aItem );
1320  MarkTargetDirty( l.target );
1321  }
1322 }
1323 
1324 
1326 {
1327  VIEW_ITEM_DATA* viewData = aItem->viewPrivData();
1328  int layers[VIEW_MAX_LAYERS], layers_count;
1329 
1330  if( !viewData )
1331  return;
1332 
1333  // Remove the item from previous layer set
1334  viewData->getLayers( layers, layers_count );
1335 
1336  for( int i = 0; i < layers_count; ++i )
1337  {
1338  VIEW_LAYER& l = m_layers[layers[i]];
1339  l.items->Remove( aItem );
1340  MarkTargetDirty( l.target );
1341 
1342  if( IsCached( l.id ) )
1343  {
1344  // Redraw the item from scratch
1345  int prevGroup = viewData->getGroup( layers[i] );
1346 
1347  if( prevGroup >= 0 )
1348  {
1349  m_gal->DeleteGroup( prevGroup );
1350  viewData->setGroup( l.id, -1 );
1351  }
1352  }
1353  }
1354 
1355  // Add the item to new layer set
1356  aItem->ViewGetLayers( layers, layers_count );
1357  viewData->saveLayers( layers, layers_count );
1358 
1359  for( int i = 0; i < layers_count; i++ )
1360  {
1361  VIEW_LAYER& l = m_layers[layers[i]];
1362  l.items->Insert( aItem );
1363  MarkTargetDirty( l.target );
1364  }
1365 }
1366 
1367 
1368 bool VIEW::areRequiredLayersEnabled( int aLayerId ) const
1369 {
1370  wxCHECK( (unsigned) aLayerId < m_layers.size(), false );
1371 
1372  std::set<int>::const_iterator it, it_end;
1373 
1374  for( int layer : m_layers.at( aLayerId ).requiredLayers )
1375  {
1376  // That is enough if just one layer is not enabled
1377  if( !m_layers.at( layer ).visible || !areRequiredLayersEnabled( layer ) )
1378  return false;
1379  }
1380 
1381  return true;
1382 }
1383 
1384 
1386 {
1387  BOX2I r;
1388 
1389  r.SetMaximum();
1390 
1391  for( const VIEW_LAYER& l : m_layers )
1392  {
1393  if( IsCached( l.id ) )
1394  {
1395  RECACHE_ITEM_VISITOR visitor( this, m_gal, l.id );
1396  l.items->Query( r, visitor );
1397  }
1398  }
1399 }
1400 
1401 
1403 {
1404  if( !m_gal->IsVisible() )
1405  return;
1406 
1407  unsigned int cntGeomUpdate = 0;
1408  unsigned int cntAnyUpdate = 0;
1409 
1410  for( VIEW_ITEM* item : *m_allItems )
1411  {
1412  auto vpd = item->viewPrivData();
1413 
1414  if( !vpd )
1415  continue;
1416 
1417  if( vpd->m_requiredUpdate & ( GEOMETRY | LAYERS ) )
1418  {
1419  cntGeomUpdate++;
1420  }
1421  if( vpd->m_requiredUpdate != NONE )
1422  {
1423  cntAnyUpdate++;
1424  }
1425  }
1426 
1427  unsigned int cntTotal = m_allItems->size();
1428 
1429  double ratio = (double) cntGeomUpdate / (double) cntTotal;
1430 
1431  // Optimization to improve view update time. If a lot of items (say, 30%) have their
1432  // bboxes/geometry changed it's way faster (around 10 times) to rebuild the R-Trees
1433  // from scratch rather than update the bbox of each changed item. Pcbnew does multiple
1434  // full geometry updates during file load, this can save a solid 30 seconds on load time
1435  // for larger designs...
1436 
1437  if( ratio > 0.3 )
1438  {
1439  auto allItems = *m_allItems;
1440  int layers[VIEW_MAX_LAYERS], layers_count;
1441 
1442  // kill all Rtrees
1443  for( VIEW_LAYER& layer : m_layers )
1444  layer.items->RemoveAll();
1445 
1446  // and re-insert items from scratch
1447  for( VIEW_ITEM* item : allItems )
1448  {
1449  item->ViewGetLayers( layers, layers_count );
1450  item->viewPrivData()->saveLayers( layers, layers_count );
1451 
1452  for( int i = 0; i < layers_count; ++i )
1453  {
1454  VIEW_LAYER& l = m_layers[layers[i]];
1455  l.items->Insert( item );
1456  MarkTargetDirty( l.target );
1457  }
1458 
1459  item->viewPrivData()->m_requiredUpdate &= ~( LAYERS | GEOMETRY );
1460  }
1461  }
1462 
1463  if( cntAnyUpdate )
1464  {
1465  GAL_UPDATE_CONTEXT ctx( m_gal );
1466 
1467  for( VIEW_ITEM* item : *m_allItems.get() )
1468  {
1469  if( item->viewPrivData() && item->viewPrivData()->m_requiredUpdate != NONE )
1470  {
1471  invalidateItem( item, item->viewPrivData()->m_requiredUpdate );
1472  item->viewPrivData()->m_requiredUpdate = NONE;
1473  }
1474  }
1475  }
1476 
1477  KI_TRACE( traceGalProfile, "View update: total items %u, geom %u updates %u\n", cntTotal,
1478  cntGeomUpdate, cntAnyUpdate );
1479 }
1480 
1481 
1482 void VIEW::UpdateAllItems( int aUpdateFlags )
1483 {
1484  for( VIEW_ITEM* item : *m_allItems )
1485  {
1486  if( item->viewPrivData() )
1487  item->viewPrivData()->m_requiredUpdate |= aUpdateFlags;
1488  }
1489 }
1490 
1491 
1492 void VIEW::UpdateAllItemsConditionally( int aUpdateFlags,
1493  std::function<bool( VIEW_ITEM* )> aCondition )
1494 {
1495  for( VIEW_ITEM* item : *m_allItems )
1496  {
1497  if( aCondition( item ) )
1498  {
1499  if( item->viewPrivData() )
1500  item->viewPrivData()->m_requiredUpdate |= aUpdateFlags;
1501  }
1502  }
1503 }
1504 
1505 
1506 std::unique_ptr<VIEW> VIEW::DataReference() const
1507 {
1508  std::unique_ptr<VIEW> ret = std::make_unique<VIEW>();
1509  ret->m_allItems = m_allItems;
1510  ret->m_layers = m_layers;
1511  ret->sortLayers();
1512  return ret;
1513 }
1514 
1515 
1516 void VIEW::SetVisible( VIEW_ITEM* aItem, bool aIsVisible )
1517 {
1518  VIEW_ITEM_DATA* viewData = aItem->viewPrivData();
1519 
1520  if( !viewData )
1521  return;
1522 
1523  bool cur_visible = viewData->m_flags & VISIBLE;
1524 
1525  if( cur_visible != aIsVisible )
1526  {
1527  if( aIsVisible )
1528  viewData->m_flags |= VISIBLE;
1529  else
1530  viewData->m_flags &= ~VISIBLE;
1531 
1532  Update( aItem, APPEARANCE | COLOR );
1533  }
1534 }
1535 
1536 
1537 void VIEW::Hide( VIEW_ITEM* aItem, bool aHide )
1538 {
1539  VIEW_ITEM_DATA* viewData = aItem->viewPrivData();
1540 
1541  if( !viewData )
1542  return;
1543 
1544  if( !( viewData->m_flags & VISIBLE ) )
1545  return;
1546 
1547  if( aHide )
1548  viewData->m_flags |= HIDDEN;
1549  else
1550  viewData->m_flags &= ~HIDDEN;
1551 
1552  Update( aItem, APPEARANCE );
1553 }
1554 
1555 
1556 bool VIEW::IsVisible( const VIEW_ITEM* aItem ) const
1557 {
1558  const VIEW_ITEM_DATA* viewData = aItem->viewPrivData();
1559 
1560  return viewData && ( viewData->m_flags & VISIBLE );
1561 }
1562 
1563 
1564 void VIEW::Update( const VIEW_ITEM* aItem ) const
1565 {
1566  Update( aItem, ALL );
1567 }
1568 
1569 
1570 void VIEW::Update( const VIEW_ITEM* aItem, int aUpdateFlags ) const
1571 {
1572  VIEW_ITEM_DATA* viewData = aItem->viewPrivData();
1573 
1574  if( !viewData )
1575  return;
1576 
1577  assert( aUpdateFlags != NONE );
1578 
1579  viewData->m_requiredUpdate |= aUpdateFlags;
1580 }
1581 
1582 
1583 std::shared_ptr<VIEW_OVERLAY> VIEW::MakeOverlay()
1584 {
1585  std::shared_ptr<VIEW_OVERLAY> overlay( new VIEW_OVERLAY );
1586 
1587  Add( overlay.get() );
1588  return overlay;
1589 }
1590 
1591 
1593 {
1594  if( !m_preview )
1595  return;
1596 
1597  m_preview->Clear();
1598 
1599  for( EDA_ITEM *item : m_ownedItems )
1600  delete item;
1601 
1602  m_ownedItems.clear();
1603  Update( m_preview.get() );
1604 }
1605 
1606 
1608 {
1609  m_preview.reset( new KIGFX::VIEW_GROUP() );
1610  Add( m_preview.get() );
1611 }
1612 
1613 
1614 void VIEW::AddToPreview( EDA_ITEM* aItem, bool aTakeOwnership )
1615 {
1616  Hide( aItem, false );
1617  m_preview->Add( aItem );
1618 
1619  if( aTakeOwnership )
1620  m_ownedItems.push_back( aItem );
1621 
1622  SetVisible( m_preview.get(), true );
1623  Hide( m_preview.get(), false );
1624  Update( m_preview.get() );
1625 }
1626 
1627 
1628 void VIEW::ShowPreview( bool aShow )
1629 {
1630  SetVisible( m_preview.get(), aShow );
1631 }
1632 
1633 
1634 const int VIEW::TOP_LAYER_MODIFIER = -VIEW_MAX_LAYERS;
1635 
1636 } // namespace KIGFX
void Hide(VIEW_ITEM *aItem, bool aHide=true)
Temporarily hide the item in the view (e.g.
Definition: view.cpp:1537
virtual void DrawGroup(int aGroupNumber)
Draw the stored group.
Item is being added to the view.
Definition: view_item.h:51
Item is temporarily hidden (e.g.
Definition: view_item.h:61
int requiredUpdate() const
Return current update flag for an item.
Definition: view.cpp:211
void deleteGroups()
Remove all of the stored group ids.
Definition: view.cpp:145
BOX2D GetViewport() const
Return the current viewport visible area rectangle.
Definition: view.cpp:512
VIEW_ITEM_DATA * m_viewPrivData
Definition: view_item.h:151
void SetViewport(const BOX2D &aViewport)
Set the visible area of the VIEW.
Definition: view.cpp:524
void updateLayers(VIEW_ITEM *aItem)
Determine rendering order of layers. Used in display order sorting function.
Definition: view.cpp:1325
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:1492
CONTAINER & m_cont
Definition: view.cpp:421
void SetLayerOrder(int aLayer, int aRenderingOrder)
Set rendering order of a particular layer.
Definition: view.cpp:635
void SetRequired(int aLayerId, int aRequiredId, bool aRequired=true)
Mark the aRequiredId layer as required for the aLayerId layer.
Definition: view.cpp:390
void updateItemColor(VIEW_ITEM *aItem, int aLayer)
Update all information needed to draw an item.
Definition: view.cpp:1260
bool m_useDrawPriority
The next sequential drawing priority.
Definition: view.h:861
std::unique_ptr< KIGFX::VIEW_GROUP > m_preview
Definition: view.h:813
The Cairo implementation of the graphics abstraction layer.
Definition: color4d.cpp:243
virtual void DeleteGroup(int aGroupNumber)
Delete the group from the memory.
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:826
std::shared_ptr< PNS_LOG_VIEWER_OVERLAY > overlay
Definition: playground.cpp:36
static const int TOP_LAYER_MODIFIER
Flag to respect draw priority when drawing items.
Definition: view.h:858
const MATRIX3x3D & GetScreenWorldMatrix() const
Get the screen <-> world transformation matrix.
void sortLayers()
Clear cached GAL group numbers (ONLY numbers stored in VIEW_ITEMs, not group objects used by GAL)
Definition: view.cpp:1245
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:449
coord_type GetTop() const
Definition: box2.h:187
void AddToPreview(EDA_ITEM *aItem, bool aTakeOwnership=true)
Definition: view.cpp:1614
int color
Definition: DXF_plotter.cpp:57
void RecacheAllItems()
Rebuild GAL display lists.
Definition: view.cpp:1385
void UpdateAllItems(int aUpdateFlags)
Update all items in the view according to the given flags.
Definition: view.cpp:1482
virtual void Remove(VIEW_ITEM *aItem)
Remove a VIEW_ITEM from the view.
Definition: view.cpp:350
bool operator()(VIEW_ITEM *aItem)
Definition: view.cpp:935
void SetFlip(bool xAxis, bool yAxis)
Sets flipping of the screen.
void InitPreview()
Definition: view.cpp:1607
bool operator()(VIEW_ITEM *aItem)
Definition: view.cpp:1180
GAL * m_gal
Dynamic VIEW (eg.
Definition: view.h:848
bool areRequiredLayersEnabled(int aLayerId) const
Definition: view.cpp:1368
coord_type GetRight() const
Definition: box2.h:182
QUERY_VISITOR(CONTAINER &aCont, int aLayer)
Definition: view.cpp:408
std::set< unsigned int > m_topLayers
Center point of the VIEW (the point at which we are looking at).
Definition: view.h:831
void SetSize(const Vec &size)
Definition: box2.h:195
void clearUpdateFlags()
Mark an item as already updated, so it is not going to be redrawn.
Definition: view.cpp:219
const wxChar *const traceGalProfile
Flag to enable debug output of GAL performance profiling.
void UpdateAllLayersOrder()
Do everything that is needed to apply the rendering order of layers.
Definition: view.cpp:893
Visibility flag has changed.
Definition: view_item.h:47
bool operator()(VIEW_ITEM *aItem)
Definition: view.cpp:1075
coord_type GetBottom() const
Definition: box2.h:183
void SetMirror(bool aMirrorX, bool aMirrorY)
Control the mirroring of the VIEW.
Definition: view.cpp:539
An abstract base class for deriving all objects that can be added to a VIEW.
Definition: view_item.h:76
Color has changed.
Definition: view_item.h:48
All except INITIAL_ADD.
Definition: view_item.h:53
virtual void ComputeWorldScreenMatrix()
Compute the world <-> screen transformation matrix.
A thread-safe event counter.
Definition: profile.h:225
virtual VIEW_ITEM * GetItem(unsigned int aIdx) const
Definition: view_group.cpp:81
virtual void SetLayerDepth(double aLayerDepth)
Set the depth of the layer (position on the z-axis)
std::shared_ptr< VIEW_OVERLAY > MakeOverlay()
Definition: view.cpp:1583
bool storesGroups() const
Return information if the item uses at least one group id (ie.
Definition: view.cpp:158
virtual void EnableTopLayer(bool aEnable)
Enable or disable display of the top layer.
Definition: view.cpp:853
void setGroup(int aLayer, int aGroup)
Set a group id for the item and the layer combination.
Definition: view.cpp:116
VECTOR2< T > GetScale() const
Get the scale components of the matrix.
Definition: matrix3x3.h:265
VECTOR2D m_center
Definition: view.h:834
VIEW * m_view
Current dynamic view the item is assigned to.
Definition: view.cpp:232
bool operator()(VIEW_ITEM *aItem)
Definition: view.cpp:413
static constexpr int VIEW_MAX_LAYERS
maximum number of layers that may be shown
Definition: view.h:711
virtual void EndGroup()
End the group.
Auxiliary rendering target (noncached)
Definition: definitions.h:49
std::shared_ptr< std::vector< VIEW_ITEM * > > m_allItems
The set of layers that are displayed on the top.
Definition: view.h:828
void SortLayers(int aLayers[], int &aCount) const
Change the order of given layer ids, so after sorting the order corresponds to layers rendering order...
Definition: view.cpp:649
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:99
void ShowPreview(bool aShow=true)
Definition: view.cpp:1628
UPDATE_COLOR_VISITOR(int aLayer, PAINTER *aPainter, GAL *aGal)
Definition: view.cpp:716
double m_minScale
Definition: view.h:838
virtual void ChangeGroupColor(int aGroupNumber, const COLOR4D &aNewColor)
Change the color used to draw the group.
const VECTOR2I & GetScreenPixelSize() const
Return GAL canvas size in pixels.
virtual unsigned int GetSize() const
Return the number of stored items.
Definition: view_group.cpp:75
int layers[VIEW_MAX_LAYERS]
Definition: view.cpp:977
Contains all the knowledge about how to draw graphical object onto any particular output device.
Definition: painter.h:57
Item needs to be redrawn.
Definition: view_item.h:52
virtual void EndDiffLayer()
Ends rendering of a differential layer.
int m_drawPriority
Order to draw this item in a layer, lowest first.
Definition: view.cpp:235
void SetCenter(const VECTOR2D &aCenter)
Set the center point of the VIEW (i.e.
Definition: view.cpp:578
UPDATE_DEPTH_VISITOR(int aLayer, int aDepth, GAL *aGal)
Definition: view.cpp:795
VECTOR2< double > VECTOR2D
Definition: vector2d.h:621
virtual void Redraw()
Immediately redraws the whole view.
Definition: view.cpp:1134
void MarkTargetDirty(int aTarget)
Set or clear target 'dirty' flag.
Definition: view.h:609
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:598
void Clear()
Remove all items from the view.
Definition: view.cpp:1100
bool IsVisible(const VIEW_ITEM *aItem) const
Return information if the item is visible (or not).
Definition: view.cpp:1556
Represent a set of closed polygons.
VIEW_ITEM_DATA * viewPrivData() const
Definition: view_item.h:138
bool operator()(VIEW_ITEM *aItem)
Definition: view.cpp:723
virtual int GetTopLayer() const
Definition: view.cpp:817
coord_type GetWidth() const
Definition: box2.h:180
virtual int BeginGroup()
Begin a group.
BOX2< Vec > & Normalize()
Ensure that the height ant width are positive.
Definition: box2.h:112
bool Contains(const Vec &aPoint) const
Definition: box2.h:134
virtual void ClearTarget(RENDER_TARGET aTarget)
Clear the target for rendering.
void SetMaximum()
Definition: box2.h:57
virtual void ViewGetLayers(int aLayers[], int &aCount) const =0
Return the all the layers within the VIEW the object is painted on.
bool m_mirrorX
Definition: view.h:841
void invalidateItem(VIEW_ITEM *aItem, int aUpdateFlags)
Manage dirty flags & redraw queuing when updating an item.
Definition: view.cpp:1203
void ClearPreview()
Definition: view.cpp:1592
const VECTOR2I & GetScreenPixelSize() const
Return the size of the our rendering area in pixels.
Definition: view.cpp:1167
void reorderGroups(std::unordered_map< int, int > aReorderMap)
Reorder the stored groups (to facilitate reordering of layers).
Definition: view.cpp:171
Extend VIEW_ITEM by possibility of grouping items into a single object.
Definition: view_group.h:46
int id
Layer ID.
Definition: view.h:722
Items that may change while the view stays the same (noncached)
Definition: definitions.h:50
#define _(s)
wxLogTrace helper definitions.
void ReorderLayerData(std::unordered_map< int, int > aReorderMap)
Remap the data between layer ids without invalidating that data.
Definition: view.cpp:677
void UpdateItems()
Iterate through the list of items that asked for updating and updates them.
Definition: view.cpp:1402
void updateBbox(VIEW_ITEM *aItem)
Update set of layers that an item occupies.
Definition: view.cpp:1309
virtual void StartNegativesLayer()
Begins rendering in a new layer that will be copied to the main layer in EndNegativesLayer().
PAINTER * m_painter
Interface to #PAINTER that is used to draw items.
Definition: view.h:845
bool m_reverseDrawOrder
Definition: view.h:867
Item is visible (in general)
Definition: view_item.h:60
E_SERIE r
Definition: eserie.cpp:41
int m_nextDrawPriority
Flag to reverse the draw order when using draw priority.
Definition: view.h:864
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:468
void saveLayers(int *aLayers, int aCount)
Save layers used by the item.
Definition: view.cpp:195
bool operator()(VIEW_ITEM *aItem)
Definition: view.cpp:802
std::vector< VIEW_LAYER > m_layers
Sorted list of pointers to members of m_layers.
Definition: view.h:822
void ClearTopLayers()
Remove all layers from the on-the-top set (they are no longer displayed over the rest of layers).
Definition: view.cpp:878
virtual bool Draw(const VIEW_ITEM *aItem, int aLayer)=0
Takes an instance of VIEW_ITEM and passes it to a function that knows how to draw the item.
void SetEnd(coord_type x, coord_type y)
Definition: box2.h:207
const Vec & GetPosition() const
Definition: box2.h:177
virtual void SetScale(double aScale, VECTOR2D aAnchor={ 0, 0 })
Set the scaling factor, zooming around a given anchor point.
Definition: view.cpp:552
virtual void StartDiffLayer()
Begins rendering of a differential layer.
void clearGroupCache()
Definition: view.cpp:1191
double m_maxScale
Definition: view.h:839
void UpdateLayerColor(int aLayer)
Apply the new coloring scheme held by RENDER_SETTINGS in case that it has changed.
Definition: view.cpp:741
std::unique_ptr< VIEW > DataReference() const
Return a new VIEW object that shares the same set of VIEW_ITEMs and LAYERs.
Definition: view.cpp:1506
std::pair< int, int > * m_groups
layer_number:group_id pairs for each layer the item occupies.
Definition: view.cpp:237
No updates are required.
Definition: view_item.h:46
virtual COLOR4D GetColor(const VIEW_ITEM *aItem, int aLayer) const =0
Returns the color that should be used to draw the specific VIEW_ITEM on the specific layer using curr...
virtual RENDER_SETTINGS * GetSettings()=0
Return a pointer to current settings that are going to be used when drawing items.
CONTAINER::value_type item_type
Definition: view.cpp:406
void redrawRect(const BOX2I &aRect)
Definition: view.cpp:983
bool isRenderable() const
Return if the item should be drawn or not.
Definition: view.cpp:227
std::vector< EDA_ITEM * > m_ownedItems
Whether to use rendering order modifier or not.
Definition: view.h:816
void updateItemGeometry(VIEW_ITEM *aItem, int aLayer)
Update bounding box of an item.
Definition: view.cpp:1279
Main rendering target (cached)
Definition: definitions.h:48
Vec Centre() const
Definition: box2.h:63
bool m_enableOrderModifier
The set of possible displayed layers and its properties.
Definition: view.h:819
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:245
BOX2D m_boundary
Definition: view.h:837
std::vector< VIEW_LAYER * > m_orderedLayers
Flat list of all items.
Definition: view.h:825
void MarkClean()
Force redraw of view on the next rendering.
Definition: view.h:642
std::pair< VIEW_ITEM *, int > LAYER_ITEM_PAIR
Definition: view.h:73
int GetLayerOrder(int aLayer) const
Return rendering order of a particular layer.
Definition: view.cpp:643
void draw(VIEW_ITEM *aItem, int aLayer, bool aImmediate=false)
Draw an item, but on a specified layers.
Definition: view.cpp:1016
bool IsCached(int aLayer) const
Return true if the layer is cached.
Definition: view.h:616
void SetOrigin(const Vec &pos)
Definition: box2.h:193
#define KI_TRACE(...)
virtual bool IsVisible() const
Return true if the GAL canvas is visible on the screen.
void SetZoomFactor(double aZoomFactor)
Set the zoom factor of the scene.
virtual void ChangeGroupDepth(int aGroupNumber, int aDepth)
Change the depth (Z-axis position) of the group.
A base class for most all the KiCad significant classes used in schematics and boards.
Definition: eda_item.h:99
bool m_mirrorY
PAINTER contains information how do draw items.
Definition: view.h:842
void ClearTargets()
Clear targets that are marked as dirty.
Definition: view.cpp:1115
coord_type GetHeight() const
Definition: box2.h:181
int m_flags
Visibility flags.
Definition: view.cpp:233
void ClearViewPrivData()
Definition: view_item.h:143
void SetVisible(VIEW_ITEM *aItem, bool aIsVisible=true)
Set the item visibility.
Definition: view.cpp:1516
virtual void EndNegativesLayer()
Ends rendering of a negatives layer and draws it to the main layer.
void CopySettings(const VIEW *aOtherView)
Copy layers and visibility settings from another view.
Definition: view.cpp:487
double m_scale
Definition: view.h:836
Layers have changed.
Definition: view_item.h:50
constexpr int delta
int renderingOrder
Rendering order of this layer.
Definition: view.h:721
void SetLookAtPoint(const VECTOR2D &aPoint)
Set the Point in world space to look at.
virtual void Add(VIEW_ITEM *aItem, int aDrawPriority=-1)
Add a VIEW_ITEM to the view.
Definition: view.cpp:320
const Vec & GetSize() const
Definition: box2.h:172
virtual 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:426
coord_type GetLeft() const
Definition: box2.h:186
virtual ~VIEW()
Definition: view.cpp:314
VIEW(bool aIsDynamic=true)
Definition: view.cpp:260
Hold a (potentially large) number of VIEW_ITEMs and renders them on a graphics device provided by the...
Definition: view.h:68
DRAW_ITEM_VISITOR(VIEW *aView, int aLayer, bool aUseDrawPriority, bool aReverseDrawOrder)
Definition: view.cpp:927
int GetFlags() const
Definition: view.cpp:69
const MATRIX3x3D & GetWorldScreenMatrix() const
Get the world <-> screen transformation matrix.
void UpdateAllLayersColor()
Apply the new coloring scheme to all layers.
Definition: view.cpp:762
double GetScale() const
Definition: view.h:264
std::vector< int > m_layers
Definition: view.cpp:241
void SetGAL(GAL *aGal)
Assign a rendering device for the VIEW.
Definition: view.cpp:493
int m_requiredUpdate
Flag required for updating.
Definition: view.cpp:234
static bool compareRenderingOrder(VIEW_LAYER *aI, VIEW_LAYER *aJ)
Check if every layer required by the aLayerId layer is enabled.
Definition: view.h:800
virtual void ClearCache()
Delete all data created during caching of graphic items.
virtual void SetTarget(RENDER_TARGET aTarget)
Set the target for rendering.
void MarkDirty()
Force redraw of view on the next rendering.
Definition: view.h:633
virtual double ViewGetLOD(int aLayer, VIEW *aView) const
Return the level of detail (LOD) of the item.
Definition: view_item.h:132
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:1570
std::vector< VIEW_ITEM * > drawItems
Definition: view.cpp:979
void getLayers(int *aLayers, int &aCount) const
Return layer numbers used by the item.
Definition: view.cpp:83
Abstract interface for drawing on a 2D-surface.
Position or shape has changed.
Definition: view_item.h:49
RECACHE_ITEM_VISITOR(VIEW *aView, GAL *aGal, int aLayer)
Definition: view.cpp:1068
virtual void ViewDraw(int aLayer, VIEW *aView) const
Draw the parts of the object belonging to layer aLayer.
Definition: view_item.h:106
A color representation with 4 components: red, green, blue, alpha.
Definition: color4d.h:103
RENDER_TARGET target
Where the layer should be rendered.
Definition: view.h:723
std::shared_ptr< VIEW_RTREE > items
R-tree indexing all items on this layer.
Definition: view.h:720