don't update min/max bounding box when drawing with CLEAR polarity
[geda-gerbv.git] / src / render.c
bloba879da3c58d808eba7dfa698d8a8a4397402f9bc
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;
104 half_w = screenRenderInfo.displayWidth / 2;
105 half_h = screenRenderInfo.displayHeight / 2;
108 oldWidth = screenRenderInfo.displayWidth / screenRenderInfo.scaleFactorX;
109 oldHeight = screenRenderInfo.displayHeight / screenRenderInfo.scaleFactorY;
110 if (zoomType == ZOOM_IN_CMOUSE || zoomType == ZOOM_OUT_CMOUSE) {
111 /* calculate what user coordinate the mouse is pointing at */
112 mouseCoordinateX = mouseX / screenRenderInfo.scaleFactorX + screenRenderInfo.lowerLeftX;
113 mouseCoordinateY = (screenRenderInfo.displayHeight - mouseY) /
114 screenRenderInfo.scaleFactorY + screenRenderInfo.lowerLeftY;
118 us_midx = screenRenderInfo.lowerLeftX + (screenRenderInfo.displayWidth / 2.0 )/
119 screenRenderInfo.scaleFactorX;
120 us_midy = screenRenderInfo.lowerLeftY + (screenRenderInfo.displayHeight / 2.0 )/
121 screenRenderInfo.scaleFactorY;
124 switch(zoomType) {
125 case ZOOM_IN : /* Zoom In */
126 case ZOOM_IN_CMOUSE : /* Zoom In Around Mouse Pointer */
127 screenRenderInfo.scaleFactorX += screenRenderInfo.scaleFactorX/3;
128 screenRenderInfo.scaleFactorY += screenRenderInfo.scaleFactorY/3;
129 (void) render_check_scale_factor_limits ();
130 screenRenderInfo.lowerLeftX += (oldWidth - (screenRenderInfo.displayWidth /
131 screenRenderInfo.scaleFactorX)) / 2.0;
132 screenRenderInfo.lowerLeftY += (oldHeight - (screenRenderInfo.displayHeight /
133 screenRenderInfo.scaleFactorY)) / 2.0;
134 break;
135 case ZOOM_OUT : /* Zoom Out */
136 case ZOOM_OUT_CMOUSE : /* Zoom Out Around Mouse Pointer */
137 if ((screenRenderInfo.scaleFactorX > 10)&&(screenRenderInfo.scaleFactorY > 10)) {
138 screenRenderInfo.scaleFactorX -= screenRenderInfo.scaleFactorX/3;
139 screenRenderInfo.scaleFactorY -= screenRenderInfo.scaleFactorY/3;
140 screenRenderInfo.lowerLeftX += (oldWidth - (screenRenderInfo.displayWidth /
141 screenRenderInfo.scaleFactorX)) / 2.0;
142 screenRenderInfo.lowerLeftY += (oldHeight - (screenRenderInfo.displayHeight /
143 screenRenderInfo.scaleFactorY)) / 2.0;
145 break;
146 case ZOOM_FIT : /* Zoom Fit */
147 gerbv_render_zoom_to_fit_display (mainProject, &screenRenderInfo);
148 break;
149 case ZOOM_SET : /*explicit scale set by user */
150 screenRenderInfo.scaleFactorX = scaleFactor;
151 screenRenderInfo.scaleFactorY = scaleFactor;
152 (void) render_check_scale_factor_limits ();
153 screenRenderInfo.lowerLeftX += (oldWidth - (screenRenderInfo.displayWidth /
154 screenRenderInfo.scaleFactorX)) / 2.0;
155 screenRenderInfo.lowerLeftY += (oldHeight - (screenRenderInfo.displayHeight /
156 screenRenderInfo.scaleFactorY)) / 2.0;
157 break;
158 default :
159 GERB_MESSAGE("Illegal zoom direction %d\n", zoomType);
162 if (zoomType == ZOOM_IN_CMOUSE || zoomType == ZOOM_OUT_CMOUSE) {
163 /* make sure the mouse is still pointing at the point calculated earlier */
164 screenRenderInfo.lowerLeftX = mouseCoordinateX - mouseX / screenRenderInfo.scaleFactorX;
165 screenRenderInfo.lowerLeftY = mouseCoordinateY - (screenRenderInfo.displayHeight - mouseY) /
166 screenRenderInfo.scaleFactorY;
168 render_refresh_rendered_image_on_screen();
169 return;
173 /* --------------------------------------------------------- */
174 /** Will determine the outline of the zoomed regions.
175 * In case region to be zoomed is too small (which correspondes
176 * e.g. to a double click) it is interpreted as a right-click
177 * and will be used to identify a part from the CURRENT selection,
178 * which is drawn on screen*/
179 void
180 render_calculate_zoom_from_outline(GtkWidget *widget, GdkEventButton *event)
182 int x1, y1, x2, y2, dx, dy; /* Zoom outline (UR and LL corners) */
183 double centerPointX, centerPointY;
184 int half_x, half_y; /* cache for half window dimensions */
186 x1 = MIN(screen.start_x, event->x);
187 y1 = MIN(screen.start_y, event->y);
188 x2 = MAX(screen.start_x, event->x);
189 y2 = MAX(screen.start_y, event->y);
190 dx = x2-x1;
191 dy = y2-y1;
193 if ((dx >= 4) && (dy >= 4)) {
194 if (screen.centered_outline_zoom) {
195 /* Centered outline mode */
196 x1 = screen.start_x - dx;
197 y1 = screen.start_y - dy;
198 dx *= 2;
199 dy *= 2;
201 half_x = (x1+x2)/2;
202 half_y = (y1+y2)/2;
203 centerPointX = half_x/screenRenderInfo.scaleFactorX + screenRenderInfo.lowerLeftX;
204 centerPointY = (screenRenderInfo.displayHeight - half_y)/screenRenderInfo.scaleFactorY +
205 screenRenderInfo.lowerLeftY;
207 screenRenderInfo.scaleFactorX *= MIN(((double)screenRenderInfo.displayWidth / dx),
208 ((double)screenRenderInfo.displayHeight / dy));
209 screenRenderInfo.scaleFactorY = screenRenderInfo.scaleFactorX;
210 (void) render_check_scale_factor_limits ();
211 screenRenderInfo.lowerLeftX = centerPointX - (screenRenderInfo.displayWidth /
212 2.0 / screenRenderInfo.scaleFactorX);
213 screenRenderInfo.lowerLeftY = centerPointY - (screenRenderInfo.displayHeight /
214 2.0 / screenRenderInfo.scaleFactorY);
216 render_refresh_rendered_image_on_screen();
219 /* ------------------------------------------------------ */
220 void
221 render_draw_selection_box_outline(void) {
222 GdkGC *gc;
223 GdkGCValues values;
224 GdkGCValuesMask values_mask;
225 gint x1, y1, x2, y2, dx, dy;
227 memset(&values, 0, sizeof(values));
228 values.function = GDK_XOR;
229 if (!screen.zoom_outline_color.pixel)
230 gdk_colormap_alloc_color(gdk_colormap_get_system(), &screen.zoom_outline_color, FALSE, TRUE);
231 values.foreground = screen.zoom_outline_color;
232 values_mask = GDK_GC_FUNCTION | GDK_GC_FOREGROUND;
233 gc = gdk_gc_new_with_values(screen.drawing_area->window, &values, values_mask);
235 x1 = MIN(screen.start_x, screen.last_x);
236 y1 = MIN(screen.start_y, screen.last_y);
237 x2 = MAX(screen.start_x, screen.last_x);
238 y2 = MAX(screen.start_y, screen.last_y);
239 dx = x2-x1;
240 dy = y2-y1;
242 gdk_draw_rectangle(screen.drawing_area->window, gc, FALSE, x1, y1, dx, dy);
243 gdk_gc_unref(gc);
246 /* --------------------------------------------------------- */
247 void
248 render_draw_zoom_outline(gboolean centered)
250 GdkGC *gc;
251 GdkGCValues values;
252 GdkGCValuesMask values_mask;
253 gint x1, y1, x2, y2, dx, dy;
255 memset(&values, 0, sizeof(values));
256 values.function = GDK_XOR;
257 if (!screen.zoom_outline_color.pixel)
258 gdk_colormap_alloc_color(gdk_colormap_get_system(), &screen.zoom_outline_color, FALSE, TRUE);
259 values.foreground = screen.zoom_outline_color;
260 values_mask = GDK_GC_FUNCTION | GDK_GC_FOREGROUND;
261 gc = gdk_gc_new_with_values(screen.drawing_area->window, &values, values_mask);
263 x1 = MIN(screen.start_x, screen.last_x);
264 y1 = MIN(screen.start_y, screen.last_y);
265 x2 = MAX(screen.start_x, screen.last_x);
266 y2 = MAX(screen.start_y, screen.last_y);
267 dx = x2-x1;
268 dy = y2-y1;
270 if (centered) {
271 /* Centered outline mode */
272 x1 = screen.start_x - dx;
273 y1 = screen.start_y - dy;
274 dx *= 2;
275 dy *= 2;
276 x2 = x1+dx;
277 y2 = y1+dy;
280 gdk_draw_rectangle(screen.drawing_area->window, gc, FALSE, x1, y1, dx, dy);
281 gdk_gc_unref(gc);
283 /* Draw actual zoom area in dashed lines */
284 memset(&values, 0, sizeof(values));
285 values.function = GDK_XOR;
286 values.foreground = screen.zoom_outline_color;
287 values.line_style = GDK_LINE_ON_OFF_DASH;
288 values_mask = GDK_GC_FUNCTION | GDK_GC_FOREGROUND | GDK_GC_LINE_STYLE;
289 gc = gdk_gc_new_with_values(screen.drawing_area->window, &values,
290 values_mask);
292 if ((dy == 0) || ((double)dx/dy > (double)screen.drawing_area->allocation.width/
293 screen.drawing_area->allocation.height)) {
294 dy = dx * (double)screen.drawing_area->allocation.height/
295 screen.drawing_area->allocation.width;
297 else {
298 dx = dy * (double)screen.drawing_area->allocation.width/
299 screen.drawing_area->allocation.height;
302 gdk_draw_rectangle(screen.drawing_area->window, gc, FALSE, (x1+x2-dx)/2,
303 (y1+y2-dy)/2, dx, dy);
305 gdk_gc_unref(gc);
308 /* ------------------------------------------------------ */
309 /* Transforms board coordinates to screen ones */
310 static void
311 render_board2screen(gdouble *X, gdouble *Y, gdouble x, gdouble y) {
312 *X = (x - screenRenderInfo.lowerLeftX) * screenRenderInfo.scaleFactorX;
313 *Y = screenRenderInfo.displayHeight - (y - screenRenderInfo.lowerLeftY)
314 * screenRenderInfo.scaleFactorY;
317 /* Trims the coordinates to avoid overflows in gdk_draw_line */
318 static void
319 render_trim_point(gdouble *start_x, gdouble *start_y, gdouble last_x, gdouble last_y)
321 const gdouble max_coord = (1<<15) - 2;/* a value that causes no overflow
322 and lies out of screen */
323 gdouble dx, dy;
325 if (fabs (*start_x) < max_coord && fabs (*start_y) < max_coord)
326 return;
328 dx = last_x - *start_x;
329 dy = last_y - *start_y;
331 if (*start_x < -max_coord) {
332 *start_x = -max_coord;
333 if (last_x > -max_coord && fabs (dx) > 0.1)
334 *start_y = last_y - (last_x + max_coord) / dx * dy;
336 if (*start_x > max_coord) {
337 *start_x = max_coord;
338 if (last_x < max_coord && fabs (dx) > 0.1)
339 *start_y = last_y - (last_x - max_coord) / dx * dy;
342 dx = last_x - *start_x;
343 dy = last_y - *start_y;
345 if (*start_y < -max_coord) {
346 *start_y = -max_coord;
347 if (last_y > -max_coord && fabs (dy) > 0.1)
348 *start_x = last_x - (last_y + max_coord) / dy * dx;
350 if (*start_y > max_coord) {
351 *start_y = max_coord;
352 if (last_y < max_coord && fabs (dy) > 0.1)
353 *start_x = last_x - (last_y - max_coord) / dy * dx;
357 /* ------------------------------------------------------ */
358 /** Draws/erases measure line
360 void
361 render_toggle_measure_line(void)
364 GdkGC *gc;
365 GdkGCValues values;
366 GdkGCValuesMask values_mask;
367 gdouble start_x, start_y, last_x, last_y;
368 memset(&values, 0, sizeof(values));
369 values.function = GDK_XOR;
370 if (!screen.zoom_outline_color.pixel)
371 gdk_colormap_alloc_color(gdk_colormap_get_system(), &screen.zoom_outline_color, FALSE, TRUE);
372 values.foreground = screen.zoom_outline_color;
373 values_mask = GDK_GC_FUNCTION | GDK_GC_FOREGROUND;
374 gc = gdk_gc_new_with_values(screen.drawing_area->window, &values,
375 values_mask);
376 render_board2screen(&start_x, &start_y,
377 screen.measure_start_x, screen.measure_start_y);
378 render_board2screen(&last_x, &last_y,
379 screen.measure_last_x, screen.measure_last_y);
380 render_trim_point(&start_x, &start_y, last_x, last_y);
381 render_trim_point(&last_x, &last_y, start_x, start_y);
382 gdk_draw_line(screen.drawing_area->window, gc, start_x,
383 start_y, last_x, last_y);
384 gdk_gc_unref(gc);
385 } /* toggle_measure_line */
387 /* ------------------------------------------------------ */
388 /** Displays a measured distance graphically on screen and in statusbar. */
389 void
390 render_draw_measure_distance(void)
392 gdouble x1, y1, x2, y2;
393 gdouble dx, dy;
395 x1 = MIN(screen.measure_start_x, screen.measure_last_x);
396 y1 = MIN(screen.measure_start_y, screen.measure_last_y);
397 x2 = MAX(screen.measure_start_x, screen.measure_last_x);
398 y2 = MAX(screen.measure_start_y, screen.measure_last_y);
399 dx = (x2 - x1);
400 dy = (y2 - y1);
402 screen.win.lastMeasuredX = dx;
403 screen.win.lastMeasuredY = dy;
404 callbacks_update_statusbar_measured_distance (dx, dy);
405 render_toggle_measure_line();
406 } /* draw_measure_distance */
408 /* ------------------------------------------------------ */
409 void render_selection_layer (void){
410 cairo_t *cr;
412 if (screen.selectionRenderData)
413 cairo_surface_destroy ((cairo_surface_t *) screen.selectionRenderData);
414 screen.selectionRenderData =
415 (gpointer) cairo_surface_create_similar ((cairo_surface_t *)screen.windowSurface,
416 CAIRO_CONTENT_COLOR_ALPHA, screenRenderInfo.displayWidth,
417 screenRenderInfo.displayHeight);
418 if (screen.selectionInfo.type != GERBV_SELECTION_EMPTY) {
419 cr= cairo_create(screen.selectionRenderData);
420 gerbv_render_cairo_set_scale_and_translation(cr, &screenRenderInfo);
421 cairo_set_source_rgba (cr, 1.0, 1.0, 1.0, 0.85);
422 /* for now, assume everything in the selection buffer is from one image */
423 gerbv_image_t *matchImage;
424 int j;
425 if (screen.selectionInfo.selectedNodeArray->len > 0) {
426 gerbv_selection_item_t sItem = g_array_index (screen.selectionInfo.selectedNodeArray,
427 gerbv_selection_item_t, 0);
428 matchImage = (gerbv_image_t *) sItem.image;
429 dprintf(" .... calling render_image_to_cairo_target on selection layer...\n");
430 for(j = mainProject->last_loaded; j >= 0; j--) {
431 if ((mainProject->file[j]) && (mainProject->file[j]->image == matchImage)) {
432 draw_image_to_cairo_target (cr, mainProject->file[j]->image,
433 1.0/MAX(screenRenderInfo.scaleFactorX,
434 screenRenderInfo.scaleFactorY),
435 DRAW_SELECTIONS, &screen.selectionInfo, &screenRenderInfo,
436 TRUE, mainProject->file[j]->transform, TRUE);
440 cairo_destroy (cr);
444 /* ------------------------------------------------------ */
445 void render_refresh_rendered_image_on_screen (void) {
446 GdkCursor *cursor;
448 dprintf("----> Entering redraw_pixmap...\n");
449 cursor = gdk_cursor_new(GDK_WATCH);
450 gdk_window_set_cursor(GDK_WINDOW(screen.drawing_area->window), cursor);
451 gdk_cursor_destroy(cursor);
453 if (screenRenderInfo.renderType <= GERBV_RENDER_TYPE_GDK_XOR){
454 if (screen.pixmap)
455 gdk_pixmap_unref(screen.pixmap);
456 screen.pixmap = gdk_pixmap_new(screen.drawing_area->window, screenRenderInfo.displayWidth,
457 screenRenderInfo.displayHeight, -1);
458 gerbv_render_to_pixmap_using_gdk (mainProject, screen.pixmap, &screenRenderInfo, &screen.selectionInfo,
459 &screen.selection_color);
460 dprintf("<---- leaving redraw_pixmap.\n");
462 else{
463 int i;
464 dprintf(" .... Now try rendering the drawing using cairo .... \n");
466 * This now allows drawing several layers on top of each other.
467 * Higher layer numbers have higher priority in the Z-order.
469 for(i = mainProject->last_loaded; i >= 0; i--) {
470 if (mainProject->file[i]) {
471 cairo_t *cr;
472 if (mainProject->file[i]->privateRenderData)
473 cairo_surface_destroy ((cairo_surface_t *) mainProject->file[i]->privateRenderData);
474 mainProject->file[i]->privateRenderData =
475 (gpointer) cairo_surface_create_similar ((cairo_surface_t *)screen.windowSurface,
476 CAIRO_CONTENT_COLOR_ALPHA, screenRenderInfo.displayWidth,
477 screenRenderInfo.displayHeight);
478 cr= cairo_create(mainProject->file[i]->privateRenderData );
479 gerbv_render_layer_to_cairo_target (cr, mainProject->file[i], &screenRenderInfo);
480 dprintf(" .... calling render_image_to_cairo_target on layer %d...\n", i);
481 cairo_destroy (cr);
484 /* render the selection layer */
485 render_selection_layer();
487 render_recreate_composite_surface ();
489 /* remove watch cursor and switch back to normal cursor */
490 callbacks_switch_to_correct_cursor ();
491 callbacks_force_expose_event_for_screen();
494 /* ------------------------------------------------------ */
495 void
496 render_clear_selection_buffer (void){
497 if (screen.selectionInfo.type == GERBV_SELECTION_EMPTY)
498 return;
500 g_array_remove_range (screen.selectionInfo.selectedNodeArray, 0,
501 screen.selectionInfo.selectedNodeArray->len);
502 screen.selectionInfo.type = GERBV_SELECTION_EMPTY;
503 callbacks_update_selected_object_message (FALSE);
506 void
507 render_remove_selected_objects_belonging_to_layer (gint index) {
508 int i;
510 for (i=screen.selectionInfo.selectedNodeArray->len-1; i>=0; i--) {
511 gerbv_selection_item_t sItem = g_array_index (screen.selectionInfo.selectedNodeArray,
512 gerbv_selection_item_t, i);
514 gerbv_image_t *matchImage = (gerbv_image_t *) sItem.image;
515 if (mainProject->file[index]->image == matchImage) {
516 g_array_remove_index (screen.selectionInfo.selectedNodeArray, index);
519 callbacks_update_selected_object_message (FALSE);
522 /* ------------------------------------------------------ */
523 gint
524 render_create_cairo_buffer_surface () {
525 if (screen.bufferSurface) {
526 cairo_surface_destroy (screen.bufferSurface);
527 screen.bufferSurface = NULL;
529 if (!screen.windowSurface)
530 return 0;
532 screen.bufferSurface= cairo_surface_create_similar ((cairo_surface_t *)screen.windowSurface,
533 CAIRO_CONTENT_COLOR, screenRenderInfo.displayWidth,
534 screenRenderInfo.displayHeight);
535 return 1;
538 /* ------------------------------------------------------ */
539 void
540 render_find_selected_objects_and_refresh_display (gint activeFileIndex, gboolean eraseOldSelection){
541 /* clear the old selection array if desired */
542 if ((eraseOldSelection)&&(screen.selectionInfo.selectedNodeArray->len))
543 g_array_remove_range (screen.selectionInfo.selectedNodeArray, 0,
544 screen.selectionInfo.selectedNodeArray->len);
546 /* make sure we have a bufferSurface...if we start up in FAST mode, we may not
547 have one yet, but we need it for selections */
548 if (!render_create_cairo_buffer_surface())
549 return;
551 /* call draw_image... passing the FILL_SELECTION mode to just search for
552 nets which match the selection, and fill the selection buffer with them */
553 cairo_t *cr= cairo_create(screen.bufferSurface);
554 gerbv_render_cairo_set_scale_and_translation(cr,&screenRenderInfo);
555 draw_image_to_cairo_target (cr, mainProject->file[activeFileIndex]->image,
556 1.0/MAX(screenRenderInfo.scaleFactorX, screenRenderInfo.scaleFactorY),
557 FIND_SELECTIONS, &screen.selectionInfo, &screenRenderInfo, TRUE,
558 mainProject->file[activeFileIndex]->transform, TRUE);
559 cairo_destroy (cr);
560 /* if the selection array is empty, switch the "mode" to empty to make it
561 easier to check if it is holding anything */
562 if (!screen.selectionInfo.selectedNodeArray->len)
563 screen.selectionInfo.type = GERBV_SELECTION_EMPTY;
564 /* re-render the selection buffer layer */
565 if (screenRenderInfo.renderType <= GERBV_RENDER_TYPE_GDK_XOR){
566 render_refresh_rendered_image_on_screen ();
568 else {
569 render_selection_layer();
570 render_recreate_composite_surface ();
571 callbacks_force_expose_event_for_screen();
575 /* ------------------------------------------------------ */
576 void
577 render_fill_selection_buffer_from_mouse_click (gint mouseX, gint mouseY, gint activeFileIndex,
578 gboolean eraseOldSelection) {
579 screen.selectionInfo.lowerLeftX = mouseX;
580 screen.selectionInfo.lowerLeftY = mouseY;
581 /* no need to populate the upperright coordinates for a point_click */
582 screen.selectionInfo.type = GERBV_SELECTION_POINT_CLICK;
583 render_find_selected_objects_and_refresh_display (activeFileIndex, eraseOldSelection);
586 /* ------------------------------------------------------ */
587 void
588 render_fill_selection_buffer_from_mouse_drag (gint corner1X, gint corner1Y,
589 gint corner2X, gint corner2Y, gint activeFileIndex, gboolean eraseOldSelection) {
590 /* figure out the lower left corner of the box */
591 screen.selectionInfo.lowerLeftX = MIN(corner1X, corner2X);
592 screen.selectionInfo.lowerLeftY = MIN(corner1Y, corner2Y);
593 /* figure out the upper right corner of the box */
594 screen.selectionInfo.upperRightX = MAX(corner1X, corner2X);
595 screen.selectionInfo.upperRightY = MAX(corner1Y, corner2Y);
597 screen.selectionInfo.type = GERBV_SELECTION_DRAG_BOX;
598 render_find_selected_objects_and_refresh_display (activeFileIndex, eraseOldSelection);
601 /* ------------------------------------------------------ */
602 void render_recreate_composite_surface () {
603 gint i;
605 if (!render_create_cairo_buffer_surface())
606 return;
608 cairo_t *cr= cairo_create(screen.bufferSurface);
609 /* fill the background with the appropriate color */
610 cairo_set_source_rgba (cr, (double) mainProject->background.red/G_MAXUINT16,
611 (double) mainProject->background.green/G_MAXUINT16,
612 (double) mainProject->background.blue/G_MAXUINT16, 1);
613 cairo_paint (cr);
615 for(i = mainProject->last_loaded; i >= 0; i--) {
616 if (mainProject->file[i] && mainProject->file[i]->isVisible) {
617 cairo_set_source_surface (cr, (cairo_surface_t *) mainProject->file[i]->privateRenderData,
618 0, 0);
619 /* ignore alpha if we are in high-speed render mode */
620 if (((double) mainProject->file[i]->alpha < 65535)&&(screenRenderInfo.renderType != GERBV_RENDER_TYPE_GDK_XOR)) {
621 cairo_paint_with_alpha(cr,(double) mainProject->file[i]->alpha/G_MAXUINT16);
623 else {
624 cairo_paint (cr);
628 /* render the selection layer at the end */
629 if (screen.selectionInfo.type != GERBV_SELECTION_EMPTY) {
630 cairo_set_source_surface (cr, (cairo_surface_t *) screen.selectionRenderData,
631 0, 0);
632 cairo_paint_with_alpha (cr,1.0);
634 cairo_destroy (cr);
637 /* ------------------------------------------------------ */
638 void render_project_to_cairo_target (cairo_t *cr) {
639 /* fill the background with the appropriate color */
640 cairo_set_source_rgba (cr, (double) mainProject->background.red/G_MAXUINT16,
641 (double) mainProject->background.green/G_MAXUINT16,
642 (double) mainProject->background.blue/G_MAXUINT16, 1);
643 cairo_paint (cr);
645 cairo_set_source_surface (cr, (cairo_surface_t *) screen.bufferSurface, 0 , 0);
647 cairo_paint (cr);
650 void
651 render_free_screen_resources (void) {
652 if (screen.selectionRenderData)
653 cairo_surface_destroy ((cairo_surface_t *)
654 screen.selectionRenderData);
655 if (screen.bufferSurface)
656 cairo_surface_destroy ((cairo_surface_t *)
657 screen.bufferSurface);
658 if (screen.windowSurface)
659 cairo_surface_destroy ((cairo_surface_t *)
660 screen.windowSurface);
661 if (screen.pixmap)
662 gdk_pixmap_unref(screen.pixmap);
666 /* ------------------------------------------------------------------ */
667 /*! This fills out the project's Gerber statistics table.
668 * It is called from within callbacks.c when the user
669 * asks for a Gerber report. */
670 gerbv_stats_t *
671 generate_gerber_analysis(void)
673 int i;
674 gerbv_stats_t *stats;
675 gerbv_stats_t *instats;
677 /* Create new stats structure to hold report for whole project
678 * (i.e. all layers together) */
679 stats = gerbv_stats_new();
681 /* Loop through open layers and compile statistics by accumulating reports from each layer */
682 for (i = 0; i <= mainProject->last_loaded; i++) {
683 if (mainProject->file[i] && mainProject->file[i]->isVisible &&
684 (mainProject->file[i]->image->layertype == GERBV_LAYERTYPE_RS274X) ) {
685 instats = mainProject->file[i]->image->gerbv_stats;
686 gerbv_stats_add_layer(stats, instats, i+1);
689 return stats;
693 /* ------------------------------------------------------------------ */
694 /*! This fills out the project's Drill statistics table.
695 * It is called from within callbacks.c when the user
696 * asks for a Drill report. */
697 gerbv_drill_stats_t *
698 generate_drill_analysis(void)
700 int i;
701 gerbv_drill_stats_t *stats;
702 gerbv_drill_stats_t *instats;
704 stats = gerbv_drill_stats_new();
706 /* Loop through open layers and compile statistics by accumulating reports from each layer */
707 for(i = mainProject->last_loaded; i >= 0; i--) {
708 if (mainProject->file[i] &&
709 mainProject->file[i]->isVisible &&
710 (mainProject->file[i]->image->layertype == GERBV_LAYERTYPE_DRILL) ) {
711 instats = mainProject->file[i]->image->drill_stats;
712 /* add this batch of stats. Send the layer
713 * index for error reporting */
714 gerbv_drill_stats_add_layer(stats, instats, i+1);
717 return stats;