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>
69 #ifdef RENDER_USING_GDK
76 #include "pick-and-place.h"
78 /* DEBUG printing. #define DEBUG 1 in config.h to use this fcn. */
79 #define dprintf if(DEBUG) printf
81 #define NUMBER_OF_DEFAULT_COLORS 18
82 #define NUMBER_OF_DEFAULT_TRANSFORMATIONS 20
84 /* ------------------------------------------------------------------ */
85 static gerbv_layer_color defaultColors
[NUMBER_OF_DEFAULT_COLORS
] = {
106 /* ------------------------------------------------------------------ */
107 static gerbv_user_transformation_t defaultTransformations
[NUMBER_OF_DEFAULT_TRANSFORMATIONS
] = {
130 /* ------------------------------------------------------------------ */
132 gerbv_create_project (void) {
133 gerbv_project_t
*returnProject
= (gerbv_project_t
*) g_new0(gerbv_project_t
,1);
135 /* default to using the current directory path for our starting guesses
136 on future file loads */
137 returnProject
->path
= g_get_current_dir ();
138 /* Will be updated to 0 when first Gerber is loaded */
139 returnProject
->last_loaded
= -1;
140 returnProject
->max_files
= 1;
141 returnProject
->check_before_delete
= TRUE
;
142 returnProject
->file
= g_new0 (gerbv_fileinfo_t
*, returnProject
->max_files
);
144 return returnProject
;
147 /* ------------------------------------------------------------------ */
149 gerbv_destroy_project (gerbv_project_t
*gerbvProject
){
152 /* destroy all the files attached to the project */
153 for(i
= gerbvProject
->last_loaded
; i
>= 0; i
--) {
154 if (gerbvProject
->file
[i
])
155 gerbv_destroy_fileinfo (gerbvProject
->file
[i
]);
157 /* destroy strings */
158 g_free (gerbvProject
->path
);
159 g_free (gerbvProject
->execname
);
160 g_free (gerbvProject
->execpath
);
161 g_free (gerbvProject
->project
);
162 /* destroy the fileinfo array */
163 g_free (gerbvProject
->file
);
164 g_free (gerbvProject
);
167 /* ------------------------------------------------------------------ */
169 gerbv_destroy_fileinfo (gerbv_fileinfo_t
*fileInfo
){
170 gerbv_destroy_image (fileInfo
->image
);
171 g_free (fileInfo
->fullPathname
);
172 g_free (fileInfo
->name
);
173 #ifndef RENDER_USING_GDK
174 if (fileInfo
->privateRenderData
) {
175 cairo_surface_destroy ((cairo_surface_t
*)
176 fileInfo
->privateRenderData
);
181 /* ------------------------------------------------------------------ */
183 gerbv_open_layer_from_filename(gerbv_project_t
*gerbvProject
, gchar
*filename
)
186 dprintf("Opening filename = %s\n", (gchar
*) filename
);
188 if (gerbv_open_image(gerbvProject
, filename
, ++gerbvProject
->last_loaded
, FALSE
, NULL
, 0, TRUE
) == -1) {
189 GERB_MESSAGE("could not read %s[%d]", (gchar
*) filename
,
190 gerbvProject
->last_loaded
);
191 gerbvProject
->last_loaded
--;
193 idx_loaded
= gerbvProject
->last_loaded
;
194 gerbvProject
->file
[idx_loaded
]->layer_dirty
= FALSE
;
195 dprintf(" Successfully opened file!\n");
197 } /* gerbv_open_layer_from_filename */
199 /* ------------------------------------------------------------------ */
201 gerbv_open_layer_from_filename_with_color(gerbv_project_t
*gerbvProject
, gchar
*filename
,
202 guint16 red
, guint16 green
, guint16 blue
, guint16 alpha
)
205 dprintf("Opening filename = %s\n", (gchar
*) filename
);
207 if (gerbv_open_image(gerbvProject
, filename
, ++gerbvProject
->last_loaded
, FALSE
, NULL
, 0, TRUE
) == -1) {
208 GERB_MESSAGE("could not read %s[%d]", (gchar
*) filename
,
209 gerbvProject
->last_loaded
);
210 gerbvProject
->last_loaded
--;
212 idx_loaded
= gerbvProject
->last_loaded
;
213 gerbvProject
->file
[idx_loaded
]->layer_dirty
= FALSE
;
214 GdkColor colorTemplate
= {0, red
, green
, blue
};
215 gerbvProject
->file
[idx_loaded
]->color
= colorTemplate
;
216 gerbvProject
->file
[idx_loaded
]->alpha
= alpha
;
217 dprintf(" Successfully opened file!\n");
219 } /* gerbv_open_layer_from_filename_with_color */
221 /* ------------------------------------------------------------------ */
223 gerbv_save_layer_from_index(gerbv_project_t
*gerbvProject
, gint index
, gchar
*filename
)
225 if (strcmp (gerbvProject
->file
[index
]->image
->info
->type
,"RS274-X (Gerber) File")==0) {
226 gerbv_export_rs274x_file_from_image (filename
, gerbvProject
->file
[index
]->image
);
228 else if (strcmp (gerbvProject
->file
[index
]->image
->info
->type
,"Excellon Drill File")==0) {
229 gerbv_export_drill_file_from_image (filename
, gerbvProject
->file
[index
]->image
);
234 gerbvProject
->file
[index
]->layer_dirty
= FALSE
;
236 } /* gerbv_save_project_from_filename */
239 /* ------------------------------------------------------------------ */
241 gerbv_revert_file(gerbv_project_t
*gerbvProject
, int idx
){
244 rv
= gerbv_open_image(gerbvProject
, gerbvProject
->file
[idx
]->fullPathname
, idx
, TRUE
, NULL
, 0, TRUE
);
245 gerbvProject
->file
[idx
]->layer_dirty
= FALSE
;
249 /* ------------------------------------------------------------------ */
251 gerbv_revert_all_files(gerbv_project_t
*gerbvProject
)
255 for (idx
= 0; idx
<= gerbvProject
->last_loaded
; idx
++) {
256 if (gerbvProject
->file
[idx
] && gerbvProject
->file
[idx
]->fullPathname
) {
257 (void) gerbv_revert_file (gerbvProject
, idx
);
258 gerbvProject
->file
[idx
]->layer_dirty
= FALSE
;
261 } /* gerbv_revert_all_files */
263 /* ------------------------------------------------------------------ */
265 gerbv_unload_layer(gerbv_project_t
*gerbvProject
, int index
)
269 gerbv_destroy_fileinfo (gerbvProject
->file
[index
]);
271 /* slide all later layers down to fill the empty slot */
272 for (i
=index
; i
<(gerbvProject
->last_loaded
); i
++) {
273 gerbvProject
->file
[i
]=gerbvProject
->file
[i
+1];
275 /* make sure the final spot is clear */
276 gerbvProject
->file
[gerbvProject
->last_loaded
] = NULL
;
277 gerbvProject
->last_loaded
--;
278 } /* gerbv_unload_layer */
280 /* ------------------------------------------------------------------ */
282 gerbv_unload_all_layers (gerbv_project_t
*gerbvProject
)
286 /* Must count down since gerbv_unload_layer collapses
287 * layers down. Otherwise, layers slide past the index */
288 for (index
= gerbvProject
->last_loaded
; index
>= 0; index
--) {
289 if (gerbvProject
->file
[index
] && gerbvProject
->file
[index
]->name
) {
290 gerbv_unload_layer (gerbvProject
, index
);
293 } /* gerbv_unload_all_layers */
296 /* ------------------------------------------------------------------ */
298 gerbv_change_layer_order(gerbv_project_t
*gerbvProject
, gint oldPosition
, gint newPosition
)
300 gerbv_fileinfo_t
*temp_file
;
303 temp_file
= gerbvProject
->file
[oldPosition
];
305 if (oldPosition
< newPosition
){
306 for (index
= oldPosition
; index
< newPosition
; index
++) {
307 gerbvProject
->file
[index
] = gerbvProject
->file
[index
+ 1];
310 for (index
= oldPosition
; index
> newPosition
; index
--) {
311 gerbvProject
->file
[index
] = gerbvProject
->file
[index
- 1];
314 gerbvProject
->file
[newPosition
] = temp_file
;
315 } /* gerbv_change_layer_order */
318 /* ------------------------------------------------------------------ */
320 gerbv_add_parsed_image_to_project (gerbv_project_t
*gerbvProject
, gerbv_image_t
*parsed_image
,
321 gchar
*filename
, gchar
*baseName
, int idx
, int reload
){
322 gerb_verify_error_t error
= GERB_IMAGE_OK
;
325 dprintf("In open_image, now error check file....\n");
326 error
= gerbv_image_verify(parsed_image
);
328 GERB_COMPILE_ERROR("%s: Parse error:\n", filename
);
329 if (error
& GERB_IMAGE_MISSING_NETLIST
)
330 GERB_COMPILE_ERROR("* Missing netlist\n");
331 if (error
& GERB_IMAGE_MISSING_FORMAT
)
332 GERB_COMPILE_ERROR("* Missing format\n");
333 if (error
& GERB_IMAGE_MISSING_APERTURES
)
334 GERB_COMPILE_ERROR("* Missing apertures/drill sizes\n");
335 if (error
& GERB_IMAGE_MISSING_INFO
)
336 GERB_COMPILE_ERROR("* Missing info\n");
337 GERB_COMPILE_ERROR("\n");
338 GERB_COMPILE_ERROR("You probably tried to read an RS-274D file, which gerbv doesn't support\n");
339 gerbv_destroy_image(parsed_image
);
343 /* Used to debug parser */
344 //if (gerbvProject->dump_parsed_image)
345 //gerb_image_dump(parsed_image);
348 * If reload, just exchange the image. Else we have to allocate
349 * a new memory before we define anything more.
352 gerbv_destroy_image(gerbvProject
->file
[idx
]->image
);
353 gerbvProject
->file
[idx
]->image
= parsed_image
;
357 gerbvProject
->file
[idx
] = (gerbv_fileinfo_t
*) g_new0 (gerbv_fileinfo_t
, 1);
358 gerbvProject
->file
[idx
]->image
= parsed_image
;
362 * Store filename for eventual reload
364 gerbvProject
->file
[idx
]->fullPathname
= g_strdup (filename
);
365 gerbvProject
->file
[idx
]->name
= g_strdup (baseName
);
369 r
= defaultColors
[idx
% NUMBER_OF_DEFAULT_COLORS
].red
*257;
370 g
= defaultColors
[idx
% NUMBER_OF_DEFAULT_COLORS
].green
*257;
371 b
= defaultColors
[idx
% NUMBER_OF_DEFAULT_COLORS
].blue
*257;
374 GdkColor colorTemplate
= {0, r
, g
, b
};
375 gerbvProject
->file
[idx
]->color
= colorTemplate
;
376 gerbvProject
->file
[idx
]->alpha
= defaultColors
[idx
% NUMBER_OF_DEFAULT_COLORS
].alpha
*257;
377 gerbvProject
->file
[idx
]->isVisible
= TRUE
;
378 gerbvProject
->file
[idx
]->transform
= defaultTransformations
[idx
% NUMBER_OF_DEFAULT_TRANSFORMATIONS
];
379 /* update the number of files if we need to */
380 if (gerbvProject
->last_loaded
<= idx
) {
381 gerbvProject
->last_loaded
= idx
;
386 /* ------------------------------------------------------------------ */
388 gerbv_open_image(gerbv_project_t
*gerbvProject
, char *filename
, int idx
, int reload
,
389 gerbv_HID_Attribute
*fattr
, int n_fattr
, gboolean forceLoadFile
)
392 gerbv_image_t
*parsed_image
= NULL
, *parsed_image2
= NULL
;
394 gboolean isPnpFile
= FALSE
, foundBinary
;
395 gerbv_HID_Attribute
*attr_list
= NULL
;
397 /* If we're reloading, we'll pass in our file format attribute list
398 * since this is our hook for letting the user override the fileformat.
402 /* We're reloading so use the attribute list in memory */
403 attr_list
= gerbvProject
->file
[idx
]->image
->info
->attr_list
;
404 n_attr
= gerbvProject
->file
[idx
]->image
->info
->n_attr
;
408 /* We're not reloading so use the attribute list read from the
409 * project file if given or NULL otherwise.
414 /* if we don't have enough spots, then grow the file list by 2 to account for the possible
415 loading of two images for PNP files */
416 if ((idx
+1) >= gerbvProject
->max_files
) {
417 gerbvProject
->file
= g_renew (gerbv_fileinfo_t
*,
418 gerbvProject
->file
, gerbvProject
->max_files
+ 2);
420 gerbvProject
->file
[gerbvProject
->max_files
] = NULL
;
421 gerbvProject
->file
[gerbvProject
->max_files
+1] = NULL
;
422 gerbvProject
->max_files
+= 2;
425 dprintf("In open_image, about to try opening filename = %s\n", filename
);
427 fd
= gerb_fopen(filename
);
429 GERB_MESSAGE("Trying to open %s:%s\n", filename
, strerror(errno
));
433 /* Store filename info fd for further use */
434 fd
->filename
= g_strdup(filename
);
436 dprintf("In open_image, successfully opened file. Now check its type....\n");
437 /* Here's where we decide what file type we have */
438 /* Note: if the file has some invalid characters in it but still appears to
439 be a valid file, we check with the user if he wants to continue (only
440 if user opens the layer from the menu...if from the command line, we go
441 ahead and try to load it anyways) */
443 if (gerber_is_rs274x_p(fd
, &foundBinary
)) {
444 dprintf("Found RS-274X file\n");
445 if ((!foundBinary
|| forceLoadFile
)) {
446 /* figure out the directory path in case parse_gerb needs to
447 * load any include files */
448 gchar
*currentLoadDirectory
= g_path_get_dirname (filename
);
449 parsed_image
= parse_gerb(fd
, currentLoadDirectory
);
450 g_free (currentLoadDirectory
);
452 } else if(drill_file_p(fd
, &foundBinary
)) {
453 dprintf("Found drill file\n");
454 if ((!foundBinary
|| forceLoadFile
))
455 parsed_image
= parse_drillfile(fd
, attr_list
, n_attr
, reload
);
457 } else if (pick_and_place_check_file_type(fd
, &foundBinary
)) {
458 dprintf("Found pick-n-place file\n");
459 if ((!foundBinary
|| forceLoadFile
)) {
460 pick_and_place_parse_file_to_images(fd
, &parsed_image
, &parsed_image2
);
463 } else if (gerber_is_rs274d_p(fd
)) {
464 dprintf("Found RS-274D file");
465 GERB_COMPILE_ERROR("%s: Found RS-274D file -- not supported by gerbv.\n", filename
);
469 /* This is not a known file */
470 dprintf("Unknown filetype");
471 GERB_COMPILE_ERROR("%s: Unknown file type.\n", filename
);
476 if (parsed_image
== NULL
) {
481 /* strip the filename to the base */
482 gchar
*baseName
= g_path_get_basename (filename
);
483 gchar
*displayedName
;
485 displayedName
= g_strconcat (baseName
, " (top)",NULL
);
487 displayedName
= g_strdup (baseName
);
488 retv
= gerbv_add_parsed_image_to_project (gerbvProject
, parsed_image
, filename
, displayedName
, idx
, reload
);
490 g_free (displayedName
);
493 /* Set layer_dirty flag to FALSE */
494 gerbvProject
->file
[idx
]->layer_dirty
= FALSE
;
496 /* for PNP place files, we may need to add a second image for the other
499 /* strip the filename to the base */
500 gchar
*baseName
= g_path_get_basename (filename
);
501 gchar
*displayedName
;
502 displayedName
= g_strconcat (baseName
, " (bottom)",NULL
);
503 retv
= gerbv_add_parsed_image_to_project (gerbvProject
, parsed_image2
, filename
, displayedName
, idx
+ 1, reload
);
505 g_free (displayedName
);
512 gerbv_create_rs274x_image_from_filename (gchar
*filename
){
513 gerbv_image_t
*returnImage
;
516 fd
= gerb_fopen(filename
);
518 GERB_MESSAGE("Trying to open %s:%s\n", filename
, strerror(errno
));
521 gchar
*currentLoadDirectory
= g_path_get_dirname (filename
);
522 returnImage
= parse_gerb(fd
, currentLoadDirectory
);
523 g_free (currentLoadDirectory
);
528 /* ------------------------------------------------------------------ */
530 gerbv_render_get_boundingbox(gerbv_project_t
*gerbvProject
, gerbv_render_size_t
*boundingbox
)
532 double x1
=HUGE_VAL
,y1
=HUGE_VAL
, x2
=-HUGE_VAL
,y2
=-HUGE_VAL
;
534 gerbv_image_info_t
*info
;
536 for(i
= 0; i
<= gerbvProject
->last_loaded
; i
++) {
537 if ((gerbvProject
->file
[i
]) && (gerbvProject
->file
[i
]->isVisible
)){
538 info
= gerbvProject
->file
[i
]->image
->info
;
540 * Find the biggest image and use as a size reference
542 #ifdef RENDER_USING_GDK
543 x1
= MIN(x1
, info
->min_x
+ info
->offsetA
);
544 y1
= MIN(y1
, info
->min_y
+ info
->offsetB
);
545 x2
= MAX(x2
, info
->max_x
+ info
->offsetA
);
546 y2
= MAX(y2
, info
->max_y
+ info
->offsetB
);
548 /* cairo info already has offset calculated into min/max */
549 x1
= MIN(x1
, info
->min_x
);
550 y1
= MIN(y1
, info
->min_y
);
551 x2
= MAX(x2
, info
->max_x
);
552 y2
= MAX(y2
, info
->max_y
);
556 boundingbox
->left
= x1
;
557 boundingbox
->right
= x2
;
558 boundingbox
->top
= y1
;
559 boundingbox
->bottom
= y2
;
562 /* ------------------------------------------------------------------ */
564 gerbv_render_zoom_to_fit_display (gerbv_project_t
*gerbvProject
, gerbv_render_info_t
*renderInfo
) {
565 gerbv_render_size_t bb
;
566 double width
, height
;
567 double x_scale
, y_scale
;
569 /* Grab maximal width and height of all layers */
570 gerbv_render_get_boundingbox(gerbvProject
, &bb
);
571 width
= bb
.right
- bb
.left
;
572 height
= bb
.bottom
- bb
.top
;
573 /* add in a 5% buffer around the drawing */
577 /* if the values aren't sane (probably we have no models loaded), then
578 put in some defaults */
579 if ((width
< 0.01) && (height
< 0.01)) {
580 renderInfo
->lowerLeftX
= 0.0;
581 renderInfo
->lowerLeftY
= 0.0;
582 renderInfo
->scaleFactorX
= 200;
583 renderInfo
->scaleFactorY
= 200;
587 * Calculate scale for both x axis and y axis
589 x_scale
= renderInfo
->displayWidth
/ width
;
590 y_scale
= renderInfo
->displayHeight
/ height
;
592 * Take the scale that fits both directions with some extra checks
594 renderInfo
->scaleFactorX
= MIN(x_scale
, y_scale
);
595 renderInfo
->scaleFactorY
= renderInfo
->scaleFactorX
;
596 if (renderInfo
->scaleFactorX
< 1){
597 renderInfo
->scaleFactorX
= 1;
598 renderInfo
->scaleFactorY
= 1;
600 renderInfo
->lowerLeftX
= ((bb
.left
+ bb
.right
) / 2.0) -
601 ((double) renderInfo
->displayWidth
/ 2.0 / renderInfo
->scaleFactorX
);
602 renderInfo
->lowerLeftY
= ((bb
.top
+ bb
.bottom
) / 2.0) -
603 ((double) renderInfo
->displayHeight
/ 2.0 / renderInfo
->scaleFactorY
);
606 /* ------------------------------------------------------------------ */
608 gerbv_render_translate_to_fit_display (gerbv_project_t
*gerbvProject
, gerbv_render_info_t
*renderInfo
) {
609 gerbv_render_size_t bb
;
611 /* Grab maximal width and height of all layers */
612 gerbv_render_get_boundingbox(gerbvProject
, &bb
);
613 renderInfo
->lowerLeftX
= ((bb
.left
+ bb
.right
) / 2.0) -
614 ((double) renderInfo
->displayWidth
/ 2.0 / renderInfo
->scaleFactorX
);
615 renderInfo
->lowerLeftY
= ((bb
.top
+ bb
.bottom
) / 2.0) -
616 ((double) renderInfo
->displayHeight
/ 2.0 / renderInfo
->scaleFactorY
);
619 /* ------------------------------------------------------------------ */
621 gerbv_render_to_pixmap_using_gdk (gerbv_project_t
*gerbvProject
, GdkPixmap
*pixmap
,
622 gerbv_render_info_t
*renderInfo
, gerbv_selection_info_t
*selectionInfo
,
623 GdkColor
*selectionColor
){
624 GdkGC
*gc
= gdk_gc_new(pixmap
);
625 GdkPixmap
*colorStamp
, *clipmask
;
629 * Remove old pixmap, allocate a new one, draw the background.
631 if (!gerbvProject
->background
.pixel
)
632 gdk_colormap_alloc_color(gdk_colormap_get_system(), &gerbvProject
->background
, FALSE
, TRUE
);
633 gdk_gc_set_foreground(gc
, &gerbvProject
->background
);
634 gdk_draw_rectangle(pixmap
, gc
, TRUE
, 0, 0, -1, -1);
637 * Allocate the pixmap and the clipmask (a one pixel pixmap)
639 colorStamp
= gdk_pixmap_new(pixmap
, renderInfo
->displayWidth
,
640 renderInfo
->displayHeight
, -1);
641 clipmask
= gdk_pixmap_new(NULL
, renderInfo
->displayWidth
,
642 renderInfo
->displayHeight
, 1);
645 * This now allows drawing several layers on top of each other.
646 * Higher layer numbers have higher priority in the Z-order.
648 for(i
= gerbvProject
->last_loaded
; i
>= 0; i
--) {
649 if (gerbvProject
->file
[i
] && gerbvProject
->file
[i
]->isVisible
) {
650 gerbv_polarity_t polarity
;
652 if (gerbvProject
->file
[i
]->transform
.inverted
) {
653 if (gerbvProject
->file
[i
]->image
->info
->polarity
== GERBV_POLARITY_POSITIVE
)
654 polarity
= GERBV_POLARITY_NEGATIVE
;
656 polarity
= GERBV_POLARITY_POSITIVE
;
658 polarity
= gerbvProject
->file
[i
]->image
->info
->polarity
;
662 * Fill up image with all the foreground color. Excess pixels
663 * will be removed by clipmask.
665 if (!gerbvProject
->file
[i
]->color
.pixel
)
666 gdk_colormap_alloc_color(gdk_colormap_get_system(), &gerbvProject
->file
[i
]->color
, FALSE
, TRUE
);
667 gdk_gc_set_foreground(gc
, &gerbvProject
->file
[i
]->color
);
669 /* switch back to regular draw function for the initial
671 gdk_gc_set_function(gc
, GDK_COPY
);
672 gdk_draw_rectangle(colorStamp
, gc
, TRUE
, 0, 0, -1, -1);
674 if (renderInfo
->renderType
== 0) {
675 gdk_gc_set_function(gc
, GDK_COPY
);
677 else if (renderInfo
->renderType
== 1) {
678 gdk_gc_set_function(gc
, GDK_XOR
);
681 * Translation is to get it inside the allocated pixmap,
682 * which is not always centered perfectly for GTK/X.
684 dprintf(" .... calling image2pixmap on image %d...\n", i
);
685 // Dirty scaling solution when using GDK; simply use scaling factor for x-axis, ignore y-axis
686 draw_gdk_image_to_pixmap(&clipmask
, gerbvProject
->file
[i
]->image
,
687 renderInfo
->scaleFactorX
, -(renderInfo
->lowerLeftX
* renderInfo
->scaleFactorX
),
688 (renderInfo
->lowerLeftY
* renderInfo
->scaleFactorY
) + renderInfo
->displayHeight
,
689 polarity
, DRAW_IMAGE
, NULL
, renderInfo
);
692 * Set clipmask and draw the clipped out image onto the
693 * screen pixmap. Afterwards we remove the clipmask, else
694 * it will screw things up when run this loop again.
696 gdk_gc_set_clip_mask(gc
, clipmask
);
697 gdk_gc_set_clip_origin(gc
, 0, 0);
698 gdk_draw_drawable(pixmap
, gc
, colorStamp
, 0, 0, 0, 0, -1, -1);
699 gdk_gc_set_clip_mask(gc
, NULL
);
702 /* render the selection group to the top of the output */
703 if ((selectionInfo
) && (selectionInfo
->type
!= GERBV_SELECTION_EMPTY
)) {
704 if (!selectionColor
->pixel
)
705 gdk_colormap_alloc_color(gdk_colormap_get_system(), selectionColor
, FALSE
, TRUE
);
707 gdk_gc_set_foreground(gc
, selectionColor
);
708 gdk_gc_set_function(gc
, GDK_COPY
);
709 gdk_draw_rectangle(colorStamp
, gc
, TRUE
, 0, 0, -1, -1);
711 /* for now, assume everything in the selection buffer is from one image */
712 gerbv_image_t
*matchImage
;
714 if (selectionInfo
->selectedNodeArray
->len
> 0) {
715 gerbv_selection_item_t sItem
= g_array_index (selectionInfo
->selectedNodeArray
,
716 gerbv_selection_item_t
, 0);
717 matchImage
= (gerbv_image_t
*) sItem
.image
;
719 for(j
= gerbvProject
->last_loaded
; j
>= 0; j
--) {
720 if ((gerbvProject
->file
[j
]) && (gerbvProject
->file
[j
]->image
== matchImage
)) {
721 draw_gdk_image_to_pixmap(&clipmask
, gerbvProject
->file
[j
]->image
,
722 renderInfo
->scaleFactorX
, -(renderInfo
->lowerLeftX
* renderInfo
->scaleFactorX
),
723 (renderInfo
->lowerLeftY
* renderInfo
->scaleFactorY
) + renderInfo
->displayHeight
,
724 GERBV_POLARITY_POSITIVE
, DRAW_SELECTIONS
, selectionInfo
,
728 gdk_gc_set_clip_mask(gc
, clipmask
);
729 gdk_gc_set_clip_origin(gc
, 0, 0);
730 gdk_draw_drawable(pixmap
, gc
, colorStamp
, 0, 0, 0, 0, -1, -1);
731 gdk_gc_set_clip_mask(gc
, NULL
);
735 gdk_pixmap_unref(colorStamp
);
736 gdk_pixmap_unref(clipmask
);
740 /* ------------------------------------------------------------------ */
741 #ifndef RENDER_USING_GDK
743 gerbv_render_all_layers_to_cairo_target_for_vector_output (gerbv_project_t
*gerbvProject
,
744 cairo_t
*cr
, gerbv_render_info_t
*renderInfo
) {
746 gerbv_render_cairo_set_scale_and_translation(cr
, renderInfo
);
747 /* don't paint background for vector output, since it isn't needed */
748 for(i
= gerbvProject
->last_loaded
; i
>= 0; i
--) {
749 if (gerbvProject
->file
[i
] && gerbvProject
->file
[i
]->isVisible
) {
751 gerbv_render_layer_to_cairo_target_without_transforming(cr
, gerbvProject
->file
[i
], renderInfo
);
757 /* ------------------------------------------------------------------ */
758 #ifndef RENDER_USING_GDK
760 gerbv_render_all_layers_to_cairo_target (gerbv_project_t
*gerbvProject
, cairo_t
*cr
,
761 gerbv_render_info_t
*renderInfo
) {
763 /* fill the background with the appropriate color */
764 cairo_set_source_rgba (cr
, (double) gerbvProject
->background
.red
/G_MAXUINT16
,
765 (double) gerbvProject
->background
.green
/G_MAXUINT16
,
766 (double) gerbvProject
->background
.blue
/G_MAXUINT16
, 1);
768 for(i
= gerbvProject
->last_loaded
; i
>= 0; i
--) {
769 if (gerbvProject
->file
[i
] && gerbvProject
->file
[i
]->isVisible
) {
770 cairo_push_group (cr
);
771 gerbv_render_layer_to_cairo_target (cr
, gerbvProject
->file
[i
], renderInfo
);
772 cairo_pop_group_to_source (cr
);
773 cairo_paint_with_alpha (cr
, (double) gerbvProject
->file
[i
]->alpha
/G_MAXUINT16
);
779 /* ------------------------------------------------------------------ */
780 #ifndef RENDER_USING_GDK
782 gerbv_render_layer_to_cairo_target (cairo_t
*cr
, gerbv_fileinfo_t
*fileInfo
,
783 gerbv_render_info_t
*renderInfo
) {
784 gerbv_render_cairo_set_scale_and_translation(cr
, renderInfo
);
785 gerbv_render_layer_to_cairo_target_without_transforming(cr
, fileInfo
, renderInfo
);
789 /* ------------------------------------------------------------------ */
790 #ifndef RENDER_USING_GDK
792 gerbv_render_cairo_set_scale_and_translation(cairo_t
*cr
, gerbv_render_info_t
*renderInfo
){
793 gdouble translateX
, translateY
;
795 translateX
= (renderInfo
->lowerLeftX
* renderInfo
->scaleFactorX
);
796 translateY
= (renderInfo
->lowerLeftY
* renderInfo
->scaleFactorY
);
798 /* renderTypes 0 and 1 use GDK rendering, so we shouldn't have made it
800 if (renderInfo
->renderType
== 2) {
801 cairo_set_tolerance (cr
, 1.5);
802 cairo_set_antialias (cr
, CAIRO_ANTIALIAS_NONE
);
804 else if (renderInfo
->renderType
== 3) {
805 cairo_set_tolerance (cr
, 1);
806 /* disable ALL anti-aliasing for now due to the way cairo is rendering
807 ground planes from PCB output */
808 cairo_set_antialias (cr
, CAIRO_ANTIALIAS_DEFAULT
);
811 /* translate the draw area before drawing. We must translate the whole
812 drawing down an additional displayHeight to account for the negative
814 cairo_translate (cr
, -translateX
, translateY
+ renderInfo
->displayHeight
);
815 /* scale the drawing by the specified scale factor (inverting y since
816 cairo y axis points down) */
817 cairo_scale (cr
, renderInfo
->scaleFactorX
, -renderInfo
->scaleFactorY
);
821 /* ------------------------------------------------------------------ */
822 #ifndef RENDER_USING_GDK
824 gerbv_render_layer_to_cairo_target_without_transforming(cairo_t
*cr
, gerbv_fileinfo_t
*fileInfo
, gerbv_render_info_t
*renderInfo
) {
825 cairo_set_source_rgba (cr
, (double) fileInfo
->color
.red
/G_MAXUINT16
,
826 (double) fileInfo
->color
.green
/G_MAXUINT16
,
827 (double) fileInfo
->color
.blue
/G_MAXUINT16
, 1);
829 /* translate the image based on the layer-specific transformation struct */
831 cairo_translate (cr
, fileInfo
->transform
.translateX
, fileInfo
->transform
.translateY
);
832 draw_image_to_cairo_target (cr
, fileInfo
->image
, fileInfo
->transform
.inverted
,
833 1.0/MAX(renderInfo
->scaleFactorX
, renderInfo
->scaleFactorY
), DRAW_IMAGE
, NULL
,
840 gerbv_attribute_destroy_HID_attribute (gerbv_HID_Attribute
*attributeList
, int n_attr
)
844 /* free the string attributes */
845 for (i
= 0 ; i
< n_attr
; i
++) {
846 if ( (attributeList
[i
].type
== HID_String
||
847 attributeList
[i
].type
== HID_Label
) &&
848 attributeList
[i
].default_val
.str_value
!= NULL
) {
849 free (attributeList
[i
].default_val
.str_value
);
853 /* and free the attribute list */
854 if (attributeList
!= NULL
) {
855 free (attributeList
);
860 /* allocate memory and make a copy of an attribute list */
861 gerbv_HID_Attribute
*
862 gerbv_attribute_dup (gerbv_HID_Attribute
*attributeList
, int n_attr
)
864 gerbv_HID_Attribute
*nl
;
867 nl
= (gerbv_HID_Attribute
*) malloc (n_attr
* sizeof (gerbv_HID_Attribute
));
869 fprintf (stderr
, "%s(): malloc failed\n", __FUNCTION__
);
873 /* copy the attribute list being sure to strdup the strings */
874 for (i
= 0 ; i
< n_attr
; i
++) {
876 if (attributeList
[i
].type
== HID_String
||
877 attributeList
[i
].type
== HID_Label
) {
879 if (attributeList
[i
].default_val
.str_value
!= NULL
) {
880 nl
[i
].default_val
.str_value
= strdup (attributeList
[i
].default_val
.str_value
);
882 nl
[i
].default_val
.str_value
= NULL
;
886 nl
[i
] = attributeList
[i
];