Removed use of fgets() to read files and gerb_file approved file operations.
[geda-gerbv/spe.git] / src / render.c
blob0d02c86d568dc858d69e03dc039f274dcbfd7976
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 #elif QUARTZ
62 #include <cairo-quartz.h>
63 #else
64 #include <cairo-xlib.h>
65 #endif
66 #include <cairo.h>
67 #include "draw-gdk.h"
68 #include "draw.h"
70 #define dprintf if(DEBUG) printf
72 /**Global variable to keep track of what's happening on the screen.
73 Declared extern in gerbv_screen.h
75 extern gerbv_screen_t screen;
77 extern gerbv_render_info_t screenRenderInfo;
80 static void
81 render_layer_to_cairo_target_without_transforming(cairo_t *cr, gerbv_fileinfo_t *fileInfo, gerbv_render_info_t *renderInfo );
84 gboolean
85 render_check_scale_factor_limits (void) {
86 if ((screenRenderInfo.scaleFactorX > 20000)||(screenRenderInfo.scaleFactorY > 20000)) {
87 screenRenderInfo.scaleFactorX = 20000;
88 screenRenderInfo.scaleFactorY = 20000;
89 return FALSE;
91 return TRUE;
94 /* ------------------------------------------------------ */
95 void
96 render_zoom_display (gint zoomType, gdouble scaleFactor, gdouble mouseX, gdouble mouseY) {
97 double us_midx, us_midy; /* unscaled translation for screen center */
98 int half_w, half_h; /* cache for half window dimensions */
99 gdouble mouseCoordinateX = 0.0;
100 gdouble mouseCoordinateY = 0.0;
101 double oldWidth, oldHeight;
103 half_w = screenRenderInfo.displayWidth / 2;
104 half_h = screenRenderInfo.displayHeight / 2;
106 oldWidth = screenRenderInfo.displayWidth / screenRenderInfo.scaleFactorX;
107 oldHeight = screenRenderInfo.displayHeight / screenRenderInfo.scaleFactorY;
108 if (zoomType == ZOOM_IN_CMOUSE || zoomType == ZOOM_OUT_CMOUSE) {
109 /* calculate what user coordinate the mouse is pointing at */
110 mouseCoordinateX = mouseX / screenRenderInfo.scaleFactorX + screenRenderInfo.lowerLeftX;
111 mouseCoordinateY = (screenRenderInfo.displayHeight - mouseY) /
112 screenRenderInfo.scaleFactorY + screenRenderInfo.lowerLeftY;
115 us_midx = screenRenderInfo.lowerLeftX + (screenRenderInfo.displayWidth / 2.0 )/
116 screenRenderInfo.scaleFactorX;
117 us_midy = screenRenderInfo.lowerLeftY + (screenRenderInfo.displayHeight / 2.0 )/
118 screenRenderInfo.scaleFactorY;
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;
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\n", zoomType);
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;
164 render_refresh_rendered_image_on_screen();
165 return;
169 /* --------------------------------------------------------- */
170 /** Will determine the outline of the zoomed regions.
171 * In case region to be zoomed is too small (which correspondes
172 * e.g. to a double click) it is interpreted as a right-click
173 * and will be used to identify a part from the CURRENT selection,
174 * which is drawn on screen*/
175 void
176 render_calculate_zoom_from_outline(GtkWidget *widget, GdkEventButton *event)
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 */
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;
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;
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;
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);
212 render_refresh_rendered_image_on_screen();
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;
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);
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;
238 gdk_draw_rectangle(screen.drawing_area->window, gc, FALSE, x1, y1, dx, dy);
239 gdk_gc_unref(gc);
242 /* --------------------------------------------------------- */
243 void
244 render_draw_zoom_outline(gboolean centered)
246 GdkGC *gc;
247 GdkGCValues values;
248 GdkGCValuesMask values_mask;
249 gint x1, y1, x2, y2, dx, dy;
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);
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;
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;
276 gdk_draw_rectangle(screen.drawing_area->window, gc, FALSE, x1, y1, dx, dy);
277 gdk_gc_unref(gc);
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);
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;
293 else {
294 dx = dy * (double)screen.drawing_area->allocation.width/
295 screen.drawing_area->allocation.height;
298 gdk_draw_rectangle(screen.drawing_area->window, gc, FALSE, (x1+x2-dx)/2,
299 (y1+y2-dy)/2, dx, dy);
301 gdk_gc_unref(gc);
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;
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)
317 const gdouble max_coord = (1<<15) - 2;/* a value that causes no overflow
318 and lies out of screen */
319 gdouble dx, dy;
321 if (fabs (*start_x) < max_coord && fabs (*start_y) < max_coord)
322 return;
324 dx = last_x - *start_x;
325 dy = last_y - *start_y;
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;
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;
338 dx = last_x - *start_x;
339 dy = last_y - *start_y;
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;
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;
353 /* ------------------------------------------------------ */
354 /** Draws/erases measure line
356 void
357 render_toggle_measure_line(void)
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 */
383 /* ------------------------------------------------------ */
384 /** Displays a measured distance graphically on screen and in statusbar. */
385 void
386 render_draw_measure_distance(void)
388 gdouble x1, y1, x2, y2;
389 gdouble dx, dy;
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);
398 screen.win.lastMeasuredX = dx;
399 screen.win.lastMeasuredY = dy;
400 callbacks_update_statusbar_measured_distance (dx, dy);
401 render_toggle_measure_line();
402 } /* draw_measure_distance */
404 /* ------------------------------------------------------ */
405 void render_selection_layer (void){
406 cairo_t *cr;
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);
436 cairo_destroy (cr);
440 /* ------------------------------------------------------ */
441 void render_refresh_rendered_image_on_screen (void) {
442 GdkCursor *cursor;
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);
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");
458 else{
459 int i;
460 dprintf(" .... Now try rendering the drawing using cairo .... \n");
462 * This now allows drawing several layers on top of each other.
463 * Higher layer numbers have higher priority in the Z-order.
465 for(i = mainProject->last_loaded; i >= 0; i--) {
466 if (mainProject->file[i]) {
467 cairo_t *cr;
468 if (mainProject->file[i]->privateRenderData)
469 cairo_surface_destroy ((cairo_surface_t *) mainProject->file[i]->privateRenderData);
470 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);
480 /* render the selection layer */
481 render_selection_layer();
483 render_recreate_composite_surface ();
485 /* remove watch cursor and switch back to normal cursor */
486 callbacks_switch_to_correct_cursor ();
487 callbacks_force_expose_event_for_screen();
490 /* ------------------------------------------------------ */
491 void
492 render_clear_selection_buffer (void){
493 if (screen.selectionInfo.type == GERBV_SELECTION_EMPTY)
494 return;
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);
502 void
503 render_remove_selected_objects_belonging_to_layer (gint index) {
504 int i;
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);
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);
515 callbacks_update_selected_object_message (FALSE);
518 /* ------------------------------------------------------ */
519 gint
520 render_create_cairo_buffer_surface () {
521 if (screen.bufferSurface) {
522 cairo_surface_destroy (screen.bufferSurface);
523 screen.bufferSurface = NULL;
525 if (!screen.windowSurface)
526 return 0;
528 screen.bufferSurface= cairo_surface_create_similar ((cairo_surface_t *)screen.windowSurface,
529 CAIRO_CONTENT_COLOR, screenRenderInfo.displayWidth,
530 screenRenderInfo.displayHeight);
531 return 1;
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);
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;
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 ();
564 else {
565 render_selection_layer();
566 render_recreate_composite_surface ();
567 callbacks_force_expose_event_for_screen();
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);
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);
593 screen.selectionInfo.type = GERBV_SELECTION_DRAG_BOX;
594 render_find_selected_objects_and_refresh_display (activeFileIndex, eraseOldSelection);
597 /* ------------------------------------------------------ */
598 void render_recreate_composite_surface () {
599 gint i;
601 if (!render_create_cairo_buffer_surface())
602 return;
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);
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);
619 else {
620 cairo_paint (cr);
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);
630 cairo_destroy (cr);
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);
641 cairo_set_source_surface (cr, (cairo_surface_t *) screen.bufferSurface, 0 , 0);
643 cairo_paint (cr);
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);
662 /* ------------------------------------------------------------------ */
663 /*! This fills out the project's Gerber statistics table.
664 * It is called from within callbacks.c when the user
665 * asks for a Gerber report. */
666 gerbv_stats_t *
667 generate_gerber_analysis(void)
669 int i;
670 gerbv_stats_t *stats;
671 gerbv_stats_t *instats;
673 /* Create new stats structure to hold report for whole project
674 * (i.e. all layers together) */
675 stats = gerbv_stats_new();
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 &&
680 (mainProject->file[i]->image->layertype == GERBV_LAYERTYPE_RS274X) ) {
681 instats = mainProject->file[i]->image->gerbv_stats;
682 gerbv_stats_add_layer(stats, instats, i+1);
685 return stats;
689 /* ------------------------------------------------------------------ */
690 /*! This fills out the project's Drill statistics table.
691 * It is called from within callbacks.c when the user
692 * asks for a Drill report. */
693 gerbv_drill_stats_t *
694 generate_drill_analysis(void)
696 int i;
697 gerbv_drill_stats_t *stats;
698 gerbv_drill_stats_t *instats;
700 stats = gerbv_drill_stats_new();
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 &&
706 (mainProject->file[i]->image->layertype == GERBV_LAYERTYPE_DRILL) ) {
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);
713 return stats;