60 Commits

Author SHA1 Message Date
a5d794461a Add license 2018-07-23 15:26:51 +02:00
6fb4d39fc8 Add application menu and about dialog 2018-07-23 15:10:40 +02:00
d0e1383861 reconstructed code to use g_application 2018-07-23 13:10:34 +02:00
6296627ac2 Merge branch 'master' of git.shimatta.de:mhu/gds-render 2018-07-23 09:59:26 +02:00
f79bab102b Remove Bounding box calculations from parser. They're not needed 2018-07-23 09:58:14 +02:00
e5300e60aa Color of Load layer mapping button changed to blue 2018-07-22 16:55:20 +02:00
4c5784c3a4 finished first version of Cairo export 2018-07-22 16:38:26 +02:00
f765e27ce8 fix rendering of box in cairo renderer 2018-07-20 23:29:27 +02:00
40760725b8 Merge branch 'master' into cairo-dev 2018-07-20 23:26:50 +02:00
dac834aef2 auto detect glade files 2018-07-20 23:22:47 +02:00
d4f2d6798e Merge branch 'master' into cairo-dev 2018-07-20 22:41:16 +02:00
f8cbf7e066 use enum name instead of pure integer value 2018-07-20 22:36:54 +02:00
59ec0c5a10 cairo layer renderer 2018-07-20 22:32:23 +02:00
2a615367d7 Add advanced export settings for LaTeX export 2018-07-19 22:09:58 +02:00
3167da4648 cairo output started 2018-07-19 18:45:37 +02:00
b72466957c Added variable scaling factor for Tex output 2018-07-19 17:54:05 +02:00
d9f0f3cdd5 settings dialog fully implemented 2018-07-19 17:49:33 +02:00
4c04ce3614 further implementation of settings dialog 2018-07-19 16:38:52 +02:00
a2bc980c64 dialog implementation 2018-07-19 15:47:57 +02:00
73ea4d6838 re-organized folder structure 2018-07-19 15:11:18 +02:00
526785cffd add dialog to compile resources 2018-07-19 15:07:20 +02:00
6a8b359f3d add dialog for conversion options 2018-07-19 15:05:44 +02:00
bbd731401d add support for boxes 2018-07-17 00:02:30 +02:00
7734467ea9 Use cairo for path bounding box 2018-07-11 12:24:15 +02:00
7d66ca1280 Support for magnification, bounding boxes fully implemented 2018-07-04 21:46:39 +02:00
542737622f smaller fixes, started boundary box scanner. Rotation, scaling and flipping is not handled correctly yet 2018-07-04 09:49:04 +02:00
221d5a5db5 important Bugfix. Flipping direction in LaTeX renderer fixed 2018-06-12 18:33:13 +02:00
a531da26d3 Merge branch 'master' of git.shimatta.de:mhu/gds-render 2018-06-11 15:18:02 +02:00
f913976a44 replaced date parser by shorter but more complicated code 2018-06-11 15:16:40 +02:00
da19037211 Activate -Wall compile flag, Fix code not to throw warnings 2018-06-05 22:51:50 +02:00
3ed83c1146 open GDS File in binary mode 2018-06-04 12:26:31 +02:00
9d10b17d7d add 0x prefix for hex number 2018-06-04 12:05:53 +02:00
ea53890cd0 Move delete-event signal connect from glade to C-File 2018-06-04 11:41:35 +02:00
88815bc007 Fix implicit function declaration 2018-06-04 11:37:36 +02:00
288965af7b move example alyouts+rendered outputs into subfolders 2018-06-02 02:58:56 +02:00
690c1cb5ae Implement full path support with correct line caps (rounded|flat|squared) 2018-06-02 02:54:38 +02:00
0f4de608a2 Enabled parser to detect path-types, fix indentation 2018-06-02 02:25:01 +02:00
d1a1cb762a update eymaples 2018-06-01 21:48:10 +02:00
223a2c6e71 add support for paths 2018-06-01 21:47:54 +02:00
27cb06afe2 Add example GDS file, mapping file, and output files generated 2018-05-31 02:18:05 +02:00
1c4ccd9153 Support for standalone rendering 2018-05-31 02:16:37 +02:00
dc208c6ad3 fix bug in parser 2018-05-31 02:16:12 +02:00
8455491c11 fix syntax error in exported LaTeX code 2018-05-31 00:08:02 +02:00
58c7f571f4 fix type cast warning 2018-05-31 00:06:00 +02:00
0290a6c9d3 Layer support added 2018-05-31 00:04:14 +02:00
9b7073604b Merge branch 'master' of git.shimatta.de:mhu/gds-render 2018-05-30 23:57:00 +02:00
f2c58e4520 LaTeX Layer support started 2018-05-30 23:56:38 +02:00
c1a7dce0a3 Add directory for rendering example 2018-05-27 16:53:02 +02:00
37a561115a fix: gtk_widget_destroy: assertion 'GTK_IS_WIDGET (widget)' failed 2018-05-24 00:36:55 +02:00
1ffe677804 Fix 2nd segfault 2018-05-24 00:23:39 +02:00
2c3c7a9a80 fix Segfault 2018-05-24 00:15:39 +02:00
da34256b83 Remove lonely 'Foo' 2018-05-23 14:22:02 +02:00
93b726a05f TeX output works
* A lot is missing (paths...)
* Dimension limit of TeX is a problem.
2018-05-23 13:17:10 +02:00
6c24cebaf7 Drag and drop layer arrangement. Major Feature 2018-05-23 01:03:16 +02:00
084c6999c7 Add option to specify layer order, wrote tex output for layer order 2018-05-22 18:45:23 +02:00
a261f61c5c fix commit 2018-05-22 16:18:28 +02:00
29f66951d1 Completely restructudred code
* Subfolders for different modules
* LaTeX output module started
* Convert button sensitivity impemented
2018-05-22 16:17:14 +02:00
9a6aee1410 Make only Cells selectable 2018-05-22 13:00:50 +02:00
4987459337 restructured code 2018-05-22 12:59:28 +02:00
1db0ac1d17 Optimized Layout in Header Bar 2018-05-22 12:47:44 +02:00
37 changed files with 18136 additions and 548 deletions

View File

@@ -2,30 +2,37 @@ cmake_minimum_required(VERSION 2.8)
find_package(PkgConfig REQUIRED)
pkg_search_module(GLIB REQUIRED glib-2.0)
pkg_check_modules(GTK3 REQUIRED gtk+-3.0)
pkg_check_modules(CAIRO REQUIRED cairo)
project(gds-render)
add_subdirectory(glade)
include_directories(${GLIB_INCLUDE_DIRS} ${GTK3_INCLUDE_DIRS} "layer-widget")
link_directories(${GLIB_LINK_DIRS} ${GTK3_LINK_DIRS})
include_directories(${GLIB_INCLUDE_DIRS} ${GTK3_INCLUDE_DIRS} ${CAIRO_INCLUDE_DIRS})
link_directories(${GLIB_LINK_DIRS} ${GTK3_LINK_DIRS} ${CAIRO_LINK_DIRS})
add_definitions(${GLIB2_CFLAGS_OTHER})
aux_source_directory("layer-widget" SUB_SOURCES)
aux_source_directory("widgets" LAYER_SOURCES)
aux_source_directory("tree-renderer" RENDERER_SOURCES)
set(SOURCE "main.c" "gdsparse.c" "layer-selector.c")
aux_source_directory("gds-parser" PARSER_SOURCES)
aux_source_directory("latex-output" LATEX_SOURCES)
aux_source_directory("cairo-output" CAIRO_SOURCES)
set(SOURCE "main.c" "layer-selector.c" "main-window.c")
set(SOURCE
${SOURCE}
${SUB_SOURCES}
${LAYER_SOURCES}
${RENDERER_SOURCES}
${PARSER_SOURCES}
${LATEX_SOURCES}
${CAIRO_SOURCES}
)
add_compile_options(-Wall)
add_executable(${PROJECT_NAME} ${SOURCE} ${CMAKE_CURRENT_BINARY_DIR}/glade/resources.c)
add_dependencies(${PROJECT_NAME} glib-resources)
SET_SOURCE_FILES_PROPERTIES(${CMAKE_CURRENT_BINARY_DIR}/glade/resources.c PROPERTIES GENERATED 1)
target_link_libraries(${PROJECT_NAME} ${GLIB_LDFLAGS} ${GTK3_LDFLAGS} m)
target_link_libraries(${PROJECT_NAME} ${GLIB_LDFLAGS} ${GTK3_LDFLAGS} ${CAIRO_LDFLAGS} m)

248
cairo-output/cairo-output.c Normal file
View File

@@ -0,0 +1,248 @@
/*
* GDSII-Converter
* Copyright (C) 2018 Mario Hüttel <mario.huettel@gmx.net>
*
* This file is part of GDSII-Converter.
*
* GDSII-Converter is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*
* GDSII-Converter is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with GDSII-Converter. If not, see <http://www.gnu.org/licenses/>.
*/
#include "cairo-output.h"
#include <math.h>
#include <stdlib.h>
#include <cairo.h>
#include <cairo-pdf.h>
struct cairo_layer {
cairo_t *cr;
cairo_surface_t *rec;
struct layer_info *linfo;
};
static void revert_inherited_transform(struct cairo_layer *layers)
{
int i;
for (i = 0; i < MAX_LAYERS; i++) {
if (layers[i].cr == NULL)
continue;
cairo_restore(layers[i].cr);
}
}
static void apply_inherited_transform_to_all_layers(struct cairo_layer *layers,
const struct gds_point *origin,
double magnification,
gboolean flipping,
double rotation,
double scale)
{
int i;
cairo_t *temp_layer_cr;
for (i = 0; i < MAX_LAYERS; i++) {
temp_layer_cr = layers[i].cr;
if (temp_layer_cr == NULL)
continue;
/* Save the state and apply transformation */
cairo_save(temp_layer_cr);
cairo_translate(temp_layer_cr, (double)origin->x/scale, (double)origin->y/scale);
cairo_rotate(temp_layer_cr, M_PI*rotation/180.0);
cairo_scale(temp_layer_cr, magnification,
(flipping == TRUE ? -magnification : magnification));
}
}
static void render_cell(struct gds_cell *cell, struct cairo_layer *layers, double scale)
{
GList *instance_list;
struct gds_cell *temp_cell;
struct gds_cell_instance *cell_instance;
GList *gfx_list;
struct gds_graphics *gfx;
GList *vertex_list;
struct gds_point *vertex;
cairo_t *cr;
/* Render child cells */
for (instance_list = cell->child_cells; instance_list != NULL; instance_list = instance_list->next) {
cell_instance = (struct gds_cell_instance *)instance_list->data;
if ((temp_cell = cell_instance->cell_ref) != NULL) {
apply_inherited_transform_to_all_layers(layers,
&cell_instance->origin,
cell_instance->magnification,
cell_instance->flipped,
cell_instance->angle,
scale);
render_cell(temp_cell, layers, scale);
revert_inherited_transform(layers);
}
}
/* Render graphics */
for (gfx_list = cell->graphic_objs; gfx_list != NULL; gfx_list = gfx_list->next) {
gfx = (struct gds_graphics *)gfx_list->data;
/* Get layer renderer */
if (gfx->layer >= MAX_LAYERS)
continue;
if ((cr = layers[gfx->layer].cr) == NULL)
continue;
/* Apply settings */
cairo_set_line_width(cr, (gfx->width_absolute ? gfx->width_absolute/scale : 1));
switch (gfx->path_render_type) {
case PATH_FLUSH:
cairo_set_line_cap(cr, CAIRO_LINE_CAP_BUTT);
break;
case PATH_ROUNDED:
cairo_set_line_cap(cr, CAIRO_LINE_CAP_ROUND);
break;
case PATH_SQUARED:
cairo_set_line_cap(cr, CAIRO_LINE_CAP_SQUARE);
break;
}
/* Add vertices */
for (vertex_list = gfx->vertices; vertex_list != NULL; vertex_list = vertex_list->next) {
vertex = (struct gds_point *)vertex_list->data;
/* If first point -> move to, else line to */
if (vertex_list->prev == NULL)
cairo_move_to(cr, vertex->x/scale, vertex->y/scale);
else
cairo_line_to(cr, vertex->x/scale, vertex->y/scale);
}
/* Create graphics object */
switch (gfx->gfx_type) {
case GRAPHIC_PATH:
cairo_stroke(cr);
break;
case GRAPHIC_BOX:
case GRAPHIC_POLYGON:
cairo_set_line_width(cr, 0.1/scale);
cairo_close_path(cr);
cairo_stroke_preserve(cr); // Prevent graphic glitches
cairo_fill(cr);
break;
}
}
}
void cairo_render_cell_to_pdf(struct gds_cell *cell, GList *layer_infos, char *pdf_file, double scale)
{
cairo_surface_t *pdf_surface;
cairo_t *pdf_cr;
struct layer_info *linfo;
struct cairo_layer *layers;
struct cairo_layer *lay;
GList *info_list;
int i;
double rec_x0, rec_y0, rec_width, rec_height;
double xmin = INT32_MAX, xmax = INT32_MIN, ymin = INT32_MAX, ymax = INT32_MIN;
layers = (struct cairo_layer *)calloc(MAX_LAYERS, sizeof(struct cairo_layer));
/* Clear layers */
for (i = 0; i < MAX_LAYERS; i++) {
layers[i].cr = NULL;
layers[i].rec = NULL;
}
/* Create recording surface for each layer */
for (info_list = layer_infos; info_list != NULL; info_list = g_list_next(info_list)) {
linfo = (struct layer_info *)info_list->data;
if (linfo->layer < MAX_LAYERS) {
lay = &(layers[(unsigned int)linfo->layer]);
lay->linfo = linfo;
lay->rec = cairo_recording_surface_create(CAIRO_CONTENT_COLOR_ALPHA,
NULL);
lay->cr = cairo_create(layers[(unsigned int)linfo->layer].rec);
cairo_scale(lay->cr, 1, -1); // Fix coordinate system
cairo_set_source_rgb(lay->cr, linfo->color.red, linfo->color.green, linfo->color.blue);
} else {
printf("Layer number (%d) too high!\n", linfo->layer);
goto ret_clear_layers;
}
}
render_cell(cell, layers, scale);
/* get size of image and top left coordinate */
for (info_list = layer_infos; info_list != NULL; info_list = g_list_next(info_list)) {
linfo = (struct layer_info *)info_list->data;
if (linfo->layer >= MAX_LAYERS) {
printf("Layer outside of Spec.\n");
continue;
}
/* Print size */
cairo_recording_surface_ink_extents(layers[linfo->layer].rec, &rec_x0, &rec_y0,
&rec_width, &rec_height);
printf("Size of layer %d: %lf -- %lf\n", linfo->layer,
rec_width, rec_height);
/* update bounding box */
xmin = MIN(xmin, rec_x0);
xmax = MAX(xmax, rec_x0);
ymin = MIN(ymin, rec_y0);
ymax = MAX(ymax, rec_y0);
xmin = MIN(xmin, rec_x0+rec_width);
xmax = MAX(xmax, rec_x0+rec_width);
ymin = MIN(ymin, rec_y0+rec_height);
ymax = MAX(ymax, rec_y0+rec_height);
}
printf("Bounding box: (%lf,%lf) -- (%lf,%lf)\n", xmin, ymin, xmax, ymax);
pdf_surface = cairo_pdf_surface_create(pdf_file, xmax-xmin, ymax-ymin);
pdf_cr = cairo_create(pdf_surface);
/* Write layers to PDF */
for (info_list = layer_infos; info_list != NULL; info_list = g_list_next(info_list)) {
linfo = (struct layer_info *)info_list->data;
if (linfo->layer >= MAX_LAYERS) {
printf("Layer outside of Spec.\n");
continue;
}
cairo_set_source_surface(pdf_cr, layers[linfo->layer].rec, -xmin, -ymin);
cairo_paint_with_alpha(pdf_cr, linfo->color.alpha);
}
cairo_show_page(pdf_cr);
cairo_destroy(pdf_cr);
cairo_surface_destroy(pdf_surface);
ret_clear_layers:
for (i = 0; i < MAX_LAYERS; i++) {
lay = &layers[i];
if(lay->cr) {
cairo_destroy(lay->cr);
cairo_surface_destroy(lay->rec);
}
}
free(layers);
printf("cairo export finished. It might still be buggy!\n");
}

