gerbv  2.6A
render.c
Go to the documentation of this file.
1 /*
2  * gEDA - GNU Electronic Design Automation
3  *
4  * render.c -- this file is a part of gerbv.
5  *
6  * Copyright (C) 2007 Stuart Brorson (SDB@cloud9.net)
7  *
8  * $Id$
9  *
10  * This program is free software; you can redistribute it and/or modify
11  * it under the terms of the GNU General Public License as published by
12  * the Free Software Foundation; either version 2 of the License, or
13  * (at your option) any later version.
14  *
15  * This program is distributed in the hope that it will be useful,
16  * but WITHOUT ANY WARRANTY; without even the implied warranty of
17  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18  * GNU General Public License for more details.
19  *
20  * You should have received a copy of the GNU General Public License
21  * along with this program; if not, write to the Free Software
22  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
23  */
24 
30 #include "gerbv.h"
31 
32 #ifdef HAVE_STDLIB_H
33 # include <stdlib.h>
34 #endif
35 
36 #ifdef HAVE_STRING_H
37 # include <string.h>
38 #endif
39 
40 #ifdef HAVE_UNISTD_H
41 # include <unistd.h>
42 #endif
43 
44 #ifdef HAVE_LIBGEN_H
45 # include <libgen.h> /* dirname */
46 #endif
47 
48 #include <math.h>
49 
50 #include "common.h"
51 #include "main.h"
52 #include "callbacks.h"
53 #include "interface.h"
54 #include "render.h"
55 
56 #ifdef WIN32
57 # include <cairo-win32.h>
58 #elif QUARTZ
59 # include <cairo-quartz.h>
60 #else
61 # include <cairo-xlib.h>
62 #endif
63 #include "draw-gdk.h"
64 #include "draw.h"
65 
66 #define dprintf if(DEBUG) printf
67 
71 extern gerbv_screen_t screen;
72 
73 extern gerbv_render_info_t screenRenderInfo;
74 
75 /*
76 static void
77 render_layer_to_cairo_target_without_transforming(cairo_t *cr, gerbv_fileinfo_t *fileInfo, gerbv_render_info_t *renderInfo );
78 */
79 
80 gboolean
81 render_check_scale_factor_limits (void) {
82  if ((screenRenderInfo.scaleFactorX > 20000)||(screenRenderInfo.scaleFactorY > 20000)) {
83  screenRenderInfo.scaleFactorX = 20000;
84  screenRenderInfo.scaleFactorY = 20000;
85  return FALSE;
86  }
87  return TRUE;
88 }
89 
90 /* ------------------------------------------------------ */
91 void
92 render_zoom_display (gint zoomType, gdouble scaleFactor, gdouble mouseX, gdouble mouseY) {
93  /*double us_midx, us_midy;*/ /* unscaled translation for screen center */
94  /*int half_w, half_h;*/ /* cache for half window dimensions */
95  gdouble mouseCoordinateX = 0.0;
96  gdouble mouseCoordinateY = 0.0;
97  double oldWidth, oldHeight;
98 
99  /*
100  half_w = screenRenderInfo.displayWidth / 2;
101  half_h = screenRenderInfo.displayHeight / 2;
102  */
103 
104  oldWidth = screenRenderInfo.displayWidth / screenRenderInfo.scaleFactorX;
105  oldHeight = screenRenderInfo.displayHeight / screenRenderInfo.scaleFactorY;
106  if (zoomType == ZOOM_IN_CMOUSE || zoomType == ZOOM_OUT_CMOUSE) {
107  /* calculate what user coordinate the mouse is pointing at */
108  mouseCoordinateX = mouseX / screenRenderInfo.scaleFactorX + screenRenderInfo.lowerLeftX;
109  mouseCoordinateY = (screenRenderInfo.displayHeight - mouseY) /
110  screenRenderInfo.scaleFactorY + screenRenderInfo.lowerLeftY;
111  }
112 
113  /*
114  us_midx = screenRenderInfo.lowerLeftX + (screenRenderInfo.displayWidth / 2.0 )/
115  screenRenderInfo.scaleFactorX;
116  us_midy = screenRenderInfo.lowerLeftY + (screenRenderInfo.displayHeight / 2.0 )/
117  screenRenderInfo.scaleFactorY;
118  */
119 
120  switch(zoomType) {
121  case ZOOM_IN : /* Zoom In */
122  case ZOOM_IN_CMOUSE : /* Zoom In Around Mouse Pointer */
123  screenRenderInfo.scaleFactorX += screenRenderInfo.scaleFactorX/3;
124  screenRenderInfo.scaleFactorY += screenRenderInfo.scaleFactorY/3;
125  (void) render_check_scale_factor_limits ();
126  screenRenderInfo.lowerLeftX += (oldWidth - (screenRenderInfo.displayWidth /
127  screenRenderInfo.scaleFactorX)) / 2.0;
128  screenRenderInfo.lowerLeftY += (oldHeight - (screenRenderInfo.displayHeight /
129  screenRenderInfo.scaleFactorY)) / 2.0;
130  break;
131  case ZOOM_OUT : /* Zoom Out */
132  case ZOOM_OUT_CMOUSE : /* Zoom Out Around Mouse Pointer */
133  if ((screenRenderInfo.scaleFactorX > 10)&&(screenRenderInfo.scaleFactorY > 10)) {
134  screenRenderInfo.scaleFactorX -= screenRenderInfo.scaleFactorX/3;
135  screenRenderInfo.scaleFactorY -= screenRenderInfo.scaleFactorY/3;
136  screenRenderInfo.lowerLeftX += (oldWidth - (screenRenderInfo.displayWidth /
137  screenRenderInfo.scaleFactorX)) / 2.0;
138  screenRenderInfo.lowerLeftY += (oldHeight - (screenRenderInfo.displayHeight /
139  screenRenderInfo.scaleFactorY)) / 2.0;
140  }
141  break;
142  case ZOOM_FIT : /* Zoom Fit */
143  gerbv_render_zoom_to_fit_display (mainProject, &screenRenderInfo);
144  break;
145  case ZOOM_SET : /*explicit scale set by user */
146  screenRenderInfo.scaleFactorX = scaleFactor;
147  screenRenderInfo.scaleFactorY = scaleFactor;
148  (void) render_check_scale_factor_limits ();
149  screenRenderInfo.lowerLeftX += (oldWidth - (screenRenderInfo.displayWidth /
150  screenRenderInfo.scaleFactorX)) / 2.0;
151  screenRenderInfo.lowerLeftY += (oldHeight - (screenRenderInfo.displayHeight /
152  screenRenderInfo.scaleFactorY)) / 2.0;
153  break;
154  default :
155  GERB_MESSAGE(_("Illegal zoom direction %d"), zoomType);
156  }
157 
158  if (zoomType == ZOOM_IN_CMOUSE || zoomType == ZOOM_OUT_CMOUSE) {
159  /* make sure the mouse is still pointing at the point calculated earlier */
160  screenRenderInfo.lowerLeftX = mouseCoordinateX - mouseX / screenRenderInfo.scaleFactorX;
161  screenRenderInfo.lowerLeftY = mouseCoordinateY - (screenRenderInfo.displayHeight - mouseY) /
162  screenRenderInfo.scaleFactorY;
163  }
164  render_refresh_rendered_image_on_screen();
165  return;
166 }
167 
168 
169 /* --------------------------------------------------------- */
175 void
176 render_calculate_zoom_from_outline(GtkWidget *widget, GdkEventButton *event)
177 {
178  int x1, y1, x2, y2, dx, dy; /* Zoom outline (UR and LL corners) */
179  double centerPointX, centerPointY;
180  int half_x, half_y; /* cache for half window dimensions */
181 
182  x1 = MIN(screen.start_x, event->x);
183  y1 = MIN(screen.start_y, event->y);
184  x2 = MAX(screen.start_x, event->x);
185  y2 = MAX(screen.start_y, event->y);
186  dx = x2-x1;
187  dy = y2-y1;
188 
189  if ((dx >= 4) && (dy >= 4)) {
190  if (screen.centered_outline_zoom) {
191  /* Centered outline mode */
192  x1 = screen.start_x - dx;
193  y1 = screen.start_y - dy;
194  dx *= 2;
195  dy *= 2;
196  }
197  half_x = (x1+x2)/2;
198  half_y = (y1+y2)/2;
199  centerPointX = half_x/screenRenderInfo.scaleFactorX + screenRenderInfo.lowerLeftX;
200  centerPointY = (screenRenderInfo.displayHeight - half_y)/screenRenderInfo.scaleFactorY +
201  screenRenderInfo.lowerLeftY;
202 
203  screenRenderInfo.scaleFactorX *= MIN(((double)screenRenderInfo.displayWidth / dx),
204  ((double)screenRenderInfo.displayHeight / dy));
205  screenRenderInfo.scaleFactorY = screenRenderInfo.scaleFactorX;
206  (void) render_check_scale_factor_limits ();
207  screenRenderInfo.lowerLeftX = centerPointX - (screenRenderInfo.displayWidth /
208  2.0 / screenRenderInfo.scaleFactorX);
209  screenRenderInfo.lowerLeftY = centerPointY - (screenRenderInfo.displayHeight /
210  2.0 / screenRenderInfo.scaleFactorY);
211  }
212  render_refresh_rendered_image_on_screen();
213 }
214 
215 /* ------------------------------------------------------ */
216 void
217 render_draw_selection_box_outline(void) {
218  GdkGC *gc;
219  GdkGCValues values;
220  GdkGCValuesMask values_mask;
221  gint x1, y1, x2, y2, dx, dy;
222 
223  memset(&values, 0, sizeof(values));
224  values.function = GDK_XOR;
225  if (!screen.zoom_outline_color.pixel)
226  gdk_colormap_alloc_color(gdk_colormap_get_system(), &screen.zoom_outline_color, FALSE, TRUE);
227  values.foreground = screen.zoom_outline_color;
228  values_mask = GDK_GC_FUNCTION | GDK_GC_FOREGROUND;
229  gc = gdk_gc_new_with_values(screen.drawing_area->window, &values, values_mask);
230 
231  x1 = MIN(screen.start_x, screen.last_x);
232  y1 = MIN(screen.start_y, screen.last_y);
233  x2 = MAX(screen.start_x, screen.last_x);
234  y2 = MAX(screen.start_y, screen.last_y);
235  dx = x2-x1;
236  dy = y2-y1;
237 
238  gdk_draw_rectangle(screen.drawing_area->window, gc, FALSE, x1, y1, dx, dy);
239  gdk_gc_unref(gc);
240 }
241 
242 /* --------------------------------------------------------- */
243 void
244 render_draw_zoom_outline(gboolean centered)
245 {
246  GdkGC *gc;
247  GdkGCValues values;
248  GdkGCValuesMask values_mask;
249  gint x1, y1, x2, y2, dx, dy;
250 
251  memset(&values, 0, sizeof(values));
252  values.function = GDK_XOR;
253  if (!screen.zoom_outline_color.pixel)
254  gdk_colormap_alloc_color(gdk_colormap_get_system(), &screen.zoom_outline_color, FALSE, TRUE);
255  values.foreground = screen.zoom_outline_color;
256  values_mask = GDK_GC_FUNCTION | GDK_GC_FOREGROUND;
257  gc = gdk_gc_new_with_values(screen.drawing_area->window, &values, values_mask);
258 
259  x1 = MIN(screen.start_x, screen.last_x);
260  y1 = MIN(screen.start_y, screen.last_y);
261  x2 = MAX(screen.start_x, screen.last_x);
262  y2 = MAX(screen.start_y, screen.last_y);
263  dx = x2-x1;
264  dy = y2-y1;
265 
266  if (centered) {
267  /* Centered outline mode */
268  x1 = screen.start_x - dx;
269  y1 = screen.start_y - dy;
270  dx *= 2;
271  dy *= 2;
272  x2 = x1+dx;
273  y2 = y1+dy;
274  }
275 
276  gdk_draw_rectangle(screen.drawing_area->window, gc, FALSE, x1, y1, dx, dy);
277  gdk_gc_unref(gc);
278 
279  /* Draw actual zoom area in dashed lines */
280  memset(&values, 0, sizeof(values));
281  values.function = GDK_XOR;
282  values.foreground = screen.zoom_outline_color;
283  values.line_style = GDK_LINE_ON_OFF_DASH;
284  values_mask = GDK_GC_FUNCTION | GDK_GC_FOREGROUND | GDK_GC_LINE_STYLE;
285  gc = gdk_gc_new_with_values(screen.drawing_area->window, &values,
286  values_mask);
287 
288  if ((dy == 0) || ((double)dx/dy > (double)screen.drawing_area->allocation.width/
289  screen.drawing_area->allocation.height)) {
290  dy = dx * (double)screen.drawing_area->allocation.height/
291  screen.drawing_area->allocation.width;
292  }
293  else {
294  dx = dy * (double)screen.drawing_area->allocation.width/
295  screen.drawing_area->allocation.height;
296  }
297 
298  gdk_draw_rectangle(screen.drawing_area->window, gc, FALSE, (x1+x2-dx)/2,
299  (y1+y2-dy)/2, dx, dy);
300 
301  gdk_gc_unref(gc);
302 }
303 
304 /* ------------------------------------------------------ */
305 /* Transforms board coordinates to screen ones */
306 static void
307 render_board2screen(gdouble *X, gdouble *Y, gdouble x, gdouble y) {
308  *X = (x - screenRenderInfo.lowerLeftX) * screenRenderInfo.scaleFactorX;
309  *Y = screenRenderInfo.displayHeight - (y - screenRenderInfo.lowerLeftY)
310  * screenRenderInfo.scaleFactorY;
311 }
312 
313 /* Trims the coordinates to avoid overflows in gdk_draw_line */
314 static void
315 render_trim_point(gdouble *start_x, gdouble *start_y, gdouble last_x, gdouble last_y)
316 {
317  const gdouble max_coord = (1<<15) - 2;/* a value that causes no overflow
318  and lies out of screen */
319  gdouble dx, dy;
320 
321  if (fabs (*start_x) < max_coord && fabs (*start_y) < max_coord)
322  return;
323 
324  dx = last_x - *start_x;
325  dy = last_y - *start_y;
326 
327  if (*start_x < -max_coord) {
328  *start_x = -max_coord;
329  if (last_x > -max_coord && fabs (dx) > 0.1)
330  *start_y = last_y - (last_x + max_coord) / dx * dy;
331  }
332  if (*start_x > max_coord) {
333  *start_x = max_coord;
334  if (last_x < max_coord && fabs (dx) > 0.1)
335  *start_y = last_y - (last_x - max_coord) / dx * dy;
336  }
337 
338  dx = last_x - *start_x;
339  dy = last_y - *start_y;
340 
341  if (*start_y < -max_coord) {
342  *start_y = -max_coord;
343  if (last_y > -max_coord && fabs (dy) > 0.1)
344  *start_x = last_x - (last_y + max_coord) / dy * dx;
345  }
346  if (*start_y > max_coord) {
347  *start_y = max_coord;
348  if (last_y < max_coord && fabs (dy) > 0.1)
349  *start_x = last_x - (last_y - max_coord) / dy * dx;
350  }
351 }
352 
353 /* ------------------------------------------------------ */
356 void
358 {
359 
360  GdkGC *gc;
361  GdkGCValues values;
362  GdkGCValuesMask values_mask;
363  gdouble start_x, start_y, last_x, last_y;
364  memset(&values, 0, sizeof(values));
365  values.function = GDK_XOR;
366  if (!screen.zoom_outline_color.pixel)
367  gdk_colormap_alloc_color(gdk_colormap_get_system(), &screen.zoom_outline_color, FALSE, TRUE);
368  values.foreground = screen.zoom_outline_color;
369  values_mask = GDK_GC_FUNCTION | GDK_GC_FOREGROUND;
370  gc = gdk_gc_new_with_values(screen.drawing_area->window, &values,
371  values_mask);
372  render_board2screen(&start_x, &start_y,
373  screen.measure_start_x, screen.measure_start_y);
374  render_board2screen(&last_x, &last_y,
375  screen.measure_last_x, screen.measure_last_y);
376  render_trim_point(&start_x, &start_y, last_x, last_y);
377  render_trim_point(&last_x, &last_y, start_x, start_y);
378  gdk_draw_line(screen.drawing_area->window, gc, start_x,
379  start_y, last_x, last_y);
380  gdk_gc_unref(gc);
381 } /* toggle_measure_line */
382 
383 /* ------------------------------------------------------ */
385 void
387 {
388  gdouble x1, y1, x2, y2;
389  gdouble dx, dy;
390 
391  x1 = MIN(screen.measure_start_x, screen.measure_last_x);
392  y1 = MIN(screen.measure_start_y, screen.measure_last_y);
393  x2 = MAX(screen.measure_start_x, screen.measure_last_x);
394  y2 = MAX(screen.measure_start_y, screen.measure_last_y);
395  dx = (x2 - x1);
396  dy = (y2 - y1);
397 
398  screen.win.lastMeasuredX = dx;
399  screen.win.lastMeasuredY = dy;
400  callbacks_update_statusbar_measured_distance (dx, dy);
402 } /* draw_measure_distance */
403 
404 /* ------------------------------------------------------ */
405 void render_selection_layer (void){
406  cairo_t *cr;
407 
408  if (screen.selectionRenderData)
409  cairo_surface_destroy ((cairo_surface_t *) screen.selectionRenderData);
410  screen.selectionRenderData =
411  (gpointer) cairo_surface_create_similar ((cairo_surface_t *)screen.windowSurface,
412  CAIRO_CONTENT_COLOR_ALPHA, screenRenderInfo.displayWidth,
413  screenRenderInfo.displayHeight);
414  if (screen.selectionInfo.type != GERBV_SELECTION_EMPTY) {
415  cr= cairo_create(screen.selectionRenderData);
416  gerbv_render_cairo_set_scale_and_translation(cr, &screenRenderInfo);
417  cairo_set_source_rgba (cr, 1.0, 1.0, 1.0, 0.85);
418  /* for now, assume everything in the selection buffer is from one image */
419  gerbv_image_t *matchImage;
420  int j;
421  if (screen.selectionInfo.selectedNodeArray->len > 0) {
422  gerbv_selection_item_t sItem = g_array_index (screen.selectionInfo.selectedNodeArray,
423  gerbv_selection_item_t, 0);
424  matchImage = (gerbv_image_t *) sItem.image;
425  dprintf(" .... calling render_image_to_cairo_target on selection layer...\n");
426  for(j = mainProject->last_loaded; j >= 0; j--) {
427  if ((mainProject->file[j]) && (mainProject->file[j]->image == matchImage)) {
428  draw_image_to_cairo_target (cr, mainProject->file[j]->image,
429  1.0/MAX(screenRenderInfo.scaleFactorX,
430  screenRenderInfo.scaleFactorY),
431  DRAW_SELECTIONS, &screen.selectionInfo, &screenRenderInfo,
432  TRUE, mainProject->file[j]->transform, TRUE);
433  }
434  }
435  }
436  cairo_destroy (cr);
437  }
438 }
439 
440 /* ------------------------------------------------------ */
441 void render_refresh_rendered_image_on_screen (void) {
442  GdkCursor *cursor;
443 
444  dprintf("----> Entering redraw_pixmap...\n");
445  cursor = gdk_cursor_new(GDK_WATCH);
446  gdk_window_set_cursor(GDK_WINDOW(screen.drawing_area->window), cursor);
447  gdk_cursor_destroy(cursor);
448 
449  if (screenRenderInfo.renderType <= GERBV_RENDER_TYPE_GDK_XOR){
450  if (screen.pixmap)
451  gdk_pixmap_unref(screen.pixmap);
452  screen.pixmap = gdk_pixmap_new(screen.drawing_area->window, screenRenderInfo.displayWidth,
453  screenRenderInfo.displayHeight, -1);
454  gerbv_render_to_pixmap_using_gdk (mainProject, screen.pixmap, &screenRenderInfo, &screen.selectionInfo,
455  &screen.selection_color);
456  dprintf("<---- leaving redraw_pixmap.\n");
457  }
458  else{
459  int i;
460  dprintf(" .... Now try rendering the drawing using cairo .... \n");
461  /*
462  * This now allows drawing several layers on top of each other.
463  * Higher layer numbers have higher priority in the Z-order.
464  */
465  for(i = mainProject->last_loaded; i >= 0; i--) {
466  if (mainProject->file[i]) {
467  cairo_t *cr;
469  cairo_surface_destroy ((cairo_surface_t *) mainProject->file[i]->privateRenderData);
471  (gpointer) cairo_surface_create_similar ((cairo_surface_t *)screen.windowSurface,
472  CAIRO_CONTENT_COLOR_ALPHA, screenRenderInfo.displayWidth,
473  screenRenderInfo.displayHeight);
474  cr= cairo_create(mainProject->file[i]->privateRenderData );
475  gerbv_render_layer_to_cairo_target (cr, mainProject->file[i], &screenRenderInfo);
476  dprintf(" .... calling render_image_to_cairo_target on layer %d...\n", i);
477  cairo_destroy (cr);
478  }
479  }
480  /* render the selection layer */
481  render_selection_layer();
482 
483  render_recreate_composite_surface ();
484  }
485  /* remove watch cursor and switch back to normal cursor */
486  callbacks_switch_to_correct_cursor ();
487  callbacks_force_expose_event_for_screen();
488 }
489 
490 /* ------------------------------------------------------ */
491 void
492 render_clear_selection_buffer (void){
493  if (screen.selectionInfo.type == GERBV_SELECTION_EMPTY)
494  return;
495 
496  g_array_remove_range (screen.selectionInfo.selectedNodeArray, 0,
497  screen.selectionInfo.selectedNodeArray->len);
498  screen.selectionInfo.type = GERBV_SELECTION_EMPTY;
499  callbacks_update_selected_object_message (FALSE);
500 }
501 
502 void
503 render_remove_selected_objects_belonging_to_layer (gint index) {
504  int i;
505 
506  for (i=screen.selectionInfo.selectedNodeArray->len-1; i>=0; i--) {
507  gerbv_selection_item_t sItem = g_array_index (screen.selectionInfo.selectedNodeArray,
508  gerbv_selection_item_t, i);
509 
510  gerbv_image_t *matchImage = (gerbv_image_t *) sItem.image;
511  if (mainProject->file[index]->image == matchImage) {
512  g_array_remove_index (screen.selectionInfo.selectedNodeArray, index);
513  }
514  }
515  callbacks_update_selected_object_message (FALSE);
516 }
517 
518 /* ------------------------------------------------------ */
519 gint
520 render_create_cairo_buffer_surface () {
521  if (screen.bufferSurface) {
522  cairo_surface_destroy (screen.bufferSurface);
523  screen.bufferSurface = NULL;
524  }
525  if (!screen.windowSurface)
526  return 0;
527 
528  screen.bufferSurface= cairo_surface_create_similar ((cairo_surface_t *)screen.windowSurface,
529  CAIRO_CONTENT_COLOR, screenRenderInfo.displayWidth,
530  screenRenderInfo.displayHeight);
531  return 1;
532 }
533 
534 /* ------------------------------------------------------ */
535 void
536 render_find_selected_objects_and_refresh_display (gint activeFileIndex, gboolean eraseOldSelection){
537  /* clear the old selection array if desired */
538  if ((eraseOldSelection)&&(screen.selectionInfo.selectedNodeArray->len))
539  g_array_remove_range (screen.selectionInfo.selectedNodeArray, 0,
540  screen.selectionInfo.selectedNodeArray->len);
541 
542  /* make sure we have a bufferSurface...if we start up in FAST mode, we may not
543  have one yet, but we need it for selections */
544  if (!render_create_cairo_buffer_surface())
545  return;
546 
547  /* call draw_image... passing the FILL_SELECTION mode to just search for
548  nets which match the selection, and fill the selection buffer with them */
549  cairo_t *cr= cairo_create(screen.bufferSurface);
550  gerbv_render_cairo_set_scale_and_translation(cr,&screenRenderInfo);
551  draw_image_to_cairo_target (cr, mainProject->file[activeFileIndex]->image,
552  1.0/MAX(screenRenderInfo.scaleFactorX, screenRenderInfo.scaleFactorY),
553  FIND_SELECTIONS, &screen.selectionInfo, &screenRenderInfo, TRUE,
554  mainProject->file[activeFileIndex]->transform, TRUE);
555  cairo_destroy (cr);
556  /* if the selection array is empty, switch the "mode" to empty to make it
557  easier to check if it is holding anything */
558  if (!screen.selectionInfo.selectedNodeArray->len)
559  screen.selectionInfo.type = GERBV_SELECTION_EMPTY;
560  /* re-render the selection buffer layer */
561  if (screenRenderInfo.renderType <= GERBV_RENDER_TYPE_GDK_XOR){
562  render_refresh_rendered_image_on_screen ();
563  }
564  else {
565  render_selection_layer();
566  render_recreate_composite_surface ();
567  callbacks_force_expose_event_for_screen();
568  }
569 }
570 
571 /* ------------------------------------------------------ */
572 void
573 render_fill_selection_buffer_from_mouse_click (gint mouseX, gint mouseY, gint activeFileIndex,
574  gboolean eraseOldSelection) {
575  screen.selectionInfo.lowerLeftX = mouseX;
576  screen.selectionInfo.lowerLeftY = mouseY;
577  /* no need to populate the upperright coordinates for a point_click */
578  screen.selectionInfo.type = GERBV_SELECTION_POINT_CLICK;
579  render_find_selected_objects_and_refresh_display (activeFileIndex, eraseOldSelection);
580 }
581 
582 /* ------------------------------------------------------ */
583 void
584 render_fill_selection_buffer_from_mouse_drag (gint corner1X, gint corner1Y,
585  gint corner2X, gint corner2Y, gint activeFileIndex, gboolean eraseOldSelection) {
586  /* figure out the lower left corner of the box */
587  screen.selectionInfo.lowerLeftX = MIN(corner1X, corner2X);
588  screen.selectionInfo.lowerLeftY = MIN(corner1Y, corner2Y);
589  /* figure out the upper right corner of the box */
590  screen.selectionInfo.upperRightX = MAX(corner1X, corner2X);
591  screen.selectionInfo.upperRightY = MAX(corner1Y, corner2Y);
592 
593  screen.selectionInfo.type = GERBV_SELECTION_DRAG_BOX;
594  render_find_selected_objects_and_refresh_display (activeFileIndex, eraseOldSelection);
595 }
596 
597 /* ------------------------------------------------------ */
598 void render_recreate_composite_surface () {
599  gint i;
600 
601  if (!render_create_cairo_buffer_surface())
602  return;
603 
604  cairo_t *cr= cairo_create(screen.bufferSurface);
605  /* fill the background with the appropriate color */
606  cairo_set_source_rgba (cr, (double) mainProject->background.red/G_MAXUINT16,
607  (double) mainProject->background.green/G_MAXUINT16,
608  (double) mainProject->background.blue/G_MAXUINT16, 1);
609  cairo_paint (cr);
610 
611  for(i = mainProject->last_loaded; i >= 0; i--) {
612  if (mainProject->file[i] && mainProject->file[i]->isVisible) {
613  cairo_set_source_surface (cr, (cairo_surface_t *) mainProject->file[i]->privateRenderData,
614  0, 0);
615  /* ignore alpha if we are in high-speed render mode */
616  if (((double) mainProject->file[i]->alpha < 65535)&&(screenRenderInfo.renderType != GERBV_RENDER_TYPE_GDK_XOR)) {
617  cairo_paint_with_alpha(cr,(double) mainProject->file[i]->alpha/G_MAXUINT16);
618  }
619  else {
620  cairo_paint (cr);
621  }
622  }
623  }
624  /* render the selection layer at the end */
625  if (screen.selectionInfo.type != GERBV_SELECTION_EMPTY) {
626  cairo_set_source_surface (cr, (cairo_surface_t *) screen.selectionRenderData,
627  0, 0);
628  cairo_paint_with_alpha (cr,1.0);
629  }
630  cairo_destroy (cr);
631 }
632 
633 /* ------------------------------------------------------ */
634 void render_project_to_cairo_target (cairo_t *cr) {
635  /* fill the background with the appropriate color */
636  cairo_set_source_rgba (cr, (double) mainProject->background.red/G_MAXUINT16,
637  (double) mainProject->background.green/G_MAXUINT16,
638  (double) mainProject->background.blue/G_MAXUINT16, 1);
639  cairo_paint (cr);
640 
641  cairo_set_source_surface (cr, (cairo_surface_t *) screen.bufferSurface, 0 , 0);
642 
643  cairo_paint (cr);
644 }
645 
646 void
647 render_free_screen_resources (void) {
648  if (screen.selectionRenderData)
649  cairo_surface_destroy ((cairo_surface_t *)
650  screen.selectionRenderData);
651  if (screen.bufferSurface)
652  cairo_surface_destroy ((cairo_surface_t *)
653  screen.bufferSurface);
654  if (screen.windowSurface)
655  cairo_surface_destroy ((cairo_surface_t *)
656  screen.windowSurface);
657  if (screen.pixmap)
658  gdk_pixmap_unref(screen.pixmap);
659 }
660 
661 
662 /* ------------------------------------------------------------------ */
668 {
669  int i;
670  gerbv_stats_t *stats;
671  gerbv_stats_t *instats;
672 
673  /* Create new stats structure to hold report for whole project
674  * (i.e. all layers together) */
675  stats = gerbv_stats_new();
676 
677  /* Loop through open layers and compile statistics by accumulating reports from each layer */
678  for (i = 0; i <= mainProject->last_loaded; i++) {
679  if (mainProject->file[i] && mainProject->file[i]->isVisible &&
681  instats = mainProject->file[i]->image->gerbv_stats;
682  gerbv_stats_add_layer(stats, instats, i+1);
683  }
684  }
685  return stats;
686 }
687 
688 
689 /* ------------------------------------------------------------------ */
695 {
696  int i;
697  gerbv_drill_stats_t *stats;
698  gerbv_drill_stats_t *instats;
699 
700  stats = gerbv_drill_stats_new();
701 
702  /* Loop through open layers and compile statistics by accumulating reports from each layer */
703  for(i = mainProject->last_loaded; i >= 0; i--) {
704  if (mainProject->file[i] &&
705  mainProject->file[i]->isVisible &&
707  instats = mainProject->file[i]->image->drill_stats;
708  /* add this batch of stats. Send the layer
709  * index for error reporting */
710  gerbv_drill_stats_add_layer(stats, instats, i+1);
711  }
712  }
713  return stats;
714 }
715