* rework export svg/pdf/ps functionality to export images with 1:1 scale. Previously...
[geda-gerbv.git] / src / render.c
blob14a7ebef7b698a4f4dd7172800a72cf3133f61a5
1 /*
2 * gEDA - GNU Electronic Design Automation
4 * render.c -- this file is a part of gerbv.
6 * Copyright (C) 2007 Stuart Brorson (SDB@cloud9.net)
8 * $Id$
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.
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.
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
25 /** \file render.c
26 \brief Rendering support functions for libgerbv
27 \ingroup libgerbv
30 #ifdef HAVE_CONFIG_H
31 # include <config.h>
32 #endif
34 #ifdef HAVE_STDLIB_H
35 #include <stdlib.h>
36 #endif
38 #ifdef HAVE_STRING_H
39 #include <string.h>
40 #endif
42 #ifdef HAVE_UNISTD_H
43 #include <unistd.h>
44 #endif
46 #ifdef HAVE_LIBGEN_H
47 #include <libgen.h> /* dirname */
48 #endif
50 #include <math.h>
52 #include "common.h"
53 #include "gerbv.h"
54 #include "main.h"
55 #include "callbacks.h"
56 #include "interface.h"
57 #include "render.h"
59 #ifdef WIN32
60 #include <cairo-win32.h>
61 #else
62 #include <cairo-xlib.h>
63 #endif
64 #include <cairo.h>
65 #include "draw-gdk.h"
66 #include "draw.h"
68 #define dprintf if(DEBUG) printf
70 /**Global variable to keep track of what's happening on the screen.
71 Declared extern in gerbv_screen.h
73 extern gerbv_screen_t screen;
75 extern gerbv_render_info_t screenRenderInfo;
78 static void
79 render_layer_to_cairo_target_without_transforming(cairo_t *cr, gerbv_fileinfo_t *fileInfo, gerbv_render_info_t *renderInfo );
82 gboolean
83 render_check_scale_factor_limits (void) {
84 if ((screenRenderInfo.scaleFactorX > 5000)||(screenRenderInfo.scaleFactorY > 5000)) {
85 screenRenderInfo.scaleFactorX = 5000;
86 screenRenderInfo.scaleFactorY = 5000;
87 return FALSE;
89 return TRUE;
92 /* ------------------------------------------------------ */
93 void
94 render_zoom_display (gint zoomType, gdouble scaleFactor, gdouble mouseX, gdouble mouseY) {
95 double us_midx, us_midy; /* unscaled translation for screen center */
96 int half_w, half_h; /* cache for half window dimensions */
97 gdouble mouseCoordinateX = 0.0;
98 gdouble mouseCoordinateY = 0.0;
99 double oldWidth, oldHeight;
101 half_w = screenRenderInfo.displayWidth / 2;
102 half_h = screenRenderInfo.displayHeight / 2;
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;
113 us_midx = screenRenderInfo.lowerLeftX + (screenRenderInfo.displayWidth / 2.0 )/
114 screenRenderInfo.scaleFactorX;
115 us_midy = screenRenderInfo.lowerLeftY + (screenRenderInfo.displayHeight / 2.0 )/
116 screenRenderInfo.scaleFactorY;
118 switch(zoomType) {
119 case ZOOM_IN : /* Zoom In */
120 case ZOOM_IN_CMOUSE : /* Zoom In Around Mouse Pointer */
121 screenRenderInfo.scaleFactorX += screenRenderInfo.scaleFactorX/3;
122 screenRenderInfo.scaleFactorY += screenRenderInfo.scaleFactorY/3;
123 (void) render_check_scale_factor_limits ();
124 screenRenderInfo.lowerLeftX += (oldWidth - (screenRenderInfo.displayWidth /
125 screenRenderInfo.scaleFactorX)) / 2.0;
126 screenRenderInfo.lowerLeftY += (oldHeight - (screenRenderInfo.displayHeight /
127 screenRenderInfo.scaleFactorY)) / 2.0;
128 break;
129 case ZOOM_OUT : /* Zoom Out */
130 case ZOOM_OUT_CMOUSE : /* Zoom Out Around Mouse Pointer */
131 if ((screenRenderInfo.scaleFactorX > 10)&&(screenRenderInfo.scaleFactorY > 10)) {
132 screenRenderInfo.scaleFactorX -= screenRenderInfo.scaleFactorX/3;
133 screenRenderInfo.scaleFactorY -= screenRenderInfo.scaleFactorY/3;
134 screenRenderInfo.lowerLeftX += (oldWidth - (screenRenderInfo.displayWidth /
135 screenRenderInfo.scaleFactorX)) / 2.0;
136 screenRenderInfo.lowerLeftY += (oldHeight - (screenRenderInfo.displayHeight /
137 screenRenderInfo.scaleFactorY)) / 2.0;
139 break;
140 case ZOOM_FIT : /* Zoom Fit */
141 gerbv_render_zoom_to_fit_display (mainProject, &screenRenderInfo);
142 break;
143 case ZOOM_SET : /*explicit scale set by user */
144 screenRenderInfo.scaleFactorX = scaleFactor;
145 screenRenderInfo.scaleFactorY = scaleFactor;
146 (void) render_check_scale_factor_limits ();
147 screenRenderInfo.lowerLeftX += (oldWidth - (screenRenderInfo.displayWidth /
148 screenRenderInfo.scaleFactorX)) / 2.0;
149 screenRenderInfo.lowerLeftY += (oldHeight - (screenRenderInfo.displayHeight /
150 screenRenderInfo.scaleFactorY)) / 2.0;
151 break;
152 default :
153 GERB_MESSAGE("Illegal zoom direction %d\n", zoomType);
156 if (zoomType == ZOOM_IN_CMOUSE || zoomType == ZOOM_OUT_CMOUSE) {
157 /* make sure the mouse is still pointing at the point calculated earlier */
158 screenRenderInfo.lowerLeftX = mouseCoordinateX - mouseX / screenRenderInfo.scaleFactorX;
159 screenRenderInfo.lowerLeftY = mouseCoordinateY - (screenRenderInfo.displayHeight - mouseY) /
160 screenRenderInfo.scaleFactorY;
162 render_refresh_rendered_image_on_screen();
163 return;
167 /* --------------------------------------------------------- */
168 /** Will determine the outline of the zoomed regions.
169 * In case region to be zoomed is too small (which correspondes
170 * e.g. to a double click) it is interpreted as a right-click
171 * and will be used to identify a part from the CURRENT selection,
172 * which is drawn on screen*/
173 void
174 render_calculate_zoom_from_outline(GtkWidget *widget, GdkEventButton *event)
176 int x1, y1, x2, y2, dx, dy; /* Zoom outline (UR and LL corners) */
177 double centerPointX, centerPointY;
178 int half_x, half_y; /* cache for half window dimensions */
180 x1 = MIN(screen.start_x, event->x);
181 y1 = MIN(screen.start_y, event->y);
182 x2 = MAX(screen.start_x, event->x);
183 y2 = MAX(screen.start_y, event->y);
184 dx = x2-x1;
185 dy = y2-y1;
187 if ((dx >= 4) && (dy >= 4)) {
188 if (screen.centered_outline_zoom) {
189 /* Centered outline mode */
190 x1 = screen.start_x - dx;
191 y1 = screen.start_y - dy;
192 dx *= 2;
193 dy *= 2;
195 half_x = (x1+x2)/2;
196 half_y = (y1+y2)/2;
197 centerPointX = half_x/screenRenderInfo.scaleFactorX + screenRenderInfo.lowerLeftX;
198 centerPointY = (screenRenderInfo.displayHeight - half_y)/screenRenderInfo.scaleFactorY +
199 screenRenderInfo.lowerLeftY;
201 screenRenderInfo.scaleFactorX *= MIN(((double)screenRenderInfo.displayWidth / dx),
202 ((double)screenRenderInfo.displayHeight / dy));
203 screenRenderInfo.scaleFactorY = screenRenderInfo.scaleFactorX;
204 (void) render_check_scale_factor_limits ();
205 screenRenderInfo.lowerLeftX = centerPointX - (screenRenderInfo.displayWidth /
206 2.0 / screenRenderInfo.scaleFactorX);
207 screenRenderInfo.lowerLeftY = centerPointY - (screenRenderInfo.displayHeight /
208 2.0 / screenRenderInfo.scaleFactorY);
210 render_refresh_rendered_image_on_screen();
213 /* ------------------------------------------------------ */
214 void
215 render_draw_selection_box_outline(void) {
216 GdkGC *gc;
217 GdkGCValues values;
218 GdkGCValuesMask values_mask;
219 gint x1, y1, x2, y2, dx, dy;
221 memset(&values, 0, sizeof(values));
222 values.function = GDK_XOR;
223 if (!screen.zoom_outline_color.pixel)
224 gdk_colormap_alloc_color(gdk_colormap_get_system(), &screen.zoom_outline_color, FALSE, TRUE);
225 values.foreground = screen.zoom_outline_color;
226 values_mask = GDK_GC_FUNCTION | GDK_GC_FOREGROUND;
227 gc = gdk_gc_new_with_values(screen.drawing_area->window, &values, values_mask);
229 x1 = MIN(screen.start_x, screen.last_x);
230 y1 = MIN(screen.start_y, screen.last_y);
231 x2 = MAX(screen.start_x, screen.last_x);
232 y2 = MAX(screen.start_y, screen.last_y);
233 dx = x2-x1;
234 dy = y2-y1;
236 gdk_draw_rectangle(screen.drawing_area->window, gc, FALSE, x1, y1, dx, dy);
237 gdk_gc_unref(gc);
240 /* --------------------------------------------------------- */
241 void
242 render_draw_zoom_outline(gboolean centered)
244 GdkGC *gc;
245 GdkGCValues values;
246 GdkGCValuesMask values_mask;
247 gint x1, y1, x2, y2, dx, dy;
249 memset(&values, 0, sizeof(values));
250 values.function = GDK_XOR;
251 if (!screen.zoom_outline_color.pixel)
252 gdk_colormap_alloc_color(gdk_colormap_get_system(), &screen.zoom_outline_color, FALSE, TRUE);
253 values.foreground = screen.zoom_outline_color;
254 values_mask = GDK_GC_FUNCTION | GDK_GC_FOREGROUND;
255 gc = gdk_gc_new_with_values(screen.drawing_area->window, &values, values_mask);
257 x1 = MIN(screen.start_x, screen.last_x);
258 y1 = MIN(screen.start_y, screen.last_y);
259 x2 = MAX(screen.start_x, screen.last_x);
260 y2 = MAX(screen.start_y, screen.last_y);
261 dx = x2-x1;
262 dy = y2-y1;
264 if (centered) {
265 /* Centered outline mode */
266 x1 = screen.start_x - dx;
267 y1 = screen.start_y - dy;
268 dx *= 2;
269 dy *= 2;
270 x2 = x1+dx;
271 y2 = y1+dy;
274 gdk_draw_rectangle(screen.drawing_area->window, gc, FALSE, x1, y1, dx, dy);
275 gdk_gc_unref(gc);
277 /* Draw actual zoom area in dashed lines */
278 memset(&values, 0, sizeof(values));
279 values.function = GDK_XOR;
280 values.foreground = screen.zoom_outline_color;
281 values.line_style = GDK_LINE_ON_OFF_DASH;
282 values_mask = GDK_GC_FUNCTION | GDK_GC_FOREGROUND | GDK_GC_LINE_STYLE;
283 gc = gdk_gc_new_with_values(screen.drawing_area->window, &values,
284 values_mask);
286 if ((dy == 0) || ((double)dx/dy > (double)screen.drawing_area->allocation.width/
287 screen.drawing_area->allocation.height)) {
288 dy = dx * (double)screen.drawing_area->allocation.height/
289 screen.drawing_area->allocation.width;
291 else {
292 dx = dy * (double)screen.drawing_area->allocation.width/
293 screen.drawing_area->allocation.height;
296 gdk_draw_rectangle(screen.drawing_area->window, gc, FALSE, (x1+x2-dx)/2,
297 (y1+y2-dy)/2, dx, dy);
299 gdk_gc_unref(gc);
302 /* ------------------------------------------------------ */
303 /* Transforms board coordinates to screen ones */
304 static void
305 render_board2screen(gdouble *X, gdouble *Y, gdouble x, gdouble y) {
306 *X = (x - screenRenderInfo.lowerLeftX) * screenRenderInfo.scaleFactorX;
307 *Y = screenRenderInfo.displayHeight - (y - screenRenderInfo.lowerLeftY)
308 * screenRenderInfo.scaleFactorY;
311 /* Trims the coordinates to avoid overflows in gdk_draw_line */
312 static void
313 render_trim_point(gdouble *start_x, gdouble *start_y, gdouble last_x, gdouble last_y)
315 const gdouble max_coord = (1<<15) - 2;/* a value that causes no overflow
316 and lies out of screen */
317 gdouble dx, dy;
319 if (fabs (*start_x) < max_coord && fabs (*start_y) < max_coord)
320 return;
322 dx = last_x - *start_x;
323 dy = last_y - *start_y;
325 if (*start_x < -max_coord) {
326 *start_x = -max_coord;
327 if (last_x > -max_coord && fabs (dx) > 0.1)
328 *start_y = last_y - (last_x + max_coord) / dx * dy;
330 if (*start_x > max_coord) {
331 *start_x = max_coord;
332 if (last_x < max_coord && fabs (dx) > 0.1)
333 *start_y = last_y - (last_x - max_coord) / dx * dy;
336 dx = last_x - *start_x;
337 dy = last_y - *start_y;
339 if (*start_y < -max_coord) {
340 *start_y = -max_coord;
341 if (last_y > -max_coord && fabs (dy) > 0.1)
342 *start_x = last_x - (last_y + max_coord) / dy * dx;
344 if (*start_y > max_coord) {
345 *start_y = max_coord;
346 if (last_y < max_coord && fabs (dy) > 0.1)
347 *start_x = last_x - (last_y - max_coord) / dy * dx;
351 /* ------------------------------------------------------ */
352 /** Draws/erases measure line
354 void
355 render_toggle_measure_line(void)
358 GdkGC *gc;
359 GdkGCValues values;
360 GdkGCValuesMask values_mask;
361 gdouble start_x, start_y, last_x, last_y;
362 memset(&values, 0, sizeof(values));
363 values.function = GDK_XOR;
364 if (!screen.zoom_outline_color.pixel)
365 gdk_colormap_alloc_color(gdk_colormap_get_system(), &screen.zoom_outline_color, FALSE, TRUE);
366 values.foreground = screen.zoom_outline_color;
367 values_mask = GDK_GC_FUNCTION | GDK_GC_FOREGROUND;
368 gc = gdk_gc_new_with_values(screen.drawing_area->window, &values,
369 values_mask);
370 render_board2screen(&start_x, &start_y,
371 screen.measure_start_x, screen.measure_start_y);
372 render_board2screen(&last_x, &last_y,
373 screen.measure_last_x, screen.measure_last_y);
374 render_trim_point(&start_x, &start_y, last_x, last_y);
375 render_trim_point(&last_x, &last_y, start_x, start_y);
376 gdk_draw_line(screen.drawing_area->window, gc, start_x,
377 start_y, last_x, last_y);
378 gdk_gc_unref(gc);
379 } /* toggle_measure_line */
381 /* ------------------------------------------------------ */
382 /** Displays a measured distance graphically on screen and in statusbar. */
383 void
384 render_draw_measure_distance(void)
386 gdouble x1, y1, x2, y2;
387 gdouble dx, dy;
389 x1 = MIN(screen.measure_start_x, screen.measure_last_x);
390 y1 = MIN(screen.measure_start_y, screen.measure_last_y);
391 x2 = MAX(screen.measure_start_x, screen.measure_last_x);
392 y2 = MAX(screen.measure_start_y, screen.measure_last_y);
393 dx = (x2 - x1);
394 dy = (y2 - y1);
396 screen.win.lastMeasuredX = dx;
397 screen.win.lastMeasuredY = dy;
398 callbacks_update_statusbar_measured_distance (dx, dy);
399 render_toggle_measure_line();
400 } /* draw_measure_distance */
402 /* ------------------------------------------------------ */
403 void render_selection_layer (void){
404 cairo_t *cr;
406 if (screen.selectionRenderData)
407 cairo_surface_destroy ((cairo_surface_t *) screen.selectionRenderData);
408 screen.selectionRenderData =
409 (gpointer) cairo_surface_create_similar ((cairo_surface_t *)screen.windowSurface,
410 CAIRO_CONTENT_COLOR_ALPHA, screenRenderInfo.displayWidth,
411 screenRenderInfo.displayHeight);
412 if (screen.selectionInfo.type != GERBV_SELECTION_EMPTY) {
413 cr= cairo_create(screen.selectionRenderData);
414 gerbv_render_cairo_set_scale_and_translation(cr, &screenRenderInfo);
415 cairo_set_source_rgba (cr, 1.0, 1.0, 1.0, 0.85);
416 /* for now, assume everything in the selection buffer is from one image */
417 gerbv_image_t *matchImage;
418 int j;
419 if (screen.selectionInfo.selectedNodeArray->len > 0) {
420 gerbv_selection_item_t sItem = g_array_index (screen.selectionInfo.selectedNodeArray,
421 gerbv_selection_item_t, 0);
422 matchImage = (gerbv_image_t *) sItem.image;
423 dprintf(" .... calling render_image_to_cairo_target on selection layer...\n");
424 for(j = mainProject->last_loaded; j >= 0; j--) {
425 if ((mainProject->file[j]) && (mainProject->file[j]->image == matchImage)) {
426 draw_image_to_cairo_target (cr, mainProject->file[j]->image,
427 1.0/MAX(screenRenderInfo.scaleFactorX,
428 screenRenderInfo.scaleFactorY),
429 DRAW_SELECTIONS, &screen.selectionInfo, &screenRenderInfo,
430 TRUE, mainProject->file[j]->transform);
434 cairo_destroy (cr);
438 /* ------------------------------------------------------ */
439 void render_refresh_rendered_image_on_screen (void) {
440 GdkCursor *cursor;
442 dprintf("----> Entering redraw_pixmap...\n");
443 cursor = gdk_cursor_new(GDK_WATCH);
444 gdk_window_set_cursor(GDK_WINDOW(screen.drawing_area->window), cursor);
445 gdk_cursor_destroy(cursor);
447 if (screenRenderInfo.renderType < 2){
448 if (screen.pixmap)
449 gdk_pixmap_unref(screen.pixmap);
450 screen.pixmap = gdk_pixmap_new(screen.drawing_area->window, screenRenderInfo.displayWidth,
451 screenRenderInfo.displayHeight, -1);
452 gerbv_render_to_pixmap_using_gdk (mainProject, screen.pixmap, &screenRenderInfo, &screen.selectionInfo,
453 &screen.selection_color);
454 dprintf("<---- leaving redraw_pixmap.\n");
456 else{
457 int i;
458 dprintf(" .... Now try rendering the drawing using cairo .... \n");
460 * This now allows drawing several layers on top of each other.
461 * Higher layer numbers have higher priority in the Z-order.
463 for(i = mainProject->last_loaded; i >= 0; i--) {
464 if (mainProject->file[i]) {
465 cairo_t *cr;
466 if (mainProject->file[i]->privateRenderData)
467 cairo_surface_destroy ((cairo_surface_t *) mainProject->file[i]->privateRenderData);
468 mainProject->file[i]->privateRenderData =
469 (gpointer) cairo_surface_create_similar ((cairo_surface_t *)screen.windowSurface,
470 CAIRO_CONTENT_COLOR_ALPHA, screenRenderInfo.displayWidth,
471 screenRenderInfo.displayHeight);
472 cr= cairo_create(mainProject->file[i]->privateRenderData );
473 gerbv_render_layer_to_cairo_target (cr, mainProject->file[i], &screenRenderInfo);
474 dprintf(" .... calling render_image_to_cairo_target on layer %d...\n", i);
475 cairo_destroy (cr);
478 /* render the selection layer */
479 render_selection_layer();
481 render_recreate_composite_surface ();
483 /* remove watch cursor and switch back to normal cursor */
484 callbacks_switch_to_correct_cursor ();
485 callbacks_force_expose_event_for_screen();
488 /* ------------------------------------------------------ */
489 void
490 render_clear_selection_buffer (void){
491 if (screen.selectionInfo.type == GERBV_SELECTION_EMPTY)
492 return;
494 g_array_remove_range (screen.selectionInfo.selectedNodeArray, 0,
495 screen.selectionInfo.selectedNodeArray->len);
496 screen.selectionInfo.type = GERBV_SELECTION_EMPTY;
497 callbacks_update_selected_object_message (FALSE);
500 void
501 render_remove_selected_objects_belonging_to_layer (gint index) {
502 int i;
504 for (i=screen.selectionInfo.selectedNodeArray->len-1; i>=0; i--) {
505 gerbv_selection_item_t sItem = g_array_index (screen.selectionInfo.selectedNodeArray,
506 gerbv_selection_item_t, i);
508 gerbv_image_t *matchImage = (gerbv_image_t *) sItem.image;
509 if (mainProject->file[index]->image == matchImage) {
510 g_array_remove_index (screen.selectionInfo.selectedNodeArray, index);
513 callbacks_update_selected_object_message (FALSE);
516 /* ------------------------------------------------------ */
517 gint
518 render_create_cairo_buffer_surface () {
519 if (screen.bufferSurface) {
520 cairo_surface_destroy (screen.bufferSurface);
521 screen.bufferSurface = NULL;
523 if (!screen.windowSurface)
524 return 0;
526 screen.bufferSurface= cairo_surface_create_similar ((cairo_surface_t *)screen.windowSurface,
527 CAIRO_CONTENT_COLOR, screenRenderInfo.displayWidth,
528 screenRenderInfo.displayHeight);
529 return 1;
532 /* ------------------------------------------------------ */
533 void
534 render_find_selected_objects_and_refresh_display (gint activeFileIndex, gboolean eraseOldSelection){
535 /* clear the old selection array if desired */
536 if ((eraseOldSelection)&&(screen.selectionInfo.selectedNodeArray->len))
537 g_array_remove_range (screen.selectionInfo.selectedNodeArray, 0,
538 screen.selectionInfo.selectedNodeArray->len);
540 /* make sure we have a bufferSurface...if we start up in FAST mode, we may not
541 have one yet, but we need it for selections */
542 if (!render_create_cairo_buffer_surface())
543 return;
545 /* call draw_image... passing the FILL_SELECTION mode to just search for
546 nets which match the selection, and fill the selection buffer with them */
547 cairo_t *cr= cairo_create(screen.bufferSurface);
548 gerbv_render_cairo_set_scale_and_translation(cr,&screenRenderInfo);
549 draw_image_to_cairo_target (cr, mainProject->file[activeFileIndex]->image,
550 1.0/MAX(screenRenderInfo.scaleFactorX, screenRenderInfo.scaleFactorY),
551 FIND_SELECTIONS, &screen.selectionInfo, &screenRenderInfo, TRUE,
552 mainProject->file[activeFileIndex]->transform);
553 cairo_destroy (cr);
554 /* if the selection array is empty, switch the "mode" to empty to make it
555 easier to check if it is holding anything */
556 if (!screen.selectionInfo.selectedNodeArray->len)
557 screen.selectionInfo.type = GERBV_SELECTION_EMPTY;
558 /* re-render the selection buffer layer */
559 if (screenRenderInfo.renderType < 2){
560 render_refresh_rendered_image_on_screen ();
562 else {
563 render_selection_layer();
564 render_recreate_composite_surface ();
565 callbacks_force_expose_event_for_screen();
569 /* ------------------------------------------------------ */
570 void
571 render_fill_selection_buffer_from_mouse_click (gint mouseX, gint mouseY, gint activeFileIndex,
572 gboolean eraseOldSelection) {
573 screen.selectionInfo.lowerLeftX = mouseX;
574 screen.selectionInfo.lowerLeftY = mouseY;
575 /* no need to populate the upperright coordinates for a point_click */
576 screen.selectionInfo.type = GERBV_SELECTION_POINT_CLICK;
577 render_find_selected_objects_and_refresh_display (activeFileIndex, eraseOldSelection);
580 /* ------------------------------------------------------ */
581 void
582 render_fill_selection_buffer_from_mouse_drag (gint corner1X, gint corner1Y,
583 gint corner2X, gint corner2Y, gint activeFileIndex, gboolean eraseOldSelection) {
584 /* figure out the lower left corner of the box */
585 screen.selectionInfo.lowerLeftX = MIN(corner1X, corner2X);
586 screen.selectionInfo.lowerLeftY = MIN(corner1Y, corner2Y);
587 /* figure out the upper right corner of the box */
588 screen.selectionInfo.upperRightX = MAX(corner1X, corner2X);
589 screen.selectionInfo.upperRightY = MAX(corner1Y, corner2Y);
591 screen.selectionInfo.type = GERBV_SELECTION_DRAG_BOX;
592 render_find_selected_objects_and_refresh_display (activeFileIndex, eraseOldSelection);
595 /* ------------------------------------------------------ */
596 void render_recreate_composite_surface () {
597 gint i;
599 if (!render_create_cairo_buffer_surface())
600 return;
602 cairo_t *cr= cairo_create(screen.bufferSurface);
603 /* fill the background with the appropriate color */
604 cairo_set_source_rgba (cr, (double) mainProject->background.red/G_MAXUINT16,
605 (double) mainProject->background.green/G_MAXUINT16,
606 (double) mainProject->background.blue/G_MAXUINT16, 1);
607 cairo_paint (cr);
609 for(i = mainProject->last_loaded; i >= 0; i--) {
610 if (mainProject->file[i] && mainProject->file[i]->isVisible) {
611 cairo_set_source_surface (cr, (cairo_surface_t *) mainProject->file[i]->privateRenderData,
612 0, 0);
613 /* ignore alpha if we are in high-speed render mode */
614 if (((double) mainProject->file[i]->alpha < 65535)&&(screenRenderInfo.renderType != 1)) {
615 cairo_paint_with_alpha(cr,(double) mainProject->file[i]->alpha/G_MAXUINT16);
617 else {
618 cairo_paint (cr);
622 /* render the selection layer at the end */
623 if (screen.selectionInfo.type != GERBV_SELECTION_EMPTY) {
624 cairo_set_source_surface (cr, (cairo_surface_t *) screen.selectionRenderData,
625 0, 0);
626 cairo_paint_with_alpha (cr,1.0);
628 cairo_destroy (cr);
631 /* ------------------------------------------------------ */
632 void render_project_to_cairo_target (cairo_t *cr) {
633 /* fill the background with the appropriate color */
634 cairo_set_source_rgba (cr, (double) mainProject->background.red/G_MAXUINT16,
635 (double) mainProject->background.green/G_MAXUINT16,
636 (double) mainProject->background.blue/G_MAXUINT16, 1);
637 cairo_paint (cr);
639 cairo_set_source_surface (cr, (cairo_surface_t *) screen.bufferSurface, 0 , 0);
641 cairo_paint (cr);
644 void
645 render_free_screen_resources (void) {
646 if (screen.selectionRenderData)
647 cairo_surface_destroy ((cairo_surface_t *)
648 screen.selectionRenderData);
649 if (screen.bufferSurface)
650 cairo_surface_destroy ((cairo_surface_t *)
651 screen.bufferSurface);
652 if (screen.windowSurface)
653 cairo_surface_destroy ((cairo_surface_t *)
654 screen.windowSurface);
655 if (screen.pixmap)
656 gdk_pixmap_unref(screen.pixmap);
660 /* ------------------------------------------------------------------ */
661 /*! This fills out the project's Gerber statistics table.
662 * It is called from within callbacks.c when the user
663 * asks for a Gerber report. */
664 gerbv_stats_t *
665 generate_gerber_analysis(void)
667 int i;
668 gerbv_stats_t *stats;
669 gerbv_stats_t *instats;
671 /* Create new stats structure to hold report for whole project
672 * (i.e. all layers together) */
673 stats = gerbv_stats_new();
675 /* Loop through open layers and compile statistics by accumulating reports from each layer */
676 for (i = 0; i <= mainProject->last_loaded; i++) {
677 if (mainProject->file[i] && mainProject->file[i]->isVisible &&
678 (mainProject->file[i]->image->layertype == GERBV_LAYERTYPE_RS274X) ) {
679 instats = mainProject->file[i]->image->gerbv_stats;
680 gerbv_stats_add_layer(stats, instats, i+1);
683 return stats;
687 /* ------------------------------------------------------------------ */
688 /*! This fills out the project's Drill statistics table.
689 * It is called from within callbacks.c when the user
690 * asks for a Drill report. */
691 gerbv_drill_stats_t *
692 generate_drill_analysis(void)
694 int i;
695 gerbv_drill_stats_t *stats;
696 gerbv_drill_stats_t *instats;
698 stats = gerbv_drill_stats_new();
700 /* Loop through open layers and compile statistics by accumulating reports from each layer */
701 for(i = mainProject->last_loaded; i >= 0; i--) {
702 if (mainProject->file[i] &&
703 mainProject->file[i]->isVisible &&
704 (mainProject->file[i]->image->layertype == GERBV_LAYERTYPE_DRILL) ) {
705 instats = mainProject->file[i]->image->drill_stats;
706 /* add this batch of stats. Send the layer
707 * index for error reporting */
708 gerbv_drill_stats_add_layer(stats, instats, i+1);
711 return stats;