Compare commits
6 Commits
4c5784c3a4
...
v1.0-rc2
Author | SHA1 | Date | |
---|---|---|---|
a5d794461a | |||
6fb4d39fc8 | |||
d0e1383861 | |||
6296627ac2 | |||
f79bab102b | |||
e5300e60aa |
@@ -18,8 +18,7 @@ aux_source_directory("tree-renderer" RENDERER_SOURCES)
|
|||||||
aux_source_directory("gds-parser" PARSER_SOURCES)
|
aux_source_directory("gds-parser" PARSER_SOURCES)
|
||||||
aux_source_directory("latex-output" LATEX_SOURCES)
|
aux_source_directory("latex-output" LATEX_SOURCES)
|
||||||
aux_source_directory("cairo-output" CAIRO_SOURCES)
|
aux_source_directory("cairo-output" CAIRO_SOURCES)
|
||||||
set(SOURCE "main.c" "layer-selector.c")
|
set(SOURCE "main.c" "layer-selector.c" "main-window.c")
|
||||||
|
|
||||||
|
|
||||||
set(SOURCE
|
set(SOURCE
|
||||||
${SOURCE}
|
${SOURCE}
|
||||||
|
@@ -224,7 +224,6 @@ static GList *append_cell(GList *curr_list, struct gds_cell **cell_ptr)
|
|||||||
cell->child_cells = NULL;
|
cell->child_cells = NULL;
|
||||||
cell->graphic_objs = NULL;
|
cell->graphic_objs = NULL;
|
||||||
cell->name[0] = 0;
|
cell->name[0] = 0;
|
||||||
cell->bounding_box.scanned = FALSE;
|
|
||||||
} else
|
} else
|
||||||
return NULL;
|
return NULL;
|
||||||
/* return cell */
|
/* return cell */
|
||||||
@@ -304,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_cell_instance *inst = (struct gds_cell_instance *)gcell_ref;
|
||||||
struct gds_library *lib = (struct gds_library *)glibrary;
|
struct gds_library *lib = (struct gds_library *)glibrary;
|
||||||
@@ -330,7 +329,7 @@ void parse_reference_list(gpointer gcell_ref, gpointer glibrary)
|
|||||||
GDS_WARN("referenced cell could not be found in library");
|
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;
|
struct gds_cell *cell = (struct gds_cell *)gcell;
|
||||||
|
|
||||||
@@ -341,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;
|
struct gds_library *lib = (struct gds_library *)library_list_item;
|
||||||
|
|
||||||
@@ -349,222 +348,7 @@ void scan_library_references(gpointer library_list_item, gpointer user)
|
|||||||
g_list_foreach(lib->cells, scan_cell_reference_dependencies, lib);
|
g_list_foreach(lib->cells, scan_cell_reference_dependencies, lib);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void apply_transforms_on_bounding_box(struct gds_cell_instance *cell_inst, struct gds_bounding_box *result)
|
static void gds_parse_date(const char *buffer, int length, struct gds_time_field *mod_date, struct gds_time_field *access_date)
|
||||||
{
|
|
||||||
struct gds_dpoint vertices[4];
|
|
||||||
int i;
|
|
||||||
double xmin= INT_MAX, xmax=INT_MIN, ymin=INT_MAX, ymax= INT_MIN;
|
|
||||||
double temp;
|
|
||||||
|
|
||||||
double phi = M_PI * cell_inst->angle / 180;
|
|
||||||
|
|
||||||
if (cell_inst->cell_ref->bounding_box.scanned == FALSE)
|
|
||||||
return;
|
|
||||||
|
|
||||||
if (!result)
|
|
||||||
return;
|
|
||||||
|
|
||||||
/* Calculate all 4 bounding box points */
|
|
||||||
vertices[0].x = cell_inst->cell_ref->bounding_box.coords[0].x;
|
|
||||||
vertices[0].y = cell_inst->cell_ref->bounding_box.coords[0].y;
|
|
||||||
vertices[1].x = cell_inst->cell_ref->bounding_box.coords[0].x;
|
|
||||||
vertices[1].y = cell_inst->cell_ref->bounding_box.coords[1].y;
|
|
||||||
vertices[2].x = cell_inst->cell_ref->bounding_box.coords[1].x;
|
|
||||||
vertices[2].y = cell_inst->cell_ref->bounding_box.coords[1].y;
|
|
||||||
vertices[3].x = cell_inst->cell_ref->bounding_box.coords[1].x;
|
|
||||||
vertices[3].y = cell_inst->cell_ref->bounding_box.coords[0].y;
|
|
||||||
|
|
||||||
/* Apply flipping and magnification */
|
|
||||||
for (i = 0; i < 4; i++) {
|
|
||||||
vertices[i].x = (vertices[i].x * cell_inst->magnification);
|
|
||||||
vertices[i].y = (vertices[i].y * cell_inst->magnification * (cell_inst->flipped ? -1 : 1));
|
|
||||||
}
|
|
||||||
/* Apply rotation */
|
|
||||||
for (i = 0; i < 4; i++) {
|
|
||||||
temp =(cos(phi) * vertices[i].x - sin(phi) * vertices[i].y);
|
|
||||||
vertices[i].y =(sin(phi) * vertices[i].x + cos(phi) * vertices[i].y);
|
|
||||||
vertices[i].x = temp;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Translate origin */
|
|
||||||
for (i = 0; i < 4; i++) {
|
|
||||||
vertices[i].x += (double)cell_inst->origin.x;
|
|
||||||
vertices[i].y += (double)cell_inst->origin.y;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Calculate new bounding box */
|
|
||||||
for (i = 0; i < 4; i++) {
|
|
||||||
xmin = MIN(xmin, vertices[i].x);
|
|
||||||
ymin = MIN(ymin, vertices[i].y);
|
|
||||||
ymax = MAX(ymax, vertices[i].y);
|
|
||||||
xmax = MAX(xmax, vertices[i].x);
|
|
||||||
}
|
|
||||||
|
|
||||||
result->scanned = TRUE;
|
|
||||||
result->coords[0].x = xmin;
|
|
||||||
result->coords[0].y = ymin;
|
|
||||||
result->coords[1].x = xmax;
|
|
||||||
result->coords[1].y = ymax;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void calculate_bounding_path_box(struct gds_graphics *path, struct gds_bounding_box *box)
|
|
||||||
{
|
|
||||||
cairo_surface_t *surf;
|
|
||||||
cairo_t *cr;
|
|
||||||
GList *vertex_list;
|
|
||||||
struct gds_point *vertex;
|
|
||||||
|
|
||||||
double x0, y0, width, height;
|
|
||||||
|
|
||||||
if (path == NULL || box == NULL)
|
|
||||||
return;
|
|
||||||
if (path->vertices == NULL)
|
|
||||||
return;
|
|
||||||
if (path->vertices->data == NULL)
|
|
||||||
return;
|
|
||||||
|
|
||||||
box->scanned = FALSE;
|
|
||||||
|
|
||||||
/* Check path length */
|
|
||||||
if (g_list_length(path->vertices) < 2)
|
|
||||||
return;
|
|
||||||
|
|
||||||
surf = cairo_recording_surface_create(CAIRO_CONTENT_COLOR_ALPHA, NULL);
|
|
||||||
cr = cairo_create(surf);
|
|
||||||
|
|
||||||
/* Prepare line properties */
|
|
||||||
switch (path->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;
|
|
||||||
default:
|
|
||||||
cairo_set_line_cap(cr, CAIRO_LINE_CAP_SQUARE);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
cairo_set_line_width(cr, path->width_absolute);
|
|
||||||
cairo_set_source_rgba(cr, 1, 1 , 0, 0.5);
|
|
||||||
|
|
||||||
/* Start at first point */
|
|
||||||
vertex = (struct gds_point *)path->vertices->data;
|
|
||||||
cairo_move_to(cr, (double)vertex->x, (double)vertex->y);
|
|
||||||
|
|
||||||
/* Remaining points */
|
|
||||||
for (vertex_list = path->vertices->next; vertex_list != NULL; vertex_list = vertex_list->next) {
|
|
||||||
vertex = (struct gds_point *)vertex_list->data;
|
|
||||||
cairo_line_to(cr, (double)vertex->x, (double)vertex->y);
|
|
||||||
}
|
|
||||||
cairo_stroke(cr);
|
|
||||||
|
|
||||||
cairo_recording_surface_ink_extents(surf, &x0, &y0, &width, &height);
|
|
||||||
box->coords[0].x = x0;
|
|
||||||
box->coords[0].y = y0;
|
|
||||||
box->coords[1].x = (x0+width);
|
|
||||||
box->coords[1].y = (y0+height);
|
|
||||||
box->scanned = TRUE;
|
|
||||||
cairo_destroy(cr);
|
|
||||||
cairo_surface_destroy(surf);
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
static void update_bounding_box_with_gfx(struct gds_graphics *gfx, double *xlow,
|
|
||||||
double *ylow, double *xhigh, double *yhigh)
|
|
||||||
{
|
|
||||||
GList *vertex_list;
|
|
||||||
struct gds_point *vertex;
|
|
||||||
struct gds_bounding_box path_box;
|
|
||||||
|
|
||||||
path_box.scanned = FALSE;
|
|
||||||
|
|
||||||
if (gfx->gfx_type == GRAPHIC_POLYGON) {
|
|
||||||
for (vertex_list = gfx->vertices; vertex_list != NULL; vertex_list = vertex_list->next) {
|
|
||||||
vertex = (struct gds_point *)vertex_list->data;
|
|
||||||
|
|
||||||
*xlow = MIN(*xlow, (double)vertex->x);
|
|
||||||
*ylow = MIN(*ylow, (double)vertex->y);
|
|
||||||
*xhigh = MAX(*xhigh, (double)vertex->x);
|
|
||||||
*yhigh = MAX(*yhigh, (double)vertex->y);
|
|
||||||
}
|
|
||||||
} else if (gfx->gfx_type == GRAPHIC_PATH) {
|
|
||||||
calculate_bounding_path_box(gfx, &path_box);
|
|
||||||
if (path_box.scanned == TRUE) {
|
|
||||||
*xlow = MIN(*xlow, path_box.coords[0].x);
|
|
||||||
*ylow = MIN(*ylow, path_box.coords[0].y);
|
|
||||||
*xhigh = MAX(*xhigh, path_box.coords[1].x);
|
|
||||||
*yhigh = MAX(*yhigh, path_box.coords[1].y);
|
|
||||||
} else
|
|
||||||
GDS_WARN("Bounding box of path not calculated");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static void cell_create_bounding_box(struct gds_cell *cell)
|
|
||||||
{
|
|
||||||
GList *ref;
|
|
||||||
GList *gfx_list;
|
|
||||||
|
|
||||||
struct gds_bounding_box box_transform;
|
|
||||||
struct gds_cell_instance *cell_inst;
|
|
||||||
struct gds_graphics *gfx;
|
|
||||||
|
|
||||||
double xlow=INT_MAX, xhigh=INT_MIN, ylow=INT_MAX, yhigh=INT_MIN;
|
|
||||||
|
|
||||||
if (cell->bounding_box.scanned == TRUE)
|
|
||||||
return;
|
|
||||||
|
|
||||||
/* Generate bounding boxes of child cells and update current box*/
|
|
||||||
for (ref = cell->child_cells; ref != NULL; ref = ref->next) {
|
|
||||||
cell_inst = (struct gds_cell_instance *)ref->data;
|
|
||||||
if (cell_inst->cell_ref) {
|
|
||||||
if (cell_inst->cell_ref->bounding_box.scanned == FALSE)
|
|
||||||
cell_create_bounding_box(cell_inst->cell_ref);
|
|
||||||
|
|
||||||
/* Apply transforms of cell in current cell to calculate the box of the specific instance */
|
|
||||||
if (cell_inst->cell_ref->bounding_box.scanned == TRUE) {
|
|
||||||
apply_transforms_on_bounding_box(cell_inst, &box_transform);
|
|
||||||
xlow = MIN(xlow, box_transform.coords[0].x);
|
|
||||||
ylow = MIN(ylow, box_transform.coords[0].y);
|
|
||||||
xhigh = MAX(xhigh, box_transform.coords[1].x);
|
|
||||||
yhigh = MAX(yhigh, box_transform.coords[1].y);
|
|
||||||
} else
|
|
||||||
GDS_WARN("Unscanned cells present: %s. This should not happen", cell_inst->ref_name);
|
|
||||||
} else
|
|
||||||
GDS_WARN("Cell referenced that does not exist: %s. Bounding box might be incorrect.",
|
|
||||||
cell_inst->ref_name);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Generate update box using graphic objects*/
|
|
||||||
for (gfx_list = cell->graphic_objs; gfx_list != NULL; gfx_list = gfx_list->next) {
|
|
||||||
gfx = (struct gds_graphics *)gfx_list->data;
|
|
||||||
|
|
||||||
update_bounding_box_with_gfx(gfx, &xlow, &ylow, &xhigh, &yhigh);
|
|
||||||
}
|
|
||||||
|
|
||||||
printf("Cell '%s' has size: %lf / %lf\n", cell->name, xhigh - xlow, yhigh - ylow);
|
|
||||||
cell->bounding_box.coords[0].x = xlow;
|
|
||||||
cell->bounding_box.coords[0].y = ylow;
|
|
||||||
cell->bounding_box.coords[1].x = xhigh;
|
|
||||||
cell->bounding_box.coords[1].y = yhigh;
|
|
||||||
cell->bounding_box.scanned = TRUE;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void library_create_bounding_boxes(gpointer library_list_item, gpointer user)
|
|
||||||
{
|
|
||||||
GList *cell_list;
|
|
||||||
struct gds_library *lib = (struct gds_library *)library_list_item;
|
|
||||||
if (!lib)
|
|
||||||
return;
|
|
||||||
for (cell_list = lib->cells; cell_list != NULL; cell_list = cell_list->next) {
|
|
||||||
cell_create_bounding_box((struct gds_cell *)cell_list->data);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
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;
|
struct gds_time_field *temp_date;
|
||||||
@@ -946,8 +730,6 @@ int parse_gds_from_file(const char *filename, GList **library_list)
|
|||||||
if (!run) {
|
if (!run) {
|
||||||
/* Iterate and find references to cells */
|
/* Iterate and find references to cells */
|
||||||
g_list_foreach(lib_list, scan_library_references, NULL);
|
g_list_foreach(lib_list, scan_library_references, NULL);
|
||||||
/* Create bounding boxes */
|
|
||||||
g_list_foreach(lib_list, library_create_bounding_boxes, NULL);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@@ -16,16 +16,6 @@ struct gds_point {
|
|||||||
int y;
|
int y;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct gds_dpoint {
|
|
||||||
double x;
|
|
||||||
double y;
|
|
||||||
};
|
|
||||||
|
|
||||||
struct gds_bounding_box {
|
|
||||||
gboolean scanned;
|
|
||||||
struct gds_dpoint coords[2];
|
|
||||||
};
|
|
||||||
|
|
||||||
struct gds_time_field {
|
struct gds_time_field {
|
||||||
uint16_t year;
|
uint16_t year;
|
||||||
uint16_t month;
|
uint16_t month;
|
||||||
@@ -59,7 +49,6 @@ struct gds_cell {
|
|||||||
struct gds_time_field access_time;
|
struct gds_time_field access_time;
|
||||||
GList *child_cells;
|
GList *child_cells;
|
||||||
GList *graphic_objs;
|
GList *graphic_objs;
|
||||||
struct gds_bounding_box bounding_box;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
struct gds_library {
|
struct gds_library {
|
||||||
|
43
glade/about.glade
Normal file
43
glade/about.glade
Normal 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 <mario.huettel@gmx.net></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>
|
@@ -4,7 +4,6 @@
|
|||||||
<requires lib="gtk+" version="3.20"/>
|
<requires lib="gtk+" version="3.20"/>
|
||||||
<object class="GtkWindow" id="main-window">
|
<object class="GtkWindow" id="main-window">
|
||||||
<property name="height_request">250</property>
|
<property name="height_request">250</property>
|
||||||
<property name="visible">True</property>
|
|
||||||
<property name="can_focus">False</property>
|
<property name="can_focus">False</property>
|
||||||
<child type="titlebar">
|
<child type="titlebar">
|
||||||
<object class="GtkHeaderBar">
|
<object class="GtkHeaderBar">
|
||||||
@@ -35,7 +34,7 @@
|
|||||||
<property name="can_focus">True</property>
|
<property name="can_focus">True</property>
|
||||||
<property name="receives_default">True</property>
|
<property name="receives_default">True</property>
|
||||||
<style>
|
<style>
|
||||||
<class name="destructive-action"/>
|
<class name="suggested-action"/>
|
||||||
</style>
|
</style>
|
||||||
</object>
|
</object>
|
||||||
<packing>
|
<packing>
|
||||||
|
@@ -2,6 +2,7 @@
|
|||||||
<gresources>
|
<gresources>
|
||||||
<gresource prefix="/">
|
<gresource prefix="/">
|
||||||
<file compressed="true">main.glade</file>
|
<file compressed="true">main.glade</file>
|
||||||
|
<file compressed="true">about.glade</file>
|
||||||
<file>layer-widget.glade</file>
|
<file>layer-widget.glade</file>
|
||||||
<file>dialog.glade</file>
|
<file>dialog.glade</file>
|
||||||
</gresource>
|
</gresource>
|
||||||
|
316
main-window.c
Normal file
316
main-window.c
Normal 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
27
main-window.h
Normal 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_ */
|
330
main.c
330
main.c
@@ -18,303 +18,85 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include "gds-parser/gds-parser.h"
|
|
||||||
#include <gtk/gtk.h>
|
#include <gtk/gtk.h>
|
||||||
#include "layer-selector.h"
|
#include "main-window.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 {
|
struct application_data {
|
||||||
GtkWindow *main_window;
|
GtkApplication *app;
|
||||||
GList **list_ptr;
|
|
||||||
GtkTreeStore *cell_store;
|
|
||||||
GtkListBox *layer_box;
|
|
||||||
};
|
|
||||||
|
|
||||||
struct convert_button_data {
|
|
||||||
GtkTreeView *tree_view;
|
|
||||||
GtkWindow *main_window;
|
GtkWindow *main_window;
|
||||||
};
|
};
|
||||||
|
|
||||||
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));
|
struct application_data *appdata = (struct application_data *)user_data;
|
||||||
gtk_main_quit();
|
gtk_widget_destroy(GTK_WIDGET(appdata->main_window));
|
||||||
return TRUE;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
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);
|
builder = gtk_builder_new_from_resource("/about.glade");
|
||||||
g_string_printf(str, "%02u.%02u.%u - %02u:%02u",
|
dialog = GTK_DIALOG(gtk_builder_get_object(builder, "about-dialog"));
|
||||||
(unsigned int)date->day,
|
gtk_window_set_transient_for(GTK_WINDOW(dialog), appdata->main_window);
|
||||||
(unsigned int)date->month,
|
gtk_dialog_run(dialog);
|
||||||
(unsigned int)date->year,
|
|
||||||
(unsigned int)date->hour,
|
gtk_widget_destroy(dialog);
|
||||||
(unsigned int)date->minute);
|
g_object_unref(builder);
|
||||||
return str;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
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;
|
GtkWindow *main_window;
|
||||||
GtkTreeIter libiter;
|
struct application_data *appdata = (struct application_data *)user_data;
|
||||||
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,
|
main_window = create_main_window();
|
||||||
"Cancel", GTK_RESPONSE_CANCEL, "Open GDSII", GTK_RESPONSE_ACCEPT, NULL);
|
appdata->main_window = main_window;
|
||||||
file_chooser = GTK_FILE_CHOOSER(open_dialog);
|
gtk_application_add_window(GTK_APPLICATION(app), main_window);
|
||||||
/* Add GDS II Filter */
|
gtk_widget_show(GTK_WIDGET(main_window));
|
||||||
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);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
int main(int argc, char **argv)
|
int main(int argc, char **argv)
|
||||||
{
|
{
|
||||||
GtkBuilder *main_builder;
|
GtkApplication *gapp;
|
||||||
GList *gds_libs = NULL;
|
int app_status;
|
||||||
GtkTreeView *cell_tree;
|
struct application_data appdata;
|
||||||
GtkTreeStore *cell_store;
|
GMenu *menu;
|
||||||
GtkWidget *conv_button;
|
GMenu *m_quit;
|
||||||
GtkWidget *listbox;
|
GMenu *m_about;
|
||||||
|
|
||||||
struct open_button_data open_data;
|
gapp = gtk_application_new("de.shimatta.gds-render", G_APPLICATION_FLAGS_NONE);
|
||||||
struct convert_button_data conv_data;
|
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);
|
||||||
gtk_init(&argc, &argv);
|
g_signal_connect (gapp, "activate", G_CALLBACK(gapp_activate), &appdata);
|
||||||
|
|
||||||
main_builder = gtk_builder_new_from_resource("/main.glade");
|
|
||||||
gtk_builder_connect_signals(main_builder, NULL);
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
cell_tree = (GtkTreeView *)gtk_builder_get_object(main_builder, "cell-tree");
|
menu = g_menu_new();
|
||||||
cell_store = setup_cell_selector(cell_tree);
|
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;
|
app_status = g_application_run (G_APPLICATION(gapp), argc, argv);
|
||||||
open_data.list_ptr = &gds_libs;
|
g_object_unref (gapp);
|
||||||
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 */
|
return app_status;
|
||||||
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);
|
|
||||||
|
|
||||||
gtk_main();
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
}
|
||||||
|
Reference in New Issue
Block a user