KiCad PCB EDA Suite
cairo_gal.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) 2012 Torsten Hueter, torstenhtr <at> gmx.de
5  * Copyright (C) 2012 Kicad Developers, see change_log.txt for contributors.
6  * Copyright (C) 2017-2018 CERN
7  * @author Maciej Suminski <maciej.suminski@cern.ch>
8  *
9  * CairoGal - Graphics Abstraction Layer for Cairo
10  *
11  * This program is free software; you can redistribute it and/or
12  * modify it under the terms of the GNU General Public License
13  * as published by the Free Software Foundation; either version 2
14  * of the License, or (at your option) any later version.
15  *
16  * This program is distributed in the hope that it will be useful,
17  * but WITHOUT ANY WARRANTY; without even the implied warranty of
18  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19  * GNU General Public License for more details.
20  *
21  * You should have received a copy of the GNU General Public License
22  * along with this program; if not, you may find one here:
23  * http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
24  * or you may search the http://www.gnu.org website for the version 2 license,
25  * or you may write to the Free Software Foundation, Inc.,
26  * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
27  */
28 
29 #include <wx/image.h>
30 #include <wx/log.h>
31 
32 #include <gal/cairo/cairo_gal.h>
34 #include <gal/definitions.h>
36 #include <bitmap_base.h>
37 
38 #include <limits>
39 
40 #include <pixman.h>
41 
42 using namespace KIGFX;
43 
44 
45 
47  GAL( aDisplayOptions )
48 {
49  // Initialise grouping
50  isGrouping = false;
51  isElementAdded = false;
52  groupCounter = 0;
53  currentGroup = nullptr;
54 
55  // Initialise Cairo state
56  cairo_matrix_init_identity( &cairoWorldScreenMatrix );
57  currentContext = nullptr;
58  context = nullptr;
59  surface = nullptr;
60 
61  // Grid color settings are different in Cairo and OpenGL
62  SetGridColor( COLOR4D( 0.1, 0.1, 0.1, 0.8 ) );
64 }
65 
66 
68 {
69  ClearCache();
70 
71  if( surface )
72  cairo_surface_destroy( surface );
73 
74  if( context )
75  cairo_destroy( context );
76 }
77 
78 
80 {
81  resetContext();
82 }
83 
84 
86 {
87  // Force remaining objects to be drawn
88  Flush();
89 }
90 
91 
92 void CAIRO_GAL_BASE::DrawLine( const VECTOR2D& aStartPoint, const VECTOR2D& aEndPoint )
93 {
94  cairo_move_to( currentContext, aStartPoint.x, aStartPoint.y );
95  cairo_line_to( currentContext, aEndPoint.x, aEndPoint.y );
96  flushPath();
97  isElementAdded = true;
98 }
99 
100 
101 void CAIRO_GAL_BASE::DrawSegment( const VECTOR2D& aStartPoint, const VECTOR2D& aEndPoint,
102  double aWidth )
103 {
104  if( isFillEnabled )
105  {
106  // Filled tracks mode
107  SetLineWidth( aWidth );
108 
109  cairo_move_to( currentContext, (double) aStartPoint.x, (double) aStartPoint.y );
110  cairo_line_to( currentContext, (double) aEndPoint.x, (double) aEndPoint.y );
111  cairo_set_source_rgba( currentContext, fillColor.r, fillColor.g, fillColor.b, fillColor.a );
112  cairo_stroke( currentContext );
113  }
114  else
115  {
116  // Outline mode for tracks
117  VECTOR2D startEndVector = aEndPoint - aStartPoint;
118  double lineAngle = atan2( startEndVector.y, startEndVector.x );
119  double lineLength = startEndVector.EuclideanNorm();
120 
121  cairo_save( currentContext );
122 
123  cairo_set_source_rgba( currentContext, strokeColor.r, strokeColor.g, strokeColor.b, strokeColor.a );
124 
125  cairo_translate( currentContext, aStartPoint.x, aStartPoint.y );
126  cairo_rotate( currentContext, lineAngle );
127 
128  cairo_arc( currentContext, 0.0, 0.0, aWidth / 2.0, M_PI / 2.0, 3.0 * M_PI / 2.0 );
129  cairo_arc( currentContext, lineLength, 0.0, aWidth / 2.0, -M_PI / 2.0, M_PI / 2.0 );
130 
131  cairo_move_to( currentContext, 0.0, aWidth / 2.0 );
132  cairo_line_to( currentContext, lineLength, aWidth / 2.0 );
133 
134  cairo_move_to( currentContext, 0.0, -aWidth / 2.0 );
135  cairo_line_to( currentContext, lineLength, -aWidth / 2.0 );
136 
137  cairo_restore( currentContext );
138  flushPath();
139  }
140 
141  isElementAdded = true;
142 }
143 
144 
145 void CAIRO_GAL_BASE::DrawCircle( const VECTOR2D& aCenterPoint, double aRadius )
146 {
147  cairo_new_sub_path( currentContext );
148  cairo_arc( currentContext, aCenterPoint.x, aCenterPoint.y, aRadius, 0.0, 2 * M_PI );
149  flushPath();
150  isElementAdded = true;
151 }
152 
153 
154 void CAIRO_GAL_BASE::DrawArc( const VECTOR2D& aCenterPoint, double aRadius, double aStartAngle,
155  double aEndAngle )
156 {
157  SWAP( aStartAngle, >, aEndAngle );
158 
159  if( isFillEnabled ) // Draw the filled area of the shape, before drawing the outline itself
160  {
161  double pen_size = GetLineWidth();
162  auto fgcolor = GetStrokeColor();
164 
165  SetLineWidth( 0 );
166  cairo_new_sub_path( currentContext );
167  cairo_arc( currentContext, aCenterPoint.x, aCenterPoint.y, aRadius, aStartAngle, aEndAngle );
168  VECTOR2D startPoint( cos( aStartAngle ) * aRadius + aCenterPoint.x,
169  sin( aStartAngle ) * aRadius + aCenterPoint.y );
170  VECTOR2D endPoint( cos( aEndAngle ) * aRadius + aCenterPoint.x,
171  sin( aEndAngle ) * aRadius + aCenterPoint.y );
172 
173  cairo_move_to( currentContext, aCenterPoint.x, aCenterPoint.y );
174  cairo_line_to( currentContext, startPoint.x, startPoint.y );
175  cairo_line_to( currentContext, endPoint.x, endPoint.y );
176  cairo_close_path( currentContext );
177  flushPath();
178  SetLineWidth( pen_size );
179  SetStrokeColor( fgcolor );
180  }
181 
182  cairo_new_sub_path( currentContext );
183  cairo_arc( currentContext, aCenterPoint.x, aCenterPoint.y, aRadius, aStartAngle, aEndAngle );
184  flushPath();
185 
186  isElementAdded = true;
187 }
188 
189 
190 void CAIRO_GAL_BASE::DrawArcSegment( const VECTOR2D& aCenterPoint, double aRadius, double aStartAngle,
191  double aEndAngle, double aWidth )
192 {
193  SWAP( aStartAngle, >, aEndAngle );
194 
195  if( isFillEnabled )
196  {
197  // Filled segments mode
198  SetLineWidth( aWidth );
199  cairo_arc( currentContext, aCenterPoint.x, aCenterPoint.y, aRadius, aStartAngle, aEndAngle );
200  cairo_set_source_rgba( currentContext, fillColor.r, fillColor.g, fillColor.b, fillColor.a );
201  cairo_stroke( currentContext );
202  }
203  else
204  {
205  double width = aWidth / 2.0;
206  VECTOR2D startPoint( cos( aStartAngle ) * aRadius,
207  sin( aStartAngle ) * aRadius );
208  VECTOR2D endPoint( cos( aEndAngle ) * aRadius,
209  sin( aEndAngle ) * aRadius );
210 
211  cairo_save( currentContext );
212 
213  cairo_set_source_rgba( currentContext, strokeColor.r, strokeColor.g, strokeColor.b, strokeColor.a );
214 
215  cairo_translate( currentContext, aCenterPoint.x, aCenterPoint.y );
216 
217  cairo_new_sub_path( currentContext );
218  cairo_arc( currentContext, 0, 0, aRadius - width, aStartAngle, aEndAngle );
219 
220  cairo_new_sub_path( currentContext );
221  cairo_arc( currentContext, 0, 0, aRadius + width, aStartAngle, aEndAngle );
222 
223  cairo_new_sub_path( currentContext );
224  cairo_arc_negative( currentContext, startPoint.x, startPoint.y, width, aStartAngle, aStartAngle + M_PI );
225 
226  cairo_new_sub_path( currentContext );
227  cairo_arc( currentContext, endPoint.x, endPoint.y, width, aEndAngle, aEndAngle + M_PI );
228 
229  cairo_restore( currentContext );
230  flushPath();
231  }
232 
233  isElementAdded = true;
234 }
235 
236 
237 void CAIRO_GAL_BASE::DrawRectangle( const VECTOR2D& aStartPoint, const VECTOR2D& aEndPoint )
238 {
239  // Calculate the diagonal points
240  VECTOR2D diagonalPointA( aEndPoint.x, aStartPoint.y );
241  VECTOR2D diagonalPointB( aStartPoint.x, aEndPoint.y );
242 
243  // The path is composed from 4 segments
244  cairo_move_to( currentContext, aStartPoint.x, aStartPoint.y );
245  cairo_line_to( currentContext, diagonalPointA.x, diagonalPointA.y );
246  cairo_line_to( currentContext, aEndPoint.x, aEndPoint.y );
247  cairo_line_to( currentContext, diagonalPointB.x, diagonalPointB.y );
248  cairo_close_path( currentContext );
249  flushPath();
250 
251  isElementAdded = true;
252 }
253 
254 
256 {
257  for( int i = 0; i < aPolySet.OutlineCount(); ++i )
258  drawPoly( aPolySet.COutline( i ) );
259 }
260 
261 
263 {
264  drawPoly( aPolygon );
265 }
266 
267 
268 void CAIRO_GAL_BASE::DrawCurve( const VECTOR2D& aStartPoint, const VECTOR2D& aControlPointA,
269  const VECTOR2D& aControlPointB, const VECTOR2D& aEndPoint )
270 {
271  cairo_move_to( currentContext, aStartPoint.x, aStartPoint.y );
272  cairo_curve_to( currentContext, aControlPointA.x, aControlPointA.y, aControlPointB.x,
273  aControlPointB.y, aEndPoint.x, aEndPoint.y );
274  cairo_line_to( currentContext, aEndPoint.x, aEndPoint.y );
275 
276  flushPath();
277  isElementAdded = true;
278 }
279 
280 
282 {
283  cairo_save( currentContext );
284 
285  // We have to calculate the pixel size in users units to draw the image.
286  // worldUnitLength is a factor used for converting IU to inches
287  double scale = 1.0 / ( aBitmap.GetPPI() * worldUnitLength );
288  cairo_scale( currentContext, scale, scale );
289 
290  // The position of the bitmap is the bitmap center.
291  // move the draw origin to the top left bitmap corner:
292  int w = aBitmap.GetSizePixels().x;
293  int h = aBitmap.GetSizePixels().y;
294  cairo_translate( currentContext, -w/2, -h/2 );
295 
296  cairo_new_path( currentContext );
297  cairo_surface_t* image = cairo_image_surface_create( CAIRO_FORMAT_ARGB32, w, h );
298  cairo_surface_flush( image );
299 
300  unsigned char* pix_buffer = cairo_image_surface_get_data( image );
301  // The pixel buffer of the initial bitmap:
302  auto bm_pix_buffer = (( BITMAP_BASE&)aBitmap).GetImageData();
303 
304  // Copy the source bitmap to the cairo bitmap buffer.
305  // In cairo bitmap buffer, a ARGB32 bitmap is an ARGB pixel packed into a uint_32
306  // 24 low bits only are used for color, top 8 are transparency.
307  for( int row = 0; row < h; row++ )
308  {
309  for( int col = 0; col < w; col++ )
310  {
311  // Build the RGB24 pixel:
312  uint32_t pixel = bm_pix_buffer->GetRed( col, row ) << 16;
313  pixel += bm_pix_buffer->GetGreen( col, row ) << 8;
314  pixel += bm_pix_buffer->GetBlue( col, row );
315 
316  if( bm_pix_buffer->HasAlpha() )
317  pixel += bm_pix_buffer->GetAlpha( col, row ) << 24;
318  else
319  pixel += ( 0xff << 24 );
320 
321  // Write the pixel to the cairo image buffer:
322  uint32_t* pix_ptr = (uint32_t*) pix_buffer;
323  *pix_ptr = pixel;
324  pix_buffer += 4;
325  }
326  }
327 
328  cairo_surface_mark_dirty( image );
329  cairo_set_source_surface( currentContext, image, 0, 0 );
330  cairo_paint( currentContext );
331  cairo_surface_destroy( image );
332 
333  isElementAdded = true;
334 
335  cairo_restore( currentContext );
336 }
337 
338 
339 void CAIRO_GAL_BASE::ResizeScreen( int aWidth, int aHeight )
340 {
341  screenSize = VECTOR2I( aWidth, aHeight );
342 }
343 
344 
346 {
347  storePath();
348 }
349 
350 
352 {
353  cairo_set_source_rgb( currentContext, m_clearColor.r, m_clearColor.g, m_clearColor.b );
354  cairo_rectangle( currentContext, 0.0, 0.0, screenSize.x, screenSize.y );
355  cairo_fill( currentContext );
356 }
357 
358 
359 void CAIRO_GAL_BASE::SetIsFill( bool aIsFillEnabled )
360 {
361  storePath();
362  isFillEnabled = aIsFillEnabled;
363 
364  if( isGrouping )
365  {
366  GROUP_ELEMENT groupElement;
367  groupElement.command = CMD_SET_FILL;
368  groupElement.argument.boolArg = aIsFillEnabled;
369  currentGroup->push_back( groupElement );
370  }
371 }
372 
373 
374 void CAIRO_GAL_BASE::SetIsStroke( bool aIsStrokeEnabled )
375 {
376  storePath();
377  isStrokeEnabled = aIsStrokeEnabled;
378 
379  if( isGrouping )
380  {
381  GROUP_ELEMENT groupElement;
382  groupElement.command = CMD_SET_STROKE;
383  groupElement.argument.boolArg = aIsStrokeEnabled;
384  currentGroup->push_back( groupElement );
385  }
386 }
387 
388 
390 {
391  storePath();
392  strokeColor = aColor;
393 
394  if( isGrouping )
395  {
396  GROUP_ELEMENT groupElement;
397  groupElement.command = CMD_SET_STROKECOLOR;
398  groupElement.argument.dblArg[0] = strokeColor.r;
399  groupElement.argument.dblArg[1] = strokeColor.g;
400  groupElement.argument.dblArg[2] = strokeColor.b;
401  groupElement.argument.dblArg[3] = strokeColor.a;
402  currentGroup->push_back( groupElement );
403  }
404 }
405 
406 
408 {
409  storePath();
410  fillColor = aColor;
411 
412  if( isGrouping )
413  {
414  GROUP_ELEMENT groupElement;
415  groupElement.command = CMD_SET_FILLCOLOR;
416  groupElement.argument.dblArg[0] = fillColor.r;
417  groupElement.argument.dblArg[1] = fillColor.g;
418  groupElement.argument.dblArg[2] = fillColor.b;
419  groupElement.argument.dblArg[3] = fillColor.a;
420  currentGroup->push_back( groupElement );
421  }
422 }
423 
424 
425 void CAIRO_GAL_BASE::SetLineWidth( float aLineWidth )
426 {
427  storePath();
428  GAL::SetLineWidth( aLineWidth );
429 
430  if( isGrouping )
431  {
432  GROUP_ELEMENT groupElement;
433  groupElement.command = CMD_SET_LINE_WIDTH;
434  groupElement.argument.dblArg[0] = aLineWidth;
435  currentGroup->push_back( groupElement );
436  }
437  else
438  {
439  // Make lines appear at least 1 pixel wide, no matter of zoom
440  double x = 1.0, y = 1.0;
441  cairo_device_to_user_distance( currentContext, &x, &y );
442  float minWidth = std::min( fabs( x ), fabs( y ) );
443  cairo_set_line_width( currentContext, std::fmax( aLineWidth, minWidth ) );
444  }
445 }
446 
447 
448 void CAIRO_GAL_BASE::SetLayerDepth( double aLayerDepth )
449 {
450  super::SetLayerDepth( aLayerDepth );
451  storePath();
452 }
453 
454 
455 void CAIRO_GAL_BASE::Transform( const MATRIX3x3D& aTransformation )
456 {
457  cairo_matrix_t cairoTransformation;
458 
459  cairo_matrix_init( &cairoTransformation,
460  aTransformation.m_data[0][0],
461  aTransformation.m_data[1][0],
462  aTransformation.m_data[0][1],
463  aTransformation.m_data[1][1],
464  aTransformation.m_data[0][2],
465  aTransformation.m_data[1][2] );
466 
467  cairo_transform( currentContext, &cairoTransformation );
468 }
469 
470 
471 void CAIRO_GAL_BASE::Rotate( double aAngle )
472 {
473  storePath();
474 
475  if( isGrouping )
476  {
477  GROUP_ELEMENT groupElement;
478  groupElement.command = CMD_ROTATE;
479  groupElement.argument.dblArg[0] = aAngle;
480  currentGroup->push_back( groupElement );
481  }
482  else
483  {
484  cairo_rotate( currentContext, aAngle );
485  }
486 }
487 
488 
489 void CAIRO_GAL_BASE::Translate( const VECTOR2D& aTranslation )
490 {
491  storePath();
492 
493  if( isGrouping )
494  {
495  GROUP_ELEMENT groupElement;
496  groupElement.command = CMD_TRANSLATE;
497  groupElement.argument.dblArg[0] = aTranslation.x;
498  groupElement.argument.dblArg[1] = aTranslation.y;
499  currentGroup->push_back( groupElement );
500  }
501  else
502  {
503  cairo_translate( currentContext, aTranslation.x, aTranslation.y );
504  }
505 }
506 
507 
508 void CAIRO_GAL_BASE::Scale( const VECTOR2D& aScale )
509 {
510  storePath();
511 
512  if( isGrouping )
513  {
514  GROUP_ELEMENT groupElement;
515  groupElement.command = CMD_SCALE;
516  groupElement.argument.dblArg[0] = aScale.x;
517  groupElement.argument.dblArg[1] = aScale.y;
518  currentGroup->push_back( groupElement );
519  }
520  else
521  {
522  cairo_scale( currentContext, aScale.x, aScale.y );
523  }
524 }
525 
526 
528 {
529  storePath();
530 
531  if( isGrouping )
532  {
533  GROUP_ELEMENT groupElement;
534  groupElement.command = CMD_SAVE;
535  currentGroup->push_back( groupElement );
536  }
537  else
538  {
539  cairo_save( currentContext );
540  }
541 }
542 
543 
545 {
546  storePath();
547 
548  if( isGrouping )
549  {
550  GROUP_ELEMENT groupElement;
551  groupElement.command = CMD_RESTORE;
552  currentGroup->push_back( groupElement );
553  }
554  else
555  {
556  cairo_restore( currentContext );
557  }
558 }
559 
560 
562 {
563  // If the grouping is started: the actual path is stored in the group, when
564  // a attribute was changed or when grouping stops with the end group method.
565  storePath();
566 
567  GROUP group;
568  int groupNumber = getNewGroupNumber();
569  groups.insert( std::make_pair( groupNumber, group ) );
570  currentGroup = &groups[groupNumber];
571  isGrouping = true;
572 
573  return groupNumber;
574 }
575 
576 
578 {
579  storePath();
580  isGrouping = false;
581 }
582 
583 
584 void CAIRO_GAL_BASE::DrawGroup( int aGroupNumber )
585 {
586  // This method implements a small Virtual Machine - all stored commands
587  // are executed; nested calling is also possible
588 
589  storePath();
590 
591  for( GROUP::iterator it = groups[aGroupNumber].begin();
592  it != groups[aGroupNumber].end(); ++it )
593  {
594  switch( it->command )
595  {
596  case CMD_SET_FILL:
597  isFillEnabled = it->argument.boolArg;
598  break;
599 
600  case CMD_SET_STROKE:
601  isStrokeEnabled = it->argument.boolArg;
602  break;
603 
604  case CMD_SET_FILLCOLOR:
605  fillColor = COLOR4D( it->argument.dblArg[0], it->argument.dblArg[1], it->argument.dblArg[2],
606  it->argument.dblArg[3] );
607  break;
608 
609  case CMD_SET_STROKECOLOR:
610  strokeColor = COLOR4D( it->argument.dblArg[0], it->argument.dblArg[1], it->argument.dblArg[2],
611  it->argument.dblArg[3] );
612  break;
613 
614  case CMD_SET_LINE_WIDTH:
615  {
616  // Make lines appear at least 1 pixel wide, no matter of zoom
617  double x = 1.0, y = 1.0;
618  cairo_device_to_user_distance( currentContext, &x, &y );
619  double minWidth = std::min( fabs( x ), fabs( y ) );
620  cairo_set_line_width( currentContext, std::max( it->argument.dblArg[0], minWidth ) );
621  }
622  break;
623 
624 
625  case CMD_STROKE_PATH:
626  cairo_set_source_rgba( currentContext, strokeColor.r, strokeColor.g, strokeColor.b, strokeColor.a );
627  cairo_append_path( currentContext, it->cairoPath );
628  cairo_stroke( currentContext );
629  break;
630 
631  case CMD_FILL_PATH:
632  cairo_set_source_rgba( currentContext, fillColor.r, fillColor.g, fillColor.b, strokeColor.a );
633  cairo_append_path( currentContext, it->cairoPath );
634  cairo_fill( currentContext );
635  break;
636 
637  /*
638  case CMD_TRANSFORM:
639  cairo_matrix_t matrix;
640  cairo_matrix_init( &matrix, it->argument.dblArg[0], it->argument.dblArg[1], it->argument.dblArg[2],
641  it->argument.dblArg[3], it->argument.dblArg[4], it->argument.dblArg[5] );
642  cairo_transform( currentContext, &matrix );
643  break;
644  */
645 
646  case CMD_ROTATE:
647  cairo_rotate( currentContext, it->argument.dblArg[0] );
648  break;
649 
650  case CMD_TRANSLATE:
651  cairo_translate( currentContext, it->argument.dblArg[0], it->argument.dblArg[1] );
652  break;
653 
654  case CMD_SCALE:
655  cairo_scale( currentContext, it->argument.dblArg[0], it->argument.dblArg[1] );
656  break;
657 
658  case CMD_SAVE:
659  cairo_save( currentContext );
660  break;
661 
662  case CMD_RESTORE:
663  cairo_restore( currentContext );
664  break;
665 
666  case CMD_CALL_GROUP:
667  DrawGroup( it->argument.intArg );
668  break;
669  }
670  }
671 }
672 
673 
674 void CAIRO_GAL_BASE::ChangeGroupColor( int aGroupNumber, const COLOR4D& aNewColor )
675 {
676  storePath();
677 
678  for( GROUP::iterator it = groups[aGroupNumber].begin();
679  it != groups[aGroupNumber].end(); ++it )
680  {
681  if( it->command == CMD_SET_FILLCOLOR || it->command == CMD_SET_STROKECOLOR )
682  {
683  it->argument.dblArg[0] = aNewColor.r;
684  it->argument.dblArg[1] = aNewColor.g;
685  it->argument.dblArg[2] = aNewColor.b;
686  it->argument.dblArg[3] = aNewColor.a;
687  }
688  }
689 }
690 
691 
692 void CAIRO_GAL_BASE::ChangeGroupDepth( int aGroupNumber, int aDepth )
693 {
694  // Cairo does not have any possibilities to change the depth coordinate of stored items,
695  // it depends only on the order of drawing
696 }
697 
698 
699 void CAIRO_GAL_BASE::DeleteGroup( int aGroupNumber )
700 {
701  storePath();
702 
703  // Delete the Cairo paths
704  std::deque<GROUP_ELEMENT>::iterator it, end;
705 
706  for( it = groups[aGroupNumber].begin(), end = groups[aGroupNumber].end(); it != end; ++it )
707  {
708  if( it->command == CMD_FILL_PATH || it->command == CMD_STROKE_PATH )
709  {
710  cairo_path_destroy( it->cairoPath );
711  }
712  }
713 
714  // Delete the group
715  groups.erase( aGroupNumber );
716 }
717 
718 
720 {
721  for( int i = groups.size() - 1; i >= 0; --i )
722  {
723  DeleteGroup( i );
724  }
725 }
726 
727 
729 {
730  cairo_set_operator( currentContext, aSetting ? CAIRO_OPERATOR_CLEAR : CAIRO_OPERATOR_OVER );
731 }
732 
733 
734 void CAIRO_GAL_BASE::DrawCursor( const VECTOR2D& aCursorPosition )
735 {
736  cursorPosition = aCursorPosition;
737 }
738 
739 
740 void CAIRO_GAL_BASE::EnableDepthTest( bool aEnabled )
741 {
742 }
743 
744 
746 {
747 
748  cairo_set_antialias( context, CAIRO_ANTIALIAS_NONE );
749 
750  ClearScreen();
751 
752  // Compute the world <-> screen transformations
754 
755  cairo_matrix_init( &cairoWorldScreenMatrix, worldScreenMatrix.m_data[0][0],
758  worldScreenMatrix.m_data[1][2] );
759 
760  cairo_set_matrix( context, &cairoWorldScreenMatrix );
761 
762  // Start drawing with a new path
763  cairo_new_path( context );
764  isElementAdded = true;
765 
766  cairo_set_line_join( context, CAIRO_LINE_JOIN_ROUND );
767  cairo_set_line_cap( context, CAIRO_LINE_CAP_ROUND );
768 
769  lineWidth = 0;
770 }
771 
772 
773 void CAIRO_GAL_BASE::drawGridLine( const VECTOR2D& aStartPoint, const VECTOR2D& aEndPoint )
774 {
775  cairo_move_to( currentContext, aStartPoint.x, aStartPoint.y );
776  cairo_line_to( currentContext, aEndPoint.x, aEndPoint.y );
777  cairo_set_source_rgba( currentContext, strokeColor.r, strokeColor.g, strokeColor.b, strokeColor.a );
778  cairo_stroke( currentContext );
779 }
780 
781 
783 {
784  if( isFillEnabled )
785  {
786  cairo_set_source_rgba( currentContext,
788 
789  if( isStrokeEnabled )
790  cairo_fill_preserve( currentContext );
791  else
792  cairo_fill( currentContext );
793  }
794 
795  if( isStrokeEnabled )
796  {
797  cairo_set_source_rgba( currentContext,
799  cairo_stroke( currentContext );
800  }
801 }
802 
803 
805 {
806  if( isElementAdded )
807  {
808  isElementAdded = false;
809 
810  if( !isGrouping )
811  {
812  if( isFillEnabled )
813  {
814  cairo_set_source_rgba( currentContext, fillColor.r, fillColor.g, fillColor.b, fillColor.a );
815  cairo_fill_preserve( currentContext );
816  }
817 
818  if( isStrokeEnabled )
819  {
820  cairo_set_source_rgba( currentContext, strokeColor.r, strokeColor.g,
822  cairo_stroke_preserve( currentContext );
823  }
824  }
825  else
826  {
827  // Copy the actual path, append it to the global path list
828  // then check, if the path needs to be stroked/filled and
829  // add this command to the group list;
830  if( isStrokeEnabled )
831  {
832  GROUP_ELEMENT groupElement;
833  groupElement.cairoPath = cairo_copy_path( currentContext );
834  groupElement.command = CMD_STROKE_PATH;
835  currentGroup->push_back( groupElement );
836  }
837 
838  if( isFillEnabled )
839  {
840  GROUP_ELEMENT groupElement;
841  groupElement.cairoPath = cairo_copy_path( currentContext );
842  groupElement.command = CMD_FILL_PATH;
843  currentGroup->push_back( groupElement );
844  }
845  }
846 
847  cairo_new_path( currentContext );
848  }
849 }
850 
851 
852 void CAIRO_GAL_BASE::blitCursor( wxMemoryDC& clientDC )
853 {
854  if( !IsCursorEnabled() )
855  return;
856 
857  auto p = ToScreen( cursorPosition );
858 
859  const auto cColor = getCursorColor();
860  const int cursorSize = fullscreenCursor ? 8000 : 80;
861 
862  wxColour color( cColor.r * cColor.a * 255, cColor.g * cColor.a * 255,
863  cColor.b * cColor.a * 255, 255 );
864  clientDC.SetPen( wxPen( color ) );
865  clientDC.DrawLine( p.x - cursorSize / 2, p.y, p.x + cursorSize / 2, p.y );
866  clientDC.DrawLine( p.x, p.y - cursorSize / 2, p.x, p.y + cursorSize / 2 );
867 }
868 
869 
870 void CAIRO_GAL_BASE::drawPoly( const std::deque<VECTOR2D>& aPointList )
871 {
872  // Iterate over the point list and draw the segments
873  std::deque<VECTOR2D>::const_iterator it = aPointList.begin();
874 
875  cairo_move_to( currentContext, it->x, it->y );
876 
877  for( ++it; it != aPointList.end(); ++it )
878  {
879  cairo_line_to( currentContext, it->x, it->y );
880  }
881 
882  flushPath();
883  isElementAdded = true;
884 }
885 
886 
887 void CAIRO_GAL_BASE::drawPoly( const VECTOR2D aPointList[], int aListSize )
888 {
889  // Iterate over the point list and draw the segments
890  const VECTOR2D* ptr = aPointList;
891 
892  cairo_move_to( currentContext, ptr->x, ptr->y );
893 
894  for( int i = 0; i < aListSize; ++i )
895  {
896  ++ptr;
897  cairo_line_to( currentContext, ptr->x, ptr->y );
898  }
899 
900  flushPath();
901  isElementAdded = true;
902 }
903 
904 
906 {
907  if( aLineChain.PointCount() < 2 )
908  return;
909 
910  auto numPoints = aLineChain.PointCount();
911 
912  if( aLineChain.IsClosed() )
913  numPoints += 1;
914 
915  const VECTOR2I start = aLineChain.CPoint( 0 );
916  cairo_move_to( currentContext, start.x, start.y );
917 
918  for( int i = 1; i < numPoints; ++i )
919  {
920  const VECTOR2I& p = aLineChain.CPoint( i );
921  cairo_line_to( currentContext, p.x, p.y );
922  }
923 
924  flushPath();
925  isElementAdded = true;
926 }
927 
928 
930 {
931  wxASSERT_MSG( groups.size() < std::numeric_limits<unsigned int>::max(),
932  wxT( "There are no free slots to store a group" ) );
933 
934  while( groups.find( groupCounter ) != groups.end() )
935  groupCounter++;
936 
937  return groupCounter++;
938 }
939 
940 
942  wxWindow* aParent, wxEvtHandler* aMouseListener,
943  wxEvtHandler* aPaintListener, const wxString& aName ) :
944  CAIRO_GAL_BASE( aDisplayOptions ),
945  wxWindow( aParent, wxID_ANY, wxDefaultPosition, wxDefaultSize, wxEXPAND, aName )
946 {
947  // Initialise compositing state
948  mainBuffer = 0;
949  overlayBuffer = 0;
950  validCompositor = false;
952 
953  parentWindow = aParent;
954  mouseListener = aMouseListener;
955  paintListener = aPaintListener;
956 
957  // Connecting the event handlers
958  Connect( wxEVT_PAINT, wxPaintEventHandler( CAIRO_GAL::onPaint ) );
959 
960  // Mouse events are skipped to the parent
961  Connect( wxEVT_MOTION, wxMouseEventHandler( CAIRO_GAL::skipMouseEvent ) );
962  Connect( wxEVT_LEFT_DOWN, wxMouseEventHandler( CAIRO_GAL::skipMouseEvent ) );
963  Connect( wxEVT_LEFT_UP, wxMouseEventHandler( CAIRO_GAL::skipMouseEvent ) );
964  Connect( wxEVT_LEFT_DCLICK, wxMouseEventHandler( CAIRO_GAL::skipMouseEvent ) );
965  Connect( wxEVT_MIDDLE_DOWN, wxMouseEventHandler( CAIRO_GAL::skipMouseEvent ) );
966  Connect( wxEVT_MIDDLE_UP, wxMouseEventHandler( CAIRO_GAL::skipMouseEvent ) );
967  Connect( wxEVT_MIDDLE_DCLICK, wxMouseEventHandler( CAIRO_GAL::skipMouseEvent ) );
968  Connect( wxEVT_RIGHT_DOWN, wxMouseEventHandler( CAIRO_GAL::skipMouseEvent ) );
969  Connect( wxEVT_RIGHT_UP, wxMouseEventHandler( CAIRO_GAL::skipMouseEvent ) );
970  Connect( wxEVT_RIGHT_DCLICK, wxMouseEventHandler( CAIRO_GAL::skipMouseEvent ) );
971  Connect( wxEVT_MOUSEWHEEL, wxMouseEventHandler( CAIRO_GAL::skipMouseEvent ) );
972 #if defined _WIN32 || defined _WIN64
973  Connect( wxEVT_ENTER_WINDOW, wxMouseEventHandler( CAIRO_GAL::skipMouseEvent ) );
974 #endif
975 
976  SetSize( aParent->GetClientSize() );
977  screenSize = VECTOR2I( aParent->GetClientSize() );
978 
979  // Allocate memory for pixel storage
980  allocateBitmaps();
981 
982  isInitialized = false;
983 }
984 
985 
987 {
988  deleteBitmaps();
989 }
990 
991 
993 {
994  initSurface();
995 
997 
998  if( !validCompositor )
999  setCompositor();
1000 
1001  compositor->SetMainContext( context );
1002  compositor->SetBuffer( mainBuffer );
1003 }
1004 
1005 
1007 {
1009 
1010  // Merge buffers on the screen
1011  compositor->DrawBuffer( mainBuffer );
1012  compositor->DrawBuffer( overlayBuffer );
1013 
1014  // Now translate the raw context data from the format stored
1015  // by cairo into a format understood by wxImage.
1016  pixman_image_t* dstImg = pixman_image_create_bits( PIXMAN_r8g8b8,
1017  screenSize.x, screenSize.y, (uint32_t*) wxOutput, wxBufferWidth * 3 );
1018  pixman_image_t* srcImg = pixman_image_create_bits( PIXMAN_a8b8g8r8,
1019  screenSize.x, screenSize.y, (uint32_t*) bitmapBuffer, wxBufferWidth * 4 );
1020 
1021  pixman_image_composite( PIXMAN_OP_SRC, srcImg, NULL, dstImg,
1022  0, 0, 0, 0, 0, 0, screenSize.x, screenSize.y );
1023 
1024  // Free allocated memory
1025  pixman_image_unref( srcImg );
1026  pixman_image_unref( dstImg );
1027 
1028  wxImage img( wxBufferWidth, screenSize.y, (unsigned char*) wxOutput, true );
1029  wxBitmap bmp( img );
1030  wxMemoryDC mdc( bmp );
1031  wxClientDC clientDC( this );
1032 
1033  // Now it is the time to blit the mouse cursor
1034  blitCursor( mdc );
1035  clientDC.Blit( 0, 0, screenSize.x, screenSize.y, &mdc, 0, 0, wxCOPY );
1036 
1037  deinitSurface();
1038 }
1039 
1040 
1041 void CAIRO_GAL::ResizeScreen( int aWidth, int aHeight )
1042 {
1043  CAIRO_GAL_BASE::ResizeScreen( aWidth, aHeight );
1044 
1045  // Recreate the bitmaps
1046  deleteBitmaps();
1047  allocateBitmaps();
1048 
1049  if( validCompositor )
1050  compositor->Resize( aWidth, aHeight );
1051 
1052  validCompositor = false;
1053 
1054  SetSize( wxSize( aWidth, aHeight ) );
1055 }
1056 
1057 
1058 bool CAIRO_GAL::Show( bool aShow )
1059 {
1060  bool s = wxWindow::Show( aShow );
1061 
1062  if( aShow )
1063  wxWindow::Raise();
1064 
1065  return s;
1066 }
1067 
1068 
1070 {
1071  // Copy the current bitmap to the backup buffer
1072  int offset = 0;
1073 
1074  for( int j = 0; j < screenSize.y; j++ )
1075  {
1076  for( int i = 0; i < stride; i++ )
1077  {
1078  bitmapBufferBackup[offset + i] = bitmapBuffer[offset + i];
1079  offset += stride;
1080  }
1081  }
1082 }
1083 
1084 
1086 {
1087  int offset = 0;
1088 
1089  for( int j = 0; j < screenSize.y; j++ )
1090  {
1091  for( int i = 0; i < stride; i++ )
1092  {
1093  bitmapBuffer[offset + i] = bitmapBufferBackup[offset + i];
1094  offset += stride;
1095  }
1096  }
1097 }
1098 
1099 
1101 {
1102  initSurface();
1103  return CAIRO_GAL_BASE::BeginGroup();
1104 }
1105 
1106 
1108 {
1110  deinitSurface();
1111 }
1112 
1113 
1115 {
1116  // If the compositor is not set, that means that there is a recaching process going on
1117  // and we do not need the compositor now
1118  if( !validCompositor )
1119  return;
1120 
1121  // Cairo grouping prevents display of overlapping items on the same layer in the lighter color
1122  if( isInitialized )
1123  storePath();
1124 
1125  switch( aTarget )
1126  {
1127  default:
1128  case TARGET_CACHED:
1129  case TARGET_NONCACHED:
1130  compositor->SetBuffer( mainBuffer );
1131  break;
1132 
1133  case TARGET_OVERLAY:
1134  compositor->SetBuffer( overlayBuffer );
1135  break;
1136  }
1137 
1138  currentTarget = aTarget;
1139 }
1140 
1141 
1143 {
1144  return currentTarget;
1145 }
1146 
1147 
1149 {
1150  // Save the current state
1151  unsigned int currentBuffer = compositor->GetBuffer();
1152 
1153  switch( aTarget )
1154  {
1155  // Cached and noncached items are rendered to the same buffer
1156  default:
1157  case TARGET_CACHED:
1158  case TARGET_NONCACHED:
1159  compositor->SetBuffer( mainBuffer );
1160  break;
1161 
1162  case TARGET_OVERLAY:
1163  compositor->SetBuffer( overlayBuffer );
1164  break;
1165  }
1166 
1167  compositor->ClearBuffer( COLOR4D::BLACK );
1168 
1169  // Restore the previous state
1170  compositor->SetBuffer( currentBuffer );
1171 }
1172 
1173 
1175 {
1176  if( isInitialized )
1177  return;
1178 
1179  surface = cairo_image_surface_create_for_data( (unsigned char*) bitmapBuffer, GAL_FORMAT,
1181 
1182  context = cairo_create( surface );
1183 
1184 #ifdef __WXDEBUG__
1185  cairo_status_t status = cairo_status( context );
1186  wxASSERT_MSG( status == CAIRO_STATUS_SUCCESS, wxT( "Cairo context creation error" ) );
1187 #endif /* __WXDEBUG__ */
1189 
1190  isInitialized = true;
1191 }
1192 
1193 
1195 {
1196  if( !isInitialized )
1197  return;
1198 
1199  cairo_destroy( context );
1200  context = nullptr;
1201  cairo_surface_destroy( surface );
1202  surface = nullptr;
1203 
1204  isInitialized = false;
1205 }
1206 
1207 
1209 {
1211  while( ( ( wxBufferWidth * 3 ) % 4 ) != 0 ) wxBufferWidth++;
1212 
1213  // Create buffer, use the system independent Cairo context backend
1214  stride = cairo_format_stride_for_width( GAL_FORMAT, wxBufferWidth );
1216 
1217  bitmapBuffer = new unsigned int[bufferSize];
1218  bitmapBufferBackup = new unsigned int[bufferSize];
1219  wxOutput = new unsigned char[wxBufferWidth * 3 * screenSize.y];
1220 }
1221 
1222 
1224 {
1225  delete[] bitmapBuffer;
1226  delete[] bitmapBufferBackup;
1227  delete[] wxOutput;
1228 }
1229 
1230 
1232 {
1233  // Recreate the compositor with the new Cairo context
1234  compositor.reset( new CAIRO_COMPOSITOR( &currentContext ) );
1235  compositor->Resize( screenSize.x, screenSize.y );
1236  compositor->SetAntialiasingMode( options.cairo_antialiasing_mode );
1237 
1238  // Prepare buffers
1239  mainBuffer = compositor->CreateBuffer();
1240  overlayBuffer = compositor->CreateBuffer();
1241 
1242  validCompositor = true;
1243 }
1244 
1245 
1246 void CAIRO_GAL::onPaint( wxPaintEvent& WXUNUSED( aEvent ) )
1247 {
1248  PostPaint();
1249 }
1250 
1251 
1252 void CAIRO_GAL::skipMouseEvent( wxMouseEvent& aEvent )
1253 {
1254  // Post the mouse event to the event listener registered in constructor, if any
1255  if( mouseListener )
1256  wxPostEvent( mouseListener, aEvent );
1257 }
1258 
1259 
1261 {
1262  bool refresh = false;
1263 
1264  if( validCompositor && aOptions.cairo_antialiasing_mode != compositor->GetAntialiasingMode() )
1265  {
1266 
1267  compositor->SetAntialiasingMode( options.cairo_antialiasing_mode );
1268  validCompositor = false;
1269  deinitSurface();
1270 
1271  refresh = true;
1272  }
1273 
1274  if( super::updatedGalDisplayOptions( aOptions ) )
1275  {
1276  Refresh();
1277  refresh = true;
1278  }
1279 
1280  return refresh;
1281 }
virtual void SetNegativeDrawMode(bool aSetting) override
Sets negative draw mode in the renderer.
Definition: cairo_gal.cpp:728
Definition: colors.h:57
void initSurface()
Prepare Cairo surfaces for drawing.
Definition: cairo_gal.cpp:1174
float GetLineWidth() const
Get the line width.
VECTOR2D cursorPosition
Current cursor position (world coordinates)
virtual void DrawBitmap(const BITMAP_BASE &aBitmap) override
Draw a bitmap image.
Definition: cairo_gal.cpp:281
virtual void ResizeScreen(int aWidth, int aHeight) override
Resizes the canvas.
Definition: cairo_gal.cpp:339
unsigned int groupCounter
Counter used for generating keys for groups.
Definition: cairo_gal.h:270
int OutlineCount() const
Returns the number of outlines in the set
virtual void EndGroup() override
End the group.
Definition: cairo_gal.cpp:577
virtual void ChangeGroupColor(int aGroupNumber, const COLOR4D &aNewColor) override
Changes the color used to draw the group.
Definition: cairo_gal.cpp:674
bool boolArg
A bool argument.
Definition: cairo_gal.h:259
bool updatedGalDisplayOptions(const GAL_DISPLAY_OPTIONS &aOptions) override
Cairo-specific update handlers
Definition: cairo_gal.cpp:1260
Class CAIRO_GAL is the cairo implementation of the graphics abstraction layer.
Definition: class_module.h:57
CAIRO_GAL(GAL_DISPLAY_OPTIONS &aDisplayOptions, wxWindow *aParent, wxEvtHandler *aMouseListener=NULL, wxEvtHandler *aPaintListener=NULL, const wxString &aName=wxT("CairoCanvas"))
Constructor CAIRO_GAL_BASE.
Definition: cairo_gal.cpp:941
virtual void ResizeScreen(int aWidth, int aHeight) override
Resizes the canvas.
Definition: cairo_gal.cpp:1041
void deinitSurface()
Destroy Cairo surfaces when are not needed anymore.
Definition: cairo_gal.cpp:1194
virtual void SetIsStroke(bool aIsStrokeEnabled) override
Enable/disable stroked outlines.
Definition: cairo_gal.cpp:374
virtual void EnableDepthTest(bool aEnabled=false) override
Definition: cairo_gal.cpp:740
virtual void ChangeGroupDepth(int aGroupNumber, int aDepth) override
Changes the depth (Z-axis position) of the group.
Definition: cairo_gal.cpp:692
cairo_surface_t * surface
Cairo surface.
Definition: cairo_gal.h:276
void onPaint(wxPaintEvent &aEvent)
Paint event handler.
Definition: cairo_gal.cpp:1246
const COLOR4D & GetFillColor() const
Get the fill color.
std::deque< GROUP_ELEMENT > GROUP
A graphic group type definition.
Definition: cairo_gal.h:268
virtual ~CAIRO_GAL()
Definition: cairo_gal.cpp:986
virtual void Translate(const VECTOR2D &aTranslation) override
Translate the context.
Definition: cairo_gal.cpp:489
VECTOR2D ToScreen(const VECTOR2D &aPoint) const
Compute the point position in screen coordinates from given world coordinates.
GAL_DISPLAY_OPTIONS & options
CAIRO_GAL_BASE(GAL_DISPLAY_OPTIONS &aDisplayOptions)
Definition: cairo_gal.cpp:46
int color
Definition: DXF_plotter.cpp:62
double dblArg[MAX_CAIRO_ARGUMENTS]
Arguments for Cairo commands.
Definition: cairo_gal.h:258
void setCompositor()
Prepare the compositor.
Definition: cairo_gal.cpp:1231
void storePath()
Store the actual path.
Definition: cairo_gal.cpp:804
Type definition for an graphics group element.
Definition: cairo_gal.h:254
Rotate the context.
Definition: cairo_gal.h:245
static const COLOR4D BLACK
Definition: color4d.h:297
void PostPaint()
Function PostPaint posts an event to m_paint_listener.
Definition: cairo_gal.h:356
virtual void DeleteGroup(int aGroupNumber) override
Delete the group from the memory.
Definition: cairo_gal.cpp:699
double g
Green component.
Definition: color4d.h:288
COLOR4D fillColor
The fill color.
bool isInitialized
Are Cairo image & surface ready to use.
Definition: cairo_gal.h:395
virtual void RestoreScreen() override
Restore the screen contents.
Definition: cairo_gal.cpp:1085
unsigned int overlayBuffer
Handle to the overlay buffer.
Definition: cairo_gal.h:379
VECTOR2< int > VECTOR2I
Definition: vector2d.h:587
int PointCount() const
Function PointCount()
virtual void ComputeWorldScreenMatrix()
Compute the world <-> screen transformation matrix.
Enable/disable filling.
Definition: cairo_gal.h:237
virtual void SetLayerDepth(double aLayerDepth) override
Set the depth of the layer (position on the z-axis)
Definition: cairo_gal.cpp:448
virtual void SetLayerDepth(double aLayerDepth)
Set the depth of the layer (position on the z-axis)
bool validCompositor
Compositor initialization flag.
Definition: cairo_gal.h:381
virtual void SetLineWidth(float aLineWidth)
Set the line width.
double b
Blue component.
Definition: color4d.h:289
Class that handles multitarget rendering (ie.
Auxiliary rendering target (noncached)
Definition: definitions.h:42
union KIGFX::CAIRO_GAL_BASE::GROUP_ELEMENT::@57 argument
T m_data[3][3]
Definition: matrix3x3.h:64
This class handle bitmap images in KiCad.
Definition: bitmap_base.h:46
virtual void ClearCache() override
Delete all data created during caching of graphic items.
Definition: cairo_gal.cpp:719
virtual void DrawCircle(const VECTOR2D &aCenterPoint, double aRadius) override
Draw a circle using world coordinates.
Definition: cairo_gal.cpp:145
CAIRO_ANTIALIASING_MODE cairo_antialiasing_mode
RENDER_TARGET currentTarget
Current rendering target.
Definition: cairo_gal.h:380
unsigned char * wxOutput
wxImage comaptible buffer
Definition: cairo_gal.h:388
virtual void DrawSegment(const VECTOR2D &aStartPoint, const VECTOR2D &aEndPoint, double aWidth) override
Draw a rounded segment.
Definition: cairo_gal.cpp:101
const VECTOR2I & CPoint(int aIndex) const
Function CPoint()
virtual void ClearScreen() override
Clear the screen.
Definition: cairo_gal.cpp:351
void SetGridColor(const COLOR4D &aGridColor)
Set the grid color.
double a
Alpha component.
Definition: color4d.h:290
virtual void drawGridLine(const VECTOR2D &aStartPoint, const VECTOR2D &aEndPoint) override
Draw a grid line (usually a simplified line function).
Definition: cairo_gal.cpp:773
const COLOR4D & GetStrokeColor() const
Get the stroke color.
virtual void ClearTarget(RENDER_TARGET aTarget) override
Clears the target for rendering.
Definition: cairo_gal.cpp:1148
virtual void DrawLine(const VECTOR2D &aStartPoint, const VECTOR2D &aEndPoint) override
Draw a line.
Definition: cairo_gal.cpp:92
bool fullscreenCursor
Shape of the cursor (fullscreen or small cross)
bool isStrokeEnabled
Are the outlines stroked ?
void Refresh()
Update the board display after modifying it by a python script (note: it is automatically called by a...
GROUP * currentGroup
Currently used group.
Definition: cairo_gal.h:271
Class SHAPE_POLY_SET.
std::shared_ptr< CAIRO_COMPOSITOR > compositor
Object for layers compositing.
Definition: cairo_gal.h:377
virtual void endDrawing() override
Definition: cairo_gal.cpp:85
void SetAxesColor(const COLOR4D &aAxesColor)
Set the axes color.
std::map< int, GROUP > groups
List of graphic groups.
Definition: cairo_gal.h:269
COLOR4D strokeColor
The color of the outlines.
virtual void DrawCurve(const VECTOR2D &startPoint, const VECTOR2D &controlPointA, const VECTOR2D &controlPointB, const VECTOR2D &endPoint) override
Draw a cubic bezier spline.
Definition: cairo_gal.cpp:268
virtual void DrawArcSegment(const VECTOR2D &aCenterPoint, double aRadius, double aStartAngle, double aEndAngle, double aWidth) override
Draw an arc segment.
Definition: cairo_gal.cpp:190
double worldUnitLength
The unit length of the world coordinates [inch].
cairo_t * context
Cairo image.
Definition: cairo_gal.h:275
Items that may change while the view stays the same (noncached)
Definition: definitions.h:43
bool isGrouping
Is grouping enabled ?
Definition: cairo_gal.h:266
virtual void DrawCursor(const VECTOR2D &aCursorPosition) override
Draw the cursor.
Definition: cairo_gal.cpp:734
MATRIX3x3D worldScreenMatrix
World transformation.
wxEvtHandler * paintListener
Paint listener.
Definition: cairo_gal.h:386
cairo_path_t * cairoPath
Pointer to a Cairo path.
Definition: cairo_gal.h:262
virtual void SetTarget(RENDER_TARGET aTarget) override
Sets the target for rendering.
Definition: cairo_gal.cpp:1114
unsigned int * bitmapBuffer
Storage of the cairo image.
Definition: cairo_gal.h:391
virtual ~CAIRO_GAL_BASE()
Definition: cairo_gal.cpp:67
void skipMouseEvent(wxMouseEvent &aEvent)
Mouse event handler, forwards the event to the child.
Definition: cairo_gal.cpp:1252
Save the transformation matrix.
Definition: cairo_gal.h:248
COLOR4D getCursorColor() const
Gets the actual cursor color to draw.
virtual void SetIsFill(bool aIsFillEnabled) override
Enable/disable fill.
Definition: cairo_gal.cpp:359
virtual bool updatedGalDisplayOptions(const GAL_DISPLAY_OPTIONS &aOptions)
Function updatedGalDisplayOptions.
float lineWidth
The line width.
bool isFillEnabled
Is filling of graphic objects enabled ?
virtual void DrawArc(const VECTOR2D &aCenterPoint, double aRadius, double aStartAngle, double aEndAngle) override
Draw an arc.
Definition: cairo_gal.cpp:154
int stride
Stride value for Cairo.
Definition: cairo_gal.h:393
virtual void SetStrokeColor(const COLOR4D &aColor) override
Set the stroke color.
Definition: cairo_gal.cpp:389
virtual void DrawRectangle(const VECTOR2D &aStartPoint, const VECTOR2D &aEndPoint) override
Draw a rectangle.
Definition: cairo_gal.cpp:237
virtual void beginDrawing() override
Definition: cairo_gal.cpp:992
virtual void Restore() override
Restore the context.
Definition: cairo_gal.cpp:544
virtual bool Show(bool aShow) override
Shows/hides the GAL canvas.
Definition: cairo_gal.cpp:1058
unsigned int * bitmapBufferBackup
Backup storage of the cairo image.
Definition: cairo_gal.h:392
virtual int BeginGroup() override
Begin a group.
Definition: cairo_gal.cpp:561
const int scale
Main rendering target (cached)
Definition: definitions.h:41
#define max(a, b)
Definition: auxiliary.h:86
virtual RENDER_TARGET GetTarget() const override
Gets the currently used target for rendering.
Definition: cairo_gal.cpp:1142
virtual void SaveScreen() override
Save the screen contents.
Definition: cairo_gal.cpp:1069
Class SHAPE_LINE_CHAIN.
GRAPHICS_COMMAND command
Command to execute.
Definition: cairo_gal.h:256
void drawPoly(const std::deque< VECTOR2D > &aPointList)
Drawing polygons & polylines is the same in cairo, so here is the common code.
Definition: cairo_gal.cpp:870
cairo_matrix_t cairoWorldScreenMatrix
Cairo world to screen transformation matrix.
Definition: cairo_gal.h:273
const SHAPE_LINE_CHAIN & COutline(int aIndex) const
size_t i
Definition: json11.cpp:597
Translate the context.
Definition: cairo_gal.h:246
wxSize GetSizePixels() const
Function GetSizePixels.
Definition: bitmap_base.h:133
VECTOR2I screenSize
Screen size in screen coordinates.
virtual void Save() override
Save the context.
Definition: cairo_gal.cpp:527
virtual void beginDrawing() override
Definition: cairo_gal.cpp:79
#define SWAP(varA, condition, varB)
Swap the variables if a condition is met.
Definition: definitions.h:31
virtual void endDrawing() override
Definition: cairo_gal.cpp:1006
virtual void SetLineWidth(float aLineWidth) override
Set the line width.
Definition: cairo_gal.cpp:425
virtual void Scale(const VECTOR2D &aScale) override
Scale the context.
Definition: cairo_gal.cpp:508
T EuclideanNorm() const
Destructor.
Definition: vector2d.h:292
void deleteBitmaps()
Allocate the bitmaps for drawing.
Definition: cairo_gal.cpp:1223
cairo_t * currentContext
Currently used Cairo context for drawing.
Definition: cairo_gal.h:274
virtual void DrawGroup(int aGroupNumber) override
Draw the stored group.
Definition: cairo_gal.cpp:584
unsigned int bufferSize
Size of buffers cairoOutput, bitmapBuffers.
Definition: cairo_gal.h:387
bool IsClosed() const
Function IsClosed()
double r
Red component.
Definition: color4d.h:287
virtual int BeginGroup() override
Begin a group.
Definition: cairo_gal.cpp:1100
RENDER_TARGET
RENDER_TARGET: Possible rendering targets.
Definition: definitions.h:39
bool isElementAdded
Was an graphic element added ?
Definition: cairo_gal.h:267
virtual void DrawPolygon(const std::deque< VECTOR2D > &aPointList) override
Draw a polygon.
Definition: cairo_gal.h:107
wxEvtHandler * mouseListener
Mouse listener.
Definition: cairo_gal.h:385
void allocateBitmaps()
Allocate the bitmaps for drawing.
Definition: cairo_gal.cpp:1208
virtual void Transform(const MATRIX3x3D &aTransformation) override
Transform the context.
Definition: cairo_gal.cpp:455
unsigned int mainBuffer
Handle to the main buffer.
Definition: cairo_gal.h:378
bool IsCursorEnabled() const
Returns information about cursor visibility.
wxWindow * parentWindow
Parent window.
Definition: cairo_gal.h:384
virtual void EndGroup() override
End the group.
Definition: cairo_gal.cpp:1107
virtual void Flush() override
Force all remaining objects to be drawn.
Definition: cairo_gal.cpp:345
int GetPPI() const
Definition: bitmap_base.h:145
Enable/disable stroking.
Definition: cairo_gal.h:238
unsigned int getNewGroupNumber()
Returns a valid key that can be used as a new group number.
Definition: cairo_gal.cpp:929
virtual void blitCursor(wxMemoryDC &clientDC)
Blits cursor into the current screen.
Definition: cairo_gal.cpp:852
Restore the transformation matrix.
Definition: cairo_gal.h:249
virtual void SetFillColor(const COLOR4D &aColor) override
Set the fill color.
Definition: cairo_gal.cpp:407
#define min(a, b)
Definition: auxiliary.h:85
Class GAL is the abstract interface for drawing on a 2D-surface.
virtual void Rotate(double aAngle) override
Rotate the context.
Definition: cairo_gal.cpp:471
static constexpr cairo_format_t GAL_FORMAT
Format used to store pixels.
Definition: cairo_gal.h:299
Class COLOR4D is the color representation with 4 components: red, green, blue, alpha.
Definition: color4d.h:39