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 
262 void CAIRO_GAL_BASE::DrawCurve( const VECTOR2D& aStartPoint, const VECTOR2D& aControlPointA,
263  const VECTOR2D& aControlPointB, const VECTOR2D& aEndPoint )
264 {
265  cairo_move_to( currentContext, aStartPoint.x, aStartPoint.y );
266  cairo_curve_to( currentContext, aControlPointA.x, aControlPointA.y, aControlPointB.x,
267  aControlPointB.y, aEndPoint.x, aEndPoint.y );
268  cairo_line_to( currentContext, aEndPoint.x, aEndPoint.y );
269 
270  flushPath();
271  isElementAdded = true;
272 }
273 
274 
276 {
277  cairo_save( currentContext );
278 
279  // We have to calculate the pixel size in users units to draw the image.
280  // worldUnitLength is a factor used for converting IU to inches
281  double scale = 1.0 / ( aBitmap.GetPPI() * worldUnitLength );
282  cairo_scale( currentContext, scale, scale );
283 
284  // The position of the bitmap is the bitmap center.
285  // move the draw origin to the top left bitmap corner:
286  int w = aBitmap.GetSizePixels().x;
287  int h = aBitmap.GetSizePixels().y;
288  cairo_translate( currentContext, -w/2, -h/2 );
289 
290  cairo_new_path( currentContext );
291  cairo_surface_t* image = cairo_image_surface_create( CAIRO_FORMAT_RGB24, w, h );
292  cairo_surface_flush( image );
293 
294  unsigned char* pix_buffer = cairo_image_surface_get_data( image );
295  // The pixel buffer of the initial bitmap:
296  auto bm_pix_buffer = (( BITMAP_BASE&)aBitmap).GetImageData();
297 
298  // Copy the source bitmap to the cairo bitmap buffer.
299  // In cairo bitmap buffer, a RGB24 bitmap is a RGB pixel packed into a uint_32
300  // 24 low bits only are used.
301  for( int row = 0; row < h; row++ )
302  {
303  for( int col = 0; col < w; col++ )
304  {
305  // Build the RGB24 pixel:
306  uint32_t pixel = bm_pix_buffer->GetRed( col, row ) << 16;
307  pixel += bm_pix_buffer->GetGreen( col, row ) << 8;
308  pixel += bm_pix_buffer->GetBlue( col, row );
309 
310  // Write the pixel to the cairo image buffer:
311  uint32_t* pix_ptr = (uint32_t*) pix_buffer;
312  *pix_ptr = pixel;
313  pix_buffer += 4;
314  }
315  }
316 
317  cairo_surface_mark_dirty( image );
318  cairo_set_source_surface( currentContext, image, 0, 0 );
319  cairo_paint( currentContext );
320  cairo_surface_destroy( image );
321 
322  isElementAdded = true;
323 
324  cairo_restore( currentContext );
325 }
326 
327 
328 void CAIRO_GAL_BASE::ResizeScreen( int aWidth, int aHeight )
329 {
330  screenSize = VECTOR2I( aWidth, aHeight );
331 }
332 
333 
335 {
336  storePath();
337 }
338 
339 
341 {
342  cairo_set_source_rgb( currentContext, m_clearColor.r, m_clearColor.g, m_clearColor.b );
343  cairo_rectangle( currentContext, 0.0, 0.0, screenSize.x, screenSize.y );
344  cairo_fill( currentContext );
345 }
346 
347 
348 void CAIRO_GAL_BASE::SetIsFill( bool aIsFillEnabled )
349 {
350  storePath();
351  isFillEnabled = aIsFillEnabled;
352 
353  if( isGrouping )
354  {
355  GROUP_ELEMENT groupElement;
356  groupElement.command = CMD_SET_FILL;
357  groupElement.argument.boolArg = aIsFillEnabled;
358  currentGroup->push_back( groupElement );
359  }
360 }
361 
362 
363 void CAIRO_GAL_BASE::SetIsStroke( bool aIsStrokeEnabled )
364 {
365  storePath();
366  isStrokeEnabled = aIsStrokeEnabled;
367 
368  if( isGrouping )
369  {
370  GROUP_ELEMENT groupElement;
371  groupElement.command = CMD_SET_STROKE;
372  groupElement.argument.boolArg = aIsStrokeEnabled;
373  currentGroup->push_back( groupElement );
374  }
375 }
376 
377 
379 {
380  storePath();
381  strokeColor = aColor;
382 
383  if( isGrouping )
384  {
385  GROUP_ELEMENT groupElement;
386  groupElement.command = CMD_SET_STROKECOLOR;
387  groupElement.argument.dblArg[0] = strokeColor.r;
388  groupElement.argument.dblArg[1] = strokeColor.g;
389  groupElement.argument.dblArg[2] = strokeColor.b;
390  groupElement.argument.dblArg[3] = strokeColor.a;
391  currentGroup->push_back( groupElement );
392  }
393 }
394 
395 
397 {
398  storePath();
399  fillColor = aColor;
400 
401  if( isGrouping )
402  {
403  GROUP_ELEMENT groupElement;
404  groupElement.command = CMD_SET_FILLCOLOR;
405  groupElement.argument.dblArg[0] = fillColor.r;
406  groupElement.argument.dblArg[1] = fillColor.g;
407  groupElement.argument.dblArg[2] = fillColor.b;
408  groupElement.argument.dblArg[3] = fillColor.a;
409  currentGroup->push_back( groupElement );
410  }
411 }
412 
413 
414 void CAIRO_GAL_BASE::SetLineWidth( float aLineWidth )
415 {
416  storePath();
417  GAL::SetLineWidth( aLineWidth );
418 
419  if( isGrouping )
420  {
421  GROUP_ELEMENT groupElement;
422  groupElement.command = CMD_SET_LINE_WIDTH;
423  groupElement.argument.dblArg[0] = aLineWidth;
424  currentGroup->push_back( groupElement );
425  }
426  else
427  {
428  // Make lines appear at least 1 pixel wide, no matter of zoom
429  double x = 1.0, y = 1.0;
430  cairo_device_to_user_distance( currentContext, &x, &y );
431  float minWidth = std::min( fabs( x ), fabs( y ) );
432  cairo_set_line_width( currentContext, std::fmax( aLineWidth, minWidth ) );
433  }
434 }
435 
436 
437 void CAIRO_GAL_BASE::SetLayerDepth( double aLayerDepth )
438 {
439  super::SetLayerDepth( aLayerDepth );
440  storePath();
441 }
442 
443 
444 void CAIRO_GAL_BASE::Transform( const MATRIX3x3D& aTransformation )
445 {
446  cairo_matrix_t cairoTransformation;
447 
448  cairo_matrix_init( &cairoTransformation,
449  aTransformation.m_data[0][0],
450  aTransformation.m_data[1][0],
451  aTransformation.m_data[0][1],
452  aTransformation.m_data[1][1],
453  aTransformation.m_data[0][2],
454  aTransformation.m_data[1][2] );
455 
456  cairo_transform( currentContext, &cairoTransformation );
457 }
458 
459 
460 void CAIRO_GAL_BASE::Rotate( double aAngle )
461 {
462  storePath();
463 
464  if( isGrouping )
465  {
466  GROUP_ELEMENT groupElement;
467  groupElement.command = CMD_ROTATE;
468  groupElement.argument.dblArg[0] = aAngle;
469  currentGroup->push_back( groupElement );
470  }
471  else
472  {
473  cairo_rotate( currentContext, aAngle );
474  }
475 }
476 
477 
478 void CAIRO_GAL_BASE::Translate( const VECTOR2D& aTranslation )
479 {
480  storePath();
481 
482  if( isGrouping )
483  {
484  GROUP_ELEMENT groupElement;
485  groupElement.command = CMD_TRANSLATE;
486  groupElement.argument.dblArg[0] = aTranslation.x;
487  groupElement.argument.dblArg[1] = aTranslation.y;
488  currentGroup->push_back( groupElement );
489  }
490  else
491  {
492  cairo_translate( currentContext, aTranslation.x, aTranslation.y );
493  }
494 }
495 
496 
497 void CAIRO_GAL_BASE::Scale( const VECTOR2D& aScale )
498 {
499  storePath();
500 
501  if( isGrouping )
502  {
503  GROUP_ELEMENT groupElement;
504  groupElement.command = CMD_SCALE;
505  groupElement.argument.dblArg[0] = aScale.x;
506  groupElement.argument.dblArg[1] = aScale.y;
507  currentGroup->push_back( groupElement );
508  }
509  else
510  {
511  cairo_scale( currentContext, aScale.x, aScale.y );
512  }
513 }
514 
515 
517 {
518  storePath();
519 
520  if( isGrouping )
521  {
522  GROUP_ELEMENT groupElement;
523  groupElement.command = CMD_SAVE;
524  currentGroup->push_back( groupElement );
525  }
526  else
527  {
528  cairo_save( currentContext );
529  }
530 }
531 
532 
534 {
535  storePath();
536 
537  if( isGrouping )
538  {
539  GROUP_ELEMENT groupElement;
540  groupElement.command = CMD_RESTORE;
541  currentGroup->push_back( groupElement );
542  }
543  else
544  {
545  cairo_restore( currentContext );
546  }
547 }
548 
549 
551 {
552  // If the grouping is started: the actual path is stored in the group, when
553  // a attribute was changed or when grouping stops with the end group method.
554  storePath();
555 
556  GROUP group;
557  int groupNumber = getNewGroupNumber();
558  groups.insert( std::make_pair( groupNumber, group ) );
559  currentGroup = &groups[groupNumber];
560  isGrouping = true;
561 
562  return groupNumber;
563 }
564 
565 
567 {
568  storePath();
569  isGrouping = false;
570 }
571 
572 
573 void CAIRO_GAL_BASE::DrawGroup( int aGroupNumber )
574 {
575  // This method implements a small Virtual Machine - all stored commands
576  // are executed; nested calling is also possible
577 
578  storePath();
579 
580  for( GROUP::iterator it = groups[aGroupNumber].begin();
581  it != groups[aGroupNumber].end(); ++it )
582  {
583  switch( it->command )
584  {
585  case CMD_SET_FILL:
586  isFillEnabled = it->argument.boolArg;
587  break;
588 
589  case CMD_SET_STROKE:
590  isStrokeEnabled = it->argument.boolArg;
591  break;
592 
593  case CMD_SET_FILLCOLOR:
594  fillColor = COLOR4D( it->argument.dblArg[0], it->argument.dblArg[1], it->argument.dblArg[2],
595  it->argument.dblArg[3] );
596  break;
597 
598  case CMD_SET_STROKECOLOR:
599  strokeColor = COLOR4D( it->argument.dblArg[0], it->argument.dblArg[1], it->argument.dblArg[2],
600  it->argument.dblArg[3] );
601  break;
602 
603  case CMD_SET_LINE_WIDTH:
604  {
605  // Make lines appear at least 1 pixel wide, no matter of zoom
606  double x = 1.0, y = 1.0;
607  cairo_device_to_user_distance( currentContext, &x, &y );
608  double minWidth = std::min( fabs( x ), fabs( y ) );
609  cairo_set_line_width( currentContext, std::max( it->argument.dblArg[0], minWidth ) );
610  }
611  break;
612 
613 
614  case CMD_STROKE_PATH:
615  cairo_set_source_rgb( currentContext, strokeColor.r, strokeColor.g, strokeColor.b );
616  cairo_append_path( currentContext, it->cairoPath );
617  cairo_stroke( currentContext );
618  break;
619 
620  case CMD_FILL_PATH:
621  cairo_set_source_rgb( currentContext, fillColor.r, fillColor.g, fillColor.b );
622  cairo_append_path( currentContext, it->cairoPath );
623  cairo_fill( currentContext );
624  break;
625 
626  /*
627  case CMD_TRANSFORM:
628  cairo_matrix_t matrix;
629  cairo_matrix_init( &matrix, it->argument.dblArg[0], it->argument.dblArg[1], it->argument.dblArg[2],
630  it->argument.dblArg[3], it->argument.dblArg[4], it->argument.dblArg[5] );
631  cairo_transform( currentContext, &matrix );
632  break;
633  */
634 
635  case CMD_ROTATE:
636  cairo_rotate( currentContext, it->argument.dblArg[0] );
637  break;
638 
639  case CMD_TRANSLATE:
640  cairo_translate( currentContext, it->argument.dblArg[0], it->argument.dblArg[1] );
641  break;
642 
643  case CMD_SCALE:
644  cairo_scale( currentContext, it->argument.dblArg[0], it->argument.dblArg[1] );
645  break;
646 
647  case CMD_SAVE:
648  cairo_save( currentContext );
649  break;
650 
651  case CMD_RESTORE:
652  cairo_restore( currentContext );
653  break;
654 
655  case CMD_CALL_GROUP:
656  DrawGroup( it->argument.intArg );
657  break;
658  }
659  }
660 }
661 
662 
663 void CAIRO_GAL_BASE::ChangeGroupColor( int aGroupNumber, const COLOR4D& aNewColor )
664 {
665  storePath();
666 
667  for( GROUP::iterator it = groups[aGroupNumber].begin();
668  it != groups[aGroupNumber].end(); ++it )
669  {
670  if( it->command == CMD_SET_FILLCOLOR || it->command == CMD_SET_STROKECOLOR )
671  {
672  it->argument.dblArg[0] = aNewColor.r;
673  it->argument.dblArg[1] = aNewColor.g;
674  it->argument.dblArg[2] = aNewColor.b;
675  it->argument.dblArg[3] = aNewColor.a;
676  }
677  }
678 }
679 
680 
681 void CAIRO_GAL_BASE::ChangeGroupDepth( int aGroupNumber, int aDepth )
682 {
683  // Cairo does not have any possibilities to change the depth coordinate of stored items,
684  // it depends only on the order of drawing
685 }
686 
687 
688 void CAIRO_GAL_BASE::DeleteGroup( int aGroupNumber )
689 {
690  storePath();
691 
692  // Delete the Cairo paths
693  std::deque<GROUP_ELEMENT>::iterator it, end;
694 
695  for( it = groups[aGroupNumber].begin(), end = groups[aGroupNumber].end(); it != end; ++it )
696  {
697  if( it->command == CMD_FILL_PATH || it->command == CMD_STROKE_PATH )
698  {
699  cairo_path_destroy( it->cairoPath );
700  }
701  }
702 
703  // Delete the group
704  groups.erase( aGroupNumber );
705 }
706 
707 
709 {
710  for( int i = groups.size() - 1; i >= 0; --i )
711  {
712  DeleteGroup( i );
713  }
714 }
715 
716 
718 {
719  cairo_set_operator( currentContext, aSetting ? CAIRO_OPERATOR_CLEAR : CAIRO_OPERATOR_OVER );
720 }
721 
722 
723 void CAIRO_GAL_BASE::DrawCursor( const VECTOR2D& aCursorPosition )
724 {
725  cursorPosition = aCursorPosition;
726 }
727 
728 
729 void CAIRO_GAL_BASE::EnableDepthTest( bool aEnabled )
730 {
731 }
732 
733 
735 {
736  cairo_set_antialias( context, CAIRO_ANTIALIAS_NONE );
737 
738  ClearScreen();
739 
740  // Compute the world <-> screen transformations
742 
743  cairo_matrix_init( &cairoWorldScreenMatrix, worldScreenMatrix.m_data[0][0],
746  worldScreenMatrix.m_data[1][2] );
747 
748  cairo_set_matrix( context, &cairoWorldScreenMatrix );
749 
750  // Start drawing with a new path
751  cairo_new_path( context );
752  isElementAdded = true;
753 
754  cairo_set_line_join( context, CAIRO_LINE_JOIN_ROUND );
755  cairo_set_line_cap( context, CAIRO_LINE_CAP_ROUND );
756 
757  lineWidth = 0;
758 }
759 
760 
761 void CAIRO_GAL_BASE::drawGridLine( const VECTOR2D& aStartPoint, const VECTOR2D& aEndPoint )
762 {
763  cairo_move_to( currentContext, aStartPoint.x, aStartPoint.y );
764  cairo_line_to( currentContext, aEndPoint.x, aEndPoint.y );
765  cairo_set_source_rgba( currentContext, strokeColor.r, strokeColor.g, strokeColor.b, strokeColor.a );
766  cairo_stroke( currentContext );
767 }
768 
769 
771 {
772  if( isFillEnabled )
773  {
774  cairo_set_source_rgba( currentContext,
776 
777  if( isStrokeEnabled )
778  cairo_fill_preserve( currentContext );
779  else
780  cairo_fill( currentContext );
781  }
782 
783  if( isStrokeEnabled )
784  {
785  cairo_set_source_rgba( currentContext,
787  cairo_stroke( currentContext );
788  }
789 }
790 
791 
793 {
794  if( isElementAdded )
795  {
796  isElementAdded = false;
797 
798  if( !isGrouping )
799  {
800  if( isFillEnabled )
801  {
802  cairo_set_source_rgb( currentContext, fillColor.r, fillColor.g, fillColor.b );
803  cairo_fill_preserve( currentContext );
804  }
805 
806  if( isStrokeEnabled )
807  {
808  cairo_set_source_rgb( currentContext, strokeColor.r, strokeColor.g,
809  strokeColor.b );
810  cairo_stroke_preserve( currentContext );
811  }
812  }
813  else
814  {
815  // Copy the actual path, append it to the global path list
816  // then check, if the path needs to be stroked/filled and
817  // add this command to the group list;
818  if( isStrokeEnabled )
819  {
820  GROUP_ELEMENT groupElement;
821  groupElement.cairoPath = cairo_copy_path( currentContext );
822  groupElement.command = CMD_STROKE_PATH;
823  currentGroup->push_back( groupElement );
824  }
825 
826  if( isFillEnabled )
827  {
828  GROUP_ELEMENT groupElement;
829  groupElement.cairoPath = cairo_copy_path( currentContext );
830  groupElement.command = CMD_FILL_PATH;
831  currentGroup->push_back( groupElement );
832  }
833  }
834 
835  cairo_new_path( currentContext );
836  }
837 }
838 
839 
840 void CAIRO_GAL_BASE::blitCursor( wxMemoryDC& clientDC )
841 {
842  if( !IsCursorEnabled() )
843  return;
844 
845  auto p = ToScreen( cursorPosition );
846 
847  const auto cColor = getCursorColor();
848  const int cursorSize = fullscreenCursor ? 8000 : 80;
849 
850  wxColour color( cColor.r * cColor.a * 255, cColor.g * cColor.a * 255,
851  cColor.b * cColor.a * 255, 255 );
852  clientDC.SetPen( wxPen( color ) );
853  clientDC.DrawLine( p.x - cursorSize / 2, p.y, p.x + cursorSize / 2, p.y );
854  clientDC.DrawLine( p.x, p.y - cursorSize / 2, p.x, p.y + cursorSize / 2 );
855 }
856 
857 
858 void CAIRO_GAL_BASE::drawPoly( const std::deque<VECTOR2D>& aPointList )
859 {
860  // Iterate over the point list and draw the segments
861  std::deque<VECTOR2D>::const_iterator it = aPointList.begin();
862 
863  cairo_move_to( currentContext, it->x, it->y );
864 
865  for( ++it; it != aPointList.end(); ++it )
866  {
867  cairo_line_to( currentContext, it->x, it->y );
868  }
869 
870  flushPath();
871  isElementAdded = true;
872 }
873 
874 
875 void CAIRO_GAL_BASE::drawPoly( const VECTOR2D aPointList[], int aListSize )
876 {
877  // Iterate over the point list and draw the segments
878  const VECTOR2D* ptr = aPointList;
879 
880  cairo_move_to( currentContext, ptr->x, ptr->y );
881 
882  for( int i = 0; i < aListSize; ++i )
883  {
884  ++ptr;
885  cairo_line_to( currentContext, ptr->x, ptr->y );
886  }
887 
888  flushPath();
889  isElementAdded = true;
890 }
891 
892 
894 {
895  if( aLineChain.PointCount() < 2 )
896  return;
897 
898  auto numPoints = aLineChain.PointCount();
899 
900  if( aLineChain.IsClosed() )
901  numPoints += 1;
902 
903  const VECTOR2I start = aLineChain.CPoint( 0 );
904  cairo_move_to( currentContext, start.x, start.y );
905 
906  for( int i = 1; i < numPoints; ++i )
907  {
908  const VECTOR2I& p = aLineChain.CPoint( i );
909  cairo_line_to( currentContext, p.x, p.y );
910  }
911 
912  flushPath();
913  isElementAdded = true;
914 }
915 
916 
918 {
919  wxASSERT_MSG( groups.size() < std::numeric_limits<unsigned int>::max(),
920  wxT( "There are no free slots to store a group" ) );
921 
922  while( groups.find( groupCounter ) != groups.end() )
923  groupCounter++;
924 
925  return groupCounter++;
926 }
927 
928 
930  wxWindow* aParent, wxEvtHandler* aMouseListener,
931  wxEvtHandler* aPaintListener, const wxString& aName ) :
932  CAIRO_GAL_BASE( aDisplayOptions ),
933  wxWindow( aParent, wxID_ANY, wxDefaultPosition, wxDefaultSize, wxEXPAND, aName )
934 {
935  // Initialise compositing state
936  mainBuffer = 0;
937  overlayBuffer = 0;
938  validCompositor = false;
940 
941  parentWindow = aParent;
942  mouseListener = aMouseListener;
943  paintListener = aPaintListener;
944 
945  // Connecting the event handlers
946  Connect( wxEVT_PAINT, wxPaintEventHandler( CAIRO_GAL::onPaint ) );
947 
948  // Mouse events are skipped to the parent
949  Connect( wxEVT_MOTION, wxMouseEventHandler( CAIRO_GAL::skipMouseEvent ) );
950  Connect( wxEVT_LEFT_DOWN, wxMouseEventHandler( CAIRO_GAL::skipMouseEvent ) );
951  Connect( wxEVT_LEFT_UP, wxMouseEventHandler( CAIRO_GAL::skipMouseEvent ) );
952  Connect( wxEVT_LEFT_DCLICK, wxMouseEventHandler( CAIRO_GAL::skipMouseEvent ) );
953  Connect( wxEVT_MIDDLE_DOWN, wxMouseEventHandler( CAIRO_GAL::skipMouseEvent ) );
954  Connect( wxEVT_MIDDLE_UP, wxMouseEventHandler( CAIRO_GAL::skipMouseEvent ) );
955  Connect( wxEVT_MIDDLE_DCLICK, wxMouseEventHandler( CAIRO_GAL::skipMouseEvent ) );
956  Connect( wxEVT_RIGHT_DOWN, wxMouseEventHandler( CAIRO_GAL::skipMouseEvent ) );
957  Connect( wxEVT_RIGHT_UP, wxMouseEventHandler( CAIRO_GAL::skipMouseEvent ) );
958  Connect( wxEVT_RIGHT_DCLICK, wxMouseEventHandler( CAIRO_GAL::skipMouseEvent ) );
959  Connect( wxEVT_MOUSEWHEEL, wxMouseEventHandler( CAIRO_GAL::skipMouseEvent ) );
960 #if defined _WIN32 || defined _WIN64
961  Connect( wxEVT_ENTER_WINDOW, wxMouseEventHandler( CAIRO_GAL::skipMouseEvent ) );
962 #endif
963 
964  SetSize( aParent->GetClientSize() );
965  screenSize = VECTOR2I( aParent->GetClientSize() );
966 
967  // Allocate memory for pixel storage
968  allocateBitmaps();
969 
970  isInitialized = false;
971 }
972 
973 
975 {
976  deleteBitmaps();
977 }
978 
979 
981 {
982  initSurface();
983 
985 
986  if( !validCompositor )
987  setCompositor();
988 
989  compositor->SetMainContext( context );
990  compositor->SetBuffer( mainBuffer );
991 }
992 
993 
995 {
997 
998  // Merge buffers on the screen
999  compositor->DrawBuffer( mainBuffer );
1000  compositor->DrawBuffer( overlayBuffer );
1001 
1002  // Now translate the raw context data from the format stored
1003  // by cairo into a format understood by wxImage.
1004  pixman_image_t* dstImg = pixman_image_create_bits( PIXMAN_r8g8b8,
1005  screenSize.x, screenSize.y, (uint32_t*) wxOutput, wxBufferWidth * 3 );
1006  pixman_image_t* srcImg = pixman_image_create_bits( PIXMAN_a8b8g8r8,
1007  screenSize.x, screenSize.y, (uint32_t*) bitmapBuffer, wxBufferWidth * 4 );
1008 
1009  pixman_image_composite( PIXMAN_OP_SRC, srcImg, NULL, dstImg,
1010  0, 0, 0, 0, 0, 0, screenSize.x, screenSize.y );
1011 
1012  // Free allocated memory
1013  pixman_image_unref( srcImg );
1014  pixman_image_unref( dstImg );
1015 
1016  wxImage img( wxBufferWidth, screenSize.y, (unsigned char*) wxOutput, true );
1017  wxBitmap bmp( img );
1018  wxMemoryDC mdc( bmp );
1019  wxClientDC clientDC( this );
1020 
1021  // Now it is the time to blit the mouse cursor
1022  blitCursor( mdc );
1023  clientDC.Blit( 0, 0, screenSize.x, screenSize.y, &mdc, 0, 0, wxCOPY );
1024 
1025  deinitSurface();
1026 }
1027 
1028 
1029 void CAIRO_GAL::ResizeScreen( int aWidth, int aHeight )
1030 {
1031  CAIRO_GAL_BASE::ResizeScreen( aWidth, aHeight );
1032 
1033  // Recreate the bitmaps
1034  deleteBitmaps();
1035  allocateBitmaps();
1036 
1037  if( validCompositor )
1038  compositor->Resize( aWidth, aHeight );
1039 
1040  validCompositor = false;
1041 
1042  SetSize( wxSize( aWidth, aHeight ) );
1043 }
1044 
1045 
1046 bool CAIRO_GAL::Show( bool aShow )
1047 {
1048  bool s = wxWindow::Show( aShow );
1049 
1050  if( aShow )
1051  wxWindow::Raise();
1052 
1053  return s;
1054 }
1055 
1056 
1058 {
1059  // Copy the current bitmap to the backup buffer
1060  int offset = 0;
1061 
1062  for( int j = 0; j < screenSize.y; j++ )
1063  {
1064  for( int i = 0; i < stride; i++ )
1065  {
1066  bitmapBufferBackup[offset + i] = bitmapBuffer[offset + i];
1067  offset += stride;
1068  }
1069  }
1070 }
1071 
1072 
1074 {
1075  int offset = 0;
1076 
1077  for( int j = 0; j < screenSize.y; j++ )
1078  {
1079  for( int i = 0; i < stride; i++ )
1080  {
1081  bitmapBuffer[offset + i] = bitmapBufferBackup[offset + i];
1082  offset += stride;
1083  }
1084  }
1085 }
1086 
1087 
1089 {
1090  initSurface();
1091  return CAIRO_GAL_BASE::BeginGroup();
1092 }
1093 
1094 
1096 {
1098  deinitSurface();
1099 }
1100 
1101 
1103 {
1104  // If the compositor is not set, that means that there is a recaching process going on
1105  // and we do not need the compositor now
1106  if( !validCompositor )
1107  return;
1108 
1109  // Cairo grouping prevents display of overlapping items on the same layer in the lighter color
1110  if( isInitialized )
1111  storePath();
1112 
1113  switch( aTarget )
1114  {
1115  default:
1116  case TARGET_CACHED:
1117  case TARGET_NONCACHED:
1118  compositor->SetBuffer( mainBuffer );
1119  break;
1120 
1121  case TARGET_OVERLAY:
1122  compositor->SetBuffer( overlayBuffer );
1123  break;
1124  }
1125 
1126  currentTarget = aTarget;
1127 }
1128 
1129 
1131 {
1132  return currentTarget;
1133 }
1134 
1135 
1137 {
1138  // Save the current state
1139  unsigned int currentBuffer = compositor->GetBuffer();
1140 
1141  switch( aTarget )
1142  {
1143  // Cached and noncached items are rendered to the same buffer
1144  default:
1145  case TARGET_CACHED:
1146  case TARGET_NONCACHED:
1147  compositor->SetBuffer( mainBuffer );
1148  break;
1149 
1150  case TARGET_OVERLAY:
1151  compositor->SetBuffer( overlayBuffer );
1152  break;
1153  }
1154 
1155  compositor->ClearBuffer( COLOR4D::BLACK );
1156 
1157  // Restore the previous state
1158  compositor->SetBuffer( currentBuffer );
1159 }
1160 
1161 
1163 {
1164  if( isInitialized )
1165  return;
1166 
1167  surface = cairo_image_surface_create_for_data( (unsigned char*) bitmapBuffer, GAL_FORMAT,
1169 
1170  context = cairo_create( surface );
1171 
1172 #ifdef __WXDEBUG__
1173  cairo_status_t status = cairo_status( context );
1174  wxASSERT_MSG( status == CAIRO_STATUS_SUCCESS, wxT( "Cairo context creation error" ) );
1175 #endif /* __WXDEBUG__ */
1177 
1178  isInitialized = true;
1179 }
1180 
1181 
1183 {
1184  if( !isInitialized )
1185  return;
1186 
1187  cairo_destroy( context );
1188  context = nullptr;
1189  cairo_surface_destroy( surface );
1190  surface = nullptr;
1191 
1192  isInitialized = false;
1193 }
1194 
1195 
1197 {
1199  while( ( ( wxBufferWidth * 3 ) % 4 ) != 0 ) wxBufferWidth++;
1200 
1201  // Create buffer, use the system independent Cairo context backend
1202  stride = cairo_format_stride_for_width( GAL_FORMAT, wxBufferWidth );
1204 
1205  bitmapBuffer = new unsigned int[bufferSize];
1206  bitmapBufferBackup = new unsigned int[bufferSize];
1207  wxOutput = new unsigned char[wxBufferWidth * 3 * screenSize.y];
1208 }
1209 
1210 
1212 {
1213  delete[] bitmapBuffer;
1214  delete[] bitmapBufferBackup;
1215  delete[] wxOutput;
1216 }
1217 
1218 
1220 {
1221  // Recreate the compositor with the new Cairo context
1222  compositor.reset( new CAIRO_COMPOSITOR( &currentContext ) );
1223  compositor->Resize( screenSize.x, screenSize.y );
1224 
1225  // Prepare buffers
1226  mainBuffer = compositor->CreateBuffer();
1227  overlayBuffer = compositor->CreateBuffer();
1228 
1229  validCompositor = true;
1230 }
1231 
1232 
1233 void CAIRO_GAL::onPaint( wxPaintEvent& WXUNUSED( aEvent ) )
1234 {
1235  PostPaint();
1236 }
1237 
1238 
1239 void CAIRO_GAL::skipMouseEvent( wxMouseEvent& aEvent )
1240 {
1241  // Post the mouse event to the event listener registered in constructor, if any
1242  if( mouseListener )
1243  wxPostEvent( mouseListener, aEvent );
1244 }
1245 
1246 
1248 {
1249  bool refresh = false;
1250 
1251  if( super::updatedGalDisplayOptions( aOptions ) )
1252  {
1253  Refresh();
1254  refresh = true;
1255  }
1256 
1257  return refresh;
1258 }
virtual void SetNegativeDrawMode(bool aSetting) override
Sets negative draw mode in the renderer.
Definition: cairo_gal.cpp:717
Definition: colors.h:57
bool IsCursorEnabled() const
Returns information about cursor visibility.
void initSurface()
Prepare Cairo surfaces for drawing.
Definition: cairo_gal.cpp:1162
VECTOR2D cursorPosition
Current cursor position (world coordinates)
virtual void DrawBitmap(const BITMAP_BASE &aBitmap) override
Draw a bitmap image.
Definition: cairo_gal.cpp:275
const COLOR4D & GetStrokeColor() const
Get the stroke color.
virtual void ResizeScreen(int aWidth, int aHeight) override
Resizes the canvas.
Definition: cairo_gal.cpp:328
unsigned int groupCounter
Counter used for generating keys for groups.
Definition: cairo_gal.h:267
virtual void EndGroup() override
End the group.
Definition: cairo_gal.cpp:566
virtual void ChangeGroupColor(int aGroupNumber, const COLOR4D &aNewColor) override
Changes the color used to draw the group.
Definition: cairo_gal.cpp:663
bool boolArg
A bool argument.
Definition: cairo_gal.h:256
bool updatedGalDisplayOptions(const GAL_DISPLAY_OPTIONS &aOptions) override
Cairo-specific update handlers
Definition: cairo_gal.cpp:1247
Class CAIRO_GAL is the cairo implementation of the graphics abstraction layer.
Definition: class_module.h:58
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:929
virtual void ResizeScreen(int aWidth, int aHeight) override
Resizes the canvas.
Definition: cairo_gal.cpp:1029
void deinitSurface()
Destroy Cairo surfaces when are not needed anymore.
Definition: cairo_gal.cpp:1182
virtual void SetIsStroke(bool aIsStrokeEnabled) override
Enable/disable stroked outlines.
Definition: cairo_gal.cpp:363
virtual void EnableDepthTest(bool aEnabled=false) override
Definition: cairo_gal.cpp:729
virtual void ChangeGroupDepth(int aGroupNumber, int aDepth) override
Changes the depth (Z-axis position) of the group.
Definition: cairo_gal.cpp:681
cairo_surface_t * surface
Cairo surface.
Definition: cairo_gal.h:273
int PointCount() const
Function PointCount()
void onPaint(wxPaintEvent &aEvent)
Paint event handler.
Definition: cairo_gal.cpp:1233
std::deque< GROUP_ELEMENT > GROUP
A graphic group type definition.
Definition: cairo_gal.h:265
virtual ~CAIRO_GAL()
Definition: cairo_gal.cpp:974
virtual void Translate(const VECTOR2D &aTranslation) override
Translate the context.
Definition: cairo_gal.cpp:478
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:255
void setCompositor()
Prepare the compositor.
Definition: cairo_gal.cpp:1219
void storePath()
Store the actual path.
Definition: cairo_gal.cpp:792
Type definition for an graphics group element.
Definition: cairo_gal.h:251
Rotate the context.
Definition: cairo_gal.h:242
static const COLOR4D BLACK
Definition: color4d.h:297
void PostPaint()
Function PostPaint posts an event to m_paint_listener.
Definition: cairo_gal.h:353
virtual void DeleteGroup(int aGroupNumber) override
Delete the group from the memory.
Definition: cairo_gal.cpp:688
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:392
int OutlineCount() const
Returns the number of outlines in the set
virtual void RestoreScreen() override
Restore the screen contents.
Definition: cairo_gal.cpp:1073
unsigned int overlayBuffer
Handle to the overlay buffer.
Definition: cairo_gal.h:376
VECTOR2< int > VECTOR2I
Definition: vector2d.h:587
virtual void ComputeWorldScreenMatrix()
Compute the world <-> screen transformation matrix.
Enable/disable filling.
Definition: cairo_gal.h:234
virtual void SetLayerDepth(double aLayerDepth) override
Set the depth of the layer (position on the z-axis)
Definition: cairo_gal.cpp:437
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:378
VECTOR2D ToScreen(const VECTOR2D &aPoint) const
Compute the point position in screen coordinates from given world coordinates.
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
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:708
virtual void DrawCircle(const VECTOR2D &aCenterPoint, double aRadius) override
Draw a circle using world coordinates.
Definition: cairo_gal.cpp:145
RENDER_TARGET currentTarget
Current rendering target.
Definition: cairo_gal.h:377
unsigned char * wxOutput
wxImage comaptible buffer
Definition: cairo_gal.h:385
virtual void DrawSegment(const VECTOR2D &aStartPoint, const VECTOR2D &aEndPoint, double aWidth) override
Draw a rounded segment.
Definition: cairo_gal.cpp:101
virtual void ClearScreen() override
Clear the screen.
Definition: cairo_gal.cpp:340
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:761
virtual void ClearTarget(RENDER_TARGET aTarget) override
Clears the target for rendering.
Definition: cairo_gal.cpp:1136
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)
T EuclideanNorm() const
Destructor.
Definition: vector2d.h:292
bool isStrokeEnabled
Are the outlines stroked ?
COLOR4D getCursorColor() const
Gets the actual cursor color to draw.
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:268
Class SHAPE_POLY_SET.
std::shared_ptr< CAIRO_COMPOSITOR > compositor
Object for layers compositing.
Definition: cairo_gal.h:374
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:266
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:262
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:272
Items that may change while the view stays the same (noncached)
Definition: definitions.h:43
bool isGrouping
Is grouping enabled ?
Definition: cairo_gal.h:263
const SHAPE_LINE_CHAIN & COutline(int aIndex) const
wxSize GetSizePixels() const
Function GetSizePixels.
Definition: bitmap_base.h:133
virtual void DrawCursor(const VECTOR2D &aCursorPosition) override
Draw the cursor.
Definition: cairo_gal.cpp:723
MATRIX3x3D worldScreenMatrix
World transformation.
wxEvtHandler * paintListener
Paint listener.
Definition: cairo_gal.h:383
cairo_path_t * cairoPath
Pointer to a Cairo path.
Definition: cairo_gal.h:259
virtual void SetTarget(RENDER_TARGET aTarget) override
Sets the target for rendering.
Definition: cairo_gal.cpp:1102
unsigned int * bitmapBuffer
Storage of the cairo image.
Definition: cairo_gal.h:388
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:1239
const COLOR4D & GetFillColor() const
Get the fill color.
Save the transformation matrix.
Definition: cairo_gal.h:245
virtual void SetIsFill(bool aIsFillEnabled) override
Enable/disable fill.
Definition: cairo_gal.cpp:348
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:390
virtual void SetStrokeColor(const COLOR4D &aColor) override
Set the stroke color.
Definition: cairo_gal.cpp:378
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:980
virtual void Restore() override
Restore the context.
Definition: cairo_gal.cpp:533
virtual bool Show(bool aShow) override
Shows/hides the GAL canvas.
Definition: cairo_gal.cpp:1046
unsigned int * bitmapBufferBackup
Backup storage of the cairo image.
Definition: cairo_gal.h:389
virtual int BeginGroup() override
Begin a group.
Definition: cairo_gal.cpp:550
const int scale
int GetPPI() const
Definition: bitmap_base.h:145
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:1130
virtual void SaveScreen() override
Save the screen contents.
Definition: cairo_gal.cpp:1057
Class SHAPE_LINE_CHAIN.
GRAPHICS_COMMAND command
Command to execute.
Definition: cairo_gal.h:253
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:858
cairo_matrix_t cairoWorldScreenMatrix
Cairo world to screen transformation matrix.
Definition: cairo_gal.h:270
size_t i
Definition: json11.cpp:597
Translate the context.
Definition: cairo_gal.h:243
VECTOR2I screenSize
Screen size in screen coordinates.
virtual void Save() override
Save the context.
Definition: cairo_gal.cpp:516
virtual void beginDrawing() override
Definition: cairo_gal.cpp:79
union KIGFX::CAIRO_GAL_BASE::GROUP_ELEMENT::@53 argument
#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:994
bool IsClosed() const
Function IsClosed()
virtual void SetLineWidth(float aLineWidth) override
Set the line width.
Definition: cairo_gal.cpp:414
virtual void Scale(const VECTOR2D &aScale) override
Scale the context.
Definition: cairo_gal.cpp:497
void deleteBitmaps()
Allocate the bitmaps for drawing.
Definition: cairo_gal.cpp:1211
cairo_t * currentContext
Currently used Cairo context for drawing.
Definition: cairo_gal.h:271
virtual void DrawGroup(int aGroupNumber) override
Draw the stored group.
Definition: cairo_gal.cpp:573
unsigned int bufferSize
Size of buffers cairoOutput, bitmapBuffers.
Definition: cairo_gal.h:384
double r
Red component.
Definition: color4d.h:287
virtual int BeginGroup() override
Begin a group.
Definition: cairo_gal.cpp:1088
RENDER_TARGET
RENDER_TARGET: Possible rendering targets.
Definition: definitions.h:39
bool isElementAdded
Was an graphic element added ?
Definition: cairo_gal.h:264
virtual void DrawPolygon(const std::deque< VECTOR2D > &aPointList) override
Draw a polygon.
Definition: cairo_gal.h:105
float GetLineWidth() const
Get the line width.
wxEvtHandler * mouseListener
Mouse listener.
Definition: cairo_gal.h:382
void allocateBitmaps()
Allocate the bitmaps for drawing.
Definition: cairo_gal.cpp:1196
virtual void Transform(const MATRIX3x3D &aTransformation) override
Transform the context.
Definition: cairo_gal.cpp:444
unsigned int mainBuffer
Handle to the main buffer.
Definition: cairo_gal.h:375
const VECTOR2I & CPoint(int aIndex) const
Function CPoint()
wxWindow * parentWindow
Parent window.
Definition: cairo_gal.h:381
virtual void EndGroup() override
End the group.
Definition: cairo_gal.cpp:1095
virtual void Flush() override
Force all remaining objects to be drawn.
Definition: cairo_gal.cpp:334
Enable/disable stroking.
Definition: cairo_gal.h:235
unsigned int getNewGroupNumber()
Returns a valid key that can be used as a new group number.
Definition: cairo_gal.cpp:917
virtual void blitCursor(wxMemoryDC &clientDC)
Blits cursor into the current screen.
Definition: cairo_gal.cpp:840
Restore the transformation matrix.
Definition: cairo_gal.h:246
virtual void SetFillColor(const COLOR4D &aColor) override
Set the fill color.
Definition: cairo_gal.cpp:396
#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:460
static constexpr cairo_format_t GAL_FORMAT
Format used to store pixels.
Definition: cairo_gal.h:296
Class COLOR4D is the color representation with 4 components: red, green, blue, alpha.
Definition: color4d.h:39