View File

@@ -0,0 +1,30 @@
/*
* GDSII-Converter
* Copyright (C) 2018 Mario Hüttel <mario.huettel@gmx.net>
*
* This file is part of GDSII-Converter.
*
* GDSII-Converter is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*
* GDSII-Converter is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with GDSII-Converter. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef __CAIRO_OUTPUT_H__
#define __CAIRO_OUTPUT_H__
#include "../layer-selector.h"
#include "../gds-parser/gds-types.h"
#define MAX_LAYERS (300)
void cairo_render_cell_to_pdf(struct gds_cell *cell, GList *layer_infos, char *pdf_file, double scale);
#endif /* __CAIRO_OUTPUT_H__ */

View File

@@ -27,12 +27,13 @@
*/
#include "gdsparse.h"
#include "gds-parser.h"
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <stdbool.h>
#include <math.h>
#include <cairo.h>
#define GDS_ERROR(fmt, ...) printf("[PARSE_ERROR] " fmt "\n", ##__VA_ARGS__)
#define GDS_WARN(fmt, ...) printf("[PARSE_WARNING] " fmt "\n", ##__VA_ARGS__)
@@ -58,6 +59,8 @@ enum record {
STRANS = 0x1A01,
BOX = 0x2D00,
LAYER = 0x0D02,
WIDTH = 0x0F03,
PATHTYPE = 0x2102
};
static int name_cell_ref(struct gds_cell_instance *cell_inst,
@@ -188,7 +191,8 @@ static GList *append_graphics(GList *curr_list, enum graphics_type type,
gfx->layer = 0;
gfx->vertices = NULL;
gfx->width_absolute = 0;
gfx->type = type;
gfx->gfx_type = type;
gfx->path_render_type = PATH_FLUSH;
} else
return NULL;
@@ -299,7 +303,7 @@ static int name_cell(struct gds_cell *cell, unsigned int bytes,
}
void parse_reference_list(gpointer gcell_ref, gpointer glibrary)
static void parse_reference_list(gpointer gcell_ref, gpointer glibrary)
{
struct gds_cell_instance *inst = (struct gds_cell_instance *)gcell_ref;
struct gds_library *lib = (struct gds_library *)glibrary;
@@ -325,7 +329,7 @@ void parse_reference_list(gpointer gcell_ref, gpointer glibrary)
GDS_WARN("referenced cell could not be found in library");
}
void scan_cell_reference_dependencies(gpointer gcell, gpointer library)
static void scan_cell_reference_dependencies(gpointer gcell, gpointer library)
{
struct gds_cell *cell = (struct gds_cell *)gcell;
@@ -336,7 +340,7 @@ void scan_cell_reference_dependencies(gpointer gcell, gpointer library)
}
void scan_library_references(gpointer library_list_item, gpointer user)
static void scan_library_references(gpointer library_list_item, gpointer user)
{
struct gds_library *lib = (struct gds_library *)library_list_item;
@@ -344,8 +348,11 @@ void scan_library_references(gpointer library_list_item, gpointer user)
g_list_foreach(lib->cells, scan_cell_reference_dependencies, lib);
}
void gds_parse_date(const char *buffer, int length, struct gds_time_field *mod_date, struct gds_time_field *access_date)
static void gds_parse_date(const char *buffer, int length, struct gds_time_field *mod_date, struct gds_time_field *access_date)
{
struct gds_time_field *temp_date;
if (!access_date || !mod_date) {
GDS_WARN("Date structures invalid");
return;
@@ -356,37 +363,28 @@ void gds_parse_date(const char *buffer, int length, struct gds_time_field *mod_d
return;
}
mod_date->year = gds_convert_unsigend_int16(buffer);
buffer += 2;
mod_date->month = gds_convert_unsigend_int16(buffer);
buffer += 2;
mod_date->day = gds_convert_unsigend_int16(buffer);
buffer += 2;
mod_date->hour = gds_convert_unsigend_int16(buffer);
buffer += 2;
mod_date->minute = gds_convert_unsigend_int16(buffer);
buffer += 2;
mod_date->second = gds_convert_unsigend_int16(buffer);
buffer += 2;
access_date->year = gds_convert_unsigend_int16(buffer);
buffer += 2;
access_date->month = gds_convert_unsigend_int16(buffer);
buffer += 2;
access_date->day = gds_convert_unsigend_int16(buffer);
buffer += 2;
access_date->hour = gds_convert_unsigend_int16(buffer);
buffer += 2;
access_date->minute = gds_convert_unsigend_int16(buffer);
buffer += 2;
access_date->second = gds_convert_unsigend_int16(buffer);
for (temp_date = mod_date; 1; temp_date = access_date) {
temp_date->year = gds_convert_unsigend_int16(buffer);
buffer += 2;
temp_date->month = gds_convert_unsigend_int16(buffer);
buffer += 2;
temp_date->day = gds_convert_unsigend_int16(buffer);
buffer += 2;
temp_date->hour = gds_convert_unsigend_int16(buffer);
buffer += 2;
temp_date->minute = gds_convert_unsigend_int16(buffer);
buffer += 2;
temp_date->second = gds_convert_unsigend_int16(buffer);
buffer += 2;
if (temp_date == access_date)
break;
}
}
int parse_gds_from_file(const char *filename, GList **library_list)
{
char workbuff[1024];
char *workbuff;
int read;
int i;
int run = 1;
@@ -403,8 +401,14 @@ int parse_gds_from_file(const char *filename, GList **library_list)
lib_list = *library_list;
/* Allocate working buffer */
workbuff = (char *)malloc(sizeof(char)*128*1024);
if(!workbuff)
return -100;
/* open File */
gds_file = fopen(filename, "r");
gds_file = fopen(filename, "rb");
if (gds_file == NULL) {
GDS_ERROR("Could not open File %s", filename);
return -1;
@@ -427,8 +431,7 @@ int parse_gds_from_file(const char *filename, GList **library_list)
break;
}
rec_data_length = (uint16_t)((((uint16_t)(workbuff[0])) << 8) |
(uint16_t)(workbuff[1]));
rec_data_length = gds_convert_unsigend_int16(workbuff);
if (rec_data_length < 4) {
/* Possible Zero-Padding: */
@@ -451,8 +454,7 @@ int parse_gds_from_file(const char *filename, GList **library_list)
GDS_ERROR("Unexpected end of file");
break;
}
rec_type = (uint16_t)((((uint16_t)(workbuff[0])) << 8) |
(uint16_t)(workbuff[1]));
rec_type = gds_convert_unsigend_int16(workbuff);
/* if begin: Allocate structures */
switch (rec_type) {
@@ -506,21 +508,22 @@ int parse_gds_from_file(const char *filename, GList **library_list)
current_cell = NULL;
printf("Leaving Cell\n");
break;
//case BOX:
case BOX:
case BOUNDARY:
if (current_cell == NULL) {
GDS_ERROR("Boundary outside of cell");
GDS_ERROR("Boundary/Box outside of cell");
run = -3;
break;
}
current_cell->graphic_objs = append_graphics(current_cell->graphic_objs,
GRAPHIC_POLYGON, &current_graphics);
(rec_type == BOUNDARY ? GRAPHIC_POLYGON : GRAPHIC_BOX),
&current_graphics);
if (current_cell->graphic_objs == NULL) {
GDS_ERROR("Memory allocation failed");
run = -4;
break;
}
printf("\tEntering boundary\n");
printf("\tEntering boundary/Box\n");
break;
case SREF:
if (current_cell == NULL) {
@@ -556,7 +559,7 @@ int parse_gds_from_file(const char *filename, GList **library_list)
case ENDEL:
if (current_graphics != NULL) {
printf("\tLeaving %s\n", (current_graphics->type == GRAPHIC_POLYGON ? "boundary" : "path"));
printf("\tLeaving %s\n", (current_graphics->gfx_type == GRAPHIC_POLYGON ? "boundary" : "path"));
current_graphics = NULL;
}
if (current_s_reference != NULL) {
@@ -574,12 +577,17 @@ int parse_gds_from_file(const char *filename, GList **library_list)
}
break;
case MAG:
break;
case ANGLE:
break;
case STRANS:
break;
case WIDTH:
break;
case PATHTYPE:
break;
default:
//GDS_WARN("Record: %04x, len: %u", (unsigned int)rec_type, (unsigned int)rec_data_length);
break;
@@ -592,12 +600,26 @@ int parse_gds_from_file(const char *filename, GList **library_list)
read = fread(workbuff, sizeof(char), rec_data_length, gds_file);
if (read != rec_data_length) {
GDS_ERROR("Could not read enough data");
GDS_ERROR("Could not read enough data: requested: %u, read: %u | Type: 0x%04x\n",
(unsigned int)rec_data_length, (unsigned int)read, (unsigned int)rec_type);
run = -5;
break;
}
switch (rec_type) {
case HEADER:
case UNITS:
case ENDLIB:
case ENDSTR:
case BOUNDARY:
case PATH:
case SREF:
case ENDEL:
case BOX:
case INVALID:
break;
case BGNLIB:
/* Parse date record */
gds_parse_date(workbuff, read, &current_lib->mod_time, &current_lib->access_time);
@@ -640,6 +662,12 @@ int parse_gds_from_file(const char *filename, GList **library_list)
case SNAME:
name_cell_ref(current_s_reference, read, workbuff);
break;
case WIDTH:
if (!current_graphics) {
GDS_WARN("Width defined outside of path element");
}
current_graphics->width_absolute = gds_convert_signed_int(workbuff);
break;
case LAYER:
if (!current_graphics) {
GDS_WARN("Layer has to be defined inside graphics object. Probably unknown object. Implement it yourself!");
@@ -679,6 +707,18 @@ int parse_gds_from_file(const char *filename, GList **library_list)
printf("\t\tAngle defined: %lf\n", current_s_reference->angle);
}
break;
case PATHTYPE:
if (current_graphics == NULL) {
GDS_WARN("Path type defined outside of path. Ignoring");
break;
}
if (current_graphics->gfx_type == GRAPHIC_PATH) {
current_graphics->path_render_type = (int)gds_convert_signed_int16(workbuff);
printf("\t\tPathtype: %d\n", current_graphics->path_render_type);
} else {
GDS_WARN("Path type defined inside non-path graphics object. Ignoring");
}
break;
}
@@ -687,10 +727,18 @@ int parse_gds_from_file(const char *filename, GList **library_list)
fclose(gds_file);
/* Iterate and find references to cells */
g_list_foreach(lib_list, scan_library_references, NULL);
if (!run) {
/* Iterate and find references to cells */
g_list_foreach(lib_list, scan_library_references, NULL);
}
*library_list = lib_list;
free(workbuff);
return run;
}

63
gds-parser/gds-types.h Normal file
View File

@@ -0,0 +1,63 @@
#ifndef __GDS_TYPES_H__
#define __GDS_TYPES_H__
#include <stdint.h>
#include <glib.h>
#define CELL_NAME_MAX (100)
#define MIN(a,b) (((a) < (b)) ? (a) : (b))
#define MAX(a,b) (((a) > (b)) ? (a) : (b))
enum graphics_type {GRAPHIC_PATH = 0, GRAPHIC_POLYGON = 1, GRAPHIC_BOX};
enum path_type {PATH_FLUSH = 0, PATH_ROUNDED = 1, PATH_SQUARED = 2};
struct gds_point {
int x;
int y;
};
struct gds_time_field {
uint16_t year;
uint16_t month;
uint16_t day;
uint16_t hour;
uint16_t minute;
uint16_t second;
};
struct gds_graphics {
enum graphics_type gfx_type;
GList *vertices;
enum path_type path_render_type;
int width_absolute;
int16_t layer;
uint16_t datatype;
};
struct gds_cell_instance {
char ref_name[CELL_NAME_MAX];
struct gds_cell *cell_ref;
struct gds_point origin;
int flipped;
double angle;
double magnification;
};
struct gds_cell {
char name[CELL_NAME_MAX];
struct gds_time_field mod_time;
struct gds_time_field access_time;
GList *child_cells;
GList *graphic_objs;
};
struct gds_library {
char name[CELL_NAME_MAX];
struct gds_time_field mod_time;
struct gds_time_field access_time;
double unit_to_meters;
GList *cells;
GList *cell_names;
};
#endif /* __GDS_TYPES_H__ */

View File

@@ -1,59 +0,0 @@
#ifndef __GDS_TYPES_H__
#define __GDS_TYPES_H__
#include <stdint.h>
#define CELL_NAME_MAX (100)
enum graphics_type {GRAPHIC_PATH = 0, GRAPHIC_POLYGON = 1};
struct gds_time_field {
uint16_t year;
uint16_t month;
uint16_t day;
uint16_t hour;
uint16_t minute;
uint16_t second;
};
struct gds_point {
int x;
int y;
};
struct gds_graphics {
enum graphics_type type;
GList *vertices;
unsigned int path_width;
int width_absolute;
int16_t layer;
uint16_t datatype;
};
struct gds_cell_instance {
char ref_name[CELL_NAME_MAX];
struct gds_cell *cell_ref;
struct gds_point origin;
int flipped;
double angle;
double magnification;
};
struct gds_cell {
char name[CELL_NAME_MAX];
struct gds_time_field mod_time;
struct gds_time_field access_time;
GList *child_cells;
GList *graphic_objs;
};
struct gds_library {
char name[CELL_NAME_MAX];
struct gds_time_field mod_time;
struct gds_time_field access_time;
double unit_to_meters;
GList *cells;
GList *cell_names;
};
#endif /* __GDS_TYPES_H__ */

View File

@@ -1,8 +1,6 @@
add_custom_target(glib-resources DEPENDS ${CMAKE_CURRENT_BINARY_DIR}/resources.c)
add_custom_command(DEPENDS
${CMAKE_CURRENT_SOURCE_DIR}/resources.xml
${CMAKE_CURRENT_SOURCE_DIR}/main.glade
${CMAKE_CURRENT_SOURCE_DIR}/layer-widget.glade
${CMAKE_CURRENT_SOURCE_DIR}/*.glade
OUTPUT
${CMAKE_CURRENT_BINARY_DIR}/resources.c
COMMAND

43
glade/about.glade Normal file
View File

@@ -0,0 +1,43 @@
<?xml version="1.0" encoding="UTF-8"?>
<!-- Generated with glade 3.22.1 -->
<interface>
<requires lib="gtk+" version="3.20"/>
<object class="GtkAboutDialog" id="about-dialog">
<property name="can_focus">False</property>
<property name="type_hint">dialog</property>
<property name="program_name">GDS-Render Tool </property>
<property name="comments" translatable="yes">Tool for rendering GDS(II) layout files into LaTeX/TikZ code or directly into a PDF file</property>
<property name="website">https://git.shimatta.de/mhu/gds-render</property>
<property name="website_label" translatable="yes">Git Repository</property>
<property name="authors">Mario Hüttel &lt;mario.huettel@gmx.net&gt;</property>
<property name="logo_icon_name">applications-graphics</property>
<property name="license_type">gpl-2-0-only</property>
<child>
<placeholder/>
</child>
<child internal-child="vbox">
<object class="GtkBox">
<property name="can_focus">False</property>
<property name="orientation">vertical</property>
<property name="spacing">2</property>
<child internal-child="action_area">
<object class="GtkButtonBox">
<property name="can_focus">False</property>
<property name="layout_style">end</property>
<child>
<placeholder/>
</child>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">False</property>
<property name="position">0</property>
</packing>
</child>
<child>
<placeholder/>
</child>
</object>
</child>
</object>
</interface>

90
glade/dialog.glade Normal file
View File

@@ -0,0 +1,90 @@
<?xml version="1.0" encoding="UTF-8"?>
<!-- Generated with glade 3.22.1 -->
<interface>
<requires lib="gtk+" version="3.20"/>
<object class="GtkAdjustment" id="adjustment1">
<property name="lower">1</property>
<property name="upper">3000</property>
<property name="value">1000</property>
<property name="step_increment">10</property>
<property name="page_increment">1000</property>
</object>
<object class="GtkBox" id="dialog-box">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="orientation">vertical</property>
<child>
<object class="GtkRadioButton" id="latex-radio">
<property name="label" translatable="yes">Generate LaTeX/TikZ output</property>
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="receives_default">False</property>
<property name="active">True</property>
<property name="draw_indicator">True</property>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="position">0</property>
</packing>
</child>
<child>
<object class="GtkRadioButton" id="cairo-radio">
<property name="label" translatable="yes">Render PDF using Cairographics</property>
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="receives_default">False</property>
<property name="active">True</property>
<property name="draw_indicator">True</property>
<property name="group">latex-radio</property>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="position">1</property>
</packing>
</child>
<child>
<object class="GtkScale" id="dialog-scale">
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="adjustment">adjustment1</property>
<property name="round_digits">0</property>
<property name="digits">0</property>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="position">2</property>
</packing>
</child>
<child>
<object class="GtkCheckButton" id="standalone-check">
<property name="label" translatable="yes">Configure LaTeX as standalone document</property>
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="receives_default">False</property>
<property name="draw_indicator">True</property>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="position">3</property>
</packing>
</child>
<child>
<object class="GtkCheckButton" id="layer-check">
<property name="label" translatable="yes">Generate PDF Layers</property>
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="receives_default">False</property>
<property name="draw_indicator">True</property>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="position">4</property>
</packing>
</child>
</object>
</interface>

View File

@@ -12,6 +12,24 @@
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="spacing">3</property>
<child>
<object class="GtkEventBox" id="event-box">
<property name="visible">True</property>
<property name="can_focus">False</property>
<child>
<object class="GtkImage">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="stock">gtk-justify-fill</property>
</object>
</child>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="position">0</property>
</packing>
</child>
<child>
<object class="GtkLabel" id="layer">
<property name="visible">True</property>
@@ -21,7 +39,7 @@
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="position">0</property>
<property name="position">1</property>
</packing>
</child>
<child>
@@ -36,7 +54,7 @@
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="position">1</property>
<property name="position">2</property>
</packing>
</child>
<child>
@@ -50,7 +68,7 @@
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="position">2</property>
<property name="position">3</property>
</packing>
</child>
<child>
@@ -61,7 +79,7 @@
<packing>
<property name="expand">True</property>
<property name="fill">True</property>
<property name="position">3</property>
<property name="position">4</property>
</packing>
</child>
</object>

View File

@@ -3,9 +3,8 @@
<interface>
<requires lib="gtk+" version="3.20"/>
<object class="GtkWindow" id="main-window">
<property name="visible">True</property>
<property name="height_request">250</property>
<property name="can_focus">False</property>
<signal name="delete-event" handler="on_window_close" swapped="no"/>
<child type="titlebar">
<object class="GtkHeaderBar">
<property name="name">header</property>
@@ -15,63 +14,66 @@
<property name="subtitle" translatable="yes">GDSII to PDF Converter</property>
<property name="show_close_button">True</property>
<child>
<object class="GtkBox">
<object class="GtkButton" id="button-load-gds">
<property name="label">gtk-open</property>
<property name="visible">True</property>
<property name="can_focus">False</property>
<child>
<object class="GtkButton" id="button-load-gds">
<property name="label">gtk-open</property>
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="receives_default">True</property>
<property name="use_stock">True</property>
<property name="always_show_image">True</property>
<style>
<class name="suggested-action"/>
</style>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="position">0</property>
</packing>
</child>
<child>
<object class="GtkButton" id="button-load-mapping">
<property name="label" translatable="yes">Load Mapping</property>
<property name="visible">True</property>
<property name="sensitive">False</property>
<property name="can_focus">True</property>
<property name="receives_default">True</property>
<style>
<class name="destructive-action"/>
</style>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="position">2</property>
</packing>
</child>
<child>
<object class="GtkButton" id="button-save-mapping">
<property name="label" translatable="yes">Save Mapping</property>
<property name="visible">True</property>
<property name="sensitive">False</property>
<property name="can_focus">True</property>
<property name="receives_default">True</property>
<style>
<class name="suggested-action"/>
</style>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="position">3</property>
</packing>
</child>
<property name="can_focus">True</property>
<property name="receives_default">True</property>
<property name="use_stock">True</property>
<property name="always_show_image">True</property>
<style>
<class name="suggested-action"/>
</style>
</object>
</child>
<child>
<object class="GtkButton" id="button-load-mapping">
<property name="label" translatable="yes">Load Mapping</property>
<property name="visible">True</property>
<property name="sensitive">False</property>
<property name="can_focus">True</property>
<property name="receives_default">True</property>
<style>
<class name="suggested-action"/>
</style>
</object>
<packing>
<property name="position">1</property>
</packing>
</child>
<child>
<object class="GtkButton" id="button-save-mapping">
<property name="label" translatable="yes">Save Mapping</property>
<property name="visible">True</property>
<property name="sensitive">False</property>
<property name="can_focus">True</property>
<property name="receives_default">True</property>
<style>
<class name="suggested-action"/>
</style>
</object>
<packing>
<property name="position">2</property>
</packing>
</child>
<child>
<object class="GtkButton" id="convert-button">
<property name="label">gtk-convert</property>
<property name="name">button-convert</property>
<property name="visible">True</property>
<property name="sensitive">False</property>
<property name="can_focus">True</property>
<property name="receives_default">True</property>
<property name="use_stock">True</property>
<property name="always_show_image">True</property>
<style>
<class name="suggested-action"/>
</style>
</object>
<packing>
<property name="position">3</property>
</packing>
</child>
</object>
</child>
<child>
@@ -79,15 +81,23 @@
<property name="visible">True</property>
<property name="can_focus">False</property>
<child>
<object class="GtkTreeView" id="cell-tree">
<object class="GtkScrolledWindow">
<property name="visible">True</property>
<property name="can_focus">True</property>
<child internal-child="selection">
<object class="GtkTreeSelection"/>
<property name="hscrollbar_policy">never</property>
<property name="shadow_type">in</property>
<child>
<object class="GtkTreeView" id="cell-tree">
<property name="visible">True</property>
<property name="can_focus">True</property>
<child internal-child="selection">
<object class="GtkTreeSelection"/>
</child>
</object>
</child>
</object>
<packing>
<property name="expand">False</property>
<property name="expand">True</property>
<property name="fill">True</property>
<property name="position">0</property>
</packing>
@@ -96,6 +106,7 @@
<object class="GtkScrolledWindow">
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="hscrollbar_policy">never</property>
<property name="shadow_type">in</property>
<child>
<object class="GtkViewport">
@@ -117,43 +128,6 @@
<property name="position">1</property>
</packing>
</child>
<child>
<object class="GtkBox" id="button-box">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="orientation">vertical</property>
<child>
<object class="GtkButton" id="convert-button">
<property name="label">gtk-convert</property>
<property name="name">button-convert</property>
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="receives_default">True</property>
<property name="use_stock">True</property>
<property name="always_show_image">True</property>
<style>
<class name="suggested-action"/>
</style>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="position">0</property>
</packing>
</child>
<child>
<placeholder/>
</child>
<child>
<placeholder/>
</child>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="position">2</property>
</packing>
</child>
</object>
</child>
</object>

View File

@@ -2,7 +2,9 @@
<gresources>
<gresource prefix="/">
<file compressed="true">main.glade</file>
<file compressed="true">about.glade</file>
<file>layer-widget.glade</file>
<file>dialog.glade</file>
</gresource>
</gresources>

240
latex-output/latex-output.c Normal file
View File

@@ -0,0 +1,240 @@
/*
* GDSII-Converter
* Copyright (C) 2018 Mario Hüttel <mario.huettel@gmx.net>
*
* This file is part of GDSII-Converter.
*
* GDSII-Converter is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*
* GDSII-Converter is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with GDSII-Converter. If not, see <http://www.gnu.org/licenses/>.
*/
#include "latex-output.h"
#include <math.h>
#define WRITEOUT_BUFFER(buff) fwrite((buff)->str, sizeof(char), (buff)->len, tex_file)
static void write_layer_definitions(FILE *tex_file, GList *layer_infos, GString *buffer)
{
GList *list;
struct layer_info *lifo;
char *end_str;
for (list = layer_infos; list != NULL; list = list->next) {
lifo = (struct layer_info *)list->data;
g_string_printf(buffer, "\\pgfdeclarelayer{l%d}\n\\definecolor{c%d}{rgb}{%lf,%lf,%lf}\n",
lifo->layer, lifo->layer,
lifo->color.red, lifo->color.green, lifo->color.blue);
WRITEOUT_BUFFER(buffer);
}
g_string_printf(buffer, "\\pgfsetlayers{");
WRITEOUT_BUFFER(buffer);
for (list = layer_infos; list != NULL; list = list->next) {
lifo = (struct layer_info *)list->data;
if (list->next == NULL)
end_str = ",main}";
else
end_str = ",";
g_string_printf(buffer, "l%d%s", lifo->layer, end_str);
WRITEOUT_BUFFER(buffer);
}
fwrite("\n", sizeof(char), 1, tex_file);
}
/**
* @brief write_layer_env
* @param tex_file
* @param layer
* @param buffer
* @return TRUE if layer is placeable
*/
static gboolean write_layer_env(FILE *tex_file, GdkRGBA *color, int layer, GList *linfo, GString *buffer)
{
GList *temp;
struct layer_info *inf;
for (temp = linfo; temp != NULL; temp = temp->next) {
inf = (struct layer_info *)temp->data;
if (inf->layer == layer) {
color->alpha = inf->color.alpha;
color->red = inf->color.red;
color->green = inf->color.green;
color->blue = inf->color.blue;
g_string_printf(buffer, "\\begin{pgfonlayer}{l%d}\n\\ifcreatepdflayers\n\\begin{scope}[ocg={ref=%d, status=visible,name={%s}}]\n\\fi]\n",
layer, layer, inf->name);
WRITEOUT_BUFFER(buffer);
return TRUE;
}
}
return FALSE;
}
static void generate_graphics(FILE *tex_file, GList *graphics, GList *linfo, GString *buffer, double scale)
{
GList *temp;
GList *temp_vertex;
struct gds_graphics *gfx;
struct gds_point *pt;
GdkRGBA color;
static const char *line_caps[] = {"butt", "round", "rect"};
for (temp = graphics; temp != NULL; temp = temp->next) {
gfx = (struct gds_graphics *)temp->data;
if (write_layer_env(tex_file, &color, (int)gfx->layer, linfo, buffer) == TRUE) {
/* Layer is defined => create graphics */
if (gfx->gfx_type == GRAPHIC_POLYGON || gfx->gfx_type == GRAPHIC_BOX ) {
g_string_printf(buffer, "\\draw[line width=0.00001 pt, draw={c%d}, fill={c%d}, fill opacity={%lf}] ",
gfx->layer, gfx->layer, color.alpha);
WRITEOUT_BUFFER(buffer);
/* Append vertices */
for (temp_vertex = gfx->vertices; temp_vertex != NULL; temp_vertex = temp_vertex->next) {
pt = (struct gds_point *)temp_vertex->data;
g_string_printf(buffer, "(%lf pt, %lf pt) -- ", ((double)pt->x)/scale, ((double)pt->y)/scale);
WRITEOUT_BUFFER(buffer);
}
g_string_printf(buffer, "cycle;\n");
WRITEOUT_BUFFER(buffer);
} else if (gfx->gfx_type == GRAPHIC_PATH) {
if (g_list_length(gfx->vertices) < 2) {
printf("Cannot write path with less than 2 points\n");
break;
}
if (gfx->path_render_type < 0 || gfx->path_render_type > 2) {
printf("Path type unrecognized. Setting to 'flushed'\n");
gfx->path_render_type = PATH_FLUSH;
}
g_string_printf(buffer, "\\draw[line width=%lf pt, draw={c%d}, opacity={%lf}, cap=%s] ",
gfx->width_absolute/scale, gfx->layer, color.alpha,
line_caps[gfx->path_render_type]);
WRITEOUT_BUFFER(buffer);
/* Append vertices */
for (temp_vertex = gfx->vertices; temp_vertex != NULL; temp_vertex = temp_vertex->next) {
pt = (struct gds_point *)temp_vertex->data;
g_string_printf(buffer, "(%lf pt, %lf pt)%s",
((double)pt->x)/scale,
((double)pt->y)/scale,
(temp_vertex->next ? " -- " : ""));
WRITEOUT_BUFFER(buffer);
}
g_string_printf(buffer, ";\n");
WRITEOUT_BUFFER(buffer);
}
g_string_printf(buffer, "\\ifcreatepdflayers\n\\end{scope}\n\\fi\n\\end{pgfonlayer}\n");
WRITEOUT_BUFFER(buffer);
}
} /* For graphics */
}
static void render_cell(struct gds_cell *cell, GList *layer_infos, FILE *tex_file, GString *buffer, double scale)
{
GList *list_child;
struct gds_cell_instance *inst;
/* Draw polygons of current cell */
generate_graphics(tex_file, cell->graphic_objs, layer_infos, buffer, scale);
/* Draw polygons of childs */
for (list_child = cell->child_cells; list_child != NULL; list_child = list_child->next) {
inst = (struct gds_cell_instance *)list_child->data;
/* Abort if cell has no reference */
if (!inst->cell_ref)
continue;
/* generate translation scope */
g_string_printf(buffer, "\\begin{scope}[shift={(%lf pt,%lf pt)}]\n",
((double)inst->origin.x)/scale,((double)inst->origin.y)/scale);
WRITEOUT_BUFFER(buffer);
g_string_printf(buffer, "\\begin{scope}[rotate=%lf]\n", inst->angle);
WRITEOUT_BUFFER(buffer);
g_string_printf(buffer, "\\begin{scope}[yscale=%lf, xscale=%lf]\n", (inst->flipped ? -1*inst->magnification : inst->magnification),
inst->magnification);
WRITEOUT_BUFFER(buffer);
render_cell(inst->cell_ref, layer_infos, tex_file, buffer, scale);
g_string_printf(buffer, "\\end{scope}\n");
WRITEOUT_BUFFER(buffer);
g_string_printf(buffer, "\\end{scope}\n");
WRITEOUT_BUFFER(buffer);
g_string_printf(buffer, "\\end{scope}\n");
WRITEOUT_BUFFER(buffer);
}
}
void latex_render_cell_to_code(struct gds_cell *cell, GList *layer_infos, FILE *tex_file, double scale,
gboolean create_pdf_layers, gboolean standalone_document)
{
GString *working_line;
if (!tex_file || !layer_infos || !cell)
return;
/* 10 kB Line working buffer should be enough */
working_line = g_string_new_len(NULL, LATEX_LINE_BUFFER_KB*1024);
/* standalone foo */
g_string_printf(working_line, "\\newif\\iftestmode\n\\testmode%s\n",
(standalone_document ? "true" : "false"));
WRITEOUT_BUFFER(working_line);
g_string_printf(working_line, "\\newif\\ifcreatepdflayers\n\\createpdflayers%s\n",
(create_pdf_layers ? "true" : "false"));
WRITEOUT_BUFFER(working_line);
g_string_printf(working_line, "\\iftestmode\n");
WRITEOUT_BUFFER(working_line);
g_string_printf(working_line, "\\documentclass[tikz]{standalone}\n\\usepackage{xcolor}\n\\usetikzlibrary{ocgx}\n\\begin{document}\n");
WRITEOUT_BUFFER(working_line);
g_string_printf(working_line, "\\fi\n");
WRITEOUT_BUFFER(working_line);
/* Write layer definitions */
write_layer_definitions(tex_file, layer_infos, working_line);
/* Open tikz Pictute */
g_string_printf(working_line, "\\begin{tikzpicture}\n");
WRITEOUT_BUFFER(working_line);
/* Generate graphics output */
render_cell(cell, layer_infos, tex_file, working_line, scale);
g_string_printf(working_line, "\\end{tikzpicture}\n");
WRITEOUT_BUFFER(working_line);
g_string_printf(working_line, "\\iftestmode\n");
WRITEOUT_BUFFER(working_line);
g_string_printf(working_line, "\\end{document}\n");
WRITEOUT_BUFFER(working_line);
g_string_printf(working_line, "\\fi\n");
WRITEOUT_BUFFER(working_line);
fflush(tex_file);
g_string_free(working_line, TRUE);
}

View File

@@ -0,0 +1,33 @@
/*
* GDSII-Converter
* Copyright (C) 2018 Mario Hüttel <mario.huettel@gmx.net>
*
* This file is part of GDSII-Converter.
*
* GDSII-Converter is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*
* GDSII-Converter is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with GDSII-Converter. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef __LATEX_OUTPUT_H__
#define __LATEX_OUTPUT_H__
#include "../gds-parser/gds-types.h"
#include <glib.h>
#include <stdio.h>
#include "../layer-selector.h"
#define LATEX_LINE_BUFFER_KB (10)
void latex_render_cell_to_code(struct gds_cell *cell, GList *layer_infos, FILE *tex_file, double scale,
gboolean create_pdf_layers, gboolean standalone_document);
#endif /* __LATEX_OUTPUT_H__ */

View File

@@ -18,71 +18,95 @@
*/
#include "layer-selector.h"
#include "gdsparse.h"
#include "gds-parser/gds-parser.h"
#include "widgets/layer-element.h"
#include <glib.h>
#include <string.h>
#include <stdio.h>
#include <stdlib.h>
static GList *layer_widgets = NULL;
static GtkWidget *load_button;
static GtkWidget *save_button;
static GtkWidget *global_load_button;
static GtkWidget *global_save_button;
static GtkListBox *global_list_box;
static void layer_list_remove_element(struct layer_info *inf)
void delete_layer_info_struct(struct layer_info *info)
{
if (inf)
free(inf);
if (info)
free(info);
}
void get_layer_info(GList **info_list, GtkListBox *box)
/**
* @brief export_rendered_layer_info
* @return new list with all info elements needed to render cells
*/
GList *export_rendered_layer_info()
{
GList *local_list = NULL;
GList *info_list = NULL;
LayerElement *le;
struct layer_info *linfo;
GList *row_list;
GList *temp;
int i;
/* Clear info Glist */
if (*info_list != NULL) {
g_list_free_full(*info_list, (GDestroyNotify)layer_list_remove_element);
*info_list = NULL;
row_list = gtk_container_get_children(GTK_CONTAINER(global_list_box));
/* Iterate through widgets and add layers that shall be exported */
for (i = 0, temp = row_list; temp != NULL; temp = temp->next, i++) {
le = LAYER_ELEMENT(temp->data);
if (layer_element_get_export(le) == TRUE) {
/* Allocate new info and fill with info */
linfo = (struct layer_info *)malloc(sizeof(struct layer_info));
layer_element_get_color(le, &linfo->color);
linfo->layer = layer_element_get_layer(le);
linfo->stacked_position = i;
linfo->name = (char *)layer_element_get_name(le);
/* Append to list */
info_list = g_list_append(info_list, (gpointer)linfo);
}
}
*info_list = local_list;
}
static void delete_layer_widget(GtkWidget *widget)
{
gtk_widget_destroy(widget);
return info_list;
}
void clear_list_box_widgets(GtkListBox *box)
{
GList *list;
GList *temp;
list = gtk_container_get_children(GTK_CONTAINER(box));
for (;list != NULL; list = list->next) {
gtk_container_remove(GTK_CONTAINER(box), GTK_WIDGET(list->data));
for (temp = list; temp != NULL; temp = temp->next) {
gtk_container_remove(GTK_CONTAINER(box), GTK_WIDGET(temp->data));
}
/* Widgets are already destroyed when removed from box because they are only referenced inside the container */
g_list_free(layer_widgets);
layer_widgets = NULL;
g_list_free(list);
/* Deactivate buttons */
gtk_widget_set_sensitive(load_button, FALSE);
gtk_widget_set_sensitive(save_button, FALSE);
gtk_widget_set_sensitive(global_load_button, FALSE);
gtk_widget_set_sensitive(global_save_button, FALSE);
}
static gboolean check_if_layer_widget_exists(int layer) {
GList *list;
GList *temp;
LayerElement *widget;
gboolean ret = FALSE;
for (list = layer_widgets; list != NULL; list = list->next) {
widget = (LayerElement *)list->data;
list = gtk_container_get_children(GTK_CONTAINER(global_list_box));
for (temp = list; temp != NULL; temp = temp->next) {
widget = LAYER_ELEMENT(temp->data);
if (layer_element_get_layer(widget) == layer) {
ret = TRUE;
break;
}
}
g_list_free(list);
return ret;
}
@@ -101,28 +125,20 @@ static void analyze_cell_layers(GtkListBox *listbox, struct gds_cell *cell)
layer_element_set_layer(LAYER_ELEMENT(le), layer);
gtk_list_box_insert(listbox, le, -1);
gtk_widget_show(le);
layer_widgets = g_list_append(layer_widgets, le);
}
}
}
gint sort_func(GtkListBoxRow *row1, GtkListBoxRow *row2, gpointer unused)
{
GList *children1, *children2;
LayerElement *le1, *le2;
gint ret;
children1 = gtk_container_get_children(GTK_CONTAINER(row1));
children2 = gtk_container_get_children(GTK_CONTAINER(row2));
le1 = LAYER_ELEMENT(children1->data);
le2 = LAYER_ELEMENT(children2->data);
le1 = LAYER_ELEMENT(row1);
le2 = LAYER_ELEMENT(row2);
ret = layer_element_get_layer(le1) - layer_element_get_layer(le2);
g_list_free(children1);
g_list_free(children2);
return ret;
}
@@ -130,8 +146,10 @@ void generate_layer_widgets(GtkListBox *listbox, GList *libs)
{
GList *cell_list = NULL;
struct gds_library *lib;
clear_list_box_widgets(listbox);
global_list_box = listbox;
clear_list_box_widgets(listbox);
gtk_list_box_set_sort_func(listbox, sort_func, NULL, NULL);
for (; libs != NULL; libs = libs->next) {
@@ -144,9 +162,12 @@ void generate_layer_widgets(GtkListBox *listbox, GList *libs)
/* Force sort */
gtk_list_box_invalidate_sort(listbox);
/* Disable sort, so user can sort layers */
gtk_list_box_set_sort_func(listbox, NULL, NULL, NULL);
/* Activate Buttons */
gtk_widget_set_sensitive(load_button, TRUE);
gtk_widget_set_sensitive(save_button, TRUE);
gtk_widget_set_sensitive(global_load_button, TRUE);
gtk_widget_set_sensitive(global_save_button, TRUE);
}
/**
@@ -186,7 +207,7 @@ static int load_csv_line(GDataInputStream *stream, gboolean *export, char **name
if (g_match_info_matches(mi)) {
/* Line is valid */
match = g_match_info_fetch_named(mi, "layer");
*layer = g_ascii_strtoll(match, NULL, 10);
*layer = (int)g_ascii_strtoll(match, NULL, 10);
g_free(match);
match = g_match_info_fetch_named(mi, "r");
color->red = g_ascii_strtod(match, NULL);
@@ -222,34 +243,31 @@ ret_direct:
}
static LayerElement *find_layer_in_list(GList *list, int layer)
static LayerElement *find_layer_element_in_list(GList *el_list, int layer)
{
LayerElement *le_found, *temp;
for (le_found = NULL; list != NULL; list = list->next) {
temp = LAYER_ELEMENT(list->data);
if (layer_element_get_layer(temp) == layer) {
le_found = temp;
LayerElement *ret = NULL;
for (; el_list != NULL; el_list = el_list->next) {
if (layer_element_get_layer(LAYER_ELEMENT(el_list->data)) == layer) {
ret = LAYER_ELEMENT(el_list->data);
break;
}
}
return le_found;
return ret;
}
static void load_layer_mapping_from_file(gchar *file_name)
{
GFile *file;
GFileInputStream *stream;
GDataInputStream *dstream;
LayerElement *le;
char *name;
gboolean export;
int layer;
GdkRGBA color;
int result;
GList *rows;
GList *temp;
file = g_file_new_for_path(file_name);
stream = g_file_read(file, NULL, NULL);
@@ -259,20 +277,47 @@ static void load_layer_mapping_from_file(gchar *file_name)
dstream = g_data_input_stream_new(G_INPUT_STREAM(stream));
rows = gtk_container_get_children(GTK_CONTAINER(global_list_box));
/* Reference and remove all rows from box */
for (temp = rows; temp != NULL; temp = temp->next) {
le = LAYER_ELEMENT(temp->data);
/* Referencing protets the widget from being deleted when removed */
g_object_ref(G_OBJECT(le));
gtk_container_remove(GTK_CONTAINER(global_list_box), GTK_WIDGET(le));
}
while((result = load_csv_line(dstream, &export, &name, &layer, &color)) >= 0) {
/* skip broken line */
if (result == 1)
continue;
/* search for layer widget */
if (le = find_layer_in_list(layer_widgets, layer)) {
layer_element_set_name(le, name);
/* Add rows in the same order as in file */
if ((le = find_layer_element_in_list(rows, layer))) {
gtk_list_box_insert(global_list_box, GTK_WIDGET(le), -1);
layer_element_set_color(le, &color);
layer_element_set_export(le, export);
layer_element_set_name(le, name);
g_free(name);
/* Dereference and remove from list */
g_object_unref(G_OBJECT(le));
rows = g_list_remove(rows, le);
}
g_free(name);
}
/* Add remaining elements */
for (temp = rows; temp != NULL; temp = temp->next) {
le = LAYER_ELEMENT(temp->data);
/* Referencing protets the widget from being deleted when removed */
gtk_list_box_insert(global_list_box, GTK_WIDGET(le), -1);
g_object_unref(G_OBJECT(le));
}
/* Delete list */
g_list_free(rows);
/* read line */
g_object_unref(dstream);
g_object_unref(stream);
@@ -314,7 +359,8 @@ static void create_csv_line(LayerElement *layer_element, char *line_buffer, size
layer_element_get_color(layer_element, &color);
/* print values to line */
g_string_printf(string, "%d,%lf,%lf,%lf,%lf,%d,%s\n", layer, color.red, color.green,
g_string_printf(string, "%d,%lf,%lf,%lf,%lf,%d,%s\n",
layer, color.red, color.green,
color.blue, color.alpha, (export == TRUE ? 1 : 0), name);
if (string->len > (max_len-1)) {
@@ -331,23 +377,28 @@ static void create_csv_line(LayerElement *layer_element, char *line_buffer, size
g_string_free(string, TRUE);
}
static void save_layer_mapping_data(const gchar *file_name)
static void save_layer_mapping_data(const gchar *file_name, GtkListBox *list_box)
{
FILE *file;
char workbuff[512];
GList *le_list;
GList *temp;
/* Overwrite existing file */
file = fopen((const char *)file_name, "w");
/* File format is CSV: <Layer>,<R>,<G>,<B>,<Alpha>,<Export?>,<Name> */
for (le_list = layer_widgets; le_list != NULL; le_list = le_list->next) {
le_list = gtk_container_get_children(GTK_CONTAINER(list_box));
/* File format is CSV: <Layer>,<target_pos>,<R>,<G>,<B>,<Alpha>,<Export?>,<Name> */
for (temp = le_list; temp != NULL; temp = temp->next) {
/* To be sure it is a valid string */
workbuff[0] = 0;
create_csv_line((LayerElement *)le_list->data, workbuff, sizeof(workbuff));
create_csv_line(LAYER_ELEMENT(temp->data), workbuff, sizeof(workbuff));
fwrite(workbuff, sizeof(char), strlen(workbuff), file);
}
g_list_free(le_list);
/* Save File */
fflush(file);
fclose(file);
@@ -364,7 +415,7 @@ static void save_mapping_clicked(GtkWidget *button, gpointer user_data)
res = gtk_dialog_run(GTK_DIALOG(dialog));
if (res == GTK_RESPONSE_ACCEPT) {
file_name = gtk_file_chooser_get_filename(GTK_FILE_CHOOSER(dialog));
save_layer_mapping_data(file_name);
save_layer_mapping_data(file_name, global_list_box);
g_free(file_name);
}
gtk_widget_destroy(dialog);
@@ -373,13 +424,13 @@ static void save_mapping_clicked(GtkWidget *button, gpointer user_data)
void setup_load_mapping_callback(GtkWidget *button, GtkWindow *main_window)
{
g_object_ref(G_OBJECT(button));
load_button = button;
global_load_button = button;
g_signal_connect(button, "clicked", G_CALLBACK(load_mapping_clicked), main_window);
}
void setup_save_mapping_callback(GtkWidget *button, GtkWindow *main_window)
{
g_object_ref(G_OBJECT(button));
save_button = button;
global_save_button = button;
g_signal_connect(button, "clicked", G_CALLBACK(save_mapping_clicked), main_window);
}

View File

@@ -22,21 +22,19 @@
#include <gtk/gtk.h>
#include <glib.h>
#include <layer-element.h>
struct layer_info {
int id;
/* This contains both: opacity and Color */
GdkRGBA color;
struct layer_info
{
int layer;
char *name;
int stacked_position; ///< Lower is bottom, higher is top
GdkRGBA color;
};
void generate_layer_widgets(GtkListBox *listbox, GList *libs);
void clear_list_box_widgets();
void setup_load_mapping_callback(GtkWidget *button, GtkWindow *main_window);
void setup_save_mapping_callback(GtkWidget *button, GtkWindow *main_window);
void get_layer_info(GList **info_list, GtkListBox *box);
GList *export_rendered_layer_info();
void delete_layer_info_struct(struct layer_info *info);
#endif /* __LAYER_SELECTOR_H__ */

316
main-window.c Normal file
View File

@@ -0,0 +1,316 @@
/*
* GDSII-Converter
* Copyright (C) 2018 Mario Hüttel <mario.huettel@gmx.net>
*
* This file is part of GDSII-Converter.
*
* GDSII-Converter is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*
* GDSII-Converter is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with GDSII-Converter. If not, see <http://www.gnu.org/licenses/>.
*/
#include "main-window.h"
#include <stdio.h>
#include "gds-parser/gds-parser.h"
#include <gtk/gtk.h>
#include "layer-selector.h"
#include "tree-renderer/tree-store.h"
#include "latex-output/latex-output.h"
#include "widgets/conv-settings-dialog.h"
#include "cairo-output/cairo-output.h"
struct open_button_data {
GtkWindow *main_window;
GList **list_ptr;
GtkTreeStore *cell_store;
GtkListBox *layer_box;
};
struct convert_button_data {
GtkTreeView *tree_view;
GtkWindow *main_window;
};
static gboolean on_window_close(gpointer window, gpointer user)
{
gtk_widget_destroy(GTK_WIDGET(window));
return TRUE;
}
static GString *generate_string_from_date(struct gds_time_field *date)
{
GString *str;
str = g_string_new_len(NULL, 50);
g_string_printf(str, "%02u.%02u.%u - %02u:%02u",
(unsigned int)date->day,
(unsigned int)date->month,
(unsigned int)date->year,
(unsigned int)date->hour,
(unsigned int)date->minute);
return str;
}
static void on_load_gds(gpointer button, gpointer user)
{
GList *cell;
GtkTreeIter libiter;
GtkTreeIter celliter;
GList *lib;
struct gds_library *gds_lib;
struct gds_cell *gds_c;
struct open_button_data *ptr = (struct open_button_data *)user;
GtkTreeStore *store = ptr->cell_store;
GtkWidget *open_dialog;
GtkFileChooser *file_chooser;
GtkFileFilter *filter;
GtkStyleContext *button_style;
gint dialog_result;
int gds_result;
char *filename;
GString *mod_date;
GString *acc_date;
open_dialog = gtk_file_chooser_dialog_new("Open GDSII File", ptr->main_window, GTK_FILE_CHOOSER_ACTION_OPEN,
"Cancel", GTK_RESPONSE_CANCEL, "Open GDSII", GTK_RESPONSE_ACCEPT, NULL);
file_chooser = GTK_FILE_CHOOSER(open_dialog);
/* Add GDS II Filter */
filter = gtk_file_filter_new();
gtk_file_filter_add_pattern(filter, "*.gds");
gtk_file_filter_set_name(filter, "GDSII-Files");
gtk_file_chooser_add_filter(file_chooser, filter);
dialog_result = gtk_dialog_run(GTK_DIALOG(open_dialog));
if (dialog_result == GTK_RESPONSE_ACCEPT) {
/* Get File name */
filename = gtk_file_chooser_get_filename(file_chooser);
gtk_tree_store_clear(store);
clear_lib_list(ptr->list_ptr);
/* Parse new GDSII file */
gds_result = parse_gds_from_file(filename, ptr->list_ptr);
/* Delete file name afterwards */
g_free(filename);
if (gds_result)
goto end_destroy;
/* remove suggested action from Open button */
button_style = gtk_widget_get_style_context(GTK_WIDGET(button));
gtk_style_context_remove_class(button_style, "suggested-action");
for (lib = *(ptr->list_ptr); lib != NULL; lib = lib->next) {
gds_lib = (struct gds_library *)lib->data;
/* Create top level iter */
gtk_tree_store_append (store, &libiter, NULL);
/* Convert dates to String */
mod_date = generate_string_from_date(&gds_lib->mod_time);
acc_date = generate_string_from_date(&gds_lib->access_time);
gtk_tree_store_set (store, &libiter,
CELL_SEL_LIBRARY, gds_lib,
CELL_SEL_MODDATE, mod_date->str,
CELL_SEL_ACCESSDATE, acc_date->str,
-1);
/* Delete GStrings including string data. */
/* Cell store copies String type data items */
g_string_free(mod_date, TRUE);
g_string_free(acc_date, TRUE);
for (cell = gds_lib->cells; cell != NULL; cell = cell->next) {
gds_c = (struct gds_cell *)cell->data;
gtk_tree_store_append (store, &celliter, &libiter);
/* Convert dates to String */
mod_date = generate_string_from_date(&gds_c->mod_time);
acc_date = generate_string_from_date(&gds_c->access_time);
gtk_tree_store_set (store, &celliter,
CELL_SEL_CELL, gds_c,
CELL_SEL_MODDATE, mod_date->str,
CELL_SEL_ACCESSDATE, acc_date->str,
-1);
/* Delete GStrings including string data. */
/* Cell store copies String type data items */
g_string_free(mod_date, TRUE);
g_string_free(acc_date, TRUE);
}
}
/* Create Layers in Layer Box */
generate_layer_widgets(ptr->layer_box, *(ptr->list_ptr));
}
end_destroy:
/* Destroy dialog and filter */
gtk_widget_destroy(open_dialog);
}
static void on_convert_clicked(gpointer button, gpointer user)
{
static struct render_settings sett = {
.scale = 1000.0f,
.renderer = RENDERER_LATEX_TIKZ,
};
struct convert_button_data *data = (struct convert_button_data *)user;
GtkTreeSelection *selection;
GtkTreeIter iter;
GtkTreeModel *model;
GList *layer_list;
struct gds_cell *cell_to_render;
FILE *output_file;
GtkWidget *dialog;
RendererSettingsDialog *settings;
GtkFileFilter *filter;
gint res;
char *file_name;
/* Get selected cell */
selection = gtk_tree_view_get_selection(data->tree_view);
if (gtk_tree_selection_get_selected(selection, &model, &iter) == FALSE)
return;
gtk_tree_model_get(model, &iter, CELL_SEL_CELL, &cell_to_render, -1);
if (!cell_to_render)
return;
/* Get layers that are rendered */
layer_list = export_rendered_layer_info();
settings = renderer_settings_dialog_new(GTK_WINDOW(data->main_window));
renderer_settings_dialog_set_settings(settings, &sett);
res = gtk_dialog_run(GTK_DIALOG(settings));
if (res == GTK_RESPONSE_OK) {
renderer_settings_dialog_get_settings(settings, &sett);
gtk_widget_destroy(GTK_WIDGET(settings));
} else {
gtk_widget_destroy(GTK_WIDGET(settings));
goto ret_layer_destroy;
}
/* save file dialog */
dialog = gtk_file_chooser_dialog_new((sett.renderer == RENDERER_LATEX_TIKZ
? "Save LaTeX File" : "Save PDF"),
GTK_WINDOW(data->main_window), GTK_FILE_CHOOSER_ACTION_SAVE,
"Cancel", GTK_RESPONSE_CANCEL, "Save", GTK_RESPONSE_ACCEPT, NULL);
/* Set file filter according to settings */
filter = gtk_file_filter_new();
if (sett.renderer == RENDERER_LATEX_TIKZ) {
gtk_file_filter_add_pattern(filter, "*.tex");
gtk_file_filter_set_name(filter, "LaTeX-Files");
} else {
gtk_file_filter_add_pattern(filter, "*.pdf");
gtk_file_filter_set_name(filter, "PDF-Files");
}
gtk_file_chooser_add_filter(GTK_FILE_CHOOSER(dialog), filter);
res = gtk_dialog_run(GTK_DIALOG(dialog));
if (res == GTK_RESPONSE_ACCEPT) {
file_name = gtk_file_chooser_get_filename(GTK_FILE_CHOOSER(dialog));
gtk_widget_destroy(dialog);
switch (sett.renderer) {
case RENDERER_LATEX_TIKZ:
output_file = fopen(file_name, "w");
latex_render_cell_to_code(cell_to_render, layer_list, output_file, sett.scale,
sett.tex_pdf_layers, sett.tex_standalone);
fclose(output_file);
break;
case RENDERER_CAIROGRAPHICS:
cairo_render_cell_to_pdf(cell_to_render, layer_list, file_name, sett.scale);
break;
}
g_free(file_name);
} else {
gtk_widget_destroy(dialog);
}
ret_layer_destroy:
g_list_free_full(layer_list, (GDestroyNotify)delete_layer_info_struct);
}
/* This function activates/deactivates the convert button depending on whether
* a cell is selected for conversion or not */
static void cell_selection_changed(GtkTreeSelection *sel, GtkWidget *convert_button)
{
GtkTreeModel *model = NULL;
GtkTreeIter iter;
if (gtk_tree_selection_get_selected(sel, &model, &iter)) {
/* Node selected. Show button */
gtk_widget_set_sensitive(convert_button, TRUE);
} else {
gtk_widget_set_sensitive(convert_button, FALSE);
}
}
GtkWindow *create_main_window()
{
GtkBuilder *main_builder;
GtkTreeView *cell_tree;
GtkTreeStore *cell_store;
GtkWidget *listbox;
GtkWidget *conv_button;
static GList *gds_libs;
static struct open_button_data open_data;
static struct convert_button_data conv_data;
main_builder = gtk_builder_new_from_resource("/main.glade");
gtk_builder_connect_signals(main_builder, NULL);
cell_tree = GTK_TREE_VIEW(gtk_builder_get_object(main_builder, "cell-tree"));
cell_store = setup_cell_selector(cell_tree);
open_data.cell_store = cell_store;
open_data.list_ptr = &gds_libs;
open_data.main_window = GTK_WINDOW(gtk_builder_get_object(main_builder, "main-window"));
g_signal_connect(GTK_WIDGET(gtk_builder_get_object(main_builder, "button-load-gds")),
"clicked", G_CALLBACK(on_load_gds), (gpointer)&open_data);
/* Connect delete-event */
g_signal_connect(GTK_WIDGET(open_data.main_window), "delete-event",
G_CALLBACK(on_window_close), NULL);
/* Connect Convert button */
conv_data.tree_view = cell_tree;
conv_data.main_window = open_data.main_window;
conv_button = GTK_WIDGET(gtk_builder_get_object(main_builder, "convert-button"));
g_signal_connect(conv_button, "clicked", G_CALLBACK(on_convert_clicked), &conv_data);
listbox = GTK_WIDGET(gtk_builder_get_object(main_builder, "layer-list"));
open_data.layer_box = GTK_LIST_BOX(listbox);
/* Set buttons fpr layer mapping GUI */
setup_load_mapping_callback(GTK_WIDGET(gtk_builder_get_object(main_builder, "button-load-mapping")),
open_data.main_window);
setup_save_mapping_callback(GTK_WIDGET(gtk_builder_get_object(main_builder, "button-save-mapping")),
open_data.main_window);
/* Callback for selection change of cell selector */
g_signal_connect(G_OBJECT(gtk_tree_view_get_selection(cell_tree)), "changed",
G_CALLBACK(cell_selection_changed), conv_button);
return (conv_data.main_window);
}

27
main-window.h Normal file
View File

@@ -0,0 +1,27 @@
/*
* GDSII-Converter
* Copyright (C) 2018 Mario Hüttel <mario.huettel@gmx.net>
*
* This file is part of GDSII-Converter.
*
* GDSII-Converter is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*
* GDSII-Converter is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with GDSII-Converter. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef _MAIN_WINDOW_H_
#define _MAIN_WINDOW_H_
#include <gtk/gtk.h>
GtkWindow *create_main_window();
#endif /* _MAIN_WINDOW_H_ */

281
main.c
View File

@@ -18,254 +18,85 @@
*/
#include <stdio.h>
#include "gdsparse.h"
#include <gtk/gtk.h>
#include <layer-element.h>
#include "layer-selector.h"
#include "tree-renderer/lib-cell-renderer.h"
#include "main-window.h"
enum cell_store_columns {
LIBRARY,
CELL,
MODDATE,
ACCESSDATE,
STORE_COLUMN_COUNT
};
struct open_button_data {
struct application_data {
GtkApplication *app;
GtkWindow *main_window;
GList **list_ptr;
GtkTreeStore *cell_store;
GtkListBox *layer_box;
};
gboolean on_window_close(gpointer window, gpointer user)
static void app_quit(GSimpleAction *action, GVariant *parameter, gpointer user_data)
{
gtk_widget_destroy(GTK_WIDGET(window));
gtk_main_quit();
return TRUE;
struct application_data *appdata = (struct application_data *)user_data;
gtk_widget_destroy(GTK_WIDGET(appdata->main_window));
}
static GString *generate_string_from_date(struct gds_time_field *date)
static void app_about(GSimpleAction *action, GVariant *parameter, gpointer user_data)
{
GString *str;
GtkBuilder *builder;
GtkDialog *dialog;
struct application_data *appdata = (struct application_data *)user_data;
str = g_string_new_len(NULL, 50);
g_string_printf(str, "%02u.%02u.%u - %02u:%02u",
(unsigned int)date->day,
(unsigned int)date->month,
(unsigned int)date->year,
(unsigned int)date->hour,
(unsigned int)date->minute);
return str;
builder = gtk_builder_new_from_resource("/about.glade");
dialog = GTK_DIALOG(gtk_builder_get_object(builder, "about-dialog"));
gtk_window_set_transient_for(GTK_WINDOW(dialog), appdata->main_window);
gtk_dialog_run(dialog);
gtk_widget_destroy(dialog);
g_object_unref(builder);
}
void on_load_gds(gpointer button, gpointer user)
const GActionEntry app_actions[] = {
{ "quit", app_quit },
{ "about", app_about }
};
static void gapp_activate(GApplication *app, gpointer user_data)
{
GList *cell;
GtkTreeIter libiter;
GtkTreeIter celliter;
GList *lib;
struct gds_library *gds_lib;
struct gds_cell *gds_c;
struct open_button_data *ptr = (struct open_button_data *)user;
GtkTreeStore *store = ptr->cell_store;
GtkWidget *open_dialog;
GtkFileChooser *file_chooser;
GtkFileFilter *filter;
GtkStyleContext *button_style;
gint dialog_result;
int gds_result;
char *filename;
GString *mod_date;
GString *acc_date;
GtkWindow *main_window;
struct application_data *appdata = (struct application_data *)user_data;
open_dialog = gtk_file_chooser_dialog_new("Open GDSII File", ptr->main_window, GTK_FILE_CHOOSER_ACTION_OPEN,
"Cancel", GTK_RESPONSE_CANCEL, "Open GDSII", GTK_RESPONSE_ACCEPT, NULL);
file_chooser = GTK_FILE_CHOOSER(open_dialog);
/* Add GDS II Filter */
filter = gtk_file_filter_new();
gtk_file_filter_add_pattern(filter, "*.gds");
gtk_file_filter_set_name(filter, "GDSII-Files");
gtk_file_chooser_add_filter(file_chooser, filter);
dialog_result = gtk_dialog_run(GTK_DIALOG(open_dialog));
if (dialog_result == GTK_RESPONSE_ACCEPT) {
/* Get File name */
filename = gtk_file_chooser_get_filename(file_chooser);
gtk_tree_store_clear(store);
clear_lib_list(ptr->list_ptr);
/* Parse new GDSII file */
gds_result = parse_gds_from_file(filename, ptr->list_ptr);
/* Delete file name afterwards */
g_free(filename);
if (gds_result)
goto end_destroy;
/* remove suggested action from Open button */
button_style = gtk_widget_get_style_context(GTK_WIDGET(button));
gtk_style_context_remove_class(button_style, "suggested-action");
for (lib = *(ptr->list_ptr); lib != NULL; lib = lib->next) {
gds_lib = (struct gds_library *)lib->data;
/* Create top level iter */
gtk_tree_store_append (store, &libiter, NULL);
/* Convert dates to String */
mod_date = generate_string_from_date(&gds_lib->mod_time);
acc_date = generate_string_from_date(&gds_lib->access_time);
gtk_tree_store_set (store, &libiter,
LIBRARY, gds_lib,
MODDATE, mod_date->str,
ACCESSDATE, acc_date->str,
-1);
/* Delete GStrings including string data. */
/* Cell store copies String type data items */
g_string_free(mod_date, TRUE);
g_string_free(acc_date, TRUE);
for (cell = gds_lib->cells; cell != NULL; cell = cell->next) {
gds_c = (struct gds_cell *)cell->data;
gtk_tree_store_append (store, &celliter, &libiter);
/* Convert dates to String */
mod_date = generate_string_from_date(&gds_c->mod_time);
acc_date = generate_string_from_date(&gds_c->access_time);
gtk_tree_store_set (store, &celliter,
CELL, gds_c,
MODDATE, mod_date->str,
ACCESSDATE, acc_date->str,
-1);
/* Delete GStrings including string data. */
/* Cell store copies String type data items */
g_string_free(mod_date, TRUE);
g_string_free(acc_date, TRUE);
}
}
/* Create Layers in Layer Box */
generate_layer_widgets(ptr->layer_box, *(ptr->list_ptr));
}
end_destroy:
/* Destroy dialog and filter */
gtk_widget_destroy(open_dialog);
}
void on_convert_clicked(gpointer button, gpointer user)
{
printf("convert\n");
}
static GtkTreeStore * setup_cell_selector(GtkTreeView* view)
{
GtkTreeStore *cell_store;
GtkCellRenderer *render_dates;
GtkCellRenderer *render_cell;
GtkCellRenderer *render_lib;
GtkTreeViewColumn *column;
GdkRGBA cell_text_color;
GValue val = G_VALUE_INIT;
cell_store = gtk_tree_store_new(STORE_COLUMN_COUNT, G_TYPE_POINTER, G_TYPE_POINTER, G_TYPE_STRING, G_TYPE_STRING);
gtk_tree_view_set_model(view, GTK_TREE_MODEL(cell_store));
render_dates = gtk_cell_renderer_text_new();
render_cell = lib_cell_renderer_new();
render_lib = lib_cell_renderer_new();
/* Set foreground color for cell column */
cell_text_color.alpha = 1;
cell_text_color.red = (double)61.0/(double)255.0;
cell_text_color.green = (double)152.0/(double)255.0;
cell_text_color.blue = 0.0;
g_value_init(&val, G_TYPE_BOOLEAN);
g_value_set_boolean(&val, TRUE);
g_object_set_property(G_OBJECT(render_cell), "foreground-set", &val);
g_value_unset(&val);
g_value_init(&val, GDK_TYPE_RGBA);
g_value_set_boxed(&val, &cell_text_color);
g_object_set_property(G_OBJECT(render_cell), "foreground-rgba", &val);
g_value_unset(&val);
column = gtk_tree_view_column_new_with_attributes("Library", render_lib, "gds-lib", LIBRARY, NULL);
gtk_tree_view_append_column(view, column);
/* Cell color: #3D9801 */
column = gtk_tree_view_column_new_with_attributes("Cell", render_cell, "gds-cell", CELL, NULL);
gtk_tree_view_append_column(view, column);
column = gtk_tree_view_column_new_with_attributes("Mod. Date", render_dates, "text", MODDATE, NULL);
gtk_tree_view_append_column(view, column);
column = gtk_tree_view_column_new_with_attributes("Acc. Date", render_dates, "text", ACCESSDATE, NULL);
gtk_tree_view_append_column(view, column);
return cell_store;
main_window = create_main_window();
appdata->main_window = main_window;
gtk_application_add_window(GTK_APPLICATION(app), main_window);
gtk_widget_show(GTK_WIDGET(main_window));
}
int main(int argc, char **argv)
{
GtkBuilder *main_builder;
GList *gds_libs = NULL;
GtkTreeView *cell_tree;
GtkTreeStore *cell_store;
GtkWidget *widget_generic;
GtkWidget *layer;
GtkWidget *listbox;
GtkApplication *gapp;
int app_status;
struct application_data appdata;
GMenu *menu;
GMenu *m_quit;
GMenu *m_about;
struct open_button_data open_data;
gtk_init(&argc, &argv);
main_builder = gtk_builder_new_from_resource("/main.glade");
gtk_builder_connect_signals(main_builder, NULL);
gapp = gtk_application_new("de.shimatta.gds-render", G_APPLICATION_FLAGS_NONE);
g_application_register(G_APPLICATION(gapp), NULL, NULL);
//g_action_map_add_action_entries(G_ACTION_MAP(gapp), app_actions, G_N_ELEMENTS(app_actions), &appdata);
g_signal_connect (gapp, "activate", G_CALLBACK(gapp_activate), &appdata);
cell_tree = (GtkTreeView *)gtk_builder_get_object(main_builder, "cell-tree");
cell_store = setup_cell_selector(cell_tree);
menu = g_menu_new();
m_quit = g_menu_new();
m_about = g_menu_new();
g_menu_append(m_quit, "Quit", "app.quit");
g_menu_append(m_about, "About", "app.about");
g_menu_append_section(menu, NULL, G_MENU_MODEL(m_about));
g_menu_append_section(menu, NULL, G_MENU_MODEL(m_quit));
g_action_map_add_action_entries(G_ACTION_MAP(gapp), app_actions, G_N_ELEMENTS(app_actions), &appdata);
gtk_application_set_app_menu(GTK_APPLICATION(gapp), G_MENU_MODEL(menu));
g_object_unref(m_quit);
g_object_unref(m_about);
g_object_unref(menu);
open_data.cell_store = cell_store;
open_data.list_ptr = &gds_libs;
open_data.main_window = GTK_WINDOW(gtk_builder_get_object(main_builder, "main-window"));
g_signal_connect(GTK_WIDGET(gtk_builder_get_object(main_builder, "button-load-gds")),
"clicked", G_CALLBACK(on_load_gds), (gpointer)&open_data);
app_status = g_application_run (G_APPLICATION(gapp), argc, argv);
g_object_unref (gapp);
/* Connect Convert button */
widget_generic = GTK_WIDGET(gtk_builder_get_object(main_builder, "convert-button"));
g_signal_connect(widget_generic, "clicked", G_CALLBACK(on_convert_clicked), layer);
listbox = GTK_WIDGET(gtk_builder_get_object(main_builder, "layer-list"));
open_data.layer_box = GTK_LIST_BOX(listbox);
/* Set buttons fpr layer mapping GUI */
setup_load_mapping_callback(GTK_WIDGET(gtk_builder_get_object(main_builder, "button-load-mapping")),
open_data.main_window);
setup_save_mapping_callback(GTK_WIDGET(gtk_builder_get_object(main_builder, "button-save-mapping")),
open_data.main_window);
gtk_main();
return 0;
return app_status;
}

2
test-data/.gitignore vendored Normal file
View File

@@ -0,0 +1,2 @@
*.log
*.aux

View File

@@ -0,0 +1,2 @@
2,0.203922,0.396078,0.643137,1.000000,1,BOTTOM-Layer
1,0.450980,0.823529,0.086275,1.000000,1,TOP-Layer

Binary file not shown.

Binary file not shown.

View File

@@ -0,0 +1,56 @@
\newif\iftestmode
\testmodetrue % Change to true for standalone rendering
\newif\ifcreatepdflayers
\createpdflayerstrue % Change to true for Embedded layers in PDF output
\iftestmode
\documentclass[tikz]{standalone}
\usepackage{xcolor}
\usetikzlibrary{ocgx}
\begin{document}
\fi
\pgfdeclarelayer{l2}
\definecolor{c2}{rgb}{0.203922,0.396078,0.643137}
\pgfdeclarelayer{l1}
\definecolor{c1}{rgb}{0.450980,0.823529,0.086275}
\pgfsetlayers{l2,l1,main}
\begin{tikzpicture}
\begin{pgfonlayer}{l1}
\ifcreatepdflayers
\begin{scope}[ocg={ref=1, status=visible,name={TOP-Layer}}]
\fi]
\draw[line width=0.300000 pt, draw={c1}, opacity={1.000000}, cap=rect] (-1.108000 pt, 0.589000 pt) -- (-0.498000 pt, 0.589000 pt) -- (-0.255000 pt, 0.343000 pt);
\ifcreatepdflayers
\end{scope}
\fi
\end{pgfonlayer}
\begin{pgfonlayer}{l1}
\ifcreatepdflayers
\begin{scope}[ocg={ref=1, status=visible,name={TOP-Layer}}]
\fi]
\draw[line width=0.300000 pt, draw={c1}, opacity={1.000000}, cap=butt] (-1.031000 pt, 0.326000 pt) -- (-1.028000 pt, 0.093000 pt) -- (-0.282000 pt, -0.019000 pt);
\ifcreatepdflayers
\end{scope}
\fi
\end{pgfonlayer}
\begin{pgfonlayer}{l1}
\ifcreatepdflayers
\begin{scope}[ocg={ref=1, status=visible,name={TOP-Layer}}]
\fi]
\draw[line width=0.300000 pt, draw={c1}, opacity={1.000000}, cap=round] (0.076000 pt, 0.059000 pt) -- (0.660000 pt, 0.027000 pt) -- (0.871000 pt, 0.599000 pt);
\ifcreatepdflayers
\end{scope}
\fi
\end{pgfonlayer}
\begin{pgfonlayer}{l2}
\ifcreatepdflayers
\begin{scope}[ocg={ref=2, status=visible,name={BOTTOM-Layer}}]
\fi]
\draw[line width=0.00001 pt, draw={c2}, fill={c2}, fill opacity={1.000000}] (-1.264000 pt, -0.471000 pt) -- (-1.264000 pt, 0.768000 pt) -- (1.047000 pt, 0.768000 pt) -- (1.047000 pt, -0.471000 pt) -- (-1.264000 pt, -0.471000 pt) -- cycle;
\ifcreatepdflayers
\end{scope}
\fi
\end{pgfonlayer}
\end{tikzpicture}
\iftestmode
\end{document}
\fi

View File

@@ -0,0 +1,2 @@
2,0.203922,0.396078,0.643137,1.000000,1,BOTTOM-Layer
1,0.450980,0.823529,0.086275,1.000000,1,TOP-Layer

Binary file not shown.

Binary file not shown.

File diff suppressed because one or more lines are too long

View File

@@ -18,7 +18,7 @@
*/
#include "lib-cell-renderer.h"
#include "../gds-types.h"
#include "../gds-parser/gds-types.h"
G_DEFINE_TYPE(LibCellRenderer, lib_cell_renderer, GTK_TYPE_CELL_RENDERER_TEXT)

View File

@@ -20,12 +20,11 @@
#ifndef __LIB_CELL_RENDERER_H__
#define __LIB_CELL_RENDERER_H__
#include <gtk/gtk.h>
#define LIB_CELL_RENDERER(obj) G_TYPE_CHECK_INSTANCE_CAST(obj, lib_cell_renderer_get_type(), LibCellRenderer)
#define LIB_CELL_RENDERER_CLASS(klass) G_TYPE_CHECK_CLASS_CAST(klass, lib_cell_renderer_get_type(), LibCellRendererClass)
#define IS_LIB_CELL_RENDERER(obj) G_TYPE_CHECK_INSTANCE_TYPE(obj, layer_element_get_type())
G_BEGIN_DECLS
G_DECLARE_FINAL_TYPE(LibCellRenderer, lib_cell_renderer, LIB_CELL, RENDERER, GtkCellRendererText)
#define TYPE_LIB_CELL_RENDERER (lib_cell_renderer_get_type())
typedef struct _LibCellRenderer {
@@ -34,14 +33,9 @@ typedef struct _LibCellRenderer {
/* Custom Elements */
} LibCellRenderer;
typedef struct _LibCellRendererClass {
GtkCellRendererTextClass parent;
} LibCellRendererClass;
GType lib_cell_renderer_get_type(void);
GtkCellRenderer *lib_cell_renderer_new(void);
G_END_DECLS
#endif /* __LIB_CELL_RENDERER_H__ */

View File

@@ -0,0 +1,79 @@
#include "tree-store.h"
#include "lib-cell-renderer.h"
#include "../gds-parser/gds-types.h"
static gboolean tree_sel_func(GtkTreeSelection *selection,
GtkTreeModel *model,
GtkTreePath *path,
gboolean path_currently_selected,
gpointer data)
{
GtkTreeIter iter;
struct gds_cell *cell;
gtk_tree_model_get_iter(model, &iter, path);
gtk_tree_model_get(model, &iter, CELL_SEL_CELL, &cell, -1);
/* Allow only rows with valid cell to be selected */
if (cell)
return TRUE;
else
return FALSE;
}
GtkTreeStore *setup_cell_selector(GtkTreeView* view)
{
GtkTreeStore *cell_store;
GtkCellRenderer *render_dates;
GtkCellRenderer *render_cell;
GtkCellRenderer *render_lib;
GtkTreeViewColumn *column;
GdkRGBA cell_text_color;
GValue val = G_VALUE_INIT;
cell_store = gtk_tree_store_new(CELL_SEL_COLUMN_COUNT, G_TYPE_POINTER, G_TYPE_POINTER, G_TYPE_STRING, G_TYPE_STRING);
gtk_tree_view_set_model(view, GTK_TREE_MODEL(cell_store));
render_dates = gtk_cell_renderer_text_new();
render_cell = lib_cell_renderer_new();
render_lib = lib_cell_renderer_new();
/* Set foreground color for cell column */
cell_text_color.alpha = 1;
cell_text_color.red = (double)61.0/(double)255.0;
cell_text_color.green = (double)152.0/(double)255.0;
cell_text_color.blue = 0.0;
g_value_init(&val, G_TYPE_BOOLEAN);
g_value_set_boolean(&val, TRUE);
g_object_set_property(G_OBJECT(render_cell), "foreground-set", &val);
g_value_unset(&val);
g_value_init(&val, GDK_TYPE_RGBA);
g_value_set_boxed(&val, &cell_text_color);
g_object_set_property(G_OBJECT(render_cell), "foreground-rgba", &val);
g_value_unset(&val);
column = gtk_tree_view_column_new_with_attributes("Library", render_lib, "gds-lib", CELL_SEL_LIBRARY, NULL);
gtk_tree_view_append_column(view, column);
/* Cell color: #3D9801 */
column = gtk_tree_view_column_new_with_attributes("Cell", render_cell, "gds-cell", CELL_SEL_CELL, NULL);
gtk_tree_view_append_column(view, column);
column = gtk_tree_view_column_new_with_attributes("Mod. Date", render_dates, "text", CELL_SEL_MODDATE, NULL);
gtk_tree_view_append_column(view, column);
column = gtk_tree_view_column_new_with_attributes("Acc. Date", render_dates, "text", CELL_SEL_ACCESSDATE, NULL);
gtk_tree_view_append_column(view, column);
/* Callback for selection
* This prevents selecting a library */
gtk_tree_selection_set_select_function(gtk_tree_view_get_selection(view), tree_sel_func, NULL, NULL);
return cell_store;
}

View File

@@ -0,0 +1,16 @@
#ifndef __TREE_STORE_H__
#define __TREE_STORE_H__
#include <gtk/gtk.h>
enum cell_store_columns {
CELL_SEL_LIBRARY = 0,
CELL_SEL_CELL,
CELL_SEL_MODDATE,
CELL_SEL_ACCESSDATE,
CELL_SEL_COLUMN_COUNT
};
GtkTreeStore *setup_cell_selector(GtkTreeView* view);
#endif /* __TREE_STORE_H__ */

View File

@@ -0,0 +1,128 @@
/*
* GDSII-Converter
* Copyright (C) 2018 Mario Hüttel <mario.huettel@gmx.net>
*
* This file is part of GDSII-Converter.
*
* GDSII-Converter is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*
* GDSII-Converter is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with GDSII-Converter. If not, see <http://www.gnu.org/licenses/>.
*/
#include "conv-settings-dialog.h"
struct _RendererSettingsDialog {
GtkDialog parent;
/* Private loot */
GtkWidget *radio_latex;
GtkWidget *radio_cairo;
GtkWidget *scale;
GtkWidget *layer_check;
GtkWidget *standalone_check;
};
G_DEFINE_TYPE(RendererSettingsDialog, renderer_settings_dialog, GTK_TYPE_DIALOG)
static void renderer_settings_dialog_class_init(RendererSettingsDialogClass *klass)
{
/* No special code needed. Child cells are destroyed automatically due to reference counter */
return;
}
static void show_tex_options(RendererSettingsDialog *self)
{
gtk_widget_show(self->layer_check);
gtk_widget_show(self->standalone_check);
}
static void hide_tex_options(RendererSettingsDialog *self)
{
gtk_widget_hide(self->layer_check);
gtk_widget_hide(self->standalone_check);
}
static void latex_render_callback(GtkToggleButton *radio, RendererSettingsDialog *dialog)
{
if (gtk_toggle_button_get_active(radio))
show_tex_options(dialog);
else
hide_tex_options(dialog);
}
static void renderer_settings_dialog_init(RendererSettingsDialog *self)
{
GtkBuilder *builder;
GtkWidget *box;
GtkDialog *dialog;
dialog = &(self->parent);
builder = gtk_builder_new_from_resource("/dialog.glade");
box = GTK_WIDGET(gtk_builder_get_object(builder, "dialog-box"));
self->radio_latex = GTK_WIDGET(gtk_builder_get_object(builder, "latex-radio"));
self->radio_cairo = GTK_WIDGET(gtk_builder_get_object(builder, "cairo-radio"));
self->scale = GTK_WIDGET(gtk_builder_get_object(builder, "dialog-scale"));
self->standalone_check = GTK_WIDGET(gtk_builder_get_object(builder, "standalone-check"));
self->layer_check = GTK_WIDGET(gtk_builder_get_object(builder, "layer-check"));
gtk_dialog_add_buttons(dialog, "Cancel", GTK_RESPONSE_CANCEL, "OK", GTK_RESPONSE_OK, NULL);
gtk_container_add(GTK_CONTAINER(gtk_dialog_get_content_area(dialog)), box);
gtk_window_set_title(GTK_WINDOW(self), "Renderer Settings");
g_signal_connect(self->radio_latex, "toggled", G_CALLBACK(latex_render_callback), (gpointer)self);
g_object_unref(builder);
}
RendererSettingsDialog *renderer_settings_dialog_new(GtkWindow *parent)
{
RendererSettingsDialog *res;
res = RENDERER_SETTINGS_DIALOG(g_object_new(RENDERER_TYPE_SETTINGS_DIALOG, NULL));
if (res && parent) {
gtk_window_set_transient_for(GTK_WINDOW(res), parent);
}
return res;
}
void renderer_settings_dialog_get_settings(RendererSettingsDialog *dialog, struct render_settings *settings)
{
if (!settings || !dialog)
return;
settings->scale = gtk_range_get_value(GTK_RANGE(dialog->scale));
settings->renderer = (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(dialog->radio_latex)) == TRUE ? RENDERER_LATEX_TIKZ : RENDERER_CAIROGRAPHICS);
settings->tex_pdf_layers = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(dialog->layer_check));
settings->tex_standalone = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(dialog->standalone_check));
}
void renderer_settings_dialog_set_settings(RendererSettingsDialog *dialog, struct render_settings *settings)
{
if (!settings || !dialog)
return;
gtk_range_set_value(GTK_RANGE(dialog->scale), settings->scale);
gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(dialog->layer_check), settings->tex_pdf_layers);
gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(dialog->standalone_check), settings->tex_standalone);
switch (settings->renderer) {
case RENDERER_LATEX_TIKZ:
gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(dialog->radio_latex), TRUE);
show_tex_options(dialog);
break;
case RENDERER_CAIROGRAPHICS:
hide_tex_options(dialog);
gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(dialog->radio_cairo), TRUE);
break;
}
}

View File

@@ -0,0 +1,48 @@
/*
* GDSII-Converter
* Copyright (C) 2018 Mario Hüttel <mario.huettel@gmx.net>
*
* This file is part of GDSII-Converter.
*
* GDSII-Converter is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*
* GDSII-Converter is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with GDSII-Converter. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef __CONV_SETTINGS_DIALOG_H__
#define __CONV_SETTINGS_DIALOG_H__
#include <gtk/gtk.h>
G_BEGIN_DECLS
enum output_renderer {RENDERER_LATEX_TIKZ, RENDERER_CAIROGRAPHICS};
G_DECLARE_FINAL_TYPE(RendererSettingsDialog, renderer_settings_dialog, RENDERER, SETTINGS_DIALOG, GtkDialog)
RendererSettingsDialog *renderer_settings_dialog_new(GtkWindow *parent);
#define RENDERER_TYPE_SETTINGS_DIALOG (renderer_settings_dialog_get_type())
struct render_settings {
double scale;
enum output_renderer renderer;
gboolean tex_pdf_layers;
gboolean tex_standalone;
};
G_END_DECLS
void renderer_settings_dialog_set_settings(RendererSettingsDialog *dialog, struct render_settings *settings);
void renderer_settings_dialog_get_settings(RendererSettingsDialog *dialog, struct render_settings *settings);
#endif /* __CONV_SETTINGS_DIALOG_H__ */

View File

@@ -19,8 +19,7 @@
#include "layer-element.h"
G_DEFINE_TYPE(LayerElement, layer_element, GTK_TYPE_BOX)
G_DEFINE_TYPE(LayerElement, layer_element, GTK_TYPE_LIST_BOX_ROW)
static void layer_element_dispose(GObject *obj)
{
@@ -40,29 +39,105 @@ static void layer_element_class_init(LayerElementClass *klass)
oclass->constructed = layer_element_constructed;
}
static GtkTargetEntry entries[] = {
{ "GTK_LIST_BOX_ROW", GTK_TARGET_SAME_APP, 0 }
};
static void layer_element_drag_begin(GtkWidget *widget,
GdkDragContext *context,
gpointer data)
{
GtkWidget *row;
GtkAllocation alloc;
cairo_surface_t *surface;
cairo_t *cr;
int x, y;
row = gtk_widget_get_ancestor (widget, GTK_TYPE_LIST_BOX_ROW);
gtk_widget_get_allocation (row, &alloc);
surface = cairo_image_surface_create (CAIRO_FORMAT_ARGB32, alloc.width, alloc.height);
cr = cairo_create (surface);
gtk_style_context_add_class (gtk_widget_get_style_context (row), "drag-icon");
gtk_widget_draw (row, cr);
gtk_style_context_remove_class (gtk_widget_get_style_context (row), "drag-icon");
gtk_widget_translate_coordinates (widget, row, 0, 0, &x, &y);
cairo_surface_set_device_offset (surface, -x, -y);
gtk_drag_set_icon_surface (context, surface);
cairo_destroy (cr);
cairo_surface_destroy (surface);
}
static void layer_element_drag_data_get(GtkWidget *widget,
GdkDragContext *context,
GtkSelectionData *selection_data,
guint info,
guint time,
gpointer data)
{
gtk_selection_data_set(selection_data, gdk_atom_intern_static_string("GTK_LIST_BOX_ROW"),
32, (const guchar *)&widget, sizeof(gpointer));
}
static void layer_element_drag_data_received(GtkWidget *widget,
GdkDragContext *context,
gint x,
gint y,
GtkSelectionData *selection_data,
guint info,
guint32 time,
gpointer data)
{
GtkWidget *target;
GtkWidget *row;
GtkWidget *source;
int pos;
target = widget;
pos = gtk_list_box_row_get_index (GTK_LIST_BOX_ROW (target));
row = (gpointer) *(gpointer *)gtk_selection_data_get_data (selection_data);
source = gtk_widget_get_ancestor (row, GTK_TYPE_LIST_BOX_ROW);
if (source == target)
return;
g_object_ref (source);
gtk_container_remove (GTK_CONTAINER (gtk_widget_get_parent (source)), source);
gtk_list_box_insert (GTK_LIST_BOX (gtk_widget_get_parent (target)), source, pos);
g_object_unref (source);
}
static void layer_element_init(LayerElement *self)
{
GtkBuilder *builder;
GtkWidget *glade_box;
builder = gtk_builder_new_from_resource("/layer-widget.glade");
glade_box = GTK_WIDGET(gtk_builder_get_object(builder, "box"));
gtk_box_pack_start(GTK_BOX(self), glade_box, TRUE, TRUE, 0);
gtk_container_add(GTK_CONTAINER(self), glade_box);
/* Get Elements */
self->priv.color = GTK_COLOR_BUTTON(gtk_builder_get_object(builder, "color"));
self->priv.export = GTK_CHECK_BUTTON(gtk_builder_get_object(builder, "export"));
self->priv.layer = GTK_LABEL(gtk_builder_get_object(builder, "layer"));
self->priv.name = GTK_ENTRY(gtk_builder_get_object(builder, "entry"));
self->priv.event_handle = GTK_EVENT_BOX(gtk_builder_get_object(builder, "event-box"));
/* Connect signals */
/* None */
/* Setup drag and drop */
gtk_drag_source_set(GTK_WIDGET(self->priv.event_handle), GDK_BUTTON1_MASK, entries, 1, GDK_ACTION_MOVE);
g_signal_connect(self->priv.event_handle, "drag-begin", G_CALLBACK(layer_element_drag_begin), NULL);
g_signal_connect(self->priv.event_handle, "drag-data-get", G_CALLBACK(layer_element_drag_data_get), NULL);
gtk_drag_dest_set(GTK_WIDGET(self), GTK_DEST_DEFAULT_ALL, entries, 1, GDK_ACTION_MOVE);
g_signal_connect(GTK_WIDGET(self), "drag-data-received", G_CALLBACK(layer_element_drag_data_received), NULL);
g_object_unref(builder);
}
GtkWidget *layer_element_new(void)
{
return GTK_WIDGET(g_object_new(layer_element_get_type(), NULL));
return GTK_WIDGET(g_object_new(TYPE_LAYER_ELEMENT, NULL));
}
const char *layer_element_get_name(LayerElement *elem)
@@ -80,7 +155,7 @@ void layer_element_set_layer(LayerElement *elem, int layer)
GString *string;
string = g_string_new_len(NULL, 100);
g_string_printf(string, "Layer: %3d", layer);
g_string_printf(string, "Layer: %d", layer);
gtk_label_set_text(elem->priv.layer, (const gchar *)string->str);
elem->priv.layer_num = layer;
g_string_free(string, TRUE);

View File

@@ -21,33 +21,30 @@
#define __LAYER_ELEMENT_H__
#include <gtk/gtk.h>
// #include <gdk/gdk.h>
#define LAYER_ELEMENT(obj) G_TYPE_CHECK_INSTANCE_CAST(obj, layer_element_get_type(), LayerElement)
#define LAYER_ELEMENT_CLASS(klass) G_TYPE_CHECK_CLASS_CAST(klass, layer_element_get_type(), LayerElementClass)
#define IS_LAYER_ELEMENT(obj) G_TYPE_CHECK_INSTANCE_TYPE(obj, layer_element_get_type())
G_BEGIN_DECLS
/* Creates Class structure etc */
G_DECLARE_FINAL_TYPE(LayerElement, layer_element, LAYER, ELEMENT, GtkListBoxRow)
#define TYPE_LAYER_ELEMENT (layer_element_get_type())
typedef struct _LayerElementPriv {
GtkEntry *name;
GtkLabel *layer;
int layer_num;
GtkEventBox *event_handle;
GtkColorButton *color;
GtkCheckButton *export;
} LayerElementPriv;
typedef struct _LayerElement {
struct _LayerElement {
/* Inheritance */
GtkBox hbox;
GtkListBoxRow parent;
/* Custom Elements */
LayerElementPriv priv;
} LayerElement;
};
typedef struct _LayerElementClass {
GtkBoxClass parent_class;
} LayerElementClass;
GType layer_element_get_type(void);
GtkWidget *layer_element_new(void);
const char *layer_element_get_name(LayerElement *elem);
@@ -59,4 +56,6 @@ gboolean layer_element_get_export(LayerElement *elem);
void layer_element_get_color(LayerElement *elem, GdkRGBA *rgba);
void layer_element_set_color(LayerElement *elem, GdkRGBA *rgba);
G_END_DECLS
#endif /* __LAYER_ELEMENT_H__ */