2 * gEDA - GNU Electronic Design Automation
3 * This file is a part of gerbv.
5 * Copyright (C) 2000-2003 Stefan Petersen (spe@stacken.kth.se)
9 * This program is free software; you can redistribute it and/or modify
10 * it under the terms of the GNU General Public License as published by
11 * the Free Software Foundation; either version 2 of the License, or
12 * (at your option) any later version.
14 * This program is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 * GNU General Public License for more details.
19 * You should have received a copy of the GNU General Public License
20 * along with this program; if not, write to the Free Software
21 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111 USA
26 \brief This file contains high-level functions for the libgerbv library
39 #include <libgen.h> /* dirname */
54 #include <gdk/gdkkeysyms.h>
60 #include <pango/pango.h>
68 #ifdef RENDER_USING_GDK
75 #include "pick-and-place.h"
77 /* DEBUG printing. #define DEBUG 1 in config.h to use this fcn. */
78 #define dprintf if(DEBUG) printf
80 #define NUMBER_OF_DEFAULT_COLORS 18
81 #define NUMBER_OF_DEFAULT_TRANSFORMATIONS 20
83 /* ------------------------------------------------------------------ */
84 static gerbv_layer_color defaultColors
[NUMBER_OF_DEFAULT_COLORS
] = {
105 /* ------------------------------------------------------------------ */
106 static gerbv_user_transformation_t defaultTransformations
[NUMBER_OF_DEFAULT_TRANSFORMATIONS
] = {
129 /* ------------------------------------------------------------------ */
131 gerbv_create_project (void) {
132 gerbv_project_t
*returnProject
= (gerbv_project_t
*) g_new0(gerbv_project_t
,1);
134 /* default to using the current directory path for our starting guesses
135 on future file loads */
136 returnProject
->path
= g_get_current_dir ();
137 /* Will be updated to 0 when first Gerber is loaded */
138 returnProject
->last_loaded
= -1;
139 returnProject
->max_files
= 1;
140 returnProject
->check_before_delete
= TRUE
;
141 returnProject
->file
= g_new0 (gerbv_fileinfo_t
*, returnProject
->max_files
);
143 return returnProject
;
146 /* ------------------------------------------------------------------ */
148 gerbv_destroy_project (gerbv_project_t
*gerbvProject
){
151 /* destroy all the files attached to the project */
152 for(i
= gerbvProject
->last_loaded
; i
>= 0; i
--) {
153 if (gerbvProject
->file
[i
])
154 gerbv_destroy_fileinfo (gerbvProject
->file
[i
]);
156 /* destroy strings */
157 g_free (gerbvProject
->path
);
158 g_free (gerbvProject
->execname
);
159 g_free (gerbvProject
->execpath
);
160 g_free (gerbvProject
->project
);
161 /* destroy the fileinfo array */
162 g_free (gerbvProject
->file
);
163 g_free (gerbvProject
);
166 /* ------------------------------------------------------------------ */
168 gerbv_destroy_fileinfo (gerbv_fileinfo_t
*fileInfo
){
169 gerbv_destroy_image (fileInfo
->image
);
170 g_free (fileInfo
->fullPathname
);
171 g_free (fileInfo
->name
);
172 #ifndef RENDER_USING_GDK
173 if (fileInfo
->privateRenderData
) {
174 cairo_surface_destroy ((cairo_surface_t
*)
175 fileInfo
->privateRenderData
);
180 /* ------------------------------------------------------------------ */
182 gerbv_open_layer_from_filename(gerbv_project_t
*gerbvProject
, gchar
*filename
)
185 dprintf("Opening filename = %s\n", (gchar
*) filename
);
187 if (gerbv_open_image(gerbvProject
, filename
, ++gerbvProject
->last_loaded
, FALSE
, NULL
, 0, TRUE
) == -1) {
188 GERB_MESSAGE("could not read %s[%d]", (gchar
*) filename
,
189 gerbvProject
->last_loaded
);
190 gerbvProject
->last_loaded
--;
192 idx_loaded
= gerbvProject
->last_loaded
;
193 gerbvProject
->file
[idx_loaded
]->layer_dirty
= FALSE
;
194 dprintf(" Successfully opened file!\n");
196 } /* gerbv_open_layer_from_filename */
198 /* ------------------------------------------------------------------ */
200 gerbv_open_layer_from_filename_with_color(gerbv_project_t
*gerbvProject
, gchar
*filename
,
201 guint16 red
, guint16 green
, guint16 blue
, guint16 alpha
)
204 dprintf("Opening filename = %s\n", (gchar
*) filename
);
206 if (gerbv_open_image(gerbvProject
, filename
, ++gerbvProject
->last_loaded
, FALSE
, NULL
, 0, TRUE
) == -1) {
207 GERB_MESSAGE("could not read %s[%d]", (gchar
*) filename
,
208 gerbvProject
->last_loaded
);
209 gerbvProject
->last_loaded
--;
211 idx_loaded
= gerbvProject
->last_loaded
;
212 gerbvProject
->file
[idx_loaded
]->layer_dirty
= FALSE
;
213 GdkColor colorTemplate
= {0, red
, green
, blue
};
214 gerbvProject
->file
[idx_loaded
]->color
= colorTemplate
;
215 gerbvProject
->file
[idx_loaded
]->alpha
= alpha
;
216 dprintf(" Successfully opened file!\n");
218 } /* gerbv_open_layer_from_filename_with_color */
220 /* ------------------------------------------------------------------ */
222 gerbv_save_layer_from_index(gerbv_project_t
*gerbvProject
, gint index
, gchar
*filename
)
224 if (strcmp (gerbvProject
->file
[index
]->image
->info
->type
,"RS274-X (Gerber) File")==0) {
225 gerbv_export_rs274x_file_from_image (filename
, gerbvProject
->file
[index
]->image
);
227 else if (strcmp (gerbvProject
->file
[index
]->image
->info
->type
,"Excellon Drill File")==0) {
228 gerbv_export_drill_file_from_image (filename
, gerbvProject
->file
[index
]->image
);
233 gerbvProject
->file
[index
]->layer_dirty
= FALSE
;
235 } /* gerbv_save_project_from_filename */
238 /* ------------------------------------------------------------------ */
240 gerbv_revert_file(gerbv_project_t
*gerbvProject
, int idx
){
243 rv
= gerbv_open_image(gerbvProject
, gerbvProject
->file
[idx
]->fullPathname
, idx
, TRUE
, NULL
, 0, TRUE
);
244 gerbvProject
->file
[idx
]->layer_dirty
= FALSE
;
248 /* ------------------------------------------------------------------ */
250 gerbv_revert_all_files(gerbv_project_t
*gerbvProject
)
254 for (idx
= 0; idx
<= gerbvProject
->last_loaded
; idx
++) {
255 if (gerbvProject
->file
[idx
] && gerbvProject
->file
[idx
]->fullPathname
) {
256 (void) gerbv_revert_file (gerbvProject
, idx
);
257 gerbvProject
->file
[idx
]->layer_dirty
= FALSE
;
260 } /* gerbv_revert_all_files */
262 /* ------------------------------------------------------------------ */
264 gerbv_unload_layer(gerbv_project_t
*gerbvProject
, int index
)
268 gerbv_destroy_fileinfo (gerbvProject
->file
[index
]);
270 /* slide all later layers down to fill the empty slot */
271 for (i
=index
; i
<(gerbvProject
->last_loaded
); i
++) {
272 gerbvProject
->file
[i
]=gerbvProject
->file
[i
+1];
274 /* make sure the final spot is clear */
275 gerbvProject
->file
[gerbvProject
->last_loaded
] = NULL
;
276 gerbvProject
->last_loaded
--;
277 } /* gerbv_unload_layer */
279 /* ------------------------------------------------------------------ */
281 gerbv_unload_all_layers (gerbv_project_t
*gerbvProject
)
285 /* Must count down since gerbv_unload_layer collapses
286 * layers down. Otherwise, layers slide past the index */
287 for (index
= gerbvProject
->last_loaded
; index
>= 0; index
--) {
288 if (gerbvProject
->file
[index
] && gerbvProject
->file
[index
]->name
) {
289 gerbv_unload_layer (gerbvProject
, index
);
292 } /* gerbv_unload_all_layers */
295 /* ------------------------------------------------------------------ */
297 gerbv_change_layer_order(gerbv_project_t
*gerbvProject
, gint oldPosition
, gint newPosition
)
299 gerbv_fileinfo_t
*temp_file
;
302 temp_file
= gerbvProject
->file
[oldPosition
];
304 if (oldPosition
< newPosition
){
305 for (index
= oldPosition
; index
< newPosition
; index
++) {
306 gerbvProject
->file
[index
] = gerbvProject
->file
[index
+ 1];
309 for (index
= oldPosition
; index
> newPosition
; index
--) {
310 gerbvProject
->file
[index
] = gerbvProject
->file
[index
- 1];
313 gerbvProject
->file
[newPosition
] = temp_file
;
314 } /* gerbv_change_layer_order */
317 /* ------------------------------------------------------------------ */
319 gerbv_add_parsed_image_to_project (gerbv_project_t
*gerbvProject
, gerbv_image_t
*parsed_image
,
320 gchar
*filename
, gchar
*baseName
, int idx
, int reload
){
321 gerb_verify_error_t error
= GERB_IMAGE_OK
;
324 dprintf("In open_image, now error check file....\n");
325 error
= gerbv_image_verify(parsed_image
);
327 GERB_COMPILE_ERROR("%s: Parse error:\n", filename
);
328 if (error
& GERB_IMAGE_MISSING_NETLIST
)
329 GERB_COMPILE_ERROR("* Missing netlist\n");
330 if (error
& GERB_IMAGE_MISSING_FORMAT
)
331 GERB_COMPILE_ERROR("* Missing format\n");
332 if (error
& GERB_IMAGE_MISSING_APERTURES
)
333 GERB_COMPILE_ERROR("* Missing apertures/drill sizes\n");
334 if (error
& GERB_IMAGE_MISSING_INFO
)
335 GERB_COMPILE_ERROR("* Missing info\n");
336 GERB_COMPILE_ERROR("\n");
337 GERB_COMPILE_ERROR("You probably tried to read an RS-274D file, which gerbv doesn't support\n");
338 gerbv_destroy_image(parsed_image
);
342 /* Used to debug parser */
343 //if (gerbvProject->dump_parsed_image)
344 //gerb_image_dump(parsed_image);
347 * If reload, just exchange the image. Else we have to allocate
348 * a new memory before we define anything more.
351 gerbv_destroy_image(gerbvProject
->file
[idx
]->image
);
352 gerbvProject
->file
[idx
]->image
= parsed_image
;
356 gerbvProject
->file
[idx
] = (gerbv_fileinfo_t
*) g_new0 (gerbv_fileinfo_t
, 1);
357 gerbvProject
->file
[idx
]->image
= parsed_image
;
361 * Store filename for eventual reload
363 gerbvProject
->file
[idx
]->fullPathname
= g_strdup (filename
);
364 gerbvProject
->file
[idx
]->name
= g_strdup (baseName
);
368 r
= defaultColors
[idx
% NUMBER_OF_DEFAULT_COLORS
].red
*257;
369 g
= defaultColors
[idx
% NUMBER_OF_DEFAULT_COLORS
].green
*257;
370 b
= defaultColors
[idx
% NUMBER_OF_DEFAULT_COLORS
].blue
*257;
373 GdkColor colorTemplate
= {0, r
, g
, b
};
374 gerbvProject
->file
[idx
]->color
= colorTemplate
;
375 gerbvProject
->file
[idx
]->alpha
= defaultColors
[idx
% NUMBER_OF_DEFAULT_COLORS
].alpha
*257;
376 gerbvProject
->file
[idx
]->isVisible
= TRUE
;
377 gerbvProject
->file
[idx
]->transform
= defaultTransformations
[idx
% NUMBER_OF_DEFAULT_TRANSFORMATIONS
];
378 /* update the number of files if we need to */
379 if (gerbvProject
->last_loaded
<= idx
) {
380 gerbvProject
->last_loaded
= idx
;
385 /* ------------------------------------------------------------------ */
387 gerbv_open_image(gerbv_project_t
*gerbvProject
, char *filename
, int idx
, int reload
,
388 gerbv_HID_Attribute
*fattr
, int n_fattr
, gboolean forceLoadFile
)
391 gerbv_image_t
*parsed_image
= NULL
, *parsed_image2
= NULL
;
393 gboolean isPnpFile
= FALSE
, foundBinary
;
394 gerbv_HID_Attribute
*attr_list
= NULL
;
396 /* If we're reloading, we'll pass in our file format attribute list
397 * since this is our hook for letting the user override the fileformat.
401 /* We're reloading so use the attribute list in memory */
402 attr_list
= gerbvProject
->file
[idx
]->image
->info
->attr_list
;
403 n_attr
= gerbvProject
->file
[idx
]->image
->info
->n_attr
;
407 /* We're not reloading so use the attribute list read from the
408 * project file if given or NULL otherwise.
413 /* if we don't have enough spots, then grow the file list by 2 to account for the possible
414 loading of two images for PNP files */
415 if ((idx
+1) >= gerbvProject
->max_files
) {
416 gerbvProject
->file
= g_renew (gerbv_fileinfo_t
*,
417 gerbvProject
->file
, gerbvProject
->max_files
+ 2);
419 gerbvProject
->file
[gerbvProject
->max_files
] = NULL
;
420 gerbvProject
->file
[gerbvProject
->max_files
+1] = NULL
;
421 gerbvProject
->max_files
+= 2;
424 dprintf("In open_image, about to try opening filename = %s\n", filename
);
426 fd
= gerb_fopen(filename
);
428 GERB_MESSAGE("Trying to open %s:%s\n", filename
, strerror(errno
));
432 /* Store filename info fd for further use */
433 fd
->filename
= g_strdup(filename
);
435 dprintf("In open_image, successfully opened file. Now check its type....\n");
436 /* Here's where we decide what file type we have */
437 /* Note: if the file has some invalid characters in it but still appears to
438 be a valid file, we check with the user if he wants to continue (only
439 if user opens the layer from the menu...if from the command line, we go
440 ahead and try to load it anyways) */
442 if (gerber_is_rs274x_p(fd
, &foundBinary
)) {
443 dprintf("Found RS-274X file\n");
444 if ((!foundBinary
|| forceLoadFile
)) {
445 /* figure out the directory path in case parse_gerb needs to
446 * load any include files */
447 gchar
*currentLoadDirectory
= g_path_get_dirname (filename
);
448 parsed_image
= parse_gerb(fd
, currentLoadDirectory
);
449 g_free (currentLoadDirectory
);
451 } else if(drill_file_p(fd
, &foundBinary
)) {
452 dprintf("Found drill file\n");
453 if ((!foundBinary
|| forceLoadFile
))
454 parsed_image
= parse_drillfile(fd
, attr_list
, n_attr
, reload
);
456 } else if (pick_and_place_check_file_type(fd
, &foundBinary
)) {
457 dprintf("Found pick-n-place file\n");
458 if ((!foundBinary
|| forceLoadFile
)) {
459 pick_and_place_parse_file_to_images(fd
, &parsed_image
, &parsed_image2
);
462 } else if (gerber_is_rs274d_p(fd
)) {
463 dprintf("Found RS-274D file");
464 GERB_COMPILE_ERROR("%s: Found RS-274D file -- not supported by gerbv.\n", filename
);
468 /* This is not a known file */
469 dprintf("Unknown filetype");
470 GERB_COMPILE_ERROR("%s: Unknown file type.\n", filename
);
475 if (parsed_image
== NULL
) {
480 /* strip the filename to the base */
481 gchar
*baseName
= g_path_get_basename (filename
);
482 gchar
*displayedName
;
484 displayedName
= g_strconcat (baseName
, " (top)",NULL
);
486 displayedName
= g_strdup (baseName
);
487 retv
= gerbv_add_parsed_image_to_project (gerbvProject
, parsed_image
, filename
, displayedName
, idx
, reload
);
489 g_free (displayedName
);
492 /* Set layer_dirty flag to FALSE */
493 gerbvProject
->file
[idx
]->layer_dirty
= FALSE
;
495 /* for PNP place files, we may need to add a second image for the other
498 /* strip the filename to the base */
499 gchar
*baseName
= g_path_get_basename (filename
);
500 gchar
*displayedName
;
501 displayedName
= g_strconcat (baseName
, " (bottom)",NULL
);
502 retv
= gerbv_add_parsed_image_to_project (gerbvProject
, parsed_image2
, filename
, displayedName
, idx
+ 1, reload
);
504 g_free (displayedName
);
511 gerbv_create_rs274x_image_from_filename (gchar
*filename
){
512 gerbv_image_t
*returnImage
;
515 fd
= gerb_fopen(filename
);
517 GERB_MESSAGE("Trying to open %s:%s\n", filename
, strerror(errno
));
520 gchar
*currentLoadDirectory
= g_path_get_dirname (filename
);
521 returnImage
= parse_gerb(fd
, currentLoadDirectory
);
522 g_free (currentLoadDirectory
);
527 /* ------------------------------------------------------------------ */
529 gerbv_render_get_boundingbox(gerbv_project_t
*gerbvProject
, gerbv_render_size_t
*boundingbox
)
531 double x1
=HUGE_VAL
,y1
=HUGE_VAL
, x2
=-HUGE_VAL
,y2
=-HUGE_VAL
;
533 gerbv_image_info_t
*info
;
535 for(i
= 0; i
<= gerbvProject
->last_loaded
; i
++) {
536 if ((gerbvProject
->file
[i
]) && (gerbvProject
->file
[i
]->isVisible
)){
537 info
= gerbvProject
->file
[i
]->image
->info
;
539 * Find the biggest image and use as a size reference
541 #ifdef RENDER_USING_GDK
542 x1
= MIN(x1
, info
->min_x
+ info
->offsetA
);
543 y1
= MIN(y1
, info
->min_y
+ info
->offsetB
);
544 x2
= MAX(x2
, info
->max_x
+ info
->offsetA
);
545 y2
= MAX(y2
, info
->max_y
+ info
->offsetB
);
547 /* cairo info already has offset calculated into min/max */
548 x1
= MIN(x1
, info
->min_x
);
549 y1
= MIN(y1
, info
->min_y
);
550 x2
= MAX(x2
, info
->max_x
);
551 y2
= MAX(y2
, info
->max_y
);
555 boundingbox
->left
= x1
;
556 boundingbox
->right
= x2
;
557 boundingbox
->top
= y1
;
558 boundingbox
->bottom
= y2
;
561 /* ------------------------------------------------------------------ */
563 gerbv_render_zoom_to_fit_display (gerbv_project_t
*gerbvProject
, gerbv_render_info_t
*renderInfo
) {
564 gerbv_render_size_t bb
;
565 double width
, height
;
566 double x_scale
, y_scale
;
568 /* Grab maximal width and height of all layers */
569 gerbv_render_get_boundingbox(gerbvProject
, &bb
);
570 width
= bb
.right
- bb
.left
;
571 height
= bb
.bottom
- bb
.top
;
572 /* add in a 5% buffer around the drawing */
576 /* if the values aren't sane (probably we have no models loaded), then
577 put in some defaults */
578 if ((width
< 0.01) && (height
< 0.01)) {
579 renderInfo
->lowerLeftX
= 0.0;
580 renderInfo
->lowerLeftY
= 0.0;
581 renderInfo
->scaleFactorX
= 200;
582 renderInfo
->scaleFactorY
= 200;
586 * Calculate scale for both x axis and y axis
588 x_scale
= renderInfo
->displayWidth
/ width
;
589 y_scale
= renderInfo
->displayHeight
/ height
;
591 * Take the scale that fits both directions with some extra checks
593 renderInfo
->scaleFactorX
= MIN(x_scale
, y_scale
);
594 renderInfo
->scaleFactorY
= renderInfo
->scaleFactorX
;
595 if (renderInfo
->scaleFactorX
< 1){
596 renderInfo
->scaleFactorX
= 1;
597 renderInfo
->scaleFactorY
= 1;
599 renderInfo
->lowerLeftX
= ((bb
.left
+ bb
.right
) / 2.0) -
600 ((double) renderInfo
->displayWidth
/ 2.0 / renderInfo
->scaleFactorX
);
601 renderInfo
->lowerLeftY
= ((bb
.top
+ bb
.bottom
) / 2.0) -
602 ((double) renderInfo
->displayHeight
/ 2.0 / renderInfo
->scaleFactorY
);
605 /* ------------------------------------------------------------------ */
607 gerbv_render_translate_to_fit_display (gerbv_project_t
*gerbvProject
, gerbv_render_info_t
*renderInfo
) {
608 gerbv_render_size_t bb
;
610 /* Grab maximal width and height of all layers */
611 gerbv_render_get_boundingbox(gerbvProject
, &bb
);
612 renderInfo
->lowerLeftX
= ((bb
.left
+ bb
.right
) / 2.0) -
613 ((double) renderInfo
->displayWidth
/ 2.0 / renderInfo
->scaleFactorX
);
614 renderInfo
->lowerLeftY
= ((bb
.top
+ bb
.bottom
) / 2.0) -
615 ((double) renderInfo
->displayHeight
/ 2.0 / renderInfo
->scaleFactorY
);
618 /* ------------------------------------------------------------------ */
620 gerbv_render_to_pixmap_using_gdk (gerbv_project_t
*gerbvProject
, GdkPixmap
*pixmap
,
621 gerbv_render_info_t
*renderInfo
, gerbv_selection_info_t
*selectionInfo
,
622 GdkColor
*selectionColor
){
623 GdkGC
*gc
= gdk_gc_new(pixmap
);
624 GdkPixmap
*colorStamp
, *clipmask
;
628 * Remove old pixmap, allocate a new one, draw the background.
630 if (!gerbvProject
->background
.pixel
)
631 gdk_colormap_alloc_color(gdk_colormap_get_system(), &gerbvProject
->background
, FALSE
, TRUE
);
632 gdk_gc_set_foreground(gc
, &gerbvProject
->background
);
633 gdk_draw_rectangle(pixmap
, gc
, TRUE
, 0, 0, -1, -1);
636 * Allocate the pixmap and the clipmask (a one pixel pixmap)
638 colorStamp
= gdk_pixmap_new(pixmap
, renderInfo
->displayWidth
,
639 renderInfo
->displayHeight
, -1);
640 clipmask
= gdk_pixmap_new(NULL
, renderInfo
->displayWidth
,
641 renderInfo
->displayHeight
, 1);
644 * This now allows drawing several layers on top of each other.
645 * Higher layer numbers have higher priority in the Z-order.
647 for(i
= gerbvProject
->last_loaded
; i
>= 0; i
--) {
648 if (gerbvProject
->file
[i
] && gerbvProject
->file
[i
]->isVisible
) {
649 gerbv_polarity_t polarity
;
651 if (gerbvProject
->file
[i
]->transform
.inverted
) {
652 if (gerbvProject
->file
[i
]->image
->info
->polarity
== GERBV_POLARITY_POSITIVE
)
653 polarity
= GERBV_POLARITY_NEGATIVE
;
655 polarity
= GERBV_POLARITY_POSITIVE
;
657 polarity
= gerbvProject
->file
[i
]->image
->info
->polarity
;
661 * Fill up image with all the foreground color. Excess pixels
662 * will be removed by clipmask.
664 if (!gerbvProject
->file
[i
]->color
.pixel
)
665 gdk_colormap_alloc_color(gdk_colormap_get_system(), &gerbvProject
->file
[i
]->color
, FALSE
, TRUE
);
666 gdk_gc_set_foreground(gc
, &gerbvProject
->file
[i
]->color
);
668 /* switch back to regular draw function for the initial
670 gdk_gc_set_function(gc
, GDK_COPY
);
671 gdk_draw_rectangle(colorStamp
, gc
, TRUE
, 0, 0, -1, -1);
673 if (renderInfo
->renderType
== 0) {
674 gdk_gc_set_function(gc
, GDK_COPY
);
676 else if (renderInfo
->renderType
== 1) {
677 gdk_gc_set_function(gc
, GDK_XOR
);
680 * Translation is to get it inside the allocated pixmap,
681 * which is not always centered perfectly for GTK/X.
683 dprintf(" .... calling image2pixmap on image %d...\n", i
);
684 // Dirty scaling solution when using GDK; simply use scaling factor for x-axis, ignore y-axis
685 draw_gdk_image_to_pixmap(&clipmask
, gerbvProject
->file
[i
]->image
,
686 renderInfo
->scaleFactorX
, -(renderInfo
->lowerLeftX
* renderInfo
->scaleFactorX
),
687 (renderInfo
->lowerLeftY
* renderInfo
->scaleFactorY
) + renderInfo
->displayHeight
,
688 polarity
, DRAW_IMAGE
, NULL
, renderInfo
);
691 * Set clipmask and draw the clipped out image onto the
692 * screen pixmap. Afterwards we remove the clipmask, else
693 * it will screw things up when run this loop again.
695 gdk_gc_set_clip_mask(gc
, clipmask
);
696 gdk_gc_set_clip_origin(gc
, 0, 0);
697 gdk_draw_drawable(pixmap
, gc
, colorStamp
, 0, 0, 0, 0, -1, -1);
698 gdk_gc_set_clip_mask(gc
, NULL
);
701 /* render the selection group to the top of the output */
702 if ((selectionInfo
) && (selectionInfo
->type
!= GERBV_SELECTION_EMPTY
)) {
703 if (!selectionColor
->pixel
)
704 gdk_colormap_alloc_color(gdk_colormap_get_system(), selectionColor
, FALSE
, TRUE
);
706 gdk_gc_set_foreground(gc
, selectionColor
);
707 gdk_gc_set_function(gc
, GDK_COPY
);
708 gdk_draw_rectangle(colorStamp
, gc
, TRUE
, 0, 0, -1, -1);
710 /* for now, assume everything in the selection buffer is from one image */
711 gerbv_image_t
*matchImage
;
713 if (selectionInfo
->selectedNodeArray
->len
> 0) {
714 gerbv_selection_item_t sItem
= g_array_index (selectionInfo
->selectedNodeArray
,
715 gerbv_selection_item_t
, 0);
716 matchImage
= (gerbv_image_t
*) sItem
.image
;
718 for(j
= gerbvProject
->last_loaded
; j
>= 0; j
--) {
719 if ((gerbvProject
->file
[j
]) && (gerbvProject
->file
[j
]->image
== matchImage
)) {
720 draw_gdk_image_to_pixmap(&clipmask
, gerbvProject
->file
[j
]->image
,
721 renderInfo
->scaleFactorX
, -(renderInfo
->lowerLeftX
* renderInfo
->scaleFactorX
),
722 (renderInfo
->lowerLeftY
* renderInfo
->scaleFactorY
) + renderInfo
->displayHeight
,
723 GERBV_POLARITY_POSITIVE
, DRAW_SELECTIONS
, selectionInfo
,
727 gdk_gc_set_clip_mask(gc
, clipmask
);
728 gdk_gc_set_clip_origin(gc
, 0, 0);
729 gdk_draw_drawable(pixmap
, gc
, colorStamp
, 0, 0, 0, 0, -1, -1);
730 gdk_gc_set_clip_mask(gc
, NULL
);
734 gdk_pixmap_unref(colorStamp
);
735 gdk_pixmap_unref(clipmask
);
739 /* ------------------------------------------------------------------ */
740 #ifndef RENDER_USING_GDK
742 gerbv_render_all_layers_to_cairo_target_for_vector_output (gerbv_project_t
*gerbvProject
,
743 cairo_t
*cr
, gerbv_render_info_t
*renderInfo
) {
745 gerbv_render_cairo_set_scale_and_translation(cr
, renderInfo
);
746 /* don't paint background for vector output, since it isn't needed */
747 for(i
= gerbvProject
->last_loaded
; i
>= 0; i
--) {
748 if (gerbvProject
->file
[i
] && gerbvProject
->file
[i
]->isVisible
) {
750 gerbv_render_layer_to_cairo_target_without_transforming(cr
, gerbvProject
->file
[i
], renderInfo
);
756 /* ------------------------------------------------------------------ */
757 #ifndef RENDER_USING_GDK
759 gerbv_render_all_layers_to_cairo_target (gerbv_project_t
*gerbvProject
, cairo_t
*cr
,
760 gerbv_render_info_t
*renderInfo
) {
762 /* fill the background with the appropriate color */
763 cairo_set_source_rgba (cr
, (double) gerbvProject
->background
.red
/G_MAXUINT16
,
764 (double) gerbvProject
->background
.green
/G_MAXUINT16
,
765 (double) gerbvProject
->background
.blue
/G_MAXUINT16
, 1);
767 for(i
= gerbvProject
->last_loaded
; i
>= 0; i
--) {
768 if (gerbvProject
->file
[i
] && gerbvProject
->file
[i
]->isVisible
) {
769 cairo_push_group (cr
);
770 gerbv_render_layer_to_cairo_target (cr
, gerbvProject
->file
[i
], renderInfo
);
771 cairo_pop_group_to_source (cr
);
772 cairo_paint_with_alpha (cr
, (double) gerbvProject
->file
[i
]->alpha
/G_MAXUINT16
);
778 /* ------------------------------------------------------------------ */
779 #ifndef RENDER_USING_GDK
781 gerbv_render_layer_to_cairo_target (cairo_t
*cr
, gerbv_fileinfo_t
*fileInfo
,
782 gerbv_render_info_t
*renderInfo
) {
783 gerbv_render_cairo_set_scale_and_translation(cr
, renderInfo
);
784 gerbv_render_layer_to_cairo_target_without_transforming(cr
, fileInfo
, renderInfo
);
788 /* ------------------------------------------------------------------ */
789 #ifndef RENDER_USING_GDK
791 gerbv_render_cairo_set_scale_and_translation(cairo_t
*cr
, gerbv_render_info_t
*renderInfo
){
792 gdouble translateX
, translateY
;
794 translateX
= (renderInfo
->lowerLeftX
* renderInfo
->scaleFactorX
);
795 translateY
= (renderInfo
->lowerLeftY
* renderInfo
->scaleFactorY
);
797 /* renderTypes 0 and 1 use GDK rendering, so we shouldn't have made it
799 if (renderInfo
->renderType
== 2) {
800 cairo_set_tolerance (cr
, 1.5);
801 cairo_set_antialias (cr
, CAIRO_ANTIALIAS_NONE
);
803 else if (renderInfo
->renderType
== 3) {
804 cairo_set_tolerance (cr
, 1);
805 /* disable ALL anti-aliasing for now due to the way cairo is rendering
806 ground planes from PCB output */
807 cairo_set_antialias (cr
, CAIRO_ANTIALIAS_DEFAULT
);
810 /* translate the draw area before drawing. We must translate the whole
811 drawing down an additional displayHeight to account for the negative
813 cairo_translate (cr
, -translateX
, translateY
+ renderInfo
->displayHeight
);
814 /* scale the drawing by the specified scale factor (inverting y since
815 cairo y axis points down) */
816 cairo_scale (cr
, renderInfo
->scaleFactorX
, -renderInfo
->scaleFactorY
);
820 /* ------------------------------------------------------------------ */
821 #ifndef RENDER_USING_GDK
823 gerbv_render_layer_to_cairo_target_without_transforming(cairo_t
*cr
, gerbv_fileinfo_t
*fileInfo
, gerbv_render_info_t
*renderInfo
) {
824 cairo_set_source_rgba (cr
, (double) fileInfo
->color
.red
/G_MAXUINT16
,
825 (double) fileInfo
->color
.green
/G_MAXUINT16
,
826 (double) fileInfo
->color
.blue
/G_MAXUINT16
, 1);
828 /* translate the image based on the layer-specific transformation struct */
830 cairo_translate (cr
, fileInfo
->transform
.translateX
, fileInfo
->transform
.translateY
);
831 draw_image_to_cairo_target (cr
, fileInfo
->image
, fileInfo
->transform
.inverted
,
832 1.0/MAX(renderInfo
->scaleFactorX
, renderInfo
->scaleFactorY
), DRAW_IMAGE
, NULL
,
839 gerbv_attribute_destroy_HID_attribute (gerbv_HID_Attribute
*attributeList
, int n_attr
)
843 /* free the string attributes */
844 for (i
= 0 ; i
< n_attr
; i
++) {
845 if ( (attributeList
[i
].type
== HID_String
||
846 attributeList
[i
].type
== HID_Label
) &&
847 attributeList
[i
].default_val
.str_value
!= NULL
) {
848 free (attributeList
[i
].default_val
.str_value
);
852 /* and free the attribute list */
853 if (attributeList
!= NULL
) {
854 free (attributeList
);
859 /* allocate memory and make a copy of an attribute list */
860 gerbv_HID_Attribute
*
861 gerbv_attribute_dup (gerbv_HID_Attribute
*attributeList
, int n_attr
)
863 gerbv_HID_Attribute
*nl
;
866 nl
= (gerbv_HID_Attribute
*) malloc (n_attr
* sizeof (gerbv_HID_Attribute
));
868 fprintf (stderr
, "%s(): malloc failed\n", __FUNCTION__
);
872 /* copy the attribute list being sure to strdup the strings */
873 for (i
= 0 ; i
< n_attr
; i
++) {
875 if (attributeList
[i
].type
== HID_String
||
876 attributeList
[i
].type
== HID_Label
) {
878 if (attributeList
[i
].default_val
.str_value
!= NULL
) {
879 nl
[i
].default_val
.str_value
= strdup (attributeList
[i
].default_val
.str_value
);
881 nl
[i
].default_val
.str_value
= NULL
;
885 nl
[i
] = attributeList
[i
];