Compare commits
184 Commits
v1.0-rc3
...
731e377b6e
Author | SHA1 | Date | |
---|---|---|---|
731e377b6e | |||
0d0b692960 | |||
c2323ab43d | |||
17c9d088cc | |||
5f40f148b6 | |||
86566a038f | |||
4ca1f75813 | |||
4d2f3b0d70 | |||
ed37fc0222 | |||
d4f14c52ed | |||
58d3f5c57c | |||
2510a54aac | |||
02a59c4cc5 | |||
40c4c8b4fb | |||
01c9701492 | |||
01ab56e07a | |||
3ffd63115f | |||
31c4efe99b | |||
f5bc8de86e | |||
d107954859 | |||
5c994f892a | |||
96f1347b2c | |||
2d2ca67c48 | |||
d9282d8e5a | |||
d5f1b2edf4 | |||
f224b28613 | |||
7b10d41160 | |||
302d462cda | |||
c146bcd094 | |||
e6abaddcd1 | |||
a35231b9ec | |||
24b70eec48 | |||
8ffcba830d | |||
022d9561db | |||
f5f8509b91 | |||
61f607ac94 | |||
ee1b55120f | |||
b04788b7d4 | |||
3c05b50bc7 | |||
dfadaa241e | |||
4f02854401 | |||
f2b02c0c1f | |||
e739305f46 | |||
5729ef0db8 | |||
88cd834d13 | |||
7f7b4cc7bf | |||
f625d2daba | |||
e42aa36520 | |||
2ffa09d104 | |||
feb69b6d60 | |||
20ec6bd41b | |||
eef012fc4d | |||
e847e691bd | |||
0d6b2c7a36 | |||
583f01faae | |||
795d496949 | |||
6ebd05007e | |||
906225f47f | |||
dadafa43a3 | |||
2d3241d8b7 | |||
0ecc60d2a1 | |||
9b0f268bbd | |||
6ae316f459 | |||
082a823575 | |||
1f7f3118fa | |||
5cfd93c18d | |||
6818357f64 | |||
b0fdb261e0 | |||
de8d6967c6 | |||
493f787fd1 | |||
a7b7ba71e5 | |||
d08cd3626d | |||
ef180f3ea2 | |||
74ecde9807 | |||
cd2cf8c5c7 | |||
63eb65a3c4 | |||
aa413732f1 | |||
54165a8475 | |||
c3c4636334 | |||
f4de9c4402 | |||
a016a18587 | |||
a3626e7b33 | |||
4dcafeed3f | |||
03e2b15571 | |||
e278ad6d94 | |||
8d8af8d211 | |||
4bed016f01 | |||
e8c7f78af4 | |||
60e20f45cc | |||
cd55137951 | |||
d6fb6ba6b0 | |||
829c9a2386 | |||
a99a469cf0 | |||
f237004e6c | |||
188086de52 | |||
38f18009fc | |||
ff3f692f2c | |||
5537c076a8 | |||
b43b142a75 | |||
4c0df56386 | |||
008fe52cb2 | |||
67f9d9b4ee | |||
e289e7b301 | |||
b9cc8570ac | |||
5357aff1b8 | |||
64508104bc | |||
60f54e2240 | |||
19b26a3c26 | |||
28734a797a | |||
31d9d26aa4 | |||
45f0d90a87 | |||
33deba8ca4 | |||
587b79dc31 | |||
67e5023c1e | |||
c94c3d591e | |||
c9e2c2a76d | |||
bb2a4f7f04 | |||
6b03695824 | |||
b0c25a4bcf | |||
899c8daf81 | |||
a9c7b9f61f | |||
55fd080796 | |||
178ef2d5b2 | |||
6a78e0df15 | |||
1e6d0bd1b9 | |||
658e681c38 | |||
e24b4a8367 | |||
960a773ed1 | |||
ab23be1cfc | |||
72d5352b09 | |||
3f198f870a | |||
2a204640bd | |||
a237a89ecf | |||
1ec0f9b297 | |||
2f2eb90b69 | |||
bbf08a4d6e | |||
34a19fa11d | |||
b4ae8eee37 | |||
6e1b7d3f61 | |||
d1e6e7b05a | |||
187ae2a74b | |||
eeae61ad47 | |||
3146ca801f | |||
43fdab4533 | |||
59835018af | |||
d81c6d1037 | |||
ba53a1151e | |||
fdf2c9a42b | |||
34c113517b | |||
5291b682c7 | |||
e76f2cbb9d | |||
586339cac1 | |||
3882f3944e | |||
00b47d7ded | |||
e9b67fe1bc | |||
976bdd9854 | |||
73e4806e65 | |||
0b17c25ecc | |||
0ef6d2f40f | |||
58bb74b905 | |||
cd9030a24e | |||
546332a9c2 | |||
68e7d52cd8 | |||
91a3e8f983 | |||
f74e2d5cf5 | |||
8ffb1d42b6 | |||
845da756b7 | |||
531634b55a | |||
2e1cf456c7 | |||
bce47f11fc | |||
5573ceb46b | |||
7124c9a5cc | |||
d5997ab5f2 | |||
e692129477 | |||
af031acc38 | |||
199833d603 | |||
b0acbda6e3 | |||
7e4b915961 | |||
1fe70422db | |||
b5087769ee | |||
4f9e5ca0b4 | |||
a2b83c37a9 | |||
15ff68ea74 | |||
6bb05890b9 |
3
.gitmodules
vendored
Normal file
3
.gitmodules
vendored
Normal file
@@ -0,0 +1,3 @@
|
|||||||
|
[submodule "c-style-checker"]
|
||||||
|
path = c-style-checker
|
||||||
|
url = https://git.shimatta.de/mhu/c-style-checker
|
@@ -6,36 +6,39 @@ pkg_search_module(GLIB REQUIRED glib-2.0)
|
|||||||
pkg_check_modules(GTK3 REQUIRED gtk+-3.0)
|
pkg_check_modules(GTK3 REQUIRED gtk+-3.0)
|
||||||
pkg_check_modules(CAIRO REQUIRED cairo)
|
pkg_check_modules(CAIRO REQUIRED cairo)
|
||||||
|
|
||||||
add_subdirectory(glade)
|
add_subdirectory(resources)
|
||||||
add_subdirectory(doxygen)
|
add_subdirectory(doxygen)
|
||||||
|
add_subdirectory(version)
|
||||||
|
|
||||||
include_directories(${GLIB_INCLUDE_DIRS} ${GTK3_INCLUDE_DIRS} ${CAIRO_INCLUDE_DIRS})
|
include_directories(${GLIB_INCLUDE_DIRS} ${GTK3_INCLUDE_DIRS} ${CAIRO_INCLUDE_DIRS} ${CMAKE_CURRENT_SOURCE_DIR}/include)
|
||||||
link_directories(${GLIB_LINK_DIRS} ${GTK3_LINK_DIRS} ${CAIRO_LINK_DIRS})
|
link_directories(${GLIB_LINK_DIRS} ${GTK3_LINK_DIRS} ${CAIRO_LINK_DIRS})
|
||||||
add_definitions(${GLIB2_CFLAGS_OTHER})
|
add_definitions(${GLIB2_CFLAGS_OTHER})
|
||||||
|
|
||||||
aux_source_directory("widgets" LAYER_SOURCES)
|
aux_source_directory("widgets" LAYER_SOURCES)
|
||||||
aux_source_directory("tree-renderer" RENDERER_SOURCES)
|
aux_source_directory("cell-selector" CELL_SELECTOR_SOURCES)
|
||||||
aux_source_directory("gds-parser" PARSER_SOURCES)
|
aux_source_directory("gds-utils" GDS_SOURCES)
|
||||||
aux_source_directory("latex-output" LATEX_SOURCES)
|
aux_source_directory("output-renderers" OUTPUT_RENDERER_SOURCES)
|
||||||
aux_source_directory("cairo-output" CAIRO_SOURCES)
|
aux_source_directory("geometric" GEOMETRIC_SOURCES)
|
||||||
aux_source_directory("trigonometric" TRIG_SOURCES)
|
aux_source_directory("layer" LAYER_SELECTOR_SOURCES)
|
||||||
set(SOURCE "main.c" "layer-selector.c" "mapping-parser.c" "command-line.c" "main-window.c" "external-renderer.c")
|
set(SOURCE "main.c" "command-line.c" "gds-render-gui.c")
|
||||||
|
|
||||||
set(SOURCE
|
set(SOURCE
|
||||||
${SOURCE}
|
${SOURCE}
|
||||||
${LAYER_SOURCES}
|
${LAYER_SOURCES}
|
||||||
${RENDERER_SOURCES}
|
${CELL_SELECTOR_SOURCES}
|
||||||
${PARSER_SOURCES}
|
${GDS_SOURCES}
|
||||||
${LATEX_SOURCES}
|
${OUTPUT_RENDERER_SOURCES}
|
||||||
${CAIRO_SOURCES}
|
${GEOMETRIC_SOURCES}
|
||||||
${TRIG_SOURCES}
|
${LAYER_SELECTOR_SOURCES}
|
||||||
)
|
)
|
||||||
|
|
||||||
add_compile_options(-Wall)
|
add_compile_options(-Wall)
|
||||||
|
|
||||||
add_executable(${PROJECT_NAME} ${SOURCE} ${CMAKE_CURRENT_BINARY_DIR}/glade/resources.c)
|
add_executable(${PROJECT_NAME} ${SOURCE} ${CMAKE_CURRENT_BINARY_DIR}/resources/resources.c)
|
||||||
add_dependencies(${PROJECT_NAME} glib-resources)
|
add_dependencies(${PROJECT_NAME} glib-resources)
|
||||||
SET_SOURCE_FILES_PROPERTIES(${CMAKE_CURRENT_BINARY_DIR}/glade/resources.c PROPERTIES GENERATED 1)
|
add_dependencies(${PROJECT_NAME} version)
|
||||||
target_link_libraries(${PROJECT_NAME} ${GLIB_LDFLAGS} ${GTK3_LDFLAGS} ${CAIRO_LDFLAGS} m ${CMAKE_DL_LIBS})
|
SET_SOURCE_FILES_PROPERTIES(${CMAKE_CURRENT_BINARY_DIR}/resources/resources.c PROPERTIES GENERATED 1)
|
||||||
|
target_link_libraries(${PROJECT_NAME} ${GLIB_LDFLAGS} ${GTK3_LDFLAGS} ${CAIRO_LDFLAGS} m version ${CMAKE_DL_LIBS})
|
||||||
install (TARGETS ${PROJECT_NAME} DESTINATION bin)
|
install (TARGETS ${PROJECT_NAME} DESTINATION bin)
|
||||||
|
|
||||||
|
add_custom_target(documentation DEPENDS doxygen)
|
||||||
|
@@ -1,4 +1,4 @@
|
|||||||
# GDS-Render
|
# GDS-Render Readme
|
||||||
|
|
||||||
This software is a rendering programm for GDS2 layout files.
|
This software is a rendering programm for GDS2 layout files.
|
||||||
The GDS2 format is mainly used in integrated circuit development.
|
The GDS2 format is mainly used in integrated circuit development.
|
||||||
|
1
c-style-checker
Submodule
1
c-style-checker
Submodule
Submodule c-style-checker added at 3a58e3dd1c
@@ -17,15 +17,27 @@
|
|||||||
* along with GDSII-Converter. If not, see <http://www.gnu.org/licenses/>.
|
* along with GDSII-Converter. If not, see <http://www.gnu.org/licenses/>.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include "lib-cell-renderer.h"
|
/**
|
||||||
#include "../gds-parser/gds-types.h"
|
* @file lib-cell-renderer.c
|
||||||
|
* @brief LibCellRenderer GObject Class
|
||||||
|
* @author Mario Hüttel <mario.huettel@gmx.net>
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @addtogroup LibCellRenderer
|
||||||
|
* @{
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <gds-render/cell-selector/lib-cell-renderer.h>
|
||||||
|
#include <gds-render/gds-utils/gds-types.h>
|
||||||
|
|
||||||
G_DEFINE_TYPE(LibCellRenderer, lib_cell_renderer, GTK_TYPE_CELL_RENDERER_TEXT)
|
G_DEFINE_TYPE(LibCellRenderer, lib_cell_renderer, GTK_TYPE_CELL_RENDERER_TEXT)
|
||||||
|
|
||||||
enum {
|
enum {
|
||||||
PROP_LIB = 1,
|
PROP_LIB = 1, /**< @brief Library to display the name of */
|
||||||
PROP_CELL,
|
PROP_CELL, /**< @brief Cell to display the name of */
|
||||||
PROP_COUNT
|
PROP_ERROR_LEVEL, /**< @brief Error level of cell/library for coloring */
|
||||||
|
PROP_COUNT /**< @brief Sentinel */
|
||||||
};
|
};
|
||||||
|
|
||||||
void lib_cell_renderer_init(LibCellRenderer *self)
|
void lib_cell_renderer_init(LibCellRenderer *self)
|
||||||
@@ -38,24 +50,56 @@ static void lib_cell_renderer_constructed(GObject *obj)
|
|||||||
G_OBJECT_CLASS(lib_cell_renderer_parent_class)->constructed(obj);
|
G_OBJECT_CLASS(lib_cell_renderer_parent_class)->constructed(obj);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void convert_error_level_to_color(GdkRGBA *color, unsigned int error_level)
|
||||||
|
{
|
||||||
|
|
||||||
|
/* Always use no transparency */
|
||||||
|
color->alpha = 1.0;
|
||||||
|
|
||||||
|
if (error_level & LIB_CELL_RENDERER_ERROR_ERR) {
|
||||||
|
/* Error set. Color cell red */
|
||||||
|
color->red = 1.0;
|
||||||
|
color->blue = 0.0;
|
||||||
|
color->green = 0.0;
|
||||||
|
} else if (error_level & LIB_CELL_RENDERER_ERROR_WARN) {
|
||||||
|
/* Only warning set; orange color */
|
||||||
|
color->red = 1.0;
|
||||||
|
color->blue = 0.0;
|
||||||
|
color->green = 0.6;
|
||||||
|
} else {
|
||||||
|
/* Everything okay; green color */
|
||||||
|
color->red = (double)61.0/(double)255.0;
|
||||||
|
color->green = (double)152.0/(double)255.0;
|
||||||
|
color->blue = 0.0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
static void lib_cell_renderer_set_property(GObject *object,
|
static void lib_cell_renderer_set_property(GObject *object,
|
||||||
guint param_id,
|
guint param_id,
|
||||||
const GValue *value,
|
const GValue *value,
|
||||||
GParamSpec *pspec)
|
GParamSpec *pspec)
|
||||||
{
|
{
|
||||||
GValue val = G_VALUE_INIT;
|
GValue val = G_VALUE_INIT;
|
||||||
|
GdkRGBA color;
|
||||||
g_value_init(&val, G_TYPE_STRING);
|
|
||||||
|
|
||||||
switch (param_id) {
|
switch (param_id) {
|
||||||
case PROP_LIB:
|
case PROP_LIB:
|
||||||
|
g_value_init(&val, G_TYPE_STRING);
|
||||||
g_value_set_string(&val, ((struct gds_library *)g_value_get_pointer(value))->name);
|
g_value_set_string(&val, ((struct gds_library *)g_value_get_pointer(value))->name);
|
||||||
g_object_set_property(object, "text", &val);
|
g_object_set_property(object, "text", &val);
|
||||||
break;
|
break;
|
||||||
case PROP_CELL:
|
case PROP_CELL:
|
||||||
|
g_value_init(&val, G_TYPE_STRING);
|
||||||
g_value_set_string(&val, ((struct gds_cell *)g_value_get_pointer(value))->name);
|
g_value_set_string(&val, ((struct gds_cell *)g_value_get_pointer(value))->name);
|
||||||
g_object_set_property(object, "text", &val);
|
g_object_set_property(object, "text", &val);
|
||||||
break;
|
break;
|
||||||
|
case PROP_ERROR_LEVEL:
|
||||||
|
/* Set cell color according to error level */
|
||||||
|
g_value_init(&val, GDK_TYPE_RGBA);
|
||||||
|
convert_error_level_to_color(&color, g_value_get_uint(value));
|
||||||
|
g_value_set_boxed(&val, &color);
|
||||||
|
g_object_set_property(object, "foreground-rgba", &val);
|
||||||
|
break;
|
||||||
default:
|
default:
|
||||||
G_OBJECT_WARN_INVALID_PROPERTY_ID(object, param_id, pspec);
|
G_OBJECT_WARN_INVALID_PROPERTY_ID(object, param_id, pspec);
|
||||||
break;
|
break;
|
||||||
@@ -74,11 +118,12 @@ static void lib_cell_renderer_get_property(GObject *object,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static GParamSpec *properties [PROP_COUNT];
|
static GParamSpec *properties[PROP_COUNT];
|
||||||
|
|
||||||
void lib_cell_renderer_class_init(LibCellRendererClass *klass)
|
void lib_cell_renderer_class_init(LibCellRendererClass *klass)
|
||||||
{
|
{
|
||||||
GObjectClass *oclass = G_OBJECT_CLASS(klass);
|
GObjectClass *oclass = G_OBJECT_CLASS(klass);
|
||||||
|
|
||||||
oclass->constructed = lib_cell_renderer_constructed;
|
oclass->constructed = lib_cell_renderer_constructed;
|
||||||
oclass->set_property = lib_cell_renderer_set_property;
|
oclass->set_property = lib_cell_renderer_set_property;
|
||||||
oclass->get_property = lib_cell_renderer_get_property;
|
oclass->get_property = lib_cell_renderer_get_property;
|
||||||
@@ -89,6 +134,8 @@ void lib_cell_renderer_class_init(LibCellRendererClass *klass)
|
|||||||
properties[PROP_CELL] = g_param_spec_pointer("gds-cell", "gds-cell",
|
properties[PROP_CELL] = g_param_spec_pointer("gds-cell", "gds-cell",
|
||||||
"Cell reference to be displayed",
|
"Cell reference to be displayed",
|
||||||
G_PARAM_WRITABLE);
|
G_PARAM_WRITABLE);
|
||||||
|
properties[PROP_ERROR_LEVEL] = g_param_spec_uint("error-level", "error-level",
|
||||||
|
"Error level of this cell", 0, 255, 0, G_PARAM_WRITABLE);
|
||||||
|
|
||||||
g_object_class_install_properties(oclass, PROP_COUNT, properties);
|
g_object_class_install_properties(oclass, PROP_COUNT, properties);
|
||||||
}
|
}
|
||||||
@@ -97,3 +144,5 @@ GtkCellRenderer *lib_cell_renderer_new()
|
|||||||
{
|
{
|
||||||
return GTK_CELL_RENDERER(g_object_new(TYPE_LIB_CELL_RENDERER, NULL));
|
return GTK_CELL_RENDERER(g_object_new(TYPE_LIB_CELL_RENDERER, NULL));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** @} */
|
@@ -24,13 +24,13 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @addtogroup MainApplication
|
* @addtogroup GUI
|
||||||
* @{
|
* @{
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include "tree-store.h"
|
#include <gds-render/cell-selector/tree-store.h>
|
||||||
#include "lib-cell-renderer.h"
|
#include <gds-render/cell-selector/lib-cell-renderer.h>
|
||||||
#include "../gds-parser/gds-types.h"
|
#include <gds-render/gds-utils/gds-types.h>
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief this function olny allows cells to be selected
|
* @brief this function olny allows cells to be selected
|
||||||
@@ -49,15 +49,23 @@ static gboolean tree_sel_func(GtkTreeSelection *selection,
|
|||||||
{
|
{
|
||||||
GtkTreeIter iter;
|
GtkTreeIter iter;
|
||||||
struct gds_cell *cell;
|
struct gds_cell *cell;
|
||||||
|
unsigned int error_level;
|
||||||
|
gboolean ret = FALSE;
|
||||||
|
(void)selection;
|
||||||
|
(void)path_currently_selected;
|
||||||
|
(void)data;
|
||||||
|
|
||||||
gtk_tree_model_get_iter(model, &iter, path);
|
gtk_tree_model_get_iter(model, &iter, path);
|
||||||
gtk_tree_model_get(model, &iter, CELL_SEL_CELL, &cell, -1);
|
gtk_tree_model_get(model, &iter, CELL_SEL_CELL, &cell, CELL_SEL_CELL_ERROR_STATE, &error_level, -1);
|
||||||
|
|
||||||
/* Allow only rows with valid cell to be selected */
|
/* Allow only rows with _valid_ cell to be selected */
|
||||||
if (cell)
|
if (cell) {
|
||||||
return TRUE;
|
/* Cell available. Check if it passed the critical checks */
|
||||||
else
|
if (!(error_level & LIB_CELL_RENDERER_ERROR_ERR))
|
||||||
return FALSE;
|
ret = TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -107,6 +115,8 @@ exit_filter:
|
|||||||
static void change_filter(GtkWidget *entry, gpointer data)
|
static void change_filter(GtkWidget *entry, gpointer data)
|
||||||
{
|
{
|
||||||
struct tree_stores *stores = (struct tree_stores *)data;
|
struct tree_stores *stores = (struct tree_stores *)data;
|
||||||
|
(void)entry;
|
||||||
|
|
||||||
gtk_tree_model_filter_refilter(stores->filter);
|
gtk_tree_model_filter_refilter(stores->filter);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -127,7 +137,7 @@ struct tree_stores *setup_cell_selector(GtkTreeView* view, GtkEntry *search_entr
|
|||||||
stores.base_tree_view = view;
|
stores.base_tree_view = view;
|
||||||
stores.search_entry = search_entry;
|
stores.search_entry = search_entry;
|
||||||
|
|
||||||
stores.base_store = gtk_tree_store_new(CELL_SEL_COLUMN_COUNT, G_TYPE_POINTER, G_TYPE_POINTER, GDK_TYPE_RGBA, G_TYPE_STRING, G_TYPE_STRING);
|
stores.base_store = gtk_tree_store_new(CELL_SEL_COLUMN_COUNT, G_TYPE_POINTER, G_TYPE_POINTER, G_TYPE_UINT, G_TYPE_STRING, G_TYPE_STRING);
|
||||||
|
|
||||||
/* Searching */
|
/* Searching */
|
||||||
if (search_entry) {
|
if (search_entry) {
|
||||||
@@ -147,8 +157,8 @@ struct tree_stores *setup_cell_selector(GtkTreeView* view, GtkEntry *search_entr
|
|||||||
column = gtk_tree_view_column_new_with_attributes("Library", render_lib, "gds-lib", CELL_SEL_LIBRARY, NULL);
|
column = gtk_tree_view_column_new_with_attributes("Library", render_lib, "gds-lib", CELL_SEL_LIBRARY, NULL);
|
||||||
gtk_tree_view_append_column(view, column);
|
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,
|
||||||
column = gtk_tree_view_column_new_with_attributes("Cell", render_cell, "gds-cell", CELL_SEL_CELL, "foreground-rgba", CELL_SEL_CELL_COLOR, NULL);
|
"error-level", CELL_SEL_CELL_ERROR_STATE, NULL);
|
||||||
gtk_tree_view_append_column(view, column);
|
gtk_tree_view_append_column(view, column);
|
||||||
|
|
||||||
column = gtk_tree_view_column_new_with_attributes("Mod. Date", render_dates, "text", CELL_SEL_MODDATE, NULL);
|
column = gtk_tree_view_column_new_with_attributes("Mod. Date", render_dates, "text", CELL_SEL_MODDATE, NULL);
|
278
command-line.c
278
command-line.c
@@ -24,146 +24,214 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @addtogroup MainApplication
|
* @addtogroup cmdline
|
||||||
* @{
|
* @{
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include "command-line.h"
|
|
||||||
#include "gds-parser/gds-parser.h"
|
|
||||||
#include "mapping-parser.h"
|
|
||||||
#include "cairo-output/cairo-output.h"
|
|
||||||
#include "latex-output/latex-output.h"
|
|
||||||
#include "external-renderer.h"
|
|
||||||
|
|
||||||
/**
|
#include <gds-render/command-line.h>
|
||||||
* @brief Delete layer_info and free nem element.
|
#include <gds-render/gds-utils/gds-parser.h>
|
||||||
*
|
#include <gds-render/layer/mapping-parser.h>
|
||||||
* Like delete_layer_info_struct() but also frees layer_info::name
|
#include <gds-render/layer/layer-info.h>
|
||||||
* @param info
|
#include <gds-render/output-renderers/cairo-renderer.h>
|
||||||
*/
|
#include <gds-render/output-renderers/latex-renderer.h>
|
||||||
static void delete_layer_info_with_name(struct layer_info *info)
|
#include <gds-render/output-renderers/external-renderer.h>
|
||||||
|
#include <gds-render/gds-utils/gds-tree-checker.h>
|
||||||
|
|
||||||
|
static int string_array_count(char **string_array)
|
||||||
{
|
{
|
||||||
if (info) {
|
int count = 0;
|
||||||
if (info->name)
|
|
||||||
g_free(info->name);
|
if (!string_array)
|
||||||
free(info);
|
return 0;
|
||||||
|
|
||||||
|
for (; *string_array; string_array++) {
|
||||||
|
count++;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return count;
|
||||||
}
|
}
|
||||||
|
|
||||||
void command_line_convert_gds(char *gds_name, char *pdf_name, char *tex_name, gboolean pdf, gboolean tex,
|
static int create_renderers(char **renderers,
|
||||||
char *layer_file, char *cell_name, double scale, gboolean pdf_layers,
|
char **output_file_names,
|
||||||
gboolean pdf_standalone, gboolean svg, char *svg_name, char *so_name, char *so_out_file)
|
gboolean tex_layers,
|
||||||
|
gboolean tex_standalone,
|
||||||
|
const char *so_path,
|
||||||
|
GList **renderer_list,
|
||||||
|
LayerSettings *layer_settings)
|
||||||
|
{
|
||||||
|
char **renderer_iter;
|
||||||
|
char *current_renderer;
|
||||||
|
int idx;
|
||||||
|
char *current_out_file;
|
||||||
|
int count_render, count_out;
|
||||||
|
GdsOutputRenderer *output_renderer;
|
||||||
|
|
||||||
|
if (!renderer_list)
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
if (!renderers || !output_file_names) {
|
||||||
|
fprintf(stderr, "Please specify renderers and file names\n");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
count_render = string_array_count(renderers);
|
||||||
|
count_out = string_array_count(output_file_names);
|
||||||
|
if (count_render != count_out) {
|
||||||
|
fprintf(stderr, "Count of renderers %d does not match count of output file names %d\n",
|
||||||
|
count_render, count_out);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Parse cmd line parameters */
|
||||||
|
for (renderer_iter = renderers, idx = 0; *renderer_iter; renderer_iter++, idx++) {
|
||||||
|
current_renderer = *renderer_iter;
|
||||||
|
current_out_file = output_file_names[idx];
|
||||||
|
|
||||||
|
/* File valid ? */
|
||||||
|
if (!current_out_file || !current_out_file[0])
|
||||||
|
continue;
|
||||||
|
|
||||||
|
if (!strcmp(current_renderer, "tikz")) {
|
||||||
|
output_renderer = GDS_RENDER_OUTPUT_RENDERER(latex_renderer_new_with_options(tex_layers,
|
||||||
|
tex_standalone));
|
||||||
|
} else if (!strcmp(current_renderer, "pdf")) {
|
||||||
|
output_renderer = GDS_RENDER_OUTPUT_RENDERER(cairo_renderer_new_pdf());
|
||||||
|
} else if (!strcmp(current_renderer, "svg")) {
|
||||||
|
output_renderer = GDS_RENDER_OUTPUT_RENDERER(cairo_renderer_new_svg());
|
||||||
|
} else if (!strcmp(current_renderer, "ext")) {
|
||||||
|
if (!so_path) {
|
||||||
|
fprintf(stderr, "Please specify shared object for external renderer. Will ignore this renderer.\n");
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
output_renderer = GDS_RENDER_OUTPUT_RENDERER(external_renderer_new_with_so(so_path));
|
||||||
|
} else {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
gds_output_renderer_set_output_file(output_renderer, current_out_file);
|
||||||
|
gds_output_renderer_set_layer_settings(output_renderer, layer_settings);
|
||||||
|
*renderer_list = g_list_append(*renderer_list, output_renderer);
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static struct gds_cell *find_gds_cell_in_lib(struct gds_library *lib, const char *cell_name)
|
||||||
{
|
{
|
||||||
GList *libs = NULL;
|
|
||||||
FILE *tex_file;
|
|
||||||
int res;
|
|
||||||
GFile *file;
|
|
||||||
int i;
|
|
||||||
GFileInputStream *stream;
|
|
||||||
GDataInputStream *dstream;
|
|
||||||
gboolean layer_export;
|
|
||||||
GdkRGBA layer_color;
|
|
||||||
int layer;
|
|
||||||
char *layer_name;
|
|
||||||
GList *layer_info_list = NULL;
|
|
||||||
GList *cell_list;
|
GList *cell_list;
|
||||||
struct layer_info *linfo_temp;
|
struct gds_cell *return_cell = NULL;
|
||||||
struct gds_cell *toplevel_cell = NULL, *temp_cell;
|
struct gds_cell *temp_cell;
|
||||||
|
|
||||||
|
for (cell_list = lib->cells; cell_list; cell_list = g_list_next(cell_list)) {
|
||||||
|
temp_cell = (struct gds_cell *)cell_list->data;
|
||||||
|
if (!strncmp(temp_cell->name, cell_name, CELL_NAME_MAX)) {
|
||||||
|
return_cell = temp_cell;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return return_cell;
|
||||||
|
}
|
||||||
|
|
||||||
|
int command_line_convert_gds(const char *gds_name,
|
||||||
|
const char *cell_name,
|
||||||
|
char **renderers,
|
||||||
|
char **output_file_names,
|
||||||
|
const char *layer_file,
|
||||||
|
const char *so_path,
|
||||||
|
gboolean tex_standalone,
|
||||||
|
gboolean tex_layers,
|
||||||
|
double scale)
|
||||||
|
{
|
||||||
|
int ret = -1;
|
||||||
|
GList *libs = NULL;
|
||||||
|
int res;
|
||||||
|
GList *renderer_list = NULL;
|
||||||
|
GList *list_iter;
|
||||||
|
struct gds_library *first_lib;
|
||||||
|
struct gds_cell *toplevel_cell = NULL;
|
||||||
|
LayerSettings *layer_sett;
|
||||||
|
GdsOutputRenderer *current_renderer;
|
||||||
|
|
||||||
/* Check if parameters are valid */
|
/* Check if parameters are valid */
|
||||||
if (!gds_name || (!pdf_name && pdf) || (!tex_name && tex) || !layer_file || !cell_name) {
|
if (!gds_name || !cell_name || !output_file_names || !layer_file || !renderers) {
|
||||||
printf("Probably missing argument. Check --help option\n");
|
printf("Probably missing argument. Check --help option\n");
|
||||||
return;
|
return -2;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Load layer_settings */
|
||||||
|
layer_sett = layer_settings_new();
|
||||||
|
layer_settings_load_from_csv(layer_sett, layer_file);
|
||||||
|
|
||||||
|
/* Create renderers */
|
||||||
|
if (create_renderers(renderers, output_file_names, tex_layers, tex_standalone,
|
||||||
|
so_path, &renderer_list, layer_sett))
|
||||||
|
goto ret_destroy_layer_mapping;
|
||||||
|
|
||||||
|
|
||||||
/* Load GDS */
|
/* Load GDS */
|
||||||
clear_lib_list(&libs);
|
clear_lib_list(&libs);
|
||||||
res = parse_gds_from_file(gds_name, &libs);
|
res = parse_gds_from_file(gds_name, &libs);
|
||||||
if (res)
|
if (res)
|
||||||
return;
|
goto ret_destroy_library_list;
|
||||||
|
|
||||||
file = g_file_new_for_path(layer_file);
|
|
||||||
stream = g_file_read(file, NULL, NULL);
|
|
||||||
|
|
||||||
if (!stream) {
|
|
||||||
printf("Layer mapping not readable!\n");
|
|
||||||
goto destroy_file;
|
|
||||||
}
|
|
||||||
dstream = g_data_input_stream_new(G_INPUT_STREAM(stream));
|
|
||||||
i = 0;
|
|
||||||
do {
|
|
||||||
res = load_csv_line(dstream, &layer_export, &layer_name, &layer, &layer_color);
|
|
||||||
if (res == 0) {
|
|
||||||
if (!layer_export)
|
|
||||||
continue;
|
|
||||||
linfo_temp = (struct layer_info *)malloc(sizeof(struct layer_info));
|
|
||||||
if (!linfo_temp) {
|
|
||||||
printf("Out of memory\n");
|
|
||||||
goto ret_clear_list;
|
|
||||||
}
|
|
||||||
linfo_temp->color.alpha = layer_color.alpha;
|
|
||||||
linfo_temp->color.red = layer_color.red;
|
|
||||||
linfo_temp->color.green = layer_color.green;
|
|
||||||
linfo_temp->color.blue = layer_color.blue;
|
|
||||||
linfo_temp->name = layer_name;
|
|
||||||
linfo_temp->stacked_position = i++;
|
|
||||||
linfo_temp->layer = layer;
|
|
||||||
layer_info_list = g_list_append(layer_info_list, (gpointer)linfo_temp);
|
|
||||||
}
|
|
||||||
} while(res >= 0);
|
|
||||||
|
|
||||||
|
|
||||||
/* find_cell in first library. */
|
/* find_cell in first library. */
|
||||||
if (!libs)
|
if (!libs)
|
||||||
goto ret_clear_list;
|
goto ret_clear_renderers;
|
||||||
|
|
||||||
for (cell_list = ((struct gds_library *)libs->data)->cells; cell_list != NULL; cell_list = g_list_next(cell_list)) {
|
first_lib = (struct gds_library *)libs->data;
|
||||||
temp_cell = (struct gds_cell *)cell_list->data;
|
if (!first_lib) {
|
||||||
if (!strcmp(temp_cell->name, cell_name)) {
|
fprintf(stderr, "No library in library list. This should not happen.\n");
|
||||||
toplevel_cell = temp_cell;
|
/* This is safe. Library destruction can handle an empty list element */
|
||||||
break;
|
goto ret_destroy_library_list;
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Find cell in first library */
|
||||||
|
toplevel_cell = find_gds_cell_in_lib(first_lib, cell_name);
|
||||||
|
|
||||||
if (!toplevel_cell) {
|
if (!toplevel_cell) {
|
||||||
printf("Couldn't find cell in first library!\n");
|
printf("Couldn't find cell in first library!\n");
|
||||||
goto ret_clear_list;
|
goto ret_destroy_library_list;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Render outputs */
|
/* Check if cell passes vital checks */
|
||||||
if (pdf == TRUE || svg == TRUE) {
|
res = gds_tree_check_reference_loops(toplevel_cell->parent_library);
|
||||||
cairo_render_cell_to_vector_file(toplevel_cell, layer_info_list, (pdf == TRUE ? pdf_name : NULL),
|
if (res < 0) {
|
||||||
(svg == TRUE ? svg_name : NULL), scale);
|
fprintf(stderr, "Checking library %s failed.\n", first_lib->name);
|
||||||
|
goto ret_destroy_library_list;
|
||||||
|
} else if (res > 0) {
|
||||||
|
fprintf(stderr, "%d reference loops found.\n", res);
|
||||||
|
|
||||||
|
/* do further checking if the specified cell and/or its subcells are affected */
|
||||||
|
if (toplevel_cell->checks.affected_by_reference_loop == 1) {
|
||||||
|
fprintf(stderr, "Cell is affected by reference loop. Abort!\n");
|
||||||
|
goto ret_destroy_library_list;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (tex == TRUE) {
|
if (toplevel_cell->checks.affected_by_reference_loop == GDS_CELL_CHECK_NOT_RUN)
|
||||||
tex_file = fopen(tex_name, "w");
|
fprintf(stderr, "Cell was not checked. This should not happen. Please report this issue. Will continue either way.\n");
|
||||||
if (!tex_file)
|
|
||||||
goto ret_clear_list;
|
/* Note: unresolved references are not an abort condition.
|
||||||
latex_render_cell_to_code(toplevel_cell, layer_info_list, tex_file, scale, pdf_layers, pdf_standalone);
|
* Deal with it.
|
||||||
fclose(tex_file);
|
*/
|
||||||
|
|
||||||
|
/* Execute all rendererer instances */
|
||||||
|
for (list_iter = renderer_list; list_iter; list_iter = list_iter->next) {
|
||||||
|
current_renderer = GDS_RENDER_OUTPUT_RENDERER(list_iter->data);
|
||||||
|
gds_output_renderer_render_output(current_renderer, toplevel_cell, scale);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (so_name && so_out_file) {
|
ret_destroy_library_list:
|
||||||
if (strlen(so_name) == 0 || strlen(so_out_file) == 0)
|
clear_lib_list(&libs);
|
||||||
goto ret_clear_list;
|
ret_clear_renderers:
|
||||||
|
for (list_iter = renderer_list; list_iter; list_iter = list_iter->next) {
|
||||||
/* Render output using external renderer */
|
g_object_unref(list_iter->data);
|
||||||
printf("Invoking external renderer!\n");
|
|
||||||
external_renderer_render_cell(toplevel_cell, layer_info_list, so_out_file, so_name);
|
|
||||||
printf("External renderer finished!\n");
|
|
||||||
}
|
}
|
||||||
|
ret_destroy_layer_mapping:
|
||||||
ret_clear_list:
|
g_object_unref(layer_sett);
|
||||||
g_list_free_full(layer_info_list, (GDestroyNotify)delete_layer_info_with_name);
|
return ret;
|
||||||
|
|
||||||
g_object_unref(dstream);
|
|
||||||
g_object_unref(stream);
|
|
||||||
destroy_file:
|
|
||||||
g_object_unref(file);
|
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/** @} */
|
/** @} */
|
||||||
|
@@ -1,10 +1,10 @@
|
|||||||
find_package(Doxygen)
|
find_package(Doxygen)
|
||||||
|
|
||||||
if (DOXYGEN_FOUND)
|
if (DOXYGEN_FOUND)
|
||||||
add_custom_target(doxygen
|
add_custom_target(doxygen
|
||||||
COMMAND ./build-doxygen.sh "${PROJECT_BINARY_DIR}"
|
COMMAND ./build-doxygen.sh "${PROJECT_BINARY_DIR}"
|
||||||
WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}
|
WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}
|
||||||
COMMENT "Generating documentation with Doxygen")
|
COMMENT "Generating documentation with Doxygen")
|
||||||
|
|
||||||
else (DOXYGEN_FOUND)
|
else (DOXYGEN_FOUND)
|
||||||
message("Doxygen need to be installed to generate the doxygen documentation")
|
message("Doxygen need to be installed to generate the doxygen documentation")
|
||||||
endif (DOXYGEN_FOUND)
|
endif (DOXYGEN_FOUND)
|
||||||
|
@@ -234,7 +234,7 @@ SEPARATE_MEMBER_PAGES = NO
|
|||||||
# uses this value to replace tabs by spaces in code fragments.
|
# uses this value to replace tabs by spaces in code fragments.
|
||||||
# Minimum value: 1, maximum value: 16, default value: 4.
|
# Minimum value: 1, maximum value: 16, default value: 4.
|
||||||
|
|
||||||
TAB_SIZE = 4
|
TAB_SIZE = 8
|
||||||
|
|
||||||
# This tag can be used to specify a number of aliases that act as commands in
|
# This tag can be used to specify a number of aliases that act as commands in
|
||||||
# the documentation. An alias has the form:
|
# the documentation. An alias has the form:
|
||||||
@@ -2417,7 +2417,7 @@ DIRECTORY_GRAPH = YES
|
|||||||
# The default value is: png.
|
# The default value is: png.
|
||||||
# This tag requires that the tag HAVE_DOT is set to YES.
|
# This tag requires that the tag HAVE_DOT is set to YES.
|
||||||
|
|
||||||
DOT_IMAGE_FORMAT = png
|
DOT_IMAGE_FORMAT = svg
|
||||||
|
|
||||||
# If DOT_IMAGE_FORMAT is set to svg, then this option can be set to YES to
|
# If DOT_IMAGE_FORMAT is set to svg, then this option can be set to YES to
|
||||||
# enable generation of interactive SVG images that allow zooming and panning.
|
# enable generation of interactive SVG images that allow zooming and panning.
|
||||||
@@ -2429,7 +2429,7 @@ DOT_IMAGE_FORMAT = png
|
|||||||
# The default value is: NO.
|
# The default value is: NO.
|
||||||
# This tag requires that the tag HAVE_DOT is set to YES.
|
# This tag requires that the tag HAVE_DOT is set to YES.
|
||||||
|
|
||||||
INTERACTIVE_SVG = NO
|
INTERACTIVE_SVG = YES
|
||||||
|
|
||||||
# The DOT_PATH tag can be used to specify the path where the dot tool can be
|
# The DOT_PATH tag can be used to specify the path where the dot tool can be
|
||||||
# found. If left blank, it is assumed the dot tool can be found in the path.
|
# found. If left blank, it is assumed the dot tool can be found in the path.
|
||||||
|
6
doxygen/activity-bar.dox
Normal file
6
doxygen/activity-bar.dox
Normal file
@@ -0,0 +1,6 @@
|
|||||||
|
/**
|
||||||
|
* @defgroup ActivityBar Activity Bar
|
||||||
|
* @ingroup Widgets
|
||||||
|
*
|
||||||
|
* Activity Status Bar
|
||||||
|
*/
|
@@ -9,7 +9,7 @@ done
|
|||||||
DIR="$( cd -P "$( dirname "$SOURCE" )" >/dev/null && pwd )"
|
DIR="$( cd -P "$( dirname "$SOURCE" )" >/dev/null && pwd )"
|
||||||
cd "$DIR"
|
cd "$DIR"
|
||||||
|
|
||||||
export PROJECT_NUMBER=`git describe --tags`
|
export PROJECT_NUMBER=`../version/generate-version-string.sh`
|
||||||
|
|
||||||
if [ $# != 1 ]; then
|
if [ $# != 1 ]; then
|
||||||
export OUTPUT_DIRECTORY="./output"
|
export OUTPUT_DIRECTORY="./output"
|
||||||
|
4
doxygen/cairo-renderer.dox
Normal file
4
doxygen/cairo-renderer.dox
Normal file
@@ -0,0 +1,4 @@
|
|||||||
|
/**
|
||||||
|
* @defgroup Cairo-Renderer Cairo Renderer
|
||||||
|
* @ingroup renderers
|
||||||
|
*/
|
3
doxygen/command-line.dox
Normal file
3
doxygen/command-line.dox
Normal file
@@ -0,0 +1,3 @@
|
|||||||
|
/**
|
||||||
|
* @defgroup cmdline Command Line Interface
|
||||||
|
*/
|
88
doxygen/compilation.dox
Normal file
88
doxygen/compilation.dox
Normal file
@@ -0,0 +1,88 @@
|
|||||||
|
/**
|
||||||
|
|
||||||
|
@page compilation Compilation
|
||||||
|
|
||||||
|
@section Preface
|
||||||
|
|
||||||
|
GDS-Render is designed for UNIX-like, especially GNU/Linux based systems.
|
||||||
|
It was developed under a Linux system. Therefore, best performance is expected using a Linux operating system.
|
||||||
|
|
||||||
|
@section depencencies Dependencies
|
||||||
|
The dependencies of GDS-Render are:
|
||||||
|
|
||||||
|
@subsection run-deps Program Dependencies
|
||||||
|
|
||||||
|
- GLib2
|
||||||
|
- GTK3
|
||||||
|
- Cairographics
|
||||||
|
|
||||||
|
@subsection comp-deps Compilation Dependencies
|
||||||
|
These dependencies are not needed for running the program; just for compilation.
|
||||||
|
|
||||||
|
- Build System (GCC + binutils, make, etc...). Most distributions supply a "development" meta-package containing this stuff.
|
||||||
|
- cmake >= 2.8
|
||||||
|
- More or less optional: git. Used for extraction of the precise version number. It is strongly recommended to provide git!
|
||||||
|
- Optional: doxygen for this nice documentation.
|
||||||
|
|
||||||
|
The dependency list of GTK3 already includes Cairographics and GLib2. You should be on the safe side with a recent GTK3 version.
|
||||||
|
|
||||||
|
Development is done with the following library versions:
|
||||||
|
|
||||||
|
| Cairographics | GLib2 | GTK3 |
|
||||||
|
| ------------- | ---------- | ------ |
|
||||||
|
| 1.16.0-2 | 2.60.0-1 | 3.24.7 |
|
||||||
|
|
||||||
|
@section comp-instr Compilation Instructions
|
||||||
|
@subsection linux-build General Linux Build Instruction
|
||||||
|
Go to the build directory you want to compile in. This may be the gds-render project root.
|
||||||
|
Execute
|
||||||
|
@code
|
||||||
|
cmake <Path to gds-render root>
|
||||||
|
@endcode
|
||||||
|
|
||||||
|
Cmake will check the dependencies. Once cmake has finished. Type
|
||||||
|
|
||||||
|
@code
|
||||||
|
make
|
||||||
|
@endcode
|
||||||
|
|
||||||
|
in order to build the program and
|
||||||
|
|
||||||
|
@code
|
||||||
|
make documentation
|
||||||
|
@endcode
|
||||||
|
to build the doxygen documentation.
|
||||||
|
|
||||||
|
@subsection arch-makepkg Archlinux Package
|
||||||
|
|
||||||
|
The subfolder 'AUR' contains a PKGBUILD file to build an Archlinux/Pacman package.
|
||||||
|
|
||||||
|
@subsection comp-warnings Compiler Warnings
|
||||||
|
|
||||||
|
The compiler will throw the following warnings. Compiled with GCC 8.2.1.
|
||||||
|
|
||||||
|
| Warning | Assessment |
|
||||||
|
| ------- | ---------- |
|
||||||
|
| warning: ‘calculate_path_miter_points’ defined but not used [-Wunused-function] | Ignore. Function will be used in later versions. |
|
||||||
|
|
||||||
|
|
||||||
|
@subsection windows-compilation Compilation for Windows
|
||||||
|
|
||||||
|
@warning Windows is not a target system for this application, considering that this program converts GDS files which are most likely generated under a Linux system. The tips shown in this section are a guidance for anyone trying to build this application for Windows.
|
||||||
|
|
||||||
|
@warning Note that the Windows compatibility may decrease in future releases and a simple compilation like with this version might not be possible anymore.
|
||||||
|
|
||||||
|
The current release of 'gds-render' does not compile under a windows system, due to incompatibilities in the external library renderer.
|
||||||
|
It is possible to comment out the code that causes the incompatibility. The external renderer will not be usable after this.
|
||||||
|
|
||||||
|
Steps:
|
||||||
|
|
||||||
|
- Go to file external-renderer.c
|
||||||
|
- Remove `#include` <dlfcn.h>
|
||||||
|
- comment out all code in #external_renderer_render_cell
|
||||||
|
|
||||||
|
The program should now compile.
|
||||||
|
|
||||||
|
@note In versions currently in development, the cairo renderer will be unusable under Windows due to Issue `#16`. So you might want to stick with this version.
|
||||||
|
|
||||||
|
*/
|
4
doxygen/external-renderer.dox
Normal file
4
doxygen/external-renderer.dox
Normal file
@@ -0,0 +1,4 @@
|
|||||||
|
/**
|
||||||
|
* @defgroup external-renderer External Shared Object Renderer
|
||||||
|
* @ingroup renderers
|
||||||
|
*/
|
8
doxygen/geometric.dox
Normal file
8
doxygen/geometric.dox
Normal file
@@ -0,0 +1,8 @@
|
|||||||
|
/* This file only contains help information for doxygen */
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @defgroup geometric Geometric Helper Functions
|
||||||
|
*
|
||||||
|
* The geometric helper function are used to calculate bounding boxes
|
||||||
|
* @warning Code is incomplete. Please double check for functionality!
|
||||||
|
*/
|
@@ -1,6 +1,5 @@
|
|||||||
/* This file only contains help information for doxygen */
|
/* This file only contains help information for doxygen */
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @defgroup MainApplication Main Application
|
* @defgroup GUI Graphical User Interface
|
||||||
*
|
|
||||||
*/
|
*/
|
Binary file not shown.
BIN
doxygen/images/gui.png
Normal file
BIN
doxygen/images/gui.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 37 KiB |
File diff suppressed because it is too large
Load Diff
Before Width: | Height: | Size: 114 KiB |
4
doxygen/latex-renderer.dox
Normal file
4
doxygen/latex-renderer.dox
Normal file
@@ -0,0 +1,4 @@
|
|||||||
|
/**
|
||||||
|
* @defgroup LaTeX-Renderer LaTeX/TikZ Renderer
|
||||||
|
* @ingroup renderers
|
||||||
|
*/
|
7
doxygen/layer-selector.dox
Normal file
7
doxygen/layer-selector.dox
Normal file
@@ -0,0 +1,7 @@
|
|||||||
|
/**
|
||||||
|
* @defgroup layer-selector LayerSelector Object
|
||||||
|
* @ingroup GUI
|
||||||
|
*
|
||||||
|
* This objects implements the layer selector and displays the layers in a list box.
|
||||||
|
* It uses @ref LayerElement objects to display the individual layers inside the list box.
|
||||||
|
*/
|
18
doxygen/lib-cell-renderer.dox
Normal file
18
doxygen/lib-cell-renderer.dox
Normal file
@@ -0,0 +1,18 @@
|
|||||||
|
/**
|
||||||
|
* @defgroup LibCellRenderer LibCellRenderer GObject
|
||||||
|
* @ingroup GUI
|
||||||
|
*
|
||||||
|
* The LibCellRenderer Object is used to render @ref gds_cell and @ref gds_library elements
|
||||||
|
* to a GtkTreeView.
|
||||||
|
*
|
||||||
|
* The LibCellRenderer class is derived from a GtkCellRendererText and works the same way.
|
||||||
|
* The additinal features are three new properties:
|
||||||
|
*
|
||||||
|
* - *gds-lib*: This property can be used to set a @ref gds_library structure. The renderer will render the name of the library.
|
||||||
|
* - *gds-cell*: This property can be used to set a @ref gds_cell structure. The renderer will render the name of the cell.
|
||||||
|
* - *error-level*: Set the error level of the cell/library. This affects the foreground color of hte rendered output.
|
||||||
|
*
|
||||||
|
* Internally the class operates by setting the 'text' property, which is inherited form the base class to the library/cell name (gds_library::name and gds_cell::name fields).
|
||||||
|
* The error level (@ref LIB_CELL_RENDERER_ERROR_WARN and @ref LIB_CELL_RENDERER_ERROR_ERR) is translated to the inherited 'foreground-rgba' property.
|
||||||
|
*
|
||||||
|
*/
|
@@ -6,10 +6,7 @@ This programm converts GDS layout files to
|
|||||||
- PDF Files using the @ref Cairo-Renderer
|
- PDF Files using the @ref Cairo-Renderer
|
||||||
- Latex code (TikZ) using the @ref LaTeX-Renderer
|
- Latex code (TikZ) using the @ref LaTeX-Renderer
|
||||||
|
|
||||||
See the @subpage usage page for details
|
See the @subpage usage page for details and @subpage compilation for building instructions and @subpage versioning for the versioning scheme of this program.
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
9
doxygen/renderers.dox
Normal file
9
doxygen/renderers.dox
Normal file
@@ -0,0 +1,9 @@
|
|||||||
|
/**
|
||||||
|
* @defgroup renderers Output Renderers
|
||||||
|
*
|
||||||
|
* The renderers are used to convert the cell structures read from the GDS layout file
|
||||||
|
* into different output formats.
|
||||||
|
*
|
||||||
|
* Currently the renders are statically implemented without the use of GObjects.
|
||||||
|
* This will probably change in future releases in order to make it easier to integrate new rendering methods.
|
||||||
|
*/
|
@@ -1,8 +0,0 @@
|
|||||||
/* This file only contains help information for doxygen */
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @defgroup trigonometric Trigonometric Helper Functions
|
|
||||||
* @description The trigonometric helper function will be used in future releases to pcalculate bounding boxes
|
|
||||||
* @note Currently not in use!
|
|
||||||
* @warning Code is incomplete. DO NOT USE!
|
|
||||||
*/
|
|
@@ -1,21 +1,27 @@
|
|||||||
/**
|
/**
|
||||||
@page usage Usage
|
@page usage Usage
|
||||||
@section cmd Command Line Interface
|
@section cmd Command Line Interface
|
||||||
To use the application on the command line check 'gds-render --help'.
|
To use the application on the command line check 'gds-render `--`help'.
|
||||||
|
|
||||||
|
Usage:
|
||||||
|
gds-render [OPTION…] FILE - Convert GDS file <FILE> to graphic
|
||||||
|
|
||||||
|
Help Options:
|
||||||
|
-h, '--'help Show help options
|
||||||
|
'--'help-all Show all help options
|
||||||
|
'--'help-gtk Show GTK+ Options
|
||||||
|
|
||||||
Application Options:
|
Application Options:
|
||||||
- -t, --tikz Output TikZ code
|
-v, '--'version Print version
|
||||||
- -p, --pdf Output PDF document
|
-r, '--'renderer=pdf|svg|tikz|ext Renderer to use
|
||||||
- -s, --scale=<SCALE> Divide output coordinates by <SCALE>
|
-s, '--'scale=<SCALE> Divide output coordinates by <SCALE>
|
||||||
- -o, --tex-output=PATH Optional path for TeX file
|
-o, '--'output-file=PATH Output file path
|
||||||
- -O, --pdf-output=PATH Optional path for PDF file
|
-m, '--'mapping=PATH Path for Layer Mapping File
|
||||||
- -m, --mapping=PATH Path for Layer Mapping File
|
-c, '--'cell=NAME Cell to render
|
||||||
- -c, --cell=NAME Cell to render
|
-a, '--'tex-standalone Create standalone PDF
|
||||||
- -a, --tex-standalone Create standalone PDF
|
-l, '--'tex-layers Create PDF Layers (OCG)
|
||||||
- -l, --tex-layers Create PDF Layers (OCG)
|
-P, '--'custom-render-lib=PATH Path to a custom shared object, that implements the render_cell_to_file function
|
||||||
- -P, --custom-render-lib=PATH Path to a custom shared object, that implements the render_cell_to_file function
|
'--'display=DISPLAY X display to use
|
||||||
- -e, --external-lib-output=PATH Output path for external render library
|
|
||||||
- --display=DISPLAY X display to use
|
|
||||||
|
|
||||||
|
|
||||||
@section gui Graphical User Interface
|
@section gui Graphical User Interface
|
||||||
@@ -24,7 +30,11 @@ The graphical user interface (GUI) can be used to open GDS Files, configure the
|
|||||||
|
|
||||||
It is possible to export the layer configurations so they can be used later on. Even in the @ref cmd
|
It is possible to export the layer configurations so they can be used later on. Even in the @ref cmd
|
||||||
|
|
||||||
@image html gui.svg
|
@image html gui.png
|
||||||
@image latex gui.pdf
|
@image latex gui.png
|
||||||
|
|
||||||
|
The cell selector on the left shows the GDS Libraries and Cells. The cells are marked green if all references inside the cell could be found. If not all references could be found, the cell is marked orange. This doens't show if child cells have missing childs. Only one level of the hierarchy is checked in order to make it easier to spot an errorneous cell. Cells with missing child cells are still renderable but '--' obviously '--' faulty. If a cell or any sub-cell contains a reference loop, the cell is marked red. In this case it can't be selected for rendering.
|
||||||
|
|
||||||
|
In the above image the cell is green; so everything is okay.
|
||||||
|
|
||||||
*/
|
*/
|
||||||
|
36
doxygen/versioning.dox
Normal file
36
doxygen/versioning.dox
Normal file
@@ -0,0 +1,36 @@
|
|||||||
|
/**
|
||||||
|
@page versioning Version Number
|
||||||
|
|
||||||
|
@section main-version Main Versioning Scheme
|
||||||
|
The version number of this application consists of a given version in the format of 'v1.0'.
|
||||||
|
Where the first number indicates a major release and the second number indicates minor changes.
|
||||||
|
|
||||||
|
Versions, including release candidates and path-levels, are tagged in git.
|
||||||
|
|
||||||
|
@subsection rc Release Candidates
|
||||||
|
Release candidates are software versions that seem stable and functional to become a new version but testing is not fully finished. These versions are marked with an '-rcX', where X is the number of the release candidate.
|
||||||
|
The 3rd release candidate of version 4.2 would be '*v4.2-rc3*'.
|
||||||
|
Release candidates are in a frozen state. Only bugfixes that are necessary for functionality are applied to these versions before releasing the final version.
|
||||||
|
|
||||||
|
@subsection patch-level Patch Levels
|
||||||
|
If an already released version contains bugs that need to be fixed, the version number is not incremented. Insted a new version number with a patch-level is created. The patch-level is appended with a dash directly after the version number. The fist patch-level of version 3.5 would be: 'v3.5-1'.
|
||||||
|
|
||||||
|
|
||||||
|
@section git-version-num Git Based Version Number
|
||||||
|
|
||||||
|
The application and this documentation contain a git-based version number. With this version number not only released versions but all development points of the software can be uniquely identified.
|
||||||
|
|
||||||
|
An example for such a version number is: *v1.0-rc4-41-gaa41373-dirty*
|
||||||
|
|
||||||
|
It consists of the last @ref main-version (in this case version 1.0 -- Release candidate 4) and some other information from the source code management system. The number after the version tag is the commit count after the given version. In this case the specified version is 41 commits after the last tagged version 'v1.0-rc4'. The next section always starts with a 'g' (for git) and after that contains the first letters of the commit ID. In this case an additional '-dirty' is appended, showing that the software version contains unstaged changes.
|
||||||
|
|
||||||
|
In tabular form: *v1.0-rc4-41-gaa41373-dirty*
|
||||||
|
|
||||||
|
| Last tagged version | Commits since that version | Start of commit ID | Unstaged changes? |
|
||||||
|
|---------------------|----------------------------|--------------------|---------------------|
|
||||||
|
| 1.0-rc4 | 41 | aa41373 | yes |
|
||||||
|
|
||||||
|
|
||||||
|
This git-based version number is automatically put into the application and this documentation during the application's compilation / the documentation's generation. For this *git* is needed. Therefore, it is highly recommended to have 'git' installed for compilation although it is no build dependency. In case of a missing git installation, the string "! version not set !" is compiled into the application.
|
||||||
|
|
||||||
|
**/
|
@@ -2,5 +2,5 @@
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* @defgroup Widgets Custom GTK Widgets
|
* @defgroup Widgets Custom GTK Widgets
|
||||||
*
|
* @ingroup GUI
|
||||||
*/
|
*/
|
||||||
|
@@ -1,70 +0,0 @@
|
|||||||
/*
|
|
||||||
* 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/>.
|
|
||||||
*/
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @file external-renderer.c
|
|
||||||
* @brief This file implements the dynamic library loading for the external rendering feature
|
|
||||||
* @author Mario Hüttel <mario.huettel@gmx.net>
|
|
||||||
*/
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @addtogroup MainApplication
|
|
||||||
* @{
|
|
||||||
*/
|
|
||||||
|
|
||||||
#include "external-renderer.h"
|
|
||||||
#include <dlfcn.h>
|
|
||||||
#include <stdio.h>
|
|
||||||
|
|
||||||
int external_renderer_render_cell(struct gds_cell *toplevel_cell, GList *layer_info_list, char *output_file, char *so_path)
|
|
||||||
{
|
|
||||||
int (*so_render_func)(struct gds_cell *, GList *, char *) = NULL;
|
|
||||||
void *so_handle = NULL;
|
|
||||||
char *error_msg;
|
|
||||||
int ret = 0;
|
|
||||||
|
|
||||||
/* Check parameter sanity */
|
|
||||||
if (!output_file || !so_path || !toplevel_cell || !layer_info_list) {
|
|
||||||
return -3000;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Load shared object */
|
|
||||||
so_handle = dlopen(so_path, RTLD_LAZY);
|
|
||||||
if (!so_handle) {
|
|
||||||
printf("Could not load external library '%s'\nDetailed error is:\n%s\n", so_path, dlerror());
|
|
||||||
return -2000;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Load symbol from library */
|
|
||||||
so_render_func = (int (*)(struct gds_cell *, GList *, char *))dlsym(so_handle, EXTERNAL_LIBRARY_FUNCTION);
|
|
||||||
if ((error_msg = dlerror()) != NULL) {
|
|
||||||
printf("Rendering function not found in library:\n%s\n", error_msg);
|
|
||||||
goto ret_close_so_handle;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Execute */
|
|
||||||
if (so_render_func)
|
|
||||||
so_render_func(toplevel_cell, layer_info_list, output_file);
|
|
||||||
|
|
||||||
ret_close_so_handle:
|
|
||||||
dlclose(so_handle);
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
/** @} */
|
|
594
gds-render-gui.c
Normal file
594
gds-render-gui.c
Normal file
@@ -0,0 +1,594 @@
|
|||||||
|
/*
|
||||||
|
* 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/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @file gds-render-gui.c
|
||||||
|
* @brief Handling of GUI
|
||||||
|
* @author Mario Hüttel <mario.huettel@gmx.net>
|
||||||
|
*/
|
||||||
|
|
||||||
|
/** @addtogroup GUI
|
||||||
|
* @{
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <gtk/gtk.h>
|
||||||
|
|
||||||
|
#include <gds-render/gds-render-gui.h>
|
||||||
|
#include <gds-render/gds-utils/gds-parser.h>
|
||||||
|
#include <gds-render/gds-utils/gds-tree-checker.h>
|
||||||
|
#include <gds-render/layer/layer-selector.h>
|
||||||
|
#include <gds-render/widgets/activity-bar.h>
|
||||||
|
#include <gds-render/cell-selector/tree-store.h>
|
||||||
|
#include <gds-render/cell-selector/lib-cell-renderer.h>
|
||||||
|
//#include <gds-render/output-renderers/latex-output.h>
|
||||||
|
//#include <gds-render/output-renderers/cairo-output.h>
|
||||||
|
#include <gds-render/widgets/conv-settings-dialog.h>
|
||||||
|
#include <gds-render/geometric/cell-geometrics.h>
|
||||||
|
#include <gds-render/version.h>
|
||||||
|
|
||||||
|
enum gds_render_gui_signal_sig_ids {SIGNAL_WINDOW_CLOSED = 0, SIGNAL_COUNT};
|
||||||
|
|
||||||
|
static guint gds_render_gui_signals[SIGNAL_COUNT];
|
||||||
|
|
||||||
|
struct _GdsRenderGui {
|
||||||
|
/* Parent GObject */
|
||||||
|
GObject parent;
|
||||||
|
|
||||||
|
/* Custom fields */
|
||||||
|
GtkWindow *main_window;
|
||||||
|
GtkWidget *convert_button;
|
||||||
|
GtkTreeStore *cell_tree_store;
|
||||||
|
GtkWidget *cell_search_entry;
|
||||||
|
LayerSelector *layer_selector;
|
||||||
|
GtkTreeView *cell_tree_view;
|
||||||
|
GList *gds_libraries;
|
||||||
|
ActivityBar *activity_status_bar;
|
||||||
|
struct render_settings render_dialog_settings;
|
||||||
|
ColorPalette *palette;
|
||||||
|
};
|
||||||
|
|
||||||
|
G_DEFINE_TYPE(GdsRenderGui, gds_render_gui, G_TYPE_OBJECT)
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Main window close event
|
||||||
|
* @param window GtkWindow which is closed
|
||||||
|
* @param event unused event
|
||||||
|
* @param user GdsRenderGui instance
|
||||||
|
* @return Status of the event handling. Always true.
|
||||||
|
*/
|
||||||
|
static gboolean on_window_close(gpointer window, GdkEvent *event, gpointer user)
|
||||||
|
{
|
||||||
|
GdsRenderGui *self;
|
||||||
|
|
||||||
|
self = RENDERER_GUI(user);
|
||||||
|
/* Don't close window in case of error */
|
||||||
|
if (!self)
|
||||||
|
return TRUE;
|
||||||
|
|
||||||
|
/* Close Window. Leads to termination of the program/the current instance */
|
||||||
|
g_clear_object(&self->main_window);
|
||||||
|
gtk_widget_destroy(GTK_WIDGET(window));
|
||||||
|
|
||||||
|
/* Delete loaded library data */
|
||||||
|
clear_lib_list(&self->gds_libraries);
|
||||||
|
|
||||||
|
g_signal_emit(self, gds_render_gui_signals[SIGNAL_WINDOW_CLOSED], 0);
|
||||||
|
|
||||||
|
return TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief generate string from gds_time_field
|
||||||
|
* @param date Date to convert
|
||||||
|
* @return String with date
|
||||||
|
*/
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Callback function of Load GDS button
|
||||||
|
* @param button
|
||||||
|
* @param user GdsRenderGui instance
|
||||||
|
*/
|
||||||
|
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;
|
||||||
|
GdsRenderGui *self;
|
||||||
|
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;
|
||||||
|
unsigned int cell_error_level;
|
||||||
|
|
||||||
|
self = RENDERER_GUI(user);
|
||||||
|
if (!self)
|
||||||
|
return;
|
||||||
|
|
||||||
|
open_dialog = gtk_file_chooser_dialog_new("Open GDSII File", self->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)
|
||||||
|
goto end_destroy;
|
||||||
|
|
||||||
|
/* Get File name */
|
||||||
|
filename = gtk_file_chooser_get_filename(file_chooser);
|
||||||
|
|
||||||
|
gtk_tree_store_clear(self->cell_tree_store);
|
||||||
|
clear_lib_list(&self->gds_libraries);
|
||||||
|
|
||||||
|
/* Parse new GDSII file */
|
||||||
|
gds_result = parse_gds_from_file(filename, &self->gds_libraries);
|
||||||
|
|
||||||
|
/* 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 = self->gds_libraries; lib != NULL; lib = lib->next) {
|
||||||
|
gds_lib = (struct gds_library *)lib->data;
|
||||||
|
/* Create top level iter */
|
||||||
|
gtk_tree_store_append(self->cell_tree_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(self->cell_tree_store, &libiter,
|
||||||
|
CELL_SEL_LIBRARY, gds_lib,
|
||||||
|
CELL_SEL_MODDATE, mod_date->str,
|
||||||
|
CELL_SEL_ACCESSDATE, acc_date->str,
|
||||||
|
-1);
|
||||||
|
|
||||||
|
/* Check this library. This might take a while */
|
||||||
|
(void)gds_tree_check_cell_references(gds_lib);
|
||||||
|
(void)gds_tree_check_reference_loops(gds_lib);
|
||||||
|
/* 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(self->cell_tree_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);
|
||||||
|
|
||||||
|
/* Get the checking results for this cell */
|
||||||
|
cell_error_level = 0;
|
||||||
|
if (gds_c->checks.unresolved_child_count)
|
||||||
|
cell_error_level |= LIB_CELL_RENDERER_ERROR_WARN;
|
||||||
|
|
||||||
|
/* Check if it is completely b0rken */
|
||||||
|
if (gds_c->checks.affected_by_reference_loop)
|
||||||
|
cell_error_level |= LIB_CELL_RENDERER_ERROR_ERR;
|
||||||
|
|
||||||
|
/* Add cell to tree store model */
|
||||||
|
gtk_tree_store_set(self->cell_tree_store, &celliter,
|
||||||
|
CELL_SEL_CELL, gds_c,
|
||||||
|
CELL_SEL_MODDATE, mod_date->str,
|
||||||
|
CELL_SEL_ACCESSDATE, acc_date->str,
|
||||||
|
CELL_SEL_CELL_ERROR_STATE, cell_error_level,
|
||||||
|
-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 cells */
|
||||||
|
} /* for libraries */
|
||||||
|
|
||||||
|
/* Create Layers in Layer Box */
|
||||||
|
layer_selector_generate_layer_widgets(self->layer_selector, self->gds_libraries);
|
||||||
|
|
||||||
|
end_destroy:
|
||||||
|
/* Destroy dialog and filter */
|
||||||
|
gtk_widget_destroy(open_dialog);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Callback for auto coloring button
|
||||||
|
* @param button
|
||||||
|
* @param user
|
||||||
|
*/
|
||||||
|
static void on_auto_color_clicked(gpointer button, gpointer user)
|
||||||
|
{
|
||||||
|
GdsRenderGui *self;
|
||||||
|
(void)button;
|
||||||
|
|
||||||
|
self = RENDERER_GUI(user);
|
||||||
|
layer_selector_auto_color_layers(self->layer_selector, self->palette, 1.0);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Convert button callback
|
||||||
|
* @param button
|
||||||
|
* @param user
|
||||||
|
*/
|
||||||
|
static void on_convert_clicked(gpointer button, gpointer user)
|
||||||
|
{
|
||||||
|
(void)button;
|
||||||
|
GdsRenderGui *self;
|
||||||
|
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;
|
||||||
|
union bounding_box cell_box;
|
||||||
|
unsigned int height, width;
|
||||||
|
struct render_settings *sett;
|
||||||
|
|
||||||
|
self = RENDERER_GUI(user);
|
||||||
|
|
||||||
|
if (!self)
|
||||||
|
return;
|
||||||
|
|
||||||
|
sett = &self->render_dialog_settings;
|
||||||
|
|
||||||
|
/* Get selected cell */
|
||||||
|
selection = gtk_tree_view_get_selection(self->cell_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 = layer_selector_export_rendered_layer_info(self->layer_selector);
|
||||||
|
|
||||||
|
/* Calculate cell size in DB units */
|
||||||
|
bounding_box_prepare_empty(&cell_box);
|
||||||
|
calculate_cell_bounding_box(&cell_box, cell_to_render);
|
||||||
|
|
||||||
|
/* Calculate size in database units
|
||||||
|
* Note that the results are bound to be positive,
|
||||||
|
* so casting them to unsigned int is absolutely valid
|
||||||
|
*/
|
||||||
|
height = (unsigned int)(cell_box.vectors.upper_right.y - cell_box.vectors.lower_left.y);
|
||||||
|
width = (unsigned int)(cell_box.vectors.upper_right.x - cell_box.vectors.lower_left.x);
|
||||||
|
|
||||||
|
/* Show settings dialog */
|
||||||
|
settings = renderer_settings_dialog_new(GTK_WINDOW(self->main_window));
|
||||||
|
renderer_settings_dialog_set_settings(settings, sett);
|
||||||
|
renderer_settings_dialog_set_database_unit_scale(settings, cell_to_render->parent_library->unit_in_meters);
|
||||||
|
renderer_settings_dialog_set_cell_height(settings, height);
|
||||||
|
renderer_settings_dialog_set_cell_width(settings, width);
|
||||||
|
g_object_set(G_OBJECT(settings), "cell-name", cell_to_render->name, NULL);
|
||||||
|
|
||||||
|
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(self->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();
|
||||||
|
switch (sett->renderer) {
|
||||||
|
case RENDERER_LATEX_TIKZ:
|
||||||
|
gtk_file_filter_add_pattern(filter, "*.tex");
|
||||||
|
gtk_file_filter_set_name(filter, "LaTeX-Files");
|
||||||
|
break;
|
||||||
|
case RENDERER_CAIROGRAPHICS_PDF:
|
||||||
|
gtk_file_filter_add_pattern(filter, "*.pdf");
|
||||||
|
gtk_file_filter_set_name(filter, "PDF-Files");
|
||||||
|
break;
|
||||||
|
case RENDERER_CAIROGRAPHICS_SVG:
|
||||||
|
gtk_file_filter_add_pattern(filter, "*.svg");
|
||||||
|
gtk_file_filter_set_name(filter, "SVG-Files");
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
gtk_file_chooser_add_filter(GTK_FILE_CHOOSER(dialog), filter);
|
||||||
|
|
||||||
|
gtk_file_chooser_set_do_overwrite_confirmation(GTK_FILE_CHOOSER(dialog), TRUE);
|
||||||
|
|
||||||
|
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_SVG:
|
||||||
|
case RENDERER_CAIROGRAPHICS_PDF:
|
||||||
|
/*cairo_render_cell_to_vector_file(cell_to_render, layer_list,
|
||||||
|
(sett->renderer == RENDERER_CAIROGRAPHICS_PDF
|
||||||
|
? file_name
|
||||||
|
: NULL),
|
||||||
|
(sett->renderer == RENDERER_CAIROGRAPHICS_SVG
|
||||||
|
? file_name
|
||||||
|
: NULL),
|
||||||
|
sett->scale);
|
||||||
|
*/break;
|
||||||
|
}
|
||||||
|
g_free(file_name);
|
||||||
|
|
||||||
|
} else {
|
||||||
|
gtk_widget_destroy(dialog);
|
||||||
|
}
|
||||||
|
ret_layer_destroy:
|
||||||
|
;
|
||||||
|
// g_list_free_full(layer_list, (GDestroyNotify)layer_info_delete_struct);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief cell_tree_view_activated Callback for 'double click' on cell selector element
|
||||||
|
* @param tree_view The tree view the event occured in
|
||||||
|
* @param path path to the selected row
|
||||||
|
* @param column The clicked column
|
||||||
|
* @param user pointer to GdsRenderGui object
|
||||||
|
*/
|
||||||
|
static void cell_tree_view_activated(gpointer tree_view, GtkTreePath *path,
|
||||||
|
GtkTreeViewColumn *column, gpointer user)
|
||||||
|
{
|
||||||
|
(void)tree_view;
|
||||||
|
(void)path;
|
||||||
|
(void)column;
|
||||||
|
|
||||||
|
on_convert_clicked(NULL, user);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Callback for cell-selection change event
|
||||||
|
*
|
||||||
|
* This function activates/deactivates the convert button depending on whether
|
||||||
|
* a cell is selected for conversion or not
|
||||||
|
* @param sel
|
||||||
|
* @param self
|
||||||
|
*/
|
||||||
|
static void cell_selection_changed(GtkTreeSelection *sel, GdsRenderGui *self)
|
||||||
|
{
|
||||||
|
GtkTreeModel *model = NULL;
|
||||||
|
GtkTreeIter iter;
|
||||||
|
|
||||||
|
if (gtk_tree_selection_get_selected(sel, &model, &iter)) {
|
||||||
|
/* Node selected. Show button */
|
||||||
|
gtk_widget_set_sensitive(self->convert_button, TRUE);
|
||||||
|
} else {
|
||||||
|
gtk_widget_set_sensitive(self->convert_button, FALSE);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void sort_up_callback(GtkWidget *widget, gpointer user)
|
||||||
|
{
|
||||||
|
(void)widget;
|
||||||
|
GdsRenderGui *self;
|
||||||
|
|
||||||
|
self = RENDERER_GUI(user);
|
||||||
|
if (!self)
|
||||||
|
return;
|
||||||
|
layer_selector_force_sort(self->layer_selector, LAYER_SELECTOR_SORT_UP);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void sort_down_callback(GtkWidget *widget, gpointer user)
|
||||||
|
{
|
||||||
|
(void)widget;
|
||||||
|
GdsRenderGui *self;
|
||||||
|
|
||||||
|
self = RENDERER_GUI(user);
|
||||||
|
if (!self)
|
||||||
|
return;
|
||||||
|
layer_selector_force_sort(self->layer_selector, LAYER_SELECTOR_SORT_DOWN);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void gds_render_gui_dispose(GObject *gobject)
|
||||||
|
{
|
||||||
|
GdsRenderGui *self;
|
||||||
|
|
||||||
|
self = RENDERER_GUI(gobject);
|
||||||
|
|
||||||
|
clear_lib_list(&self->gds_libraries);
|
||||||
|
|
||||||
|
g_clear_object(&self->cell_tree_view);
|
||||||
|
g_clear_object(&self->convert_button);
|
||||||
|
g_clear_object(&self->layer_selector);
|
||||||
|
g_clear_object(&self->cell_tree_store);
|
||||||
|
g_clear_object(&self->cell_search_entry);
|
||||||
|
g_clear_object(&self->activity_status_bar);
|
||||||
|
g_clear_object(&self->palette);
|
||||||
|
|
||||||
|
if (self->main_window) {
|
||||||
|
g_signal_handlers_destroy(self->main_window);
|
||||||
|
gtk_widget_destroy(GTK_WIDGET(self->main_window));
|
||||||
|
self->main_window = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Chain up */
|
||||||
|
G_OBJECT_CLASS(gds_render_gui_parent_class)->dispose(gobject);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void gds_render_gui_class_init(GdsRenderGuiClass *klass)
|
||||||
|
{
|
||||||
|
GObjectClass *gobject_class = G_OBJECT_CLASS(klass);
|
||||||
|
|
||||||
|
gds_render_gui_signals[SIGNAL_WINDOW_CLOSED] =
|
||||||
|
g_signal_newv("window-closed", RENDERER_TYPE_GUI,
|
||||||
|
G_SIGNAL_RUN_LAST | G_SIGNAL_NO_RECURSE,
|
||||||
|
NULL,
|
||||||
|
NULL,
|
||||||
|
NULL,
|
||||||
|
NULL,
|
||||||
|
G_TYPE_NONE,
|
||||||
|
0,
|
||||||
|
NULL);
|
||||||
|
|
||||||
|
gobject_class->dispose = gds_render_gui_dispose;
|
||||||
|
}
|
||||||
|
|
||||||
|
GtkWindow *gds_render_gui_get_main_window(GdsRenderGui *gui)
|
||||||
|
{
|
||||||
|
return gui->main_window;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void gds_render_gui_init(GdsRenderGui *self)
|
||||||
|
{
|
||||||
|
GtkBuilder *main_builder;
|
||||||
|
GtkWidget *listbox;
|
||||||
|
GtkHeaderBar *header_bar;
|
||||||
|
struct tree_stores *cell_selector_stores;
|
||||||
|
GtkWidget *sort_up_button;
|
||||||
|
GtkWidget *sort_down_button;
|
||||||
|
GtkWidget *activity_bar_box;
|
||||||
|
GtkWidget *auto_color_button;
|
||||||
|
|
||||||
|
main_builder = gtk_builder_new_from_resource("/gui/main.glade");
|
||||||
|
|
||||||
|
self->cell_tree_view = GTK_TREE_VIEW(gtk_builder_get_object(main_builder, "cell-tree"));
|
||||||
|
self->cell_search_entry = GTK_WIDGET(gtk_builder_get_object(main_builder, "cell-search"));
|
||||||
|
|
||||||
|
cell_selector_stores = setup_cell_selector(self->cell_tree_view, GTK_ENTRY(self->cell_search_entry));
|
||||||
|
|
||||||
|
self->cell_tree_store = cell_selector_stores->base_store;
|
||||||
|
|
||||||
|
self->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)self);
|
||||||
|
|
||||||
|
self->convert_button = GTK_WIDGET(gtk_builder_get_object(main_builder, "convert-button"));
|
||||||
|
g_signal_connect(self->convert_button, "clicked", G_CALLBACK(on_convert_clicked), (gpointer)self);
|
||||||
|
|
||||||
|
listbox = GTK_WIDGET(gtk_builder_get_object(main_builder, "layer-list"));
|
||||||
|
/* Create layer selector */
|
||||||
|
self->layer_selector = layer_selector_new(GTK_LIST_BOX(listbox));
|
||||||
|
|
||||||
|
activity_bar_box = GTK_WIDGET(gtk_builder_get_object(main_builder, "activity-bar"));
|
||||||
|
|
||||||
|
/* Callback for selection change of cell selector */
|
||||||
|
g_signal_connect(G_OBJECT(gtk_tree_view_get_selection(self->cell_tree_view)), "changed",
|
||||||
|
G_CALLBACK(cell_selection_changed), self);
|
||||||
|
g_signal_connect(self->cell_tree_view, "row-activated", G_CALLBACK(cell_tree_view_activated), self);
|
||||||
|
|
||||||
|
/* Set version in main window subtitle */
|
||||||
|
header_bar = GTK_HEADER_BAR(gtk_builder_get_object(main_builder, "header-bar"));
|
||||||
|
gtk_header_bar_set_subtitle(header_bar, _app_version_string);
|
||||||
|
|
||||||
|
/* Get layer sorting buttons and set callbacks */
|
||||||
|
sort_up_button = GTK_WIDGET(gtk_builder_get_object(main_builder, "button-up-sort"));
|
||||||
|
sort_down_button = GTK_WIDGET(gtk_builder_get_object(main_builder, "button-down-sort"));
|
||||||
|
|
||||||
|
g_signal_connect(sort_up_button, "clicked", G_CALLBACK(sort_up_callback), self);
|
||||||
|
g_signal_connect(sort_down_button, "clicked", G_CALLBACK(sort_down_callback), self);
|
||||||
|
|
||||||
|
/* Set buttons for loading and saving */
|
||||||
|
layer_selector_set_load_mapping_button(self->layer_selector,
|
||||||
|
GTK_WIDGET(gtk_builder_get_object(main_builder, "button-load-mapping")),
|
||||||
|
self->main_window);
|
||||||
|
layer_selector_set_save_mapping_button(self->layer_selector, GTK_WIDGET(gtk_builder_get_object(main_builder, "button-save-mapping")),
|
||||||
|
self->main_window);
|
||||||
|
|
||||||
|
/* Connect delete-event */
|
||||||
|
g_signal_connect(GTK_WIDGET(self->main_window), "delete-event",
|
||||||
|
G_CALLBACK(on_window_close), self);
|
||||||
|
|
||||||
|
/* Create and apply ActivityBar */
|
||||||
|
self->activity_status_bar = activity_bar_new();
|
||||||
|
gtk_container_add(GTK_CONTAINER(activity_bar_box), GTK_WIDGET(self->activity_status_bar));
|
||||||
|
gtk_widget_show(GTK_WIDGET(self->activity_status_bar));
|
||||||
|
|
||||||
|
/* Create color palette */
|
||||||
|
self->palette = color_palette_new_from_resource("/data/color-palette.txt");
|
||||||
|
auto_color_button = GTK_WIDGET(gtk_builder_get_object(main_builder, "auto-color-button"));
|
||||||
|
g_signal_connect(auto_color_button, "clicked", G_CALLBACK(on_auto_color_clicked), self);
|
||||||
|
|
||||||
|
|
||||||
|
/* Set default conversion/rendering settings */
|
||||||
|
self->render_dialog_settings.scale = 1000;
|
||||||
|
self->render_dialog_settings.renderer = RENDERER_LATEX_TIKZ;
|
||||||
|
self->render_dialog_settings.tex_pdf_layers = FALSE;
|
||||||
|
self->render_dialog_settings.tex_standalone = FALSE;
|
||||||
|
|
||||||
|
g_object_unref(main_builder);
|
||||||
|
|
||||||
|
/* Reference all objects referenced by this object */
|
||||||
|
g_object_ref(self->activity_status_bar);
|
||||||
|
g_object_ref(self->main_window);
|
||||||
|
g_object_ref(self->cell_tree_view);
|
||||||
|
g_object_ref(self->convert_button);
|
||||||
|
g_object_ref(self->layer_selector);
|
||||||
|
g_object_ref(self->cell_tree_store);
|
||||||
|
g_object_ref(self->cell_search_entry);
|
||||||
|
g_object_ref(self->palette);
|
||||||
|
}
|
||||||
|
|
||||||
|
GdsRenderGui *gds_render_gui_new()
|
||||||
|
{
|
||||||
|
return RENDERER_GUI(g_object_new(RENDERER_TYPE_GUI, NULL));
|
||||||
|
}
|
||||||
|
|
||||||
|
/** @} */
|
@@ -17,11 +17,6 @@
|
|||||||
* along with GDSII-Converter. If not, see <http://www.gnu.org/licenses/>.
|
* along with GDSII-Converter. If not, see <http://www.gnu.org/licenses/>.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/*
|
|
||||||
|
|
||||||
*/
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @file gds-parser.c
|
* @file gds-parser.c
|
||||||
* @brief Implementation of the GDS-Parser
|
* @brief Implementation of the GDS-Parser
|
||||||
@@ -35,12 +30,10 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @addtogroup GDS-Parser
|
* @addtogroup GDS-Utilities
|
||||||
* @{
|
* @{
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
|
||||||
#include "gds-parser.h"
|
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
@@ -48,11 +41,20 @@
|
|||||||
#include <math.h>
|
#include <math.h>
|
||||||
#include <cairo.h>
|
#include <cairo.h>
|
||||||
|
|
||||||
|
#include <gds-render/gds-utils/gds-parser.h>
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Default units assumed for library.
|
||||||
|
* @note This value is usually overwritten with the value defined in the library.
|
||||||
|
*/
|
||||||
|
#define GDS_DEFAULT_UNITS (10E-9)
|
||||||
|
|
||||||
#define GDS_ERROR(fmt, ...) printf("[PARSE_ERROR] " fmt "\n", ##__VA_ARGS__) /**< @brief Print GDS error*/
|
#define GDS_ERROR(fmt, ...) printf("[PARSE_ERROR] " fmt "\n", ##__VA_ARGS__) /**< @brief Print GDS error*/
|
||||||
#define GDS_WARN(fmt, ...) printf("[PARSE_WARNING] " fmt "\n", ##__VA_ARGS__) /**< @brief Print GDS warning */
|
#define GDS_WARN(fmt, ...) printf("[PARSE_WARNING] " fmt "\n", ##__VA_ARGS__) /**< @brief Print GDS warning */
|
||||||
|
|
||||||
#if GDS_PRINT_DEBUG_INFOS
|
#if GDS_PRINT_DEBUG_INFOS
|
||||||
#define GDS_INF(fmt, ...) printf(fmt, ##__VA_ARGS__) /**< @brief standard printf. But cna be disabled in code */
|
/**< @brief standard printf. But can be disabled in code. */
|
||||||
|
#define GDS_INF(fmt, ...) printf(fmt, ##__VA_ARGS__)
|
||||||
#else
|
#else
|
||||||
#define GDS_INF(fmt, ...)
|
#define GDS_INF(fmt, ...)
|
||||||
#endif
|
#endif
|
||||||
@@ -78,7 +80,26 @@ enum gds_record {
|
|||||||
BOX = 0x2D00,
|
BOX = 0x2D00,
|
||||||
LAYER = 0x0D02,
|
LAYER = 0x0D02,
|
||||||
WIDTH = 0x0F03,
|
WIDTH = 0x0F03,
|
||||||
PATHTYPE = 0x2102
|
PATHTYPE = 0x2102,
|
||||||
|
COLROW = 0x1302,
|
||||||
|
AREF = 0x0B00
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Struct representing an array instantiation.
|
||||||
|
*
|
||||||
|
* This struct is defined locally because it is not exposed to the outside of the
|
||||||
|
* parser. Array references are internally converted to a bunch of standard @ref gds_cell_instance elements.
|
||||||
|
*/
|
||||||
|
struct gds_cell_array_instance {
|
||||||
|
char ref_name[CELL_NAME_MAX]; /**< @brief Name of referenced cell */
|
||||||
|
struct gds_cell *cell_ref; /**< @brief Referenced gds_cell structure */
|
||||||
|
struct gds_point control_points[3]; /**< @brief The three control points */
|
||||||
|
int flipped; /**< @brief Mirror each instance on x-axis before rotation */
|
||||||
|
double angle; /**< @brief Angle of rotation for each instance (counter clockwise) in degrees */
|
||||||
|
double magnification; /**< @brief Magnification of each instance */
|
||||||
|
int columns; /**< @brief Column count */
|
||||||
|
int rows; /**< @brief Row count */
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -111,6 +132,36 @@ static int name_cell_ref(struct gds_cell_instance *cell_inst,
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Name cell reference
|
||||||
|
* @param cell_inst Cell reference
|
||||||
|
* @param bytes Length of name
|
||||||
|
* @param data Name
|
||||||
|
* @return 0 if successful
|
||||||
|
*/
|
||||||
|
static int name_array_cell_ref(struct gds_cell_array_instance *cell_inst,
|
||||||
|
unsigned int bytes, char *data)
|
||||||
|
{
|
||||||
|
int len;
|
||||||
|
|
||||||
|
if (cell_inst == NULL) {
|
||||||
|
GDS_ERROR("Naming array cell ref with no opened cell ref");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
data[bytes] = 0; // Append '0'
|
||||||
|
len = (int)strlen(data);
|
||||||
|
if (len > CELL_NAME_MAX-1) {
|
||||||
|
GDS_ERROR("Cell name '%s' too long: %d\n", data, len);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* else: */
|
||||||
|
strcpy(cell_inst->ref_name, data);
|
||||||
|
GDS_INF("\tCell referenced: %s\n", cell_inst->ref_name);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Convert GDS 8-byte real to double
|
* @brief Convert GDS 8-byte real to double
|
||||||
* @param data 8 Byte GDS real
|
* @param data 8 Byte GDS real
|
||||||
@@ -132,7 +183,7 @@ static double gds_convert_double(const char *data)
|
|||||||
if (data[i] != 0)
|
if (data[i] != 0)
|
||||||
break;
|
break;
|
||||||
if (i == 7) {
|
if (i == 7) {
|
||||||
/* 7 bytes all 0 */
|
/* All 8 bytes are 0 */
|
||||||
return 0.0;
|
return 0.0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -221,7 +272,7 @@ static GList *append_library(GList *curr_list, struct gds_library **library_ptr)
|
|||||||
if (lib) {
|
if (lib) {
|
||||||
lib->cells = NULL;
|
lib->cells = NULL;
|
||||||
lib->name[0] = 0;
|
lib->name[0] = 0;
|
||||||
lib->unit_to_meters = 1; // Default. Will be overwritten
|
lib->unit_in_meters = GDS_DEFAULT_UNITS; // Default. Will be overwritten
|
||||||
lib->cell_names = NULL;
|
lib->cell_names = NULL;
|
||||||
} else
|
} else
|
||||||
return NULL;
|
return NULL;
|
||||||
@@ -297,6 +348,9 @@ 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->parent_library = NULL;
|
||||||
|
cell->checks.unresolved_child_count = GDS_CELL_CHECK_NOT_RUN;
|
||||||
|
cell->checks.affected_by_reference_loop = GDS_CELL_CHECK_NOT_RUN;
|
||||||
} else
|
} else
|
||||||
return NULL;
|
return NULL;
|
||||||
/* return cell */
|
/* return cell */
|
||||||
@@ -323,9 +377,9 @@ static GList *append_cell_ref(GList *curr_list, struct gds_cell_instance **insta
|
|||||||
if (inst) {
|
if (inst) {
|
||||||
inst->cell_ref = NULL;
|
inst->cell_ref = NULL;
|
||||||
inst->ref_name[0] = 0;
|
inst->ref_name[0] = 0;
|
||||||
inst->magnification = 1;
|
inst->magnification = 1.0;
|
||||||
inst->flipped = 0;
|
inst->flipped = 0;
|
||||||
inst->angle = 0;
|
inst->angle = 0.0;
|
||||||
} else
|
} else
|
||||||
return NULL;
|
return NULL;
|
||||||
|
|
||||||
@@ -383,7 +437,7 @@ static int name_cell(struct gds_cell *cell, unsigned int bytes,
|
|||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
data[bytes] = 0; // Append '0'
|
data[bytes] = 0; // Append '0'
|
||||||
len = strlen(data);
|
len = (int)strlen(data);
|
||||||
if (len > CELL_NAME_MAX-1) {
|
if (len > CELL_NAME_MAX-1) {
|
||||||
GDS_ERROR("Cell name '%s' too long: %d\n", data, len);
|
GDS_ERROR("Cell name '%s' too long: %d\n", data, len);
|
||||||
return -1;
|
return -1;
|
||||||
@@ -458,6 +512,7 @@ static void scan_cell_reference_dependencies(gpointer gcell, gpointer library)
|
|||||||
static 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;
|
||||||
|
(void)user;
|
||||||
|
|
||||||
GDS_INF("Scanning Library: %s\n", lib->name);
|
GDS_INF("Scanning Library: %s\n", lib->name);
|
||||||
g_list_foreach(lib->cells, scan_cell_reference_dependencies, lib);
|
g_list_foreach(lib->cells, scan_cell_reference_dependencies, lib);
|
||||||
@@ -504,6 +559,62 @@ static void gds_parse_date(const char *buffer, int length, struct gds_time_field
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Convert AREF to a bunch of SREFs and append them to \p container_cell
|
||||||
|
*
|
||||||
|
* This function converts a single array reference (\p aref) to gds_cell_array_instance::rows * gds_cell_array_instance::columns
|
||||||
|
* single references (SREFs). See @ref gds_cell_instance.
|
||||||
|
*
|
||||||
|
* Both gds_cell_array_instance::rows and gds_cell_array_instance::columns must be larger than zero.
|
||||||
|
*
|
||||||
|
* @param[in] aref Array reference to parse
|
||||||
|
* @param[in] container_cell cell to add the converted single references to.
|
||||||
|
*/
|
||||||
|
static void convert_aref_to_sref(struct gds_cell_array_instance *aref, struct gds_cell *container_cell)
|
||||||
|
{
|
||||||
|
struct gds_point origin;
|
||||||
|
struct gds_point row_shift_vector;
|
||||||
|
struct gds_point col_shift_vector;
|
||||||
|
struct gds_cell_instance *sref_inst = NULL;
|
||||||
|
int col;
|
||||||
|
int row;
|
||||||
|
|
||||||
|
if (!aref || !container_cell)
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (aref->columns == 0 || aref->rows == 0) {
|
||||||
|
GDS_ERROR("Conversion of array instance aborted. No rows / columns.");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
origin.x = aref->control_points[0].x;
|
||||||
|
origin.y = aref->control_points[0].y;
|
||||||
|
|
||||||
|
row_shift_vector.x = (aref->control_points[2].x - origin.x) / aref->rows;
|
||||||
|
row_shift_vector.y = (aref->control_points[2].y - origin.y) / aref->rows;
|
||||||
|
col_shift_vector.x = (aref->control_points[1].x - origin.x) / aref->columns;
|
||||||
|
col_shift_vector.y = (aref->control_points[1].y - origin.y) / aref->columns;
|
||||||
|
|
||||||
|
/* Iterate over columns and rows */
|
||||||
|
for (col = 0; col < aref->columns; col++) {
|
||||||
|
for (row = 0; row < aref->rows; row++) {
|
||||||
|
/* Create new instance for this row/column and aconfigure data */
|
||||||
|
container_cell->child_cells = append_cell_ref(container_cell->child_cells, &sref_inst);
|
||||||
|
if (!sref_inst) {
|
||||||
|
GDS_ERROR("Appending cell ref failed!");
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
sref_inst->angle = aref->angle;
|
||||||
|
sref_inst->magnification = aref->magnification;
|
||||||
|
sref_inst->flipped = aref->flipped;
|
||||||
|
strncpy(sref_inst->ref_name, aref->ref_name, CELL_NAME_MAX);
|
||||||
|
sref_inst->origin.x = origin.x + row_shift_vector.x * row + col_shift_vector.x * col;
|
||||||
|
sref_inst->origin.y = origin.y + row_shift_vector.y * row + col_shift_vector.y * col;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
GDS_INF("Converted AREF to SREFs\n");
|
||||||
|
}
|
||||||
|
|
||||||
int parse_gds_from_file(const char *filename, GList **library_list)
|
int parse_gds_from_file(const char *filename, GList **library_list)
|
||||||
{
|
{
|
||||||
char *workbuff;
|
char *workbuff;
|
||||||
@@ -517,6 +628,8 @@ int parse_gds_from_file(const char *filename, GList **library_list)
|
|||||||
struct gds_cell *current_cell = NULL;
|
struct gds_cell *current_cell = NULL;
|
||||||
struct gds_graphics *current_graphics = NULL;
|
struct gds_graphics *current_graphics = NULL;
|
||||||
struct gds_cell_instance *current_s_reference = NULL;
|
struct gds_cell_instance *current_s_reference = NULL;
|
||||||
|
struct gds_cell_array_instance *current_a_reference = NULL;
|
||||||
|
struct gds_cell_array_instance temp_a_reference;
|
||||||
int x, y;
|
int x, y;
|
||||||
////////////
|
////////////
|
||||||
GList *lib_list;
|
GList *lib_list;
|
||||||
@@ -578,6 +691,7 @@ int parse_gds_from_file(const char *filename, GList **library_list)
|
|||||||
}
|
}
|
||||||
rec_type = gds_convert_unsigend_int16(workbuff);
|
rec_type = gds_convert_unsigend_int16(workbuff);
|
||||||
|
|
||||||
|
|
||||||
/* if begin: Allocate structures */
|
/* if begin: Allocate structures */
|
||||||
switch (rec_type) {
|
switch (rec_type) {
|
||||||
case BGNLIB:
|
case BGNLIB:
|
||||||
@@ -607,13 +721,21 @@ int parse_gds_from_file(const char *filename, GList **library_list)
|
|||||||
GDS_INF("Leaving Library\n");
|
GDS_INF("Leaving Library\n");
|
||||||
break;
|
break;
|
||||||
case BGNSTR:
|
case BGNSTR:
|
||||||
|
if (current_lib == NULL) {
|
||||||
|
GDS_ERROR("Defining Cell outside of library!\n");
|
||||||
|
run = -4;
|
||||||
|
break;
|
||||||
|
}
|
||||||
current_lib->cells = append_cell(current_lib->cells, ¤t_cell);
|
current_lib->cells = append_cell(current_lib->cells, ¤t_cell);
|
||||||
if (current_lib->cells == NULL) {
|
if (current_lib->cells == NULL) {
|
||||||
GDS_ERROR("Allocating memory failed");
|
GDS_ERROR("Allocating memory failed");
|
||||||
run = -3;
|
run = -3;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
GDS_INF("Entering Cell\n");
|
|
||||||
|
current_cell->parent_library = current_lib;
|
||||||
|
|
||||||
|
GDS_INF("Entering cell\n");
|
||||||
break;
|
break;
|
||||||
case ENDSTR:
|
case ENDSTR:
|
||||||
if (current_cell == NULL) {
|
if (current_cell == NULL) {
|
||||||
@@ -649,7 +771,7 @@ int parse_gds_from_file(const char *filename, GList **library_list)
|
|||||||
break;
|
break;
|
||||||
case SREF:
|
case SREF:
|
||||||
if (current_cell == NULL) {
|
if (current_cell == NULL) {
|
||||||
GDS_ERROR("Path outside of cell");
|
GDS_ERROR("Cell Reference outside of cell");
|
||||||
run = -3;
|
run = -3;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@@ -680,7 +802,6 @@ int parse_gds_from_file(const char *filename, GList **library_list)
|
|||||||
break;
|
break;
|
||||||
case ENDEL:
|
case ENDEL:
|
||||||
if (current_graphics != NULL) {
|
if (current_graphics != NULL) {
|
||||||
|
|
||||||
GDS_INF("\tLeaving %s\n", (current_graphics->gfx_type == GRAPHIC_POLYGON ? "boundary" : "path"));
|
GDS_INF("\tLeaving %s\n", (current_graphics->gfx_type == GRAPHIC_POLYGON ? "boundary" : "path"));
|
||||||
current_graphics = NULL;
|
current_graphics = NULL;
|
||||||
}
|
}
|
||||||
@@ -688,6 +809,12 @@ int parse_gds_from_file(const char *filename, GList **library_list)
|
|||||||
GDS_INF("\tLeaving Reference\n");
|
GDS_INF("\tLeaving Reference\n");
|
||||||
current_s_reference = NULL;
|
current_s_reference = NULL;
|
||||||
}
|
}
|
||||||
|
if (current_a_reference != NULL) {
|
||||||
|
GDS_INF("\tLeaving Array Reference\n");
|
||||||
|
convert_aref_to_sref(current_a_reference, current_cell);
|
||||||
|
current_a_reference = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
break;
|
break;
|
||||||
case XY:
|
case XY:
|
||||||
if (current_graphics) {
|
if (current_graphics) {
|
||||||
@@ -696,28 +823,57 @@ int parse_gds_from_file(const char *filename, GList **library_list)
|
|||||||
if (rec_data_length != 8) {
|
if (rec_data_length != 8) {
|
||||||
GDS_WARN("Instance has weird coordinates. Rendered output might be screwed!");
|
GDS_WARN("Instance has weird coordinates. Rendered output might be screwed!");
|
||||||
}
|
}
|
||||||
|
} else if (current_a_reference) {
|
||||||
|
if (rec_data_length != (3*(4+4)))
|
||||||
|
GDS_WARN("Array instance has weird coordinates. Rendered output might be screwed!");
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case AREF:
|
||||||
|
if (current_cell == NULL) {
|
||||||
|
GDS_ERROR("Cell array reference outside of cell");
|
||||||
|
run = -3;
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (current_a_reference != NULL) {
|
||||||
|
GDS_ERROR("Recursive cell array reference");
|
||||||
|
run = -3;
|
||||||
break;
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
GDS_INF("Entering Array Reference\n");
|
||||||
|
|
||||||
|
/* Array references are coverted after fully declared. Therefore,
|
||||||
|
* only a static buffer is needed
|
||||||
|
*/
|
||||||
|
current_a_reference = &temp_a_reference;
|
||||||
|
current_a_reference->ref_name[0] = '\0';
|
||||||
|
current_a_reference->angle = 0.0;
|
||||||
|
current_a_reference->magnification = 1.0;
|
||||||
|
current_a_reference->flipped = 0;
|
||||||
|
current_a_reference->rows = 0;
|
||||||
|
current_a_reference->columns = 0;
|
||||||
|
break;
|
||||||
|
case COLROW:
|
||||||
case MAG:
|
case MAG:
|
||||||
break;
|
|
||||||
case ANGLE:
|
case ANGLE:
|
||||||
break;
|
|
||||||
case STRANS:
|
case STRANS:
|
||||||
break;
|
|
||||||
case WIDTH:
|
case WIDTH:
|
||||||
break;
|
|
||||||
case PATHTYPE:
|
case PATHTYPE:
|
||||||
|
case UNITS:
|
||||||
|
case LIBNAME:
|
||||||
|
case SNAME:
|
||||||
|
case LAYER:
|
||||||
|
case STRNAME:
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
//GDS_WARN("Record: %04x, len: %u", (unsigned int)rec_type, (unsigned int)rec_data_length);
|
GDS_INF("Unhandled Record: %04x, len: %u\n", (unsigned int)rec_type, (unsigned int)rec_data_length);
|
||||||
break;
|
break;
|
||||||
} /* switch(rec_type) */
|
} /* switch(rec_type) */
|
||||||
|
|
||||||
|
|
||||||
/* No Data -> No Processing, go back to top */
|
/* No Data -> No Processing, go back to top */
|
||||||
if (!rec_data_length) continue;
|
if (!rec_data_length || run != 1) continue;
|
||||||
|
|
||||||
read = fread(workbuff, sizeof(char), rec_data_length, gds_file);
|
read = fread(workbuff, sizeof(char), rec_data_length, gds_file);
|
||||||
|
|
||||||
@@ -729,9 +885,8 @@ int parse_gds_from_file(const char *filename, GList **library_list)
|
|||||||
}
|
}
|
||||||
|
|
||||||
switch (rec_type) {
|
switch (rec_type) {
|
||||||
|
case AREF:
|
||||||
case HEADER:
|
case HEADER:
|
||||||
case UNITS:
|
|
||||||
case ENDLIB:
|
case ENDLIB:
|
||||||
case ENDSTR:
|
case ENDSTR:
|
||||||
case BOUNDARY:
|
case BOUNDARY:
|
||||||
@@ -742,6 +897,34 @@ int parse_gds_from_file(const char *filename, GList **library_list)
|
|||||||
case INVALID:
|
case INVALID:
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
case COLROW:
|
||||||
|
if (!current_a_reference) {
|
||||||
|
GDS_ERROR("COLROW record defined outside of array instance");
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if (rec_data_length != 4 || read != 4) {
|
||||||
|
GDS_ERROR("COLUMN/ROW count record contains too few data. Won't set column and row counts (%d, %d)",
|
||||||
|
rec_data_length, read);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
current_a_reference->columns = (int)gds_convert_signed_int16(&workbuff[0]);
|
||||||
|
current_a_reference->rows = (int)gds_convert_signed_int16(&workbuff[2]);
|
||||||
|
GDS_INF("\tRows: %d\n\tColumns: %d\n", current_a_reference->rows, current_a_reference->columns);
|
||||||
|
break;
|
||||||
|
case UNITS:
|
||||||
|
if (!current_lib) {
|
||||||
|
GDS_WARN("Units defined outside of library!\n");
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (rec_data_length != 16) {
|
||||||
|
GDS_WARN("Unit define incomplete. Will assume database unit of %E meters\n", current_lib->unit_in_meters);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
current_lib->unit_in_meters = gds_convert_double(&workbuff[8]);
|
||||||
|
GDS_INF("Length of database unit: %E meters\n", current_lib->unit_in_meters);
|
||||||
|
break;
|
||||||
case BGNLIB:
|
case BGNLIB:
|
||||||
/* Parse date record */
|
/* Parse date record */
|
||||||
gds_parse_date(workbuff, read, ¤t_lib->mod_time, ¤t_lib->access_time);
|
gds_parse_date(workbuff, read, ¤t_lib->mod_time, ¤t_lib->access_time);
|
||||||
@@ -771,18 +954,34 @@ int parse_gds_from_file(const char *filename, GList **library_list)
|
|||||||
GDS_INF("\t\tSet coordinate: %d/%d\n", x, y);
|
GDS_INF("\t\tSet coordinate: %d/%d\n", x, y);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
} else if (current_a_reference) {
|
||||||
|
for (i = 0; i < 3; i++) {
|
||||||
|
x = gds_convert_signed_int(&workbuff[i*8]);
|
||||||
|
y = gds_convert_signed_int(&workbuff[i*8+4]);
|
||||||
|
current_a_reference->control_points[i].x = x;
|
||||||
|
current_a_reference->control_points[i].y = y;
|
||||||
|
GDS_INF("\tSet control point %d: %d/%d\n", i, x, y);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case STRANS:
|
case STRANS:
|
||||||
if (!current_s_reference) {
|
if (current_s_reference) {
|
||||||
|
current_s_reference->flipped = ((workbuff[0] & 0x80) ? 1 : 0);
|
||||||
|
} else if (current_a_reference) {
|
||||||
|
current_a_reference->flipped = ((workbuff[0] & 0x80) ? 1 : 0);
|
||||||
|
} else {
|
||||||
GDS_ERROR("Transformation defined outside of instance");
|
GDS_ERROR("Transformation defined outside of instance");
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
current_s_reference->flipped = ((workbuff[0] & 0x80) ? 1 : 0);
|
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case SNAME:
|
case SNAME:
|
||||||
name_cell_ref(current_s_reference, read, workbuff);
|
if (current_s_reference) {
|
||||||
|
name_cell_ref(current_s_reference, (unsigned int)read, workbuff);
|
||||||
|
} else if (current_a_reference) {
|
||||||
|
name_array_cell_ref(current_a_reference, (unsigned int)read, workbuff);
|
||||||
|
} else {
|
||||||
|
GDS_ERROR("Reference name set outside of cell reference");
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
case WIDTH:
|
case WIDTH:
|
||||||
if (!current_graphics) {
|
if (!current_graphics) {
|
||||||
@@ -814,12 +1013,16 @@ int parse_gds_from_file(const char *filename, GList **library_list)
|
|||||||
current_s_reference->magnification = gds_convert_double(workbuff);
|
current_s_reference->magnification = gds_convert_double(workbuff);
|
||||||
GDS_INF("\t\tMagnification defined: %lf\n", current_s_reference->magnification);
|
GDS_INF("\t\tMagnification defined: %lf\n", current_s_reference->magnification);
|
||||||
}
|
}
|
||||||
|
if (current_a_reference != NULL) {
|
||||||
|
current_a_reference->magnification = gds_convert_double(workbuff);
|
||||||
|
GDS_INF("\t\tMagnification defined: %lf\n", current_a_reference->magnification);
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
case ANGLE:
|
case ANGLE:
|
||||||
if (rec_data_length != 8) {
|
if (rec_data_length != 8) {
|
||||||
GDS_WARN("Angle is not an 8 byte real. Results may be wrong");
|
GDS_WARN("Angle is not an 8 byte real. Results may be wrong");
|
||||||
}
|
}
|
||||||
if (current_graphics != NULL && current_s_reference != NULL) {
|
if (current_graphics != NULL && current_s_reference != NULL && current_a_reference != NULL) {
|
||||||
GDS_ERROR("Open Graphics and Cell Reference\n\tMissing ENDEL?");
|
GDS_ERROR("Open Graphics and Cell Reference\n\tMissing ENDEL?");
|
||||||
run = -6;
|
run = -6;
|
||||||
break;
|
break;
|
||||||
@@ -828,6 +1031,10 @@ int parse_gds_from_file(const char *filename, GList **library_list)
|
|||||||
current_s_reference->angle = gds_convert_double(workbuff);
|
current_s_reference->angle = gds_convert_double(workbuff);
|
||||||
GDS_INF("\t\tAngle defined: %lf\n", current_s_reference->angle);
|
GDS_INF("\t\tAngle defined: %lf\n", current_s_reference->angle);
|
||||||
}
|
}
|
||||||
|
if (current_a_reference != NULL) {
|
||||||
|
current_a_reference->angle = gds_convert_double(workbuff);
|
||||||
|
GDS_INF("\t\tAngle defined: %lf\n", current_a_reference->angle);
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
case PATHTYPE:
|
case PATHTYPE:
|
||||||
if (current_graphics == NULL) {
|
if (current_graphics == NULL) {
|
||||||
@@ -835,7 +1042,7 @@ int parse_gds_from_file(const char *filename, GList **library_list)
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
if (current_graphics->gfx_type == GRAPHIC_PATH) {
|
if (current_graphics->gfx_type == GRAPHIC_PATH) {
|
||||||
current_graphics->path_render_type = (int)gds_convert_signed_int16(workbuff);
|
current_graphics->path_render_type = (enum path_type)gds_convert_signed_int16(workbuff);
|
||||||
GDS_INF("\t\tPathtype: %d\n", current_graphics->path_render_type);
|
GDS_INF("\t\tPathtype: %d\n", current_graphics->path_render_type);
|
||||||
} else {
|
} else {
|
||||||
GDS_WARN("Path type defined inside non-path graphics object. Ignoring");
|
GDS_WARN("Path type defined inside non-path graphics object. Ignoring");
|
||||||
@@ -848,15 +1055,11 @@ int parse_gds_from_file(const char *filename, GList **library_list)
|
|||||||
|
|
||||||
fclose(gds_file);
|
fclose(gds_file);
|
||||||
|
|
||||||
|
|
||||||
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);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
*library_list = lib_list;
|
*library_list = lib_list;
|
||||||
|
|
||||||
free(workbuff);
|
free(workbuff);
|
||||||
@@ -870,6 +1073,7 @@ int parse_gds_from_file(const char *filename, GList **library_list)
|
|||||||
*/
|
*/
|
||||||
static void delete_cell_inst_element(struct gds_cell_instance *cell_inst)
|
static void delete_cell_inst_element(struct gds_cell_instance *cell_inst)
|
||||||
{
|
{
|
||||||
|
if (cell_inst)
|
||||||
free(cell_inst);
|
free(cell_inst);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -879,6 +1083,7 @@ static void delete_cell_inst_element(struct gds_cell_instance *cell_inst)
|
|||||||
*/
|
*/
|
||||||
static void delete_vertex(struct gds_point *vertex)
|
static void delete_vertex(struct gds_point *vertex)
|
||||||
{
|
{
|
||||||
|
if (vertex)
|
||||||
free(vertex);
|
free(vertex);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -888,6 +1093,9 @@ static void delete_vertex(struct gds_point *vertex)
|
|||||||
*/
|
*/
|
||||||
static void delete_graphics_obj(struct gds_graphics *gfx)
|
static void delete_graphics_obj(struct gds_graphics *gfx)
|
||||||
{
|
{
|
||||||
|
if (!gfx)
|
||||||
|
return;
|
||||||
|
|
||||||
g_list_free_full(gfx->vertices, (GDestroyNotify)delete_vertex);
|
g_list_free_full(gfx->vertices, (GDestroyNotify)delete_vertex);
|
||||||
free(gfx);
|
free(gfx);
|
||||||
}
|
}
|
||||||
@@ -898,6 +1106,9 @@ static void delete_graphics_obj(struct gds_graphics *gfx)
|
|||||||
*/
|
*/
|
||||||
static void delete_cell_element(struct gds_cell *cell)
|
static void delete_cell_element(struct gds_cell *cell)
|
||||||
{
|
{
|
||||||
|
if (!cell)
|
||||||
|
return;
|
||||||
|
|
||||||
g_list_free_full(cell->child_cells, (GDestroyNotify)delete_cell_inst_element);
|
g_list_free_full(cell->child_cells, (GDestroyNotify)delete_cell_inst_element);
|
||||||
g_list_free_full(cell->graphic_objs, (GDestroyNotify)delete_graphics_obj);
|
g_list_free_full(cell->graphic_objs, (GDestroyNotify)delete_graphics_obj);
|
||||||
free(cell);
|
free(cell);
|
||||||
@@ -909,6 +1120,9 @@ static void delete_cell_element(struct gds_cell *cell)
|
|||||||
*/
|
*/
|
||||||
static void delete_library_element(struct gds_library *lib)
|
static void delete_library_element(struct gds_library *lib)
|
||||||
{
|
{
|
||||||
|
if (!lib)
|
||||||
|
return;
|
||||||
|
|
||||||
g_list_free(lib->cell_names);
|
g_list_free(lib->cell_names);
|
||||||
g_list_free_full(lib->cells, (GDestroyNotify)delete_cell_element);
|
g_list_free_full(lib->cells, (GDestroyNotify)delete_cell_element);
|
||||||
free(lib);
|
free(lib);
|
||||||
@@ -916,8 +1130,12 @@ static void delete_library_element(struct gds_library *lib)
|
|||||||
|
|
||||||
int clear_lib_list(GList **library_list)
|
int clear_lib_list(GList **library_list)
|
||||||
{
|
{
|
||||||
|
if (!library_list)
|
||||||
|
return 0;
|
||||||
|
|
||||||
if (*library_list == NULL)
|
if (*library_list == NULL)
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
g_list_free_full(*library_list, (GDestroyNotify)delete_library_element);
|
g_list_free_full(*library_list, (GDestroyNotify)delete_library_element);
|
||||||
*library_list = NULL;
|
*library_list = NULL;
|
||||||
return 0;
|
return 0;
|
208
gds-utils/gds-tree-checker.c
Normal file
208
gds-utils/gds-tree-checker.c
Normal file
@@ -0,0 +1,208 @@
|
|||||||
|
/*
|
||||||
|
* GDSII-Converter
|
||||||
|
* Copyright (C) 2019 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/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @file gds-tree-checker.c
|
||||||
|
* @brief Checking functions of a cell tree
|
||||||
|
*
|
||||||
|
* This file contains checking functions for the GDS cell tree.
|
||||||
|
* These functions include checks if all child references could be resolved,
|
||||||
|
* and if the cell tree contains loops.
|
||||||
|
*
|
||||||
|
* @author Mario Hüttel <mario.huettel@gmx.net>
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @addtogroup GDS-Utilities
|
||||||
|
* @{
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <stdio.h>
|
||||||
|
|
||||||
|
#include <gds-render/gds-utils/gds-tree-checker.h>
|
||||||
|
|
||||||
|
int gds_tree_check_cell_references(struct gds_library *lib)
|
||||||
|
{
|
||||||
|
GList *cell_iter;
|
||||||
|
struct gds_cell *cell;
|
||||||
|
GList *instance_iter;
|
||||||
|
struct gds_cell_instance *cell_inst;
|
||||||
|
int total_unresolved_count = 0;
|
||||||
|
|
||||||
|
if (!lib)
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
/* Iterate over all cells in library */
|
||||||
|
for (cell_iter = lib->cells; cell_iter != NULL; cell_iter = g_list_next(cell_iter)) {
|
||||||
|
cell = (struct gds_cell *)cell_iter->data;
|
||||||
|
|
||||||
|
/* Check if this list element is broken. This should never happen */
|
||||||
|
if (!cell) {
|
||||||
|
fprintf(stderr, "Broken cell list item found. Will continue.\n");
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Reset the unresolved cell reference counter to 0 */
|
||||||
|
cell->checks.unresolved_child_count = 0;
|
||||||
|
|
||||||
|
/* Iterate through all child cell references and check if the references are set */
|
||||||
|
for (instance_iter = cell->child_cells; instance_iter != NULL;
|
||||||
|
instance_iter = g_list_next(instance_iter)) {
|
||||||
|
cell_inst = (struct gds_cell_instance *)instance_iter->data;
|
||||||
|
|
||||||
|
/* Check if broken. This should not happen */
|
||||||
|
if (!cell_inst) {
|
||||||
|
fprintf(stderr, "Broken cell list item found in cell %s. Will continue.\n",
|
||||||
|
cell->name);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Check if instance is valid; else increment "error" counter of cell */
|
||||||
|
if (!cell_inst->cell_ref) {
|
||||||
|
total_unresolved_count++;
|
||||||
|
cell->checks.unresolved_child_count++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return total_unresolved_count;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Check if list contains a cell
|
||||||
|
* @param list GList to check. May be a null pointer
|
||||||
|
* @param cell Cell to check for
|
||||||
|
* @return 0 if cell is not in list. 1 if cell is in list
|
||||||
|
*/
|
||||||
|
static int gds_tree_check_list_contains_cell(GList *list, struct gds_cell *cell) {
|
||||||
|
GList *iter;
|
||||||
|
|
||||||
|
for (iter = list; iter != NULL; iter = g_list_next(iter)) {
|
||||||
|
if ((struct gds_cell *)iter->data == cell)
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief This function follows down the reference list of a cell and marks each visited subcell and detects loops
|
||||||
|
* @param cell_to_check The cell to check for reference loops
|
||||||
|
* @param visited_cells Pointer to list head. May be zero.
|
||||||
|
* @return 0 if no loops exist; error in processing: <0; loop found: >0
|
||||||
|
*/
|
||||||
|
static int gds_tree_check_iterate_ref_and_check(struct gds_cell *cell_to_check, GList **visited_cells)
|
||||||
|
{
|
||||||
|
GList *ref_iter;
|
||||||
|
struct gds_cell_instance *ref;
|
||||||
|
struct gds_cell *sub_cell;
|
||||||
|
int res;
|
||||||
|
|
||||||
|
if (!cell_to_check)
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
/* Check if this cell is already contained in visited cells. This indicates a loop */
|
||||||
|
if (gds_tree_check_list_contains_cell(*visited_cells, cell_to_check))
|
||||||
|
return 1;
|
||||||
|
|
||||||
|
/* Add cell to visited cell list */
|
||||||
|
*visited_cells = g_list_append(*visited_cells, (gpointer)cell_to_check);
|
||||||
|
|
||||||
|
/* Mark references and process sub cells */
|
||||||
|
for (ref_iter = cell_to_check->child_cells; ref_iter != NULL; ref_iter = g_list_next(ref_iter)) {
|
||||||
|
ref = (struct gds_cell_instance *)ref_iter->data;
|
||||||
|
|
||||||
|
if (!ref)
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
sub_cell = ref->cell_ref;
|
||||||
|
|
||||||
|
/* If cell is not resolved, ignore. No harm there */
|
||||||
|
if (!sub_cell)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
res = gds_tree_check_iterate_ref_and_check(sub_cell, visited_cells);
|
||||||
|
if (res < 0) {
|
||||||
|
/* Error. return. */
|
||||||
|
return -3;
|
||||||
|
} else if (res > 0) {
|
||||||
|
/* Loop in subcell found. Propagate to top */
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Remove cell from visted cells */
|
||||||
|
*visited_cells = g_list_remove(*visited_cells, cell_to_check);
|
||||||
|
|
||||||
|
/* No error found in this chain */
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int gds_tree_check_reference_loops(struct gds_library *lib)
|
||||||
|
{
|
||||||
|
int res;
|
||||||
|
int loop_count = 0;
|
||||||
|
GList *cell_iter;
|
||||||
|
struct gds_cell *cell_to_check;
|
||||||
|
GList *visited_cells = NULL;
|
||||||
|
|
||||||
|
|
||||||
|
if (!lib)
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
for (cell_iter = lib->cells; cell_iter != NULL; cell_iter = g_list_next(cell_iter)) {
|
||||||
|
cell_to_check = (struct gds_cell *)cell_iter->data;
|
||||||
|
|
||||||
|
/* A broken cell reference will be counted fatal in this case */
|
||||||
|
if (!cell_to_check)
|
||||||
|
return -2;
|
||||||
|
|
||||||
|
/* iterate through references and check if loop exists */
|
||||||
|
res = gds_tree_check_iterate_ref_and_check(cell_to_check, &visited_cells);
|
||||||
|
|
||||||
|
if (visited_cells) {
|
||||||
|
/* If cell contains no loop, print error when list not empty.
|
||||||
|
* In case of a loop, it is completely normal that the list is not empty,
|
||||||
|
* due to the instant return from gds_tree_check_iterate_ref_and_check()
|
||||||
|
*/
|
||||||
|
if (res == 0)
|
||||||
|
fprintf(stderr, "Visited cell list should be empty. This is a bug. Please report this.\n");
|
||||||
|
g_list_free(visited_cells);
|
||||||
|
visited_cells = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (res < 0) {
|
||||||
|
/* Error */
|
||||||
|
return res;
|
||||||
|
} else if (res > 0) {
|
||||||
|
/* Loop found: increment loop count and flag cell */
|
||||||
|
cell_to_check->checks.affected_by_reference_loop = 1;
|
||||||
|
loop_count++;
|
||||||
|
} else if (res == 0) {
|
||||||
|
/* No error found for this cell */
|
||||||
|
cell_to_check->checks.affected_by_reference_loop = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
return loop_count;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** @} */
|
@@ -24,21 +24,22 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @addtogroup trigonometric
|
* @addtogroup geometric
|
||||||
* @{
|
* @{
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include "bounding-box.h"
|
|
||||||
#include <math.h>
|
#include <math.h>
|
||||||
|
|
||||||
|
#include <gds-render/geometric/bounding-box.h>
|
||||||
|
|
||||||
#define MIN(a,b) (((a) < (b)) ? (a) : (b)) /**< @brief Return smaller number */
|
#define MIN(a,b) (((a) < (b)) ? (a) : (b)) /**< @brief Return smaller number */
|
||||||
#define MAX(a,b) (((a) > (b)) ? (a) : (b)) /**< @brief Return bigger number */
|
#define MAX(a,b) (((a) > (b)) ? (a) : (b)) /**< @brief Return bigger number */
|
||||||
#define ABS_DBL(a) ((a) < 0 ? -(a) : (a))
|
#define ABS_DBL(a) ((a) < 0 ? -(a) : (a))
|
||||||
|
|
||||||
void bounding_box_calculate_polygon(GList *vertices, conv_generic_to_vector_2d_t conv_func, union bounding_box *box)
|
void bounding_box_calculate_polygon(GList *vertices, conv_generic_to_vector_2d_t conv_func, union bounding_box *box)
|
||||||
{
|
{
|
||||||
double xmin = DBL_MAX, xmax = DBL_MIN, ymin = DBL_MAX, ymax = DBL_MIN;
|
double xmin = DBL_MAX, xmax = -DBL_MAX, ymin = DBL_MAX, ymax = -DBL_MAX;
|
||||||
struct vector_2d temp_vec;
|
struct vector_2d temp_vec;
|
||||||
GList *list_item;
|
GList *list_item;
|
||||||
|
|
||||||
@@ -86,8 +87,8 @@ void bounding_box_prepare_empty(union bounding_box *box)
|
|||||||
{
|
{
|
||||||
box->vectors.lower_left.x = DBL_MAX;
|
box->vectors.lower_left.x = DBL_MAX;
|
||||||
box->vectors.lower_left.y = DBL_MAX;
|
box->vectors.lower_left.y = DBL_MAX;
|
||||||
box->vectors.upper_right.x = DBL_MIN;
|
box->vectors.upper_right.x = -DBL_MAX;
|
||||||
box->vectors.upper_right.y = DBL_MIN;
|
box->vectors.upper_right.y = -DBL_MAX;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void calculate_path_miter_points(struct vector_2d *a, struct vector_2d *b, struct vector_2d *c,
|
static void calculate_path_miter_points(struct vector_2d *a, struct vector_2d *b, struct vector_2d *c,
|
||||||
@@ -133,14 +134,71 @@ static void calculate_path_miter_points(struct vector_2d *a, struct vector_2d *b
|
|||||||
vector_2d_subtract(m2, m2, &v_vec);
|
vector_2d_subtract(m2, m2, &v_vec);
|
||||||
}
|
}
|
||||||
|
|
||||||
void bounding_box_calculate_path_box(GList *vertices, conv_generic_to_vector_2d_t conv_func, union bounding_box *box)
|
void bounding_box_calculate_path_box(GList *vertices, double thickness,
|
||||||
|
conv_generic_to_vector_2d_t conv_func, union bounding_box *box)
|
||||||
{
|
{
|
||||||
|
GList *vertex_iterator;
|
||||||
|
struct vector_2d pt;
|
||||||
|
|
||||||
|
printf("Warning! Function bounding_box_calculate_path_box not yet implemented correctly!\n");
|
||||||
|
|
||||||
|
if (!vertices || !box)
|
||||||
|
return;
|
||||||
|
|
||||||
|
for (vertex_iterator = vertices; vertex_iterator != NULL; vertex_iterator = g_list_next(vertex_iterator)) {
|
||||||
|
|
||||||
|
if (conv_func != NULL)
|
||||||
|
conv_func(vertex_iterator->data, &pt);
|
||||||
|
else
|
||||||
|
(void)vector_2d_copy(&pt, (struct vector_2d *)vertex_iterator->data);
|
||||||
|
|
||||||
|
/* These are approximations.
|
||||||
|
* Used as long as miter point calculation is not fully implemented
|
||||||
|
*/
|
||||||
|
box->vectors.lower_left.x = MIN(box->vectors.lower_left.x, pt.x - thickness/2);
|
||||||
|
box->vectors.lower_left.y = MIN(box->vectors.lower_left.y, pt.y - thickness/2);
|
||||||
|
box->vectors.upper_right.x = MAX(box->vectors.upper_right.x, pt.x + thickness/2);
|
||||||
|
box->vectors.upper_right.y = MAX(box->vectors.upper_right.y, pt.y + thickness/2);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void bounding_box_update_point(union bounding_box *destination, conv_generic_to_vector_2d_t conv_func, void *pt)
|
void bounding_box_update_point(union bounding_box *destination, conv_generic_to_vector_2d_t conv_func, void *pt)
|
||||||
{
|
{
|
||||||
|
struct vector_2d point;
|
||||||
|
|
||||||
|
if (!destination || !pt)
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (conv_func)
|
||||||
|
conv_func(pt, &point);
|
||||||
|
else
|
||||||
|
(void)vector_2d_copy(&point, (struct vector_2d *)pt);
|
||||||
|
|
||||||
|
destination->vectors.lower_left.x = MIN(destination->vectors.lower_left.x, point.x);
|
||||||
|
destination->vectors.lower_left.y = MIN(destination->vectors.lower_left.y, point.y);
|
||||||
|
destination->vectors.upper_right.x = MAX(destination->vectors.upper_right.x, point.x);
|
||||||
|
destination->vectors.upper_right.y = MAX(destination->vectors.upper_right.y, point.y);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Apply transformations onto bounding box.
|
||||||
|
* @param scale Scaling factor
|
||||||
|
* @param rotation_deg Roation of bounding box around the origin in degrees (counterclockwise)
|
||||||
|
* @param flip_at_x Flip the boundig box on the x axis before rotating.
|
||||||
|
* @param box Bounding box the operations should be applied to.
|
||||||
|
*/
|
||||||
|
void bounding_box_apply_transform(double scale, double rotation_deg, bool flip_at_x, union bounding_box *box)
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
|
||||||
|
/* Due to linearity, the order of the operations does not matter.
|
||||||
|
* flip must be applied before rotation as defined by the GDS format
|
||||||
|
*/
|
||||||
|
for (i = 0; i < 2; i++) {
|
||||||
|
box->vector_array[i].y *= (flip_at_x ? -1 : 1);
|
||||||
|
vector_2d_rotate(&box->vector_array[i], rotation_deg * M_PI / 180);
|
||||||
|
vector_2d_scale(&box->vector_array[i], scale);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/** @} */
|
/** @} */
|
120
geometric/cell-geometrics.c
Normal file
120
geometric/cell-geometrics.c
Normal file
@@ -0,0 +1,120 @@
|
|||||||
|
/*
|
||||||
|
* 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/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @file cell-geometrics.c
|
||||||
|
* @brief Calculation of gds_cell trigonometrics
|
||||||
|
* @author Mario Hüttel <mario.huettel@gmx.net>
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <math.h>
|
||||||
|
|
||||||
|
#include <gds-render/geometric/cell-geometrics.h>
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @addtogroup geometric
|
||||||
|
* @{
|
||||||
|
*/
|
||||||
|
|
||||||
|
static void convert_gds_point_to_2d_vector(struct gds_point *pt, struct vector_2d *vector)
|
||||||
|
{
|
||||||
|
vector->x = pt->x;
|
||||||
|
vector->y = pt->y;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Update the given bounding box with the bounding box of a graphics element.
|
||||||
|
* @param box box to update
|
||||||
|
* @param gfx Graphics element
|
||||||
|
*/
|
||||||
|
static void update_box_with_gfx(union bounding_box *box, struct gds_graphics *gfx)
|
||||||
|
{
|
||||||
|
union bounding_box current_box;
|
||||||
|
|
||||||
|
bounding_box_prepare_empty(¤t_box);
|
||||||
|
|
||||||
|
switch (gfx->gfx_type) {
|
||||||
|
case GRAPHIC_BOX:
|
||||||
|
/* Expected fallthrough */
|
||||||
|
case GRAPHIC_POLYGON:
|
||||||
|
bounding_box_calculate_polygon(gfx->vertices,
|
||||||
|
(conv_generic_to_vector_2d_t)&convert_gds_point_to_2d_vector,
|
||||||
|
¤t_box);
|
||||||
|
break;
|
||||||
|
case GRAPHIC_PATH:
|
||||||
|
/*
|
||||||
|
* This is not implemented correctly.
|
||||||
|
* Please be aware if paths are the outmost elements of your cell.
|
||||||
|
* You might end up with a completely wrong calculated cell size.
|
||||||
|
*/
|
||||||
|
bounding_box_calculate_path_box(gfx->vertices, gfx->width_absolute,
|
||||||
|
(conv_generic_to_vector_2d_t)&convert_gds_point_to_2d_vector,
|
||||||
|
¤t_box);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
/* Unknown graphics object. */
|
||||||
|
/* Print error? Nah.. */
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Update box with results */
|
||||||
|
bounding_box_update_box(box, ¤t_box);
|
||||||
|
}
|
||||||
|
|
||||||
|
void calculate_cell_bounding_box(union bounding_box *box, struct gds_cell *cell)
|
||||||
|
{
|
||||||
|
GList *gfx_list;
|
||||||
|
struct gds_graphics *gfx;
|
||||||
|
GList *sub_cell_list;
|
||||||
|
struct gds_cell_instance *sub_cell;
|
||||||
|
union bounding_box temp_box;
|
||||||
|
|
||||||
|
if (!box || !cell)
|
||||||
|
return;
|
||||||
|
|
||||||
|
/* Update box with graphic elements */
|
||||||
|
for (gfx_list = cell->graphic_objs; gfx_list != NULL; gfx_list = gfx_list->next) {
|
||||||
|
gfx = (struct gds_graphics *)gfx_list->data;
|
||||||
|
update_box_with_gfx(box, gfx);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Update bounding box with boxes of subcells */
|
||||||
|
for (sub_cell_list = cell->child_cells; sub_cell_list != NULL;
|
||||||
|
sub_cell_list = sub_cell_list->next) {
|
||||||
|
sub_cell = (struct gds_cell_instance *)sub_cell_list->data;
|
||||||
|
bounding_box_prepare_empty(&temp_box);
|
||||||
|
/* Recursion Woohoo!! This dies if your GDS is faulty and contains a reference loop */
|
||||||
|
calculate_cell_bounding_box(&temp_box, sub_cell->cell_ref);
|
||||||
|
|
||||||
|
/* Apply transformations */
|
||||||
|
bounding_box_apply_transform(ABS(sub_cell->magnification), sub_cell->angle,
|
||||||
|
sub_cell->flipped, &temp_box);
|
||||||
|
|
||||||
|
/* Move bounding box to origin */
|
||||||
|
temp_box.vectors.lower_left.x += sub_cell->origin.x;
|
||||||
|
temp_box.vectors.upper_right.x += sub_cell->origin.x;
|
||||||
|
temp_box.vectors.lower_left.y += sub_cell->origin.y;
|
||||||
|
temp_box.vectors.upper_right.y += sub_cell->origin.y;
|
||||||
|
|
||||||
|
/* update the parent's box */
|
||||||
|
bounding_box_update_box(box, &temp_box);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/** @} */
|
@@ -24,14 +24,15 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @addtogroup trigonometric
|
* @addtogroup geometric
|
||||||
* @{
|
* @{
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include "vector-operations.h"
|
|
||||||
#include <math.h>
|
#include <math.h>
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
|
|
||||||
|
#include <gds-render/geometric/vector-operations.h>
|
||||||
|
|
||||||
#define ABS_DBL(a) ((a) < 0 ? -(a) : (a))
|
#define ABS_DBL(a) ((a) < 0 ? -(a) : (a))
|
||||||
|
|
||||||
double vector_2d_scalar_multipy(struct vector_2d *a, struct vector_2d *b)
|
double vector_2d_scalar_multipy(struct vector_2d *a, struct vector_2d *b)
|
||||||
@@ -76,18 +77,17 @@ struct vector_2d *vector_2d_copy(struct vector_2d *opt_res, struct vector_2d *ve
|
|||||||
|
|
||||||
if (!vec)
|
if (!vec)
|
||||||
return NULL;
|
return NULL;
|
||||||
if (opt_res) {
|
|
||||||
opt_res->x = vec->x;
|
if (opt_res)
|
||||||
opt_res->y = vec->y;
|
res = opt_res;
|
||||||
return opt_res;
|
else
|
||||||
} else {
|
|
||||||
res = vector_2d_alloc();
|
res = vector_2d_alloc();
|
||||||
|
|
||||||
if (res) {
|
if (res) {
|
||||||
res->x = vec->x;
|
res->x = vec->x;
|
||||||
res->y = vec->y;
|
res->y = vec->y;
|
||||||
}
|
}
|
||||||
return res;
|
return res;
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
struct vector_2d *vector_2d_alloc(void)
|
struct vector_2d *vector_2d_alloc(void)
|
164
glade/main.glade
164
glade/main.glade
@@ -1,164 +0,0 @@
|
|||||||
<?xml version="1.0" encoding="UTF-8"?>
|
|
||||||
<!-- Generated with glade 3.22.1 -->
|
|
||||||
<interface>
|
|
||||||
<requires lib="gtk+" version="3.20"/>
|
|
||||||
<object class="GtkWindow" id="main-window">
|
|
||||||
<property name="height_request">250</property>
|
|
||||||
<property name="can_focus">False</property>
|
|
||||||
<property name="icon_name">gds-render</property>
|
|
||||||
<child type="titlebar">
|
|
||||||
<object class="GtkHeaderBar">
|
|
||||||
<property name="name">header</property>
|
|
||||||
<property name="visible">True</property>
|
|
||||||
<property name="can_focus">False</property>
|
|
||||||
<property name="title" translatable="yes">GDS Renderer</property>
|
|
||||||
<property name="subtitle" translatable="yes">GDSII to PDF/TikZ Converter</property>
|
|
||||||
<property name="show_close_button">True</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>
|
|
||||||
</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>
|
|
||||||
<object class="GtkBox">
|
|
||||||
<property name="visible">True</property>
|
|
||||||
<property name="can_focus">False</property>
|
|
||||||
<child>
|
|
||||||
<object class="GtkBox">
|
|
||||||
<property name="visible">True</property>
|
|
||||||
<property name="can_focus">False</property>
|
|
||||||
<property name="orientation">vertical</property>
|
|
||||||
<child>
|
|
||||||
<object class="GtkSearchEntry" id="cell-search">
|
|
||||||
<property name="visible">True</property>
|
|
||||||
<property name="can_focus">True</property>
|
|
||||||
<property name="primary_icon_name">edit-find-symbolic</property>
|
|
||||||
<property name="primary_icon_activatable">False</property>
|
|
||||||
<property name="primary_icon_sensitive">False</property>
|
|
||||||
</object>
|
|
||||||
<packing>
|
|
||||||
<property name="expand">False</property>
|
|
||||||
<property name="fill">True</property>
|
|
||||||
<property name="position">0</property>
|
|
||||||
</packing>
|
|
||||||
</child>
|
|
||||||
<child>
|
|
||||||
<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="GtkTreeView" id="cell-tree">
|
|
||||||
<property name="visible">True</property>
|
|
||||||
<property name="can_focus">True</property>
|
|
||||||
<property name="headers_clickable">False</property>
|
|
||||||
<property name="enable_search">False</property>
|
|
||||||
<property name="enable_grid_lines">both</property>
|
|
||||||
<child internal-child="selection">
|
|
||||||
<object class="GtkTreeSelection"/>
|
|
||||||
</child>
|
|
||||||
</object>
|
|
||||||
</child>
|
|
||||||
</object>
|
|
||||||
<packing>
|
|
||||||
<property name="expand">True</property>
|
|
||||||
<property name="fill">True</property>
|
|
||||||
<property name="position">1</property>
|
|
||||||
</packing>
|
|
||||||
</child>
|
|
||||||
</object>
|
|
||||||
<packing>
|
|
||||||
<property name="expand">True</property>
|
|
||||||
<property name="fill">True</property>
|
|
||||||
<property name="position">0</property>
|
|
||||||
</packing>
|
|
||||||
</child>
|
|
||||||
<child>
|
|
||||||
<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">
|
|
||||||
<property name="visible">True</property>
|
|
||||||
<property name="can_focus">False</property>
|
|
||||||
<child>
|
|
||||||
<object class="GtkListBox" id="layer-list">
|
|
||||||
<property name="visible">True</property>
|
|
||||||
<property name="can_focus">False</property>
|
|
||||||
<property name="selection_mode">none</property>
|
|
||||||
</object>
|
|
||||||
</child>
|
|
||||||
</object>
|
|
||||||
</child>
|
|
||||||
</object>
|
|
||||||
<packing>
|
|
||||||
<property name="expand">True</property>
|
|
||||||
<property name="fill">True</property>
|
|
||||||
<property name="position">1</property>
|
|
||||||
</packing>
|
|
||||||
</child>
|
|
||||||
</object>
|
|
||||||
</child>
|
|
||||||
</object>
|
|
||||||
</interface>
|
|
@@ -1,11 +0,0 @@
|
|||||||
<?xml version="1.0" encoding="UTF-8"?>
|
|
||||||
<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>
|
|
||||||
|
|
||||||
|
|
@@ -17,6 +17,17 @@
|
|||||||
* along with GDSII-Converter. If not, see <http://www.gnu.org/licenses/>.
|
* along with GDSII-Converter. If not, see <http://www.gnu.org/licenses/>.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @file lib-cell-renderer.h
|
||||||
|
* @brief Header file for the LibCellRenderer GObject Class
|
||||||
|
* @author Mario Hüttel <mario.huettel@gmx.net>
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @addtogroup LibCellRenderer
|
||||||
|
* @{
|
||||||
|
*/
|
||||||
|
|
||||||
#ifndef __LIB_CELL_RENDERER_H__
|
#ifndef __LIB_CELL_RENDERER_H__
|
||||||
#define __LIB_CELL_RENDERER_H__
|
#define __LIB_CELL_RENDERER_H__
|
||||||
|
|
||||||
@@ -27,15 +38,33 @@ G_BEGIN_DECLS
|
|||||||
G_DECLARE_FINAL_TYPE(LibCellRenderer, lib_cell_renderer, LIB_CELL, RENDERER, GtkCellRendererText)
|
G_DECLARE_FINAL_TYPE(LibCellRenderer, lib_cell_renderer, LIB_CELL, RENDERER, GtkCellRendererText)
|
||||||
#define TYPE_LIB_CELL_RENDERER (lib_cell_renderer_get_type())
|
#define TYPE_LIB_CELL_RENDERER (lib_cell_renderer_get_type())
|
||||||
|
|
||||||
|
/** @{
|
||||||
|
* Error levels
|
||||||
|
*/
|
||||||
|
#define LIB_CELL_RENDERER_ERROR_WARN (1U<<0)
|
||||||
|
#define LIB_CELL_RENDERER_ERROR_ERR (1U<<1)
|
||||||
|
/** @} */
|
||||||
|
|
||||||
typedef struct _LibCellRenderer {
|
typedef struct _LibCellRenderer {
|
||||||
/* Inheritance */
|
/* Inheritance */
|
||||||
GtkCellRendererText super;
|
GtkCellRendererText super;
|
||||||
/* Custom Elements */
|
/* Custom Elements */
|
||||||
} LibCellRenderer;
|
} LibCellRenderer;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief lib_cell_renderer_get_type
|
||||||
|
* @return GObject Type
|
||||||
|
*/
|
||||||
GType lib_cell_renderer_get_type(void);
|
GType lib_cell_renderer_get_type(void);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Create a new renderer for renderering @ref gds_cell and @ref gds_library elements.
|
||||||
|
* @return New renderer object
|
||||||
|
*/
|
||||||
GtkCellRenderer *lib_cell_renderer_new(void);
|
GtkCellRenderer *lib_cell_renderer_new(void);
|
||||||
|
|
||||||
G_END_DECLS
|
G_END_DECLS
|
||||||
|
|
||||||
#endif /* __LIB_CELL_RENDERER_H__ */
|
#endif /* __LIB_CELL_RENDERER_H__ */
|
||||||
|
|
||||||
|
/** @} */
|
@@ -24,7 +24,7 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @addtogroup MainApplication
|
* @addtogroup GUI
|
||||||
* @{
|
* @{
|
||||||
*/
|
*/
|
||||||
|
|
||||||
@@ -37,10 +37,10 @@
|
|||||||
enum cell_store_columns {
|
enum cell_store_columns {
|
||||||
CELL_SEL_LIBRARY = 0,
|
CELL_SEL_LIBRARY = 0,
|
||||||
CELL_SEL_CELL,
|
CELL_SEL_CELL,
|
||||||
CELL_SEL_CELL_COLOR, /**< Cell column color */
|
CELL_SEL_CELL_ERROR_STATE, /**< Used for cell color and selectability */
|
||||||
CELL_SEL_MODDATE,
|
CELL_SEL_MODDATE,
|
||||||
CELL_SEL_ACCESSDATE,
|
CELL_SEL_ACCESSDATE,
|
||||||
CELL_SEL_COLUMN_COUNT /**< Not a column. Used to determine count of coumns **/
|
CELL_SEL_COLUMN_COUNT /**< @brief Not a column. Used to determine count of columns */
|
||||||
};
|
};
|
||||||
|
|
||||||
struct tree_stores {
|
struct tree_stores {
|
@@ -24,34 +24,37 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @addtogroup MainApplication
|
* @addtogroup cmdline
|
||||||
* @{
|
* @{
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#ifndef _COMMAND_LINE_H_
|
#ifndef _COMMAND_LINE_H_
|
||||||
#define _COMMAND_LINE_H_
|
#define _COMMAND_LINE_H_
|
||||||
|
|
||||||
#include <glib.h>
|
#include <glib.h>
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Convert GDS according to supplied parameters
|
* @brief Convert GDS according to command line parameters
|
||||||
* @param gds_name GDS File path
|
* @param gds_name Path to GDS File
|
||||||
* @param pdf_name Cairo-PDF path
|
* @param cell_name Cell name
|
||||||
* @param tex_name TeX/TikZ path
|
* @param renderers Renderer ids
|
||||||
* @param pdf Render Cairo
|
* @param output_file_names Output file names
|
||||||
* @param tex Render LaTeX
|
|
||||||
* @param layer_file Layer mapping file
|
* @param layer_file Layer mapping file
|
||||||
* @param cell_name Cell name to render
|
* @param so_path Shared object
|
||||||
* @param scale Scale image down by this value
|
* @param tex_standalone Standalone TeX
|
||||||
* @param pdf_layers TikZ creates OCG layers
|
* @param tec_layers TeX OCR layers
|
||||||
* @param pdf_standalone LaTeX document is standalone7
|
* @param scale Scale value
|
||||||
* @param svg Render to SVG file
|
* @return Error code, 0 if successful
|
||||||
* @param so_name Path to shared object of custom renderer
|
|
||||||
* @param so_out_file Output file path for custom renderer
|
|
||||||
* @param svg_name SVG file name
|
|
||||||
*/
|
*/
|
||||||
void command_line_convert_gds(char *gds_name, char *pdf_name, char *tex_name, gboolean pdf, gboolean tex,
|
int command_line_convert_gds(const char *gds_name,
|
||||||
char *layer_file, char *cell_name, double scale, gboolean pdf_layers,
|
const char *cell_name,
|
||||||
gboolean pdf_standalone, gboolean svg, char *svg_name, char *so_name, char *so_out_file);
|
char **renderers,
|
||||||
|
char **output_file_names,
|
||||||
|
const char *layer_file,
|
||||||
|
const char *so_path,
|
||||||
|
gboolean tex_standalone,
|
||||||
|
gboolean tex_layers,
|
||||||
|
double scale);
|
||||||
|
|
||||||
#endif /* _COMMAND_LINE_H_ */
|
#endif /* _COMMAND_LINE_H_ */
|
||||||
|
|
61
include/gds-render/gds-render-gui.h
Normal file
61
include/gds-render/gds-render-gui.h
Normal file
@@ -0,0 +1,61 @@
|
|||||||
|
/*
|
||||||
|
* 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/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @file gds-render-gui.h
|
||||||
|
* @brief Header for GdsRenderGui Object
|
||||||
|
* @author Mario Hüttel <mario.huettel@gmx.net>
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef _GDS_RENDER_GUI_
|
||||||
|
#define _GDS_RENDER_GUI_
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @addtogroup GUI
|
||||||
|
* @{
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <gtk/gtk.h>
|
||||||
|
|
||||||
|
G_BEGIN_DECLS
|
||||||
|
|
||||||
|
G_DECLARE_FINAL_TYPE(GdsRenderGui, gds_render_gui, RENDERER, GUI, GObject);
|
||||||
|
|
||||||
|
#define RENDERER_TYPE_GUI (gds_render_gui_get_type())
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Create new GdsRenderGui Object
|
||||||
|
* @return New object
|
||||||
|
*/
|
||||||
|
GdsRenderGui *gds_render_gui_new();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Get main window
|
||||||
|
*
|
||||||
|
* This function returns the main window of the GUI, which can later be displayed.
|
||||||
|
* All handling of hte GUI is taken care of inside the GdsRenderGui Object
|
||||||
|
* @return The generated main window
|
||||||
|
*/
|
||||||
|
GtkWindow *gds_render_gui_get_main_window(GdsRenderGui *gui);
|
||||||
|
|
||||||
|
G_END_DECLS
|
||||||
|
|
||||||
|
/** @} */
|
||||||
|
|
||||||
|
#endif /* _GDS_RENDER_GUI_ */
|
@@ -24,19 +24,34 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @addtogroup GDS-Parser
|
* @addtogroup GDS-Utilities
|
||||||
* @{
|
* @{
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#ifndef __GDSPARSE_H__
|
#ifndef _GDSPARSER_H_
|
||||||
#define __GDSPARSE_H__
|
#define _GDSPARSER_H_
|
||||||
|
|
||||||
#include <glib.h>
|
#include <glib.h>
|
||||||
#include "gds-types.h"
|
|
||||||
|
#include <gds-render/gds-utils/gds-types.h>
|
||||||
|
|
||||||
#define GDS_PRINT_DEBUG_INFOS (0) /**< @brief 1: Print infos, 0: Don't print */
|
#define GDS_PRINT_DEBUG_INFOS (0) /**< @brief 1: Print infos, 0: Don't print */
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Parse a GDS file
|
||||||
|
*
|
||||||
|
* This function parses a GDS File and creates a list of libraries,
|
||||||
|
* which then contain the different cells.
|
||||||
|
*
|
||||||
|
* The function appends The detected libraries to the \p library_array list.
|
||||||
|
* The library array may be empty, meaning *library_list may be NULL.
|
||||||
|
*
|
||||||
|
* @param[in] filename Path to the GDS file
|
||||||
|
* @param[in,out] library_array GList Pointer.
|
||||||
|
* @return 0 if successful
|
||||||
|
*/
|
||||||
int parse_gds_from_file(const char *filename, GList **library_array);
|
int parse_gds_from_file(const char *filename, GList **library_array);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Deletes all libraries including cells, references etc.
|
* @brief Deletes all libraries including cells, references etc.
|
||||||
* @param library_list Pointer to a list of #gds_library. Is set to NULL after completion.
|
* @param library_list Pointer to a list of #gds_library. Is set to NULL after completion.
|
||||||
@@ -46,4 +61,4 @@ int clear_lib_list(GList **library_list);
|
|||||||
|
|
||||||
/** @} */
|
/** @} */
|
||||||
|
|
||||||
#endif /* __GDSPARSE_H__ */
|
#endif /* _GDSPARSE_H_ */
|
61
include/gds-render/gds-utils/gds-tree-checker.h
Normal file
61
include/gds-render/gds-utils/gds-tree-checker.h
Normal file
@@ -0,0 +1,61 @@
|
|||||||
|
/*
|
||||||
|
* GDSII-Converter
|
||||||
|
* Copyright (C) 2019 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/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @file gds-tree-checker.h
|
||||||
|
* @brief Checking functions of a cell tree (Header)
|
||||||
|
* @author Mario Hüttel <mario.huettel@gmx.net>
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @addtogroup GDS-Utilities
|
||||||
|
* @{
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef _GDS_TREE_CHECKER_H_
|
||||||
|
#define _GDS_TREE_CHECKER_H_
|
||||||
|
|
||||||
|
#include <gds-render/gds-utils/gds-types.h>
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief gds_tree_check_cell_references checks if all child cell references can be resolved in the given library
|
||||||
|
*
|
||||||
|
* This function will only mark cells that
|
||||||
|
* directly contain unresolved references.
|
||||||
|
*
|
||||||
|
* If a cell contains a reference to a cell with unresolved references, it is not flagged.
|
||||||
|
*
|
||||||
|
* @param lib The GDS library to check
|
||||||
|
* @return less than 0 if an error occured during processing; 0 if all child cells could be resolved;
|
||||||
|
* greater than zero if the processing was successful but not all cell references could be resolved.
|
||||||
|
* In this case the number of unresolved references is returned
|
||||||
|
*/
|
||||||
|
int gds_tree_check_cell_references(struct gds_library *lib);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief gds_tree_check_reference_loops checks if the given library contains reference loops
|
||||||
|
* @param lib GDS library
|
||||||
|
* @return negative if an error occured, zero if there are no reference loops, else a positive number representing the number
|
||||||
|
* of affected cells
|
||||||
|
*/
|
||||||
|
int gds_tree_check_reference_loops(struct gds_library *lib);
|
||||||
|
|
||||||
|
#endif /* _GDS_TREE_CHECKER_H_ */
|
||||||
|
|
||||||
|
/** @} */
|
@@ -24,7 +24,7 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @addtogroup GDS-Parser
|
* @addtogroup GDS-Utilities
|
||||||
* @{
|
* @{
|
||||||
*/
|
*/
|
||||||
|
|
||||||
@@ -35,9 +35,15 @@
|
|||||||
#include <glib.h>
|
#include <glib.h>
|
||||||
|
|
||||||
#define CELL_NAME_MAX (100) /**< @brief Maximum length of a gds_cell::name or a gds_library::name */
|
#define CELL_NAME_MAX (100) /**< @brief Maximum length of a gds_cell::name or a gds_library::name */
|
||||||
|
|
||||||
|
/* Maybe use the macros that ship with the compiler? */
|
||||||
#define MIN(a,b) (((a) < (b)) ? (a) : (b)) /**< @brief Return smaller number */
|
#define MIN(a,b) (((a) < (b)) ? (a) : (b)) /**< @brief Return smaller number */
|
||||||
#define MAX(a,b) (((a) > (b)) ? (a) : (b)) /**< @brief Return bigger number */
|
#define MAX(a,b) (((a) > (b)) ? (a) : (b)) /**< @brief Return bigger number */
|
||||||
|
|
||||||
|
/** @brief Defintion of check counter default value
|
||||||
|
* that indicates that the corresponding check has not yet been executed */
|
||||||
|
enum {GDS_CELL_CHECK_NOT_RUN = -1};
|
||||||
|
|
||||||
/** @brief Types of graphic objects */
|
/** @brief Types of graphic objects */
|
||||||
enum graphics_type
|
enum graphics_type
|
||||||
{
|
{
|
||||||
@@ -59,6 +65,21 @@ struct gds_point {
|
|||||||
int y;
|
int y;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Stores the result of the cell checks.
|
||||||
|
*/
|
||||||
|
struct gds_cell_checks {
|
||||||
|
int unresolved_child_count; /**< @brief Number of unresolved cell instances inside this cell. Default: @ref GDS_CELL_CHECK_NOT_RUN */
|
||||||
|
int affected_by_reference_loop; /**< @brief 1 if the cell is affected by a reference loop and therefore not renderable. Default: @ref GDS_CELL_CHECK_NOT_RUN*/
|
||||||
|
/**
|
||||||
|
* @brief For the internal use of the checker.
|
||||||
|
* @warning Do not use this structure and its contents!
|
||||||
|
*/
|
||||||
|
struct _check_internals {
|
||||||
|
int marker;
|
||||||
|
} _internal;
|
||||||
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Date information for cells and libraries
|
* @brief Date information for cells and libraries
|
||||||
*/
|
*/
|
||||||
@@ -104,6 +125,8 @@ struct gds_cell {
|
|||||||
struct gds_time_field access_time;
|
struct gds_time_field access_time;
|
||||||
GList *child_cells; /**< @brief List of #gds_cell_instance elements */
|
GList *child_cells; /**< @brief List of #gds_cell_instance elements */
|
||||||
GList *graphic_objs; /**< @brief List of #gds_graphics */
|
GList *graphic_objs; /**< @brief List of #gds_graphics */
|
||||||
|
struct gds_library *parent_library; /**< @brief Pointer to parent library */
|
||||||
|
struct gds_cell_checks checks; /**< @brief Checking results */
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -113,7 +136,7 @@ struct gds_library {
|
|||||||
char name[CELL_NAME_MAX];
|
char name[CELL_NAME_MAX];
|
||||||
struct gds_time_field mod_time;
|
struct gds_time_field mod_time;
|
||||||
struct gds_time_field access_time;
|
struct gds_time_field access_time;
|
||||||
double unit_to_meters; /**< @warning not yet implemented */
|
double unit_in_meters; /**< Length of a database unit in meters */
|
||||||
GList *cells; /**< List of #gds_cell that contains all cells in this library*/
|
GList *cells; /**< List of #gds_cell that contains all cells in this library*/
|
||||||
GList *cell_names /**< List of strings that contains all cell names */;
|
GList *cell_names /**< List of strings that contains all cell names */;
|
||||||
};
|
};
|
@@ -24,14 +24,16 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @addtogroup trigonometric
|
* @addtogroup geometric
|
||||||
* @{
|
* @{
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#ifndef _BOUNDING_BOX_H_
|
#ifndef _BOUNDING_BOX_H_
|
||||||
#define _BOUNDING_BOX_H_
|
#define _BOUNDING_BOX_H_
|
||||||
|
|
||||||
#include <glib.h>
|
#include <glib.h>
|
||||||
#include "vector-operations.h"
|
#include <gds-render/geometric/vector-operations.h>
|
||||||
|
#include <stdbool.h>
|
||||||
|
|
||||||
union bounding_box {
|
union bounding_box {
|
||||||
/** Coordinate System is (y up | x right) */
|
/** Coordinate System is (y up | x right) */
|
||||||
@@ -48,6 +50,8 @@ void bounding_box_calculate_polygon(GList *vertices, conv_generic_to_vector_2d_t
|
|||||||
void bounding_box_update_box(union bounding_box *destination, union bounding_box *update);
|
void bounding_box_update_box(union bounding_box *destination, union bounding_box *update);
|
||||||
void bounding_box_prepare_empty(union bounding_box *box);
|
void bounding_box_prepare_empty(union bounding_box *box);
|
||||||
void bounding_box_update_point(union bounding_box *destination, conv_generic_to_vector_2d_t conv_func, void *pt);
|
void bounding_box_update_point(union bounding_box *destination, conv_generic_to_vector_2d_t conv_func, void *pt);
|
||||||
|
void bounding_box_apply_transform(double scale, double rotation_deg, bool flip_at_x, union bounding_box *box);
|
||||||
|
void bounding_box_calculate_path_box(GList *vertices, double thickness, conv_generic_to_vector_2d_t conv_func, union bounding_box *box);
|
||||||
|
|
||||||
#endif /* _BOUNDING_BOX_H_ */
|
#endif /* _BOUNDING_BOX_H_ */
|
||||||
|
|
47
include/gds-render/geometric/cell-geometrics.h
Normal file
47
include/gds-render/geometric/cell-geometrics.h
Normal file
@@ -0,0 +1,47 @@
|
|||||||
|
/*
|
||||||
|
* 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/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @file cell-geometrics.h
|
||||||
|
* @brief Calculation of gds_cell geometrics
|
||||||
|
* @author Mario Hüttel <mario.huettel@gmx.net>
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @addtogroup geometric
|
||||||
|
* @{
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef _CELL_GEOMETRICS_H_
|
||||||
|
#define _CELL_GEOMETRICS_H_
|
||||||
|
|
||||||
|
#include <gds-render/geometric/bounding-box.h>
|
||||||
|
#include <gds-render/gds-utils/gds-types.h>
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief calculate_cell_bounding_box Calculate bounding box of gds cell
|
||||||
|
* @param box Resulting boundig box. Will be uüdated and not overwritten
|
||||||
|
* @param cell Toplevel cell
|
||||||
|
* @warning Path handling not yet implemented correctly.
|
||||||
|
*/
|
||||||
|
void calculate_cell_bounding_box(union bounding_box *box, struct gds_cell *cell);
|
||||||
|
|
||||||
|
#endif /* _CELL_GEOMETRICS_H_ */
|
||||||
|
|
||||||
|
/** @} */
|
@@ -24,7 +24,7 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @addtogroup trigonometric
|
* @addtogroup geometric
|
||||||
* @{
|
* @{
|
||||||
*/
|
*/
|
||||||
|
|
70
include/gds-render/layer/color-palette.h
Normal file
70
include/gds-render/layer/color-palette.h
Normal file
@@ -0,0 +1,70 @@
|
|||||||
|
/*
|
||||||
|
* GDSII-Converter
|
||||||
|
* Copyright (C) 2019 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/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @file color-palette.h
|
||||||
|
* @brief Class representing a color palette
|
||||||
|
* @author Mario Hüttel <mario.huettel@gmx.net>
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef _COLOR_PALETTE_H_
|
||||||
|
#define _COLOR_PALETTE_H_
|
||||||
|
|
||||||
|
#include <glib.h>
|
||||||
|
#include <gtk/gtk.h>
|
||||||
|
|
||||||
|
G_BEGIN_DECLS
|
||||||
|
|
||||||
|
G_DECLARE_FINAL_TYPE(ColorPalette, color_palette, GDS_RENDER, COLOR_PALETTE, GObject);
|
||||||
|
|
||||||
|
#define TYPE_GDS_RENDER_COLOR_PALETTE (color_palette_get_type())
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Create a new object with from a resource containing the html hex color scheme
|
||||||
|
* @param resource_name Name of the resource
|
||||||
|
* @return New object
|
||||||
|
*/
|
||||||
|
ColorPalette *color_palette_new_from_resource(char *resource_name);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Get the n-th color in the palette identified by the index.
|
||||||
|
*
|
||||||
|
* This function fills the nth color into the supplied \p color.
|
||||||
|
* \p color is returned.
|
||||||
|
*
|
||||||
|
* If \p color is NULL, a new GdkRGBA is created and returned.
|
||||||
|
* This element must be freed afterwards.
|
||||||
|
*
|
||||||
|
* @param palette Color palette
|
||||||
|
* @param color GdkRGBA struct to fill data in. May be NULL.
|
||||||
|
* @param index Index of color. Starts at 0
|
||||||
|
* @return GdkRGBA color. If \p color is NULL, the returned color must be freed afterwards
|
||||||
|
*/
|
||||||
|
GdkRGBA *color_palette_get_color(ColorPalette *palette, GdkRGBA *color, unsigned int index);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Return amount of stored colors in \p palette
|
||||||
|
* @param palette Color palette
|
||||||
|
* @return Count of colors
|
||||||
|
*/
|
||||||
|
unsigned int color_palette_get_color_count(ColorPalette *palette);
|
||||||
|
|
||||||
|
G_END_DECLS
|
||||||
|
|
||||||
|
#endif /* _COLOR_PALETTE_H_ */
|
119
include/gds-render/layer/layer-info.h
Normal file
119
include/gds-render/layer/layer-info.h
Normal file
@@ -0,0 +1,119 @@
|
|||||||
|
/*
|
||||||
|
* GDSII-Converter
|
||||||
|
* Copyright (C) 2019 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/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @file layer-info.h
|
||||||
|
* @brief LayerSettings class heade file
|
||||||
|
* @author Mario Hüttel <mario.huettel@gmx.net>
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef _LAYER_INFO_H_
|
||||||
|
#define _LAYER_INFO_H_
|
||||||
|
|
||||||
|
#include <gtk/gtk.h>
|
||||||
|
|
||||||
|
G_BEGIN_DECLS
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Layer information.
|
||||||
|
*
|
||||||
|
* This structs contains information on how to render a layer
|
||||||
|
* @note You probably don't want to use this struct standalone but in combination
|
||||||
|
* with a LayerSettings object.
|
||||||
|
*/
|
||||||
|
struct layer_info
|
||||||
|
{
|
||||||
|
int layer; /**< @brief Layer number */
|
||||||
|
char *name; /**< @brief Layer name. */
|
||||||
|
int stacked_position; ///< @brief Position of layer in output @warning This parameter is not used by any renderer so far @note Lower is bottom, higher is top
|
||||||
|
GdkRGBA color; /**< @brief RGBA color used to render this layer */
|
||||||
|
int render; /**< @brief true: Render to output */
|
||||||
|
};
|
||||||
|
|
||||||
|
G_DECLARE_FINAL_TYPE(LayerSettings, layer_settings, GDS_RENDER, LAYER_SETTINGS, GObject)
|
||||||
|
|
||||||
|
#define GDS_RENDER_TYPE_LAYER_SETTINGS (layer_settings_get_type())
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Maximum length of a layer mapping CSV line
|
||||||
|
*/
|
||||||
|
#define CSV_LINE_MAX_LEN (1024)
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief New LayerSettings object
|
||||||
|
* @return New object
|
||||||
|
*/
|
||||||
|
LayerSettings *layer_settings_new();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief layer_settings_append_layer_info
|
||||||
|
* @param settings LayerSettings object.
|
||||||
|
* @param info Info to append
|
||||||
|
* @return Error code. 0 if successful
|
||||||
|
* @note \p info is copied internally. You can free this struct afterwards.
|
||||||
|
*/
|
||||||
|
int layer_settings_append_layer_info(LayerSettings *settings, struct layer_info *info);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Clear all layers in this settings object
|
||||||
|
* @param settings LayerSettings object
|
||||||
|
*/
|
||||||
|
void layer_settings_clear(LayerSettings *settings);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Remove a specific layer number from the layer settings.
|
||||||
|
* @param settings LayerSettings object
|
||||||
|
* @param layer Layer number
|
||||||
|
* @return Error code. 0 if successful
|
||||||
|
*/
|
||||||
|
int layer_settings_remove_layer(LayerSettings *settings, int layer);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Get a GList with layer_info structs
|
||||||
|
*
|
||||||
|
* This function returns a GList with all layer_info structs in rendering order
|
||||||
|
* (bottom to top) that shall be rendered.
|
||||||
|
*
|
||||||
|
* @param settings LayerSettings object
|
||||||
|
* @return GList with struct layer_info elements.
|
||||||
|
*/
|
||||||
|
GList *layer_settings_get_layer_info_list(LayerSettings *settings);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Write layer settings to a CSV file
|
||||||
|
* @param path
|
||||||
|
* @return 0 if successful
|
||||||
|
*/
|
||||||
|
int layer_settings_to_csv(LayerSettings *settings, const char *path);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Load new layer Settings from CSV
|
||||||
|
*
|
||||||
|
* This function loads the layer information from a CSV file.
|
||||||
|
* All data inside the \p settings is cleared beforehand.
|
||||||
|
*
|
||||||
|
* @param settings Settings to write to.
|
||||||
|
* @param path CSV file path
|
||||||
|
* @return 0 if successful
|
||||||
|
*/
|
||||||
|
int layer_settings_load_from_csv(LayerSettings *settings, const char *path);
|
||||||
|
|
||||||
|
G_END_DECLS
|
||||||
|
|
||||||
|
#endif // _LAYER_INFO_H_
|
106
include/gds-render/layer/layer-selector.h
Normal file
106
include/gds-render/layer/layer-selector.h
Normal file
@@ -0,0 +1,106 @@
|
|||||||
|
/*
|
||||||
|
* 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/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @file layer-selector.h
|
||||||
|
* @brief Implementation of the Layer selection list
|
||||||
|
* @author Mario Hüttel <mario.huettel@gmx.net>
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @addtogroup layer-selector
|
||||||
|
* @{
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef __LAYER_SELECTOR_H__
|
||||||
|
#define __LAYER_SELECTOR_H__
|
||||||
|
|
||||||
|
#include <gtk/gtk.h>
|
||||||
|
#include <glib.h>
|
||||||
|
#include <gds-render/layer/color-palette.h>
|
||||||
|
|
||||||
|
G_BEGIN_DECLS
|
||||||
|
|
||||||
|
G_DECLARE_FINAL_TYPE(LayerSelector, layer_selector, LAYER, SELECTOR, GObject);
|
||||||
|
|
||||||
|
#define TYPE_LAYER_SELECTOR (layer_selector_get_type())
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Defines how to sort the layer selector list box.
|
||||||
|
*/
|
||||||
|
enum layer_selector_sort_algo {LAYER_SELECTOR_SORT_DOWN = 0, LAYER_SELECTOR_SORT_UP};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief layer_selector_new
|
||||||
|
* @param list_box The associated list box, the content is displayed in
|
||||||
|
* @return Newly created layer selector
|
||||||
|
*/
|
||||||
|
LayerSelector *layer_selector_new(GtkListBox *list_box);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Generate layer widgets in in the LayerSelector instance
|
||||||
|
* @note This clears all previously inserted elements
|
||||||
|
* @param selector LayerSelector instance
|
||||||
|
* @param libs The libraries to add
|
||||||
|
*/
|
||||||
|
void layer_selector_generate_layer_widgets(LayerSelector *selector, GList *libs);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Supply button for loading the layer mapping
|
||||||
|
* @param selector LayerSelector instance
|
||||||
|
* @param button Load button. Will be referenced
|
||||||
|
* @param main_window Parent window for dialogs. Will be referenced
|
||||||
|
*/
|
||||||
|
void layer_selector_set_load_mapping_button(LayerSelector *selector, GtkWidget *button, GtkWindow *main_window);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Supply button for saving the layer mapping
|
||||||
|
* @param selector LayerSelector instance
|
||||||
|
* @param button Save button. Will be refeneced
|
||||||
|
* @param main_window Parent window for dialogs. Will be referenced
|
||||||
|
*/
|
||||||
|
void layer_selector_set_save_mapping_button(LayerSelector *selector, GtkWidget *button, GtkWindow *main_window);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Get a list of all layers that shall be exported when rendering the cells
|
||||||
|
* @param selector Layer selector instance
|
||||||
|
* @return List of layer_info structures containing the layer information
|
||||||
|
*/
|
||||||
|
GList *layer_selector_export_rendered_layer_info(LayerSelector *selector);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Force the layer selector list to be sorted according to \p sort_function
|
||||||
|
* @param selector LayerSelector instance
|
||||||
|
* @param sort_function The sorting method (up or down sorting)
|
||||||
|
*/
|
||||||
|
void layer_selector_force_sort(LayerSelector *selector, enum layer_selector_sort_algo sort_function);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Apply colors from palette to all layers. Aditionally set alpha
|
||||||
|
* @param layer_selector LayerSelector object
|
||||||
|
* @param palette Color palette to use
|
||||||
|
* @param global_alpha Additional alpha value that is applied to all layers
|
||||||
|
*/
|
||||||
|
void layer_selector_auto_color_layers(LayerSelector *layer_selector, ColorPalette *palette, double global_alpha);
|
||||||
|
|
||||||
|
G_END_DECLS
|
||||||
|
|
||||||
|
#endif /* __LAYER_SELECTOR_H__ */
|
||||||
|
|
||||||
|
/** @} */
|
@@ -27,24 +27,14 @@
|
|||||||
#define __MAPPING_PARSER_H__
|
#define __MAPPING_PARSER_H__
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @addtogroup MainApplication
|
* @addtogroup Mapping-Parser
|
||||||
* @{
|
* @{
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include <gtk/gtk.h>
|
#include <glib.h>
|
||||||
|
|
||||||
/**
|
#include <gds-render/widgets/layer-element.h>
|
||||||
* @brief Layer information.
|
#include <gds-render/layer/layer-info.h>
|
||||||
*
|
|
||||||
* This structs contains information on how to render a layer
|
|
||||||
*/
|
|
||||||
struct layer_info
|
|
||||||
{
|
|
||||||
int layer; /**< @brief Layer number */
|
|
||||||
char *name; /**< @brief Layer name */
|
|
||||||
int stacked_position; ///< @brief Position of layer in output @warning This parameter is not used by any renderer so far @note Lower is bottom, higher is top
|
|
||||||
GdkRGBA color; /**< @brief RGBA color used to render this layer */
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Load a line from \p stream and parse try to parse it as layer information
|
* @brief Load a line from \p stream and parse try to parse it as layer information
|
||||||
@@ -55,7 +45,15 @@ struct layer_info
|
|||||||
* @param color RGBA color.
|
* @param color RGBA color.
|
||||||
* @return 1 if malformatted line, 0 if parsing was successful and parameters are valid, -1 if file end
|
* @return 1 if malformatted line, 0 if parsing was successful and parameters are valid, -1 if file end
|
||||||
*/
|
*/
|
||||||
int load_csv_line(GDataInputStream *stream, gboolean *export, char **name, int *layer, GdkRGBA *color);
|
int mapping_parser_load_line(GDataInputStream *stream, gboolean *export, char **name, int *layer, GdkRGBA *color);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Create Line for LayerMapping file with supplied information
|
||||||
|
* @param layer_element information
|
||||||
|
* @param line_buffer buffer to write to
|
||||||
|
* @param max_len Maximum length that cna be used in \p line_buffer
|
||||||
|
*/
|
||||||
|
void mapping_parser_gen_csv_line(LayerElement *layer_element, char *line_buffer, size_t max_len);
|
||||||
|
|
||||||
/** @} */
|
/** @} */
|
||||||
|
|
@@ -21,28 +21,41 @@
|
|||||||
* @brief Header File for Cairo output renderer
|
* @brief Header File for Cairo output renderer
|
||||||
* @author Mario Hüttel <mario.huettel@gmx.net>
|
* @author Mario Hüttel <mario.huettel@gmx.net>
|
||||||
*/
|
*/
|
||||||
#ifndef __CAIRO_OUTPUT_H__
|
#ifndef _CAIRO_OUTPUT_H_
|
||||||
#define __CAIRO_OUTPUT_H__
|
#define _CAIRO_OUTPUT_H_
|
||||||
|
|
||||||
#include "../layer-selector.h"
|
#include <gds-render/gds-utils/gds-types.h>
|
||||||
#include "../gds-parser/gds-types.h"
|
#include <gds-render/layer/layer-info.h>
|
||||||
|
#include <gds-render/output-renderers/gds-output-renderer.h>
|
||||||
|
#include <glib-object.h>
|
||||||
|
|
||||||
/** @addtogroup Cairo-Renderer
|
G_BEGIN_DECLS
|
||||||
|
|
||||||
|
/** @addtogroup CairoRenderer
|
||||||
* @{
|
* @{
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
G_DECLARE_FINAL_TYPE(CairoRenderer, cairo_renderer, GDS_RENDER, CAIRO_RENDERER, GdsOutputRenderer)
|
||||||
|
|
||||||
|
#define GDS_RENDER_TYPE_CAIRO_RENDERER (cairo_renderer_get_type())
|
||||||
|
|
||||||
#define MAX_LAYERS (300) /**< \brief Maximum layer count the output renderer can process. Typically GDS only specifies up to 255 layers.*/
|
#define MAX_LAYERS (300) /**< \brief Maximum layer count the output renderer can process. Typically GDS only specifies up to 255 layers.*/
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Render \p cell to a PDF file specified by \p pdf_file
|
* @brief Create new CairoRenderer for SVG output
|
||||||
* @param cell Toplevel cell to @ref Cairo-Renderer
|
* @return New object
|
||||||
* @param layer_infos List of layer information. Specifies color and layer stacking
|
|
||||||
* @param pdf_file PDF output file. Set to NULL if no PDF file has to be generated
|
|
||||||
* @param svg_file SVG output file. Set to NULL if no SVG file has to be generated
|
|
||||||
* @param scale Scale the output image down by \p scale
|
|
||||||
*/
|
*/
|
||||||
void cairo_render_cell_to_vector_file(struct gds_cell *cell, GList *layer_infos, char *pdf_file, char *svg_file, double scale);
|
CairoRenderer *cairo_renderer_new_svg();
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Create new CairoRenderer for PDF output
|
||||||
|
* @return New object
|
||||||
|
*/
|
||||||
|
CairoRenderer *cairo_renderer_new_pdf();
|
||||||
|
|
||||||
/** @} */
|
/** @} */
|
||||||
|
|
||||||
#endif /* __CAIRO_OUTPUT_H__ */
|
G_END_DECLS
|
||||||
|
|
||||||
|
#endif /* _CAIRO_OUTPUT_H_ */
|
@@ -24,34 +24,46 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @addtogroup MainApplication
|
* @addtogroup ExternalRenderer
|
||||||
* @{
|
* @{
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#ifndef _EXTERNAL_RENDERER_H_
|
#ifndef _EXTERNAL_RENDERER_H_
|
||||||
#define _EXTERNAL_RENDERER_H_
|
#define _EXTERNAL_RENDERER_H_
|
||||||
|
|
||||||
#include "gds-parser/gds-types.h"
|
#include <gds-render/output-renderers/gds-output-renderer.h>
|
||||||
#include <glib.h>
|
#include <gds-render/gds-utils/gds-types.h>
|
||||||
|
|
||||||
|
G_BEGIN_DECLS
|
||||||
|
|
||||||
|
#define GDS_RENDER_TYPE_EXTERNAL_RENDERER (external_renderer_get_type())
|
||||||
|
|
||||||
|
G_DECLARE_FINAL_TYPE(ExternalRenderer, external_renderer, GDS_RENDER, EXTERNAL_RENDERER, GdsOutputRenderer)
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief function name expected to be found in external library.
|
* @brief function name expected to be found in external library.
|
||||||
* @detail The function has to be defined as follows:
|
*
|
||||||
|
* The function has to be defined as follows:
|
||||||
* @code
|
* @code
|
||||||
* int function_name(gds_cell *toplevel, GList *layer_info_list, char *output_file_name)
|
* int EXTERNAL_LIBRARY_FUNCTION(struct gds_cell *toplevel, GList *layer_info_list, const char *output_file_name, double scale)
|
||||||
* @endcode
|
* @endcode
|
||||||
*/
|
*/
|
||||||
#define EXTERNAL_LIBRARY_FUNCTION "render_cell_to_file"
|
#define EXTERNAL_LIBRARY_FUNCTION "render_cell_to_file"
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief external_renderer_render_cell
|
* @brief Create new ExternalRenderer object
|
||||||
* @param toplevel_cell The toplevel cell to render
|
* @return New object
|
||||||
* @param layer_info_list The layer information. Contains #layer_info elements
|
|
||||||
* @param output_file Output file
|
|
||||||
* @param so_path Path to the shared object file containing #EXTERNAL_LIBRARY_FUNCTION
|
|
||||||
* @return 0 on success
|
|
||||||
*/
|
*/
|
||||||
int external_renderer_render_cell(struct gds_cell *toplevel_cell, GList *layer_info_list, char *output_file, char *so_path);
|
ExternalRenderer *external_renderer_new();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Create new ExternalRenderer object with specified shared object path
|
||||||
|
* @param so_path Path to shared object, the rendering function is searched in
|
||||||
|
* @return New object.
|
||||||
|
*/
|
||||||
|
ExternalRenderer *external_renderer_new_with_so(const char *so_path);
|
||||||
|
|
||||||
|
G_END_DECLS
|
||||||
|
|
||||||
#endif /* _EXTERNAL_RENDERER_H_ */
|
#endif /* _EXTERNAL_RENDERER_H_ */
|
||||||
|
|
151
include/gds-render/output-renderers/gds-output-renderer.h
Normal file
151
include/gds-render/output-renderers/gds-output-renderer.h
Normal file
@@ -0,0 +1,151 @@
|
|||||||
|
/*
|
||||||
|
* 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/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @file gds-output-renderer.h
|
||||||
|
* @brief Header for output renderer base class
|
||||||
|
* @author Mario Hüttel <mario.huettel@gmx.net>
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @addtogroup GdsOutputRenderer
|
||||||
|
* @{
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef _GDS_OUTPUT_RENDERER_H_
|
||||||
|
#define _GDS_OUTPUT_RENDERER_H_
|
||||||
|
|
||||||
|
#include <gds-render/gds-utils/gds-types.h>
|
||||||
|
#include <glib-object.h>
|
||||||
|
#include <glib.h>
|
||||||
|
#include <gds-render/layer/layer-info.h>
|
||||||
|
|
||||||
|
G_BEGIN_DECLS
|
||||||
|
|
||||||
|
#define GDS_RENDER_TYPE_OUTPUT_RENDERER (gds_output_renderer_get_type())
|
||||||
|
|
||||||
|
G_DECLARE_DERIVABLE_TYPE(GdsOutputRenderer, gds_output_renderer, GDS_RENDER, OUTPUT_RENDERER, GObject);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Base output renderer class structure.
|
||||||
|
* @note This structure is only used for internal inheritance of GObjects. Do not use in code outside of these classes.
|
||||||
|
*/
|
||||||
|
struct _GdsOutputRendererClass {
|
||||||
|
GObjectClass parent_class;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Virtual render output function. Overwritten by final class implementation
|
||||||
|
*/
|
||||||
|
int (*render_output)(GdsOutputRenderer *renderer,
|
||||||
|
struct gds_cell *cell,
|
||||||
|
double scale);
|
||||||
|
gpointer padding[4];
|
||||||
|
};
|
||||||
|
|
||||||
|
enum {
|
||||||
|
GDS_OUTPUT_RENDERER_GEN_ERR = -100, /**< @brief Error set by the _GdsOutputRendererClass::render_output virtual function, if renderer is invalid. */
|
||||||
|
GDS_OUTPUT_RENDERER_PARAM_ERR = -200 /**< @brief Error set by the _GdsOutputRendererClass::render_output virtual function, if parameters are faulty. */
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Create a new GdsOutputRenderer GObject.
|
||||||
|
* @return New object
|
||||||
|
*/
|
||||||
|
GdsOutputRenderer *gds_output_renderer_new();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Create a new GdsOutputRenderer GObject with its properties
|
||||||
|
* @param output_file Output file of the renderer
|
||||||
|
* @param layer_settings Layer settings object
|
||||||
|
* @return New object
|
||||||
|
*/
|
||||||
|
GdsOutputRenderer *gds_output_renderer_new_with_props(const char *output_file, LayerSettings *layer_settings);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief gds_output_renderer_render_output
|
||||||
|
* @param renderer Renderer object
|
||||||
|
* @param cell Cell to render
|
||||||
|
* @param scale scale value. The output is scaled *down* by this value
|
||||||
|
* @return 0 if successful
|
||||||
|
*/
|
||||||
|
int gds_output_renderer_render_output(GdsOutputRenderer *renderer,
|
||||||
|
struct gds_cell *cell,
|
||||||
|
double scale);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Convenience function for setting the "output-file" property
|
||||||
|
* @param renderer Renderer object
|
||||||
|
* @param file_name Output file path
|
||||||
|
*/
|
||||||
|
void gds_output_renderer_set_output_file(GdsOutputRenderer *renderer, const gchar *file_name);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Convenience function for getting the "output-file" property
|
||||||
|
* @param renderer
|
||||||
|
* @return Output file path. This must not be freed
|
||||||
|
*/
|
||||||
|
const char *gds_output_renderer_get_output_file(GdsOutputRenderer *renderer);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Get layer settings
|
||||||
|
*
|
||||||
|
* This is a convenience function for getting the
|
||||||
|
* "layer-settings" property. This also references it.
|
||||||
|
* This is to prevent race conditions with another thread that might
|
||||||
|
* alter the layer settings before they are read out.
|
||||||
|
*
|
||||||
|
* @param renderer Renderer
|
||||||
|
* @return Layer settings object
|
||||||
|
*/
|
||||||
|
LayerSettings *gds_output_renderer_get_and_ref_layer_settings(GdsOutputRenderer *renderer);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Set layer settings
|
||||||
|
*
|
||||||
|
* This is a convenience function for setting the
|
||||||
|
* "layer-settings" property.
|
||||||
|
*
|
||||||
|
* If another Layer settings has previously been supplied,
|
||||||
|
* it is unref'd.
|
||||||
|
*
|
||||||
|
* @param renderer Renderer
|
||||||
|
* @param settings LayerSettings object
|
||||||
|
*/
|
||||||
|
void gds_output_renderer_set_layer_settings(GdsOutputRenderer *renderer, LayerSettings *settings);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Render output asynchronously
|
||||||
|
*
|
||||||
|
* This function will render in a separate thread.
|
||||||
|
* To wait for the completion of the rendering process.
|
||||||
|
*
|
||||||
|
* @note A second async thread cannot be spawned.
|
||||||
|
*
|
||||||
|
* @param renderer Output renderer
|
||||||
|
* @param cell Cell to render
|
||||||
|
* @param scale Scale
|
||||||
|
* @return 0 if successful. In case no thread can be spawned < 0
|
||||||
|
*/
|
||||||
|
int gds_output_renderer_render_output_async(GdsOutputRenderer *renderer, struct gds_cell *cell, double scale);
|
||||||
|
|
||||||
|
G_END_DECLS
|
||||||
|
|
||||||
|
#endif /* _GDS_OUTPUT_RENDERER_H_ */
|
||||||
|
|
||||||
|
/** @} */
|
74
include/gds-render/output-renderers/latex-renderer.h
Normal file
74
include/gds-render/output-renderers/latex-renderer.h
Normal file
@@ -0,0 +1,74 @@
|
|||||||
|
/*
|
||||||
|
* 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/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @file latex-output.h
|
||||||
|
* @brief LaTeX output renderer
|
||||||
|
* @author Mario Hüttel <mario.huettel@gmx.net>
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @addtogroup LaTeX-Renderer
|
||||||
|
* @{
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef _LATEX_OUTPUT_H_
|
||||||
|
#define _LATEX_OUTPUT_H_
|
||||||
|
|
||||||
|
#include <gds-render/output-renderers/gds-output-renderer.h>
|
||||||
|
#include <gds-render/gds-utils/gds-types.h>
|
||||||
|
|
||||||
|
G_BEGIN_DECLS
|
||||||
|
|
||||||
|
G_DECLARE_FINAL_TYPE(LatexRenderer, latex_renderer, GDS_RENDER, LATEX_RENDERER, GdsOutputRenderer)
|
||||||
|
|
||||||
|
#define GDS_RENDER_TYPE_LATEX_RENDERER (latex_renderer_get_type())
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Buffer for LaTeX Code line in KiB
|
||||||
|
*/
|
||||||
|
#define LATEX_LINE_BUFFER_KB (10)
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Create new LatexRenderer object
|
||||||
|
* @return New object
|
||||||
|
*/
|
||||||
|
LatexRenderer *latex_renderer_new();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Create new LatexRenderer object
|
||||||
|
*
|
||||||
|
* This function sets the 'pdf-layers' and 'standalone'
|
||||||
|
* properties for the newly created object.
|
||||||
|
*
|
||||||
|
* They can later be changes by modifying the properties again.
|
||||||
|
* On top of that, The options can be changed in the resulting
|
||||||
|
* LaTeX output file if needed.
|
||||||
|
*
|
||||||
|
* @param pdf_layers If PDF OCR layers should be enabled
|
||||||
|
* @param standalone If output TeX file should be standalone compilable
|
||||||
|
* @return New object
|
||||||
|
*/
|
||||||
|
LatexRenderer *latex_renderer_new_with_options(gboolean pdf_layers, gboolean standalone);
|
||||||
|
|
||||||
|
G_END_DECLS
|
||||||
|
|
||||||
|
#endif /* _LATEX_OUTPUT_H_ */
|
||||||
|
|
||||||
|
/** @} */
|
@@ -18,29 +18,11 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @file main-window.h
|
* @addtogroup version
|
||||||
* @brief Header for main-window
|
|
||||||
* @author Mario Hüttel <mario.huettel@gmx.net>
|
|
||||||
*/
|
|
||||||
|
|
||||||
#ifndef _MAIN_WINDOW_H_
|
|
||||||
#define _MAIN_WINDOW_H_
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @addtogroup MainApplication
|
|
||||||
* @{
|
* @{
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include <gtk/gtk.h>
|
/** @brief This string holds the @ref git-version-num of the app */
|
||||||
|
extern const char *_app_version_string;
|
||||||
/**
|
|
||||||
* @brief Create main window
|
|
||||||
*
|
|
||||||
* This function creates the main window and sets the necessary callback routines.
|
|
||||||
* @return
|
|
||||||
*/
|
|
||||||
GtkWindow *create_main_window();
|
|
||||||
|
|
||||||
/** @} */
|
/** @} */
|
||||||
|
|
||||||
#endif /* _MAIN_WINDOW_H_ */
|
|
60
include/gds-render/widgets/activity-bar.h
Normal file
60
include/gds-render/widgets/activity-bar.h
Normal file
@@ -0,0 +1,60 @@
|
|||||||
|
/*
|
||||||
|
* GDSII-Converter
|
||||||
|
* Copyright (C) 2019 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/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @file activity-bar.h
|
||||||
|
* @brief Header file for activity bar widget
|
||||||
|
* @author Mario Hüttel <mario.huettel@gmx.net>
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @addtogroup ActivityBar
|
||||||
|
* @ingroup Widgets
|
||||||
|
* @{
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef __LAYER_ELEMENT_H__
|
||||||
|
#define __LAYER_ELEMENT_H__
|
||||||
|
|
||||||
|
#include <gtk/gtk.h>
|
||||||
|
|
||||||
|
G_BEGIN_DECLS
|
||||||
|
|
||||||
|
/* Creates Class structure etc */
|
||||||
|
G_DECLARE_FINAL_TYPE(ActivityBar, activity_bar, ACTIVITY, BAR, GtkBox)
|
||||||
|
|
||||||
|
#define TYPE_ACTIVITY_BAR (activity_bar_get_type())
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Create new Object ActivityBar
|
||||||
|
* @return New object. In case of error: NULL.
|
||||||
|
*/
|
||||||
|
ActivityBar *activity_bar_new();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Deletes all applied tasks and sets bar to "Ready".
|
||||||
|
* @param[in] bar AcitivityBar object.
|
||||||
|
*/
|
||||||
|
void activity_bar_set_ready(ActivityBar *bar);
|
||||||
|
|
||||||
|
G_END_DECLS
|
||||||
|
|
||||||
|
#endif /* __LAYER_ELEMENT_H__ */
|
||||||
|
|
||||||
|
/** @} */
|
@@ -24,7 +24,8 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @addtogroup Widgets
|
* @addtogroup RendererSettingsDialog
|
||||||
|
* @ingroup Widgets
|
||||||
* @{
|
* @{
|
||||||
*/
|
*/
|
||||||
|
|
||||||
@@ -75,6 +76,27 @@ void renderer_settings_dialog_set_settings(RendererSettingsDialog *dialog, struc
|
|||||||
*/
|
*/
|
||||||
void renderer_settings_dialog_get_settings(RendererSettingsDialog *dialog, struct render_settings *settings);
|
void renderer_settings_dialog_get_settings(RendererSettingsDialog *dialog, struct render_settings *settings);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief renderer_settings_dialog_set_cell_width Set width for rendered cell
|
||||||
|
* @param dialog
|
||||||
|
* @param width Width in database units
|
||||||
|
*/
|
||||||
|
void renderer_settings_dialog_set_cell_width(RendererSettingsDialog *dialog, unsigned int width);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief renderer_settings_dialog_set_cell_height Set height for rendered cell
|
||||||
|
* @param dialog
|
||||||
|
* @param height Height in database units
|
||||||
|
*/
|
||||||
|
void renderer_settings_dialog_set_cell_height(RendererSettingsDialog *dialog, unsigned int height);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief renderer_settings_dialog_set_database_unit_scale Set database scale
|
||||||
|
* @param dialog dialog element
|
||||||
|
* @param unit_in_meters Database unit in meters
|
||||||
|
*/
|
||||||
|
void renderer_settings_dialog_set_database_unit_scale(RendererSettingsDialog *dialog, double unit_in_meters);
|
||||||
|
|
||||||
#endif /* __CONV_SETTINGS_DIALOG_H__ */
|
#endif /* __CONV_SETTINGS_DIALOG_H__ */
|
||||||
|
|
||||||
/** @} */
|
/** @} */
|
@@ -19,12 +19,13 @@
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* @file layer-element.h
|
* @file layer-element.h
|
||||||
* @brief Omplementation of the layer element used for configuring layer colors etc.
|
* @brief Implementation of the layer element used for configuring layer colors etc.
|
||||||
* @author Mario Hüttel <mario.huettel@gmx.net>
|
* @author Mario Hüttel <mario.huettel@gmx.net>
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @addtogroup Widgets
|
* @addtogroup LayerElement
|
||||||
|
* @ingroup Widgets
|
||||||
* @{
|
* @{
|
||||||
*/
|
*/
|
||||||
|
|
||||||
@@ -56,6 +57,22 @@ struct _LayerElement {
|
|||||||
LayerElementPriv priv;
|
LayerElementPriv priv;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief This structure holds the necessary data to set up a LayerElement for Drag'n'Drop
|
||||||
|
*/
|
||||||
|
struct layer_element_dnd_data {
|
||||||
|
/** @brief Array of target entries for the DnD operation */
|
||||||
|
GtkTargetEntry *entries;
|
||||||
|
/** @brief Count of elements in layer_element_dnd_data::entries array */
|
||||||
|
int entry_count;
|
||||||
|
/** @brief Callback function for drag_begin event */
|
||||||
|
void (*drag_begin)(GtkWidget *, GdkDragContext *, gpointer);
|
||||||
|
/** @brief Callback fucktion for data_get event */
|
||||||
|
void (*drag_data_get)(GtkWidget *, GdkDragContext *, GtkSelectionData *, guint, guint, gpointer);
|
||||||
|
/** @brief Callback function for drag_end event */
|
||||||
|
void (*drag_end)(GtkWidget *, GdkDragContext *, gpointer);
|
||||||
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Create new layer element object
|
* @brief Create new layer element object
|
||||||
* @return new object
|
* @return new object
|
||||||
@@ -118,6 +135,13 @@ void layer_element_get_color(LayerElement *elem, GdkRGBA *rgba);
|
|||||||
*/
|
*/
|
||||||
void layer_element_set_color(LayerElement *elem, GdkRGBA *rgba);
|
void layer_element_set_color(LayerElement *elem, GdkRGBA *rgba);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Setup drag and drop of \p elem for use in the LayerSelector
|
||||||
|
* @param elem Layer element to set up
|
||||||
|
* @param data Data array containing the necessary callbacks etc. for drag and drop.
|
||||||
|
*/
|
||||||
|
void layer_element_set_dnd_callbacks(LayerElement *elem, struct layer_element_dnd_data *data);
|
||||||
|
|
||||||
G_END_DECLS
|
G_END_DECLS
|
||||||
|
|
||||||
#endif /* __LAYER_ELEMENT_H__ */
|
#endif /* __LAYER_ELEMENT_H__ */
|
@@ -1,55 +0,0 @@
|
|||||||
/*
|
|
||||||
* 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/>.
|
|
||||||
*/
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @file latex-output.h
|
|
||||||
* @brief LaTeX output renderer
|
|
||||||
* @author Mario Hüttel <mario.huettel@gmx.net>
|
|
||||||
*/
|
|
||||||
|
|
||||||
#ifndef __LATEX_OUTPUT_H__
|
|
||||||
#define __LATEX_OUTPUT_H__
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @addtogroup LaTeX-Renderer
|
|
||||||
* @{
|
|
||||||
*/
|
|
||||||
|
|
||||||
#include "../gds-parser/gds-types.h"
|
|
||||||
#include <glib.h>
|
|
||||||
#include <stdio.h>
|
|
||||||
#include "../mapping-parser.h"
|
|
||||||
|
|
||||||
#define LATEX_LINE_BUFFER_KB (10) /**< @brief Buffer for LaTeX Code line in KiB */
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief Render \p cell to LateX/TikZ code
|
|
||||||
* @param cell Cell to render
|
|
||||||
* @param layer_infos Layer information
|
|
||||||
* @param tex_file Already opened file to write data in
|
|
||||||
* @param scale Scale image down by this value
|
|
||||||
* @param create_pdf_layers Optional content groups used
|
|
||||||
* @param standalone_document document can be compiled standalone
|
|
||||||
*/
|
|
||||||
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__ */
|
|
438
layer-selector.c
438
layer-selector.c
@@ -1,438 +0,0 @@
|
|||||||
/*
|
|
||||||
* 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/>.
|
|
||||||
*/
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @file layer-selector.c
|
|
||||||
* @brief Implementation of the layer selector
|
|
||||||
* @author Mario Hüttel <mario.huettel@gmx.net>
|
|
||||||
*/
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @addtogroup MainApplication
|
|
||||||
* @{
|
|
||||||
*/
|
|
||||||
|
|
||||||
#include "layer-selector.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 GtkWidget *global_load_button;
|
|
||||||
static GtkWidget *global_save_button;
|
|
||||||
static GtkListBox *global_list_box;
|
|
||||||
|
|
||||||
void delete_layer_info_struct(struct layer_info *info)
|
|
||||||
{
|
|
||||||
if (info)
|
|
||||||
free(info);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief export_rendered_layer_info
|
|
||||||
* @return new list with all info elements needed to render cells
|
|
||||||
*/
|
|
||||||
GList *export_rendered_layer_info()
|
|
||||||
{
|
|
||||||
GList *info_list = NULL;
|
|
||||||
LayerElement *le;
|
|
||||||
struct layer_info *linfo;
|
|
||||||
GList *row_list;
|
|
||||||
GList *temp;
|
|
||||||
int i;
|
|
||||||
|
|
||||||
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);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return info_list;
|
|
||||||
}
|
|
||||||
|
|
||||||
void clear_list_box_widgets(GtkListBox *box)
|
|
||||||
{
|
|
||||||
GList *list;
|
|
||||||
GList *temp;
|
|
||||||
|
|
||||||
list = gtk_container_get_children(GTK_CONTAINER(box));
|
|
||||||
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(list);
|
|
||||||
|
|
||||||
/* Deactivate buttons */
|
|
||||||
gtk_widget_set_sensitive(global_load_button, FALSE);
|
|
||||||
gtk_widget_set_sensitive(global_save_button, FALSE);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief Check if specific layer number is present in list box
|
|
||||||
* @param layer Layer nu,ber
|
|
||||||
* @return TRUE if present
|
|
||||||
*/
|
|
||||||
static gboolean check_if_layer_widget_exists(int layer) {
|
|
||||||
GList *list;
|
|
||||||
GList *temp;
|
|
||||||
LayerElement *widget;
|
|
||||||
gboolean ret = FALSE;
|
|
||||||
|
|
||||||
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;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief Analyze \p cell and append used layers to list box
|
|
||||||
* @param listbox listbox to add layer
|
|
||||||
* @param cell Cell to analyze
|
|
||||||
*/
|
|
||||||
static void analyze_cell_layers(GtkListBox *listbox, struct gds_cell *cell)
|
|
||||||
{
|
|
||||||
GList *graphics;
|
|
||||||
struct gds_graphics *gfx;
|
|
||||||
int layer;
|
|
||||||
GtkWidget *le;
|
|
||||||
|
|
||||||
for (graphics = cell->graphic_objs; graphics != NULL; graphics = graphics->next) {
|
|
||||||
gfx = (struct gds_graphics *)graphics->data;
|
|
||||||
layer = (int)gfx->layer;
|
|
||||||
if (check_if_layer_widget_exists(layer) == FALSE) {
|
|
||||||
le = layer_element_new();
|
|
||||||
layer_element_set_layer(LAYER_ELEMENT(le), layer);
|
|
||||||
gtk_list_box_insert(listbox, le, -1);
|
|
||||||
gtk_widget_show(le);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief sort_func Sort callback for list box
|
|
||||||
* @param row1
|
|
||||||
* @param row2
|
|
||||||
* @param unused
|
|
||||||
* @note Do not use this function
|
|
||||||
* @return
|
|
||||||
*/
|
|
||||||
static gint sort_func(GtkListBoxRow *row1, GtkListBoxRow *row2, gpointer unused)
|
|
||||||
{
|
|
||||||
LayerElement *le1, *le2;
|
|
||||||
gint ret;
|
|
||||||
|
|
||||||
le1 = LAYER_ELEMENT(row1);
|
|
||||||
le2 = LAYER_ELEMENT(row2);
|
|
||||||
|
|
||||||
ret = layer_element_get_layer(le1) - layer_element_get_layer(le2);
|
|
||||||
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
void generate_layer_widgets(GtkListBox *listbox, GList *libs)
|
|
||||||
{
|
|
||||||
GList *cell_list = NULL;
|
|
||||||
struct gds_library *lib;
|
|
||||||
|
|
||||||
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) {
|
|
||||||
lib = (struct gds_library *)libs->data;
|
|
||||||
for (cell_list = lib->cells; cell_list != NULL; cell_list = cell_list->next) {
|
|
||||||
analyze_cell_layers(listbox, (struct gds_cell *)cell_list->data);
|
|
||||||
} /* For Cell List */
|
|
||||||
} /* For 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(global_load_button, TRUE);
|
|
||||||
gtk_widget_set_sensitive(global_save_button, TRUE);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief Find LayerElement in list with specified layer number
|
|
||||||
* @param el_list List with elements of type LayerElement
|
|
||||||
* @param layer Layer number
|
|
||||||
* @return Found LayerElement. If nothing is found, NULL.
|
|
||||||
*/
|
|
||||||
static LayerElement *find_layer_element_in_list(GList *el_list, int layer)
|
|
||||||
{
|
|
||||||
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 ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief Load file and apply layer definitions to listbox
|
|
||||||
* @param file_name CSV Layer Mapping File
|
|
||||||
*/
|
|
||||||
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);
|
|
||||||
|
|
||||||
if (!stream)
|
|
||||||
goto destroy_file;
|
|
||||||
|
|
||||||
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;
|
|
||||||
|
|
||||||
/* 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);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/* 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);
|
|
||||||
destroy_file:
|
|
||||||
g_object_unref(file);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief Callback for Load Mapping Button
|
|
||||||
* @param button
|
|
||||||
* @param user_data
|
|
||||||
*/
|
|
||||||
static void load_mapping_clicked(GtkWidget *button, gpointer user_data)
|
|
||||||
{
|
|
||||||
GtkWidget *dialog;
|
|
||||||
gint res;
|
|
||||||
gchar *file_name;
|
|
||||||
|
|
||||||
dialog = gtk_file_chooser_dialog_new("Load Mapping File", GTK_WINDOW(user_data), GTK_FILE_CHOOSER_ACTION_OPEN,
|
|
||||||
"Cancel", GTK_RESPONSE_CANCEL, "Load Mapping", GTK_RESPONSE_ACCEPT, NULL);
|
|
||||||
res = gtk_dialog_run(GTK_DIALOG(dialog));
|
|
||||||
if (res == GTK_RESPONSE_ACCEPT) {
|
|
||||||
file_name = gtk_file_chooser_get_filename(GTK_FILE_CHOOSER(dialog));
|
|
||||||
load_layer_mapping_from_file(file_name);
|
|
||||||
g_free(file_name);
|
|
||||||
}
|
|
||||||
gtk_widget_destroy(dialog);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief Create Line for LayerMapping file with supplied information
|
|
||||||
* @param layer_element information
|
|
||||||
* @param line_buffer buffer to write to
|
|
||||||
* @param max_len Maximum length that cna be used in \p line_buffer
|
|
||||||
*/
|
|
||||||
static void create_csv_line(LayerElement *layer_element, char *line_buffer, size_t max_len)
|
|
||||||
{
|
|
||||||
int i;
|
|
||||||
GString *string;
|
|
||||||
gboolean export;
|
|
||||||
const gchar *name;
|
|
||||||
int layer;
|
|
||||||
GdkRGBA color;
|
|
||||||
|
|
||||||
string = g_string_new_len(NULL, max_len-1);
|
|
||||||
|
|
||||||
/* Extract values */
|
|
||||||
export = layer_element_get_export(layer_element);
|
|
||||||
name = (const gchar*)layer_element_get_name(layer_element);
|
|
||||||
layer = layer_element_get_layer(layer_element);
|
|
||||||
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,
|
|
||||||
color.blue, color.alpha, (export == TRUE ? 1 : 0), name);
|
|
||||||
/* Fix broken locale settings */
|
|
||||||
for (i = 0; string->str[i]; i++) {
|
|
||||||
if (string->str[i] == ',')
|
|
||||||
string->str[i] = '.';
|
|
||||||
}
|
|
||||||
|
|
||||||
for (i = 0; string->str[i]; i++) {
|
|
||||||
if (string->str[i] == ':')
|
|
||||||
string->str[i] = ',';
|
|
||||||
}
|
|
||||||
|
|
||||||
if (string->len > (max_len-1)) {
|
|
||||||
printf("Layer Definition too long. Please shorten Layer Name!!\n");
|
|
||||||
line_buffer[0] = 0x0;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* copy max_len bytes of string */
|
|
||||||
strncpy(line_buffer, (char *)string->str, max_len-1);
|
|
||||||
line_buffer[max_len-1] = 0;
|
|
||||||
|
|
||||||
/* Completely remove string */
|
|
||||||
g_string_free(string, TRUE);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief Save layer mapping of whole list box into file
|
|
||||||
* @param file_name layer mapping file
|
|
||||||
* @param list_box listbox
|
|
||||||
*/
|
|
||||||
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");
|
|
||||||
|
|
||||||
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(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);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief Callback for Save Layer Mapping Button
|
|
||||||
* @param button
|
|
||||||
* @param user_data
|
|
||||||
*/
|
|
||||||
static void save_mapping_clicked(GtkWidget *button, gpointer user_data)
|
|
||||||
{
|
|
||||||
GtkWidget *dialog;
|
|
||||||
gint res;
|
|
||||||
gchar *file_name;
|
|
||||||
|
|
||||||
dialog = gtk_file_chooser_dialog_new("Save Mapping File", GTK_WINDOW(user_data), GTK_FILE_CHOOSER_ACTION_SAVE,
|
|
||||||
"Cancel", GTK_RESPONSE_CANCEL, "Save Mapping", GTK_RESPONSE_ACCEPT, NULL);
|
|
||||||
gtk_file_chooser_set_do_overwrite_confirmation(GTK_FILE_CHOOSER(dialog), TRUE);
|
|
||||||
|
|
||||||
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, global_list_box);
|
|
||||||
g_free(file_name);
|
|
||||||
}
|
|
||||||
gtk_widget_destroy(dialog);
|
|
||||||
}
|
|
||||||
|
|
||||||
void setup_load_mapping_callback(GtkWidget *button, GtkWindow *main_window)
|
|
||||||
{
|
|
||||||
g_object_ref(G_OBJECT(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));
|
|
||||||
global_save_button = button;
|
|
||||||
g_signal_connect(button, "clicked", G_CALLBACK(save_mapping_clicked), main_window);
|
|
||||||
}
|
|
||||||
|
|
||||||
/** @} */
|
|
@@ -1,67 +0,0 @@
|
|||||||
/*
|
|
||||||
* 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/>.
|
|
||||||
*/
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @file layer-selector.h
|
|
||||||
* @brief Implementation of the Layer selection list
|
|
||||||
* @author Mario Hüttel <mario.huettel@gmx.net>
|
|
||||||
*/
|
|
||||||
|
|
||||||
#ifndef __LAYER_SELECTOR_H__
|
|
||||||
#define __LAYER_SELECTOR_H__
|
|
||||||
|
|
||||||
#include <gtk/gtk.h>
|
|
||||||
#include <glib.h>
|
|
||||||
#include "mapping-parser.h"
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief Generate layer widgets in \p listbox
|
|
||||||
* @note This clears all previously inserted elements
|
|
||||||
* @param listbox
|
|
||||||
* @param libs The library to add
|
|
||||||
*/
|
|
||||||
void generate_layer_widgets(GtkListBox *listbox, GList *libs);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief Supply button for loading the layer mapping
|
|
||||||
* @param button
|
|
||||||
* @param main_window Parent window for dialogs
|
|
||||||
*/
|
|
||||||
void setup_load_mapping_callback(GtkWidget *button, GtkWindow *main_window);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief Supply button for saving the layer mapping
|
|
||||||
* @param button
|
|
||||||
* @param main_window
|
|
||||||
*/
|
|
||||||
void setup_save_mapping_callback(GtkWidget *button, GtkWindow *main_window);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief get the layer information present in the listbox of the selector
|
|
||||||
* @return List with layer_info elements
|
|
||||||
*/
|
|
||||||
GList *export_rendered_layer_info();
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief Delete a layer_info struct
|
|
||||||
* @param info Struct to be deleted.
|
|
||||||
* @note The layer_info::name Element has to be freed manually
|
|
||||||
*/
|
|
||||||
void delete_layer_info_struct(struct layer_info *info);
|
|
||||||
#endif /* __LAYER_SELECTOR_H__ */
|
|
258
layer/color-palette.c
Normal file
258
layer/color-palette.c
Normal file
@@ -0,0 +1,258 @@
|
|||||||
|
/*
|
||||||
|
* GDSII-Converter
|
||||||
|
* Copyright (C) 2019 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/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @file color-palette.c
|
||||||
|
* @brief Class representing a color palette
|
||||||
|
* @author Mario Hüttel <mario.huettel@gmx.net>
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <gds-render/layer/color-palette.h>
|
||||||
|
|
||||||
|
struct _ColorPalette {
|
||||||
|
/* Inheritance */
|
||||||
|
GObject parent;
|
||||||
|
|
||||||
|
/* Custom fields */
|
||||||
|
/** @brief The internal array to store the colors */
|
||||||
|
GdkRGBA *color_array;
|
||||||
|
/** @brief The length of the _ColorPalette::color_array array */
|
||||||
|
unsigned int color_array_length;
|
||||||
|
|
||||||
|
/* Dummy bytes to ensure ABI compatibility in future versions */
|
||||||
|
gpointer dummy[4];
|
||||||
|
};
|
||||||
|
|
||||||
|
G_DEFINE_TYPE(ColorPalette, color_palette, G_TYPE_OBJECT)
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Return the number of non empty lines in array
|
||||||
|
*
|
||||||
|
* This function returns the number of non empty lines in an
|
||||||
|
* array. The scanning is either terminated by the given length
|
||||||
|
* or if a \0 terminator is found.
|
||||||
|
*
|
||||||
|
* @param[in] data Array to count lines in
|
||||||
|
* @param[in] length Length of \p data
|
||||||
|
* @return < 0: Error, >=0: Lines
|
||||||
|
*/
|
||||||
|
static int count_non_empty_lines_in_array(const char *data, size_t length)
|
||||||
|
{
|
||||||
|
unsigned int idx;
|
||||||
|
int non_empty_lines;
|
||||||
|
char last_char = '\n';
|
||||||
|
|
||||||
|
if (!data)
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
/* Count each '\n' as a new line if it is not directly preceded by another '\n' */
|
||||||
|
for (idx = 0; idx < length && data[idx]; idx++) {
|
||||||
|
if (data[idx] == '\n' && last_char != '\n')
|
||||||
|
non_empty_lines++;
|
||||||
|
last_char = data[idx];
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Count the last line in case the data does not end with a '\n' */
|
||||||
|
if (data[idx-1] != '\n')
|
||||||
|
non_empty_lines++;
|
||||||
|
|
||||||
|
return non_empty_lines;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief color_palette_fill_with_resource
|
||||||
|
* @param palette
|
||||||
|
* @param resource_name
|
||||||
|
* @return 0 if successful
|
||||||
|
*/
|
||||||
|
static int color_palette_fill_with_resource(ColorPalette *palette, char *resource_name)
|
||||||
|
{
|
||||||
|
GBytes *data;
|
||||||
|
char line[10];
|
||||||
|
int line_idx;
|
||||||
|
unsigned int color_idx;
|
||||||
|
int idx;
|
||||||
|
const char *char_array;
|
||||||
|
gsize byte_count;
|
||||||
|
int lines;
|
||||||
|
GRegex *regex;
|
||||||
|
GMatchInfo *mi;
|
||||||
|
char *match;
|
||||||
|
|
||||||
|
if (!palette || !resource_name)
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
data = g_resources_lookup_data(resource_name, 0, NULL);
|
||||||
|
|
||||||
|
if (!data)
|
||||||
|
return -2;
|
||||||
|
|
||||||
|
char_array = (const char *)g_bytes_get_data(data, &byte_count);
|
||||||
|
|
||||||
|
if (!char_array || !byte_count)
|
||||||
|
goto ret_unref;
|
||||||
|
|
||||||
|
/* Get maximum lenght of color palette, assuming all entries are valid */
|
||||||
|
lines = count_non_empty_lines_in_array(char_array, byte_count);
|
||||||
|
|
||||||
|
if (lines <= 0)
|
||||||
|
goto ret_unref;
|
||||||
|
|
||||||
|
palette->color_array = (GdkRGBA *)malloc(sizeof(GdkRGBA) * (unsigned int)lines);
|
||||||
|
|
||||||
|
/* Setup regex for hexadecimal RGB colors like 'A0CB3F' */
|
||||||
|
regex = g_regex_new("^(?<red>[0-9A-Fa-f][0-9A-Fa-f])(?<green>[0-9A-Fa-f][0-9A-Fa-f])(?<blue>[0-9A-Fa-f][0-9A-Fa-f])$",
|
||||||
|
0, 0, NULL);
|
||||||
|
|
||||||
|
/* Reset line */
|
||||||
|
line_idx = 0;
|
||||||
|
line[0] = '\0';
|
||||||
|
|
||||||
|
/* Set color index */
|
||||||
|
color_idx = 0;
|
||||||
|
|
||||||
|
/* interate over lines and match */
|
||||||
|
for (idx = 0 ; idx < byte_count; idx++) {
|
||||||
|
/* Fillup line. */
|
||||||
|
line[line_idx] = char_array[idx];
|
||||||
|
|
||||||
|
|
||||||
|
/* If end of line/string is reached, process */
|
||||||
|
if (line[line_idx] == '\n' || line[line_idx] == '\0') {
|
||||||
|
line[line_idx] = '\0';
|
||||||
|
|
||||||
|
/* Match the line */
|
||||||
|
g_regex_match(regex, line, 0, &mi);
|
||||||
|
if (g_match_info_matches(mi) && color_idx < lines) {
|
||||||
|
match = g_match_info_fetch_named(mi, "red");
|
||||||
|
palette->color_array[color_idx].red = (double)g_ascii_strtoll(match, NULL, 16) / 255.0;
|
||||||
|
g_free(match);
|
||||||
|
match = g_match_info_fetch_named(mi, "green");
|
||||||
|
palette->color_array[color_idx].green = (double)g_ascii_strtoll(match, NULL, 16) / 255.0;
|
||||||
|
g_free(match);
|
||||||
|
match = g_match_info_fetch_named(mi, "blue");
|
||||||
|
palette->color_array[color_idx].blue = (double)g_ascii_strtoll(match, NULL, 16) / 255.0;
|
||||||
|
g_free(match);
|
||||||
|
|
||||||
|
/* Only RGB supported so far. Fix alpha channel to 1.0 */
|
||||||
|
palette->color_array[color_idx].alpha = 1.0;
|
||||||
|
|
||||||
|
color_idx++;
|
||||||
|
}
|
||||||
|
|
||||||
|
g_match_info_free(mi);
|
||||||
|
|
||||||
|
/* End of string */
|
||||||
|
if (char_array[idx] == '\0')
|
||||||
|
break;
|
||||||
|
|
||||||
|
line_idx = 0;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* increment line index. If end is reached write all bytes to the line end
|
||||||
|
* line is longer than required for parsing. This ensures, that everything works as expected
|
||||||
|
*/
|
||||||
|
line_idx += (line_idx < sizeof(line)-1 ? 1 : 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Data read; Shrink array in case of invalid lines */
|
||||||
|
palette->color_array = realloc(palette->color_array, (size_t)color_idx * sizeof(GdkRGBA));
|
||||||
|
palette->color_array_length = color_idx;
|
||||||
|
|
||||||
|
g_regex_unref(regex);
|
||||||
|
ret_unref:
|
||||||
|
g_bytes_unref(data);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
ColorPalette *color_palette_new_from_resource(char *resource_name)
|
||||||
|
{
|
||||||
|
ColorPalette *palette;
|
||||||
|
|
||||||
|
palette = GDS_RENDER_COLOR_PALETTE(g_object_new(TYPE_GDS_RENDER_COLOR_PALETTE, NULL));
|
||||||
|
if (palette)
|
||||||
|
(void)color_palette_fill_with_resource(palette, resource_name);
|
||||||
|
|
||||||
|
return palette;
|
||||||
|
}
|
||||||
|
|
||||||
|
GdkRGBA *color_palette_get_color(ColorPalette *palette, GdkRGBA *color, unsigned int index)
|
||||||
|
{
|
||||||
|
GdkRGBA *c = NULL;
|
||||||
|
|
||||||
|
if (!palette)
|
||||||
|
goto ret_c;
|
||||||
|
|
||||||
|
if (index >= palette->color_array_length)
|
||||||
|
goto ret_c;
|
||||||
|
|
||||||
|
if (color)
|
||||||
|
c = color;
|
||||||
|
else
|
||||||
|
c = (GdkRGBA *)malloc(sizeof(GdkRGBA));
|
||||||
|
|
||||||
|
/* Copy color */
|
||||||
|
c->red = palette->color_array[index].red;
|
||||||
|
c->green = palette->color_array[index].green;
|
||||||
|
c->blue = palette->color_array[index].blue;
|
||||||
|
c->alpha = palette->color_array[index].alpha;
|
||||||
|
ret_c:
|
||||||
|
return c;
|
||||||
|
}
|
||||||
|
|
||||||
|
unsigned int color_palette_get_color_count(ColorPalette *palette)
|
||||||
|
{
|
||||||
|
unsigned int return_val = 0;
|
||||||
|
|
||||||
|
if (palette)
|
||||||
|
return_val = palette->color_array_length;
|
||||||
|
|
||||||
|
return return_val;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void color_palette_dispose(GObject *gobj)
|
||||||
|
{
|
||||||
|
ColorPalette *palette;
|
||||||
|
|
||||||
|
palette = GDS_RENDER_COLOR_PALETTE(gobj);
|
||||||
|
if (palette->color_array)
|
||||||
|
{
|
||||||
|
palette->color_array_length = 0;
|
||||||
|
free(palette->color_array);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Chain up to parent class */
|
||||||
|
G_OBJECT_CLASS(color_palette_parent_class)->dispose(gobj);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void color_palette_class_init(ColorPaletteClass *klass)
|
||||||
|
{
|
||||||
|
GObjectClass *gclass;
|
||||||
|
|
||||||
|
gclass = G_OBJECT_CLASS(klass);
|
||||||
|
gclass->dispose = color_palette_dispose;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void color_palette_init(ColorPalette *self)
|
||||||
|
{
|
||||||
|
self->color_array = NULL;
|
||||||
|
self->color_array_length = 0;
|
||||||
|
}
|
330
layer/layer-info.c
Normal file
330
layer/layer-info.c
Normal file
@@ -0,0 +1,330 @@
|
|||||||
|
/*
|
||||||
|
* GDSII-Converter
|
||||||
|
* Copyright (C) 2019 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/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @file layer-info.c
|
||||||
|
* @brief Implementation of the LayerSettings class
|
||||||
|
* @author Mario Hüttel <mario.huettel@gmx.net>
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <gds-render/layer/layer-info.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
|
||||||
|
struct _LayerSettings {
|
||||||
|
GObject parent;
|
||||||
|
GList *layer_infos;
|
||||||
|
gpointer padding[12];
|
||||||
|
};
|
||||||
|
|
||||||
|
G_DEFINE_TYPE(LayerSettings, layer_settings, G_TYPE_OBJECT)
|
||||||
|
|
||||||
|
static void layer_settings_init(LayerSettings *self)
|
||||||
|
{
|
||||||
|
self->layer_infos = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void layer_settings_class_init(LayerSettingsClass *klass)
|
||||||
|
{
|
||||||
|
(void)klass;
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Copy layer_info struct
|
||||||
|
*
|
||||||
|
* This function copies a layer info struct.
|
||||||
|
* Be aware, that it does not only copy the pointer to the
|
||||||
|
* layer name, but instead duplicates the string.
|
||||||
|
*
|
||||||
|
* @param info Info to copy
|
||||||
|
* @return new layer_info struct
|
||||||
|
*/
|
||||||
|
static struct layer_info *layer_info_copy(const struct layer_info * const info)
|
||||||
|
{
|
||||||
|
struct layer_info *copy;
|
||||||
|
|
||||||
|
if (!info)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
copy = (struct layer_info *)malloc(sizeof(struct layer_info));
|
||||||
|
if (!copy)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
/* Copy data */
|
||||||
|
memcpy(copy, info, sizeof(struct layer_info));
|
||||||
|
/* Duplicate string */
|
||||||
|
if (info->name)
|
||||||
|
copy->name = strdup(info->name);
|
||||||
|
|
||||||
|
return copy;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void layer_info_delete_with_name(struct layer_info *const info)
|
||||||
|
{
|
||||||
|
if (!info)
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (info->name)
|
||||||
|
free(info->name);
|
||||||
|
free(info);
|
||||||
|
}
|
||||||
|
|
||||||
|
LayerSettings *layer_settings_new()
|
||||||
|
{
|
||||||
|
return g_object_new(GDS_RENDER_TYPE_LAYER_SETTINGS, NULL);
|
||||||
|
}
|
||||||
|
|
||||||
|
int layer_settings_append_layer_info(LayerSettings *settings, struct layer_info *info)
|
||||||
|
{
|
||||||
|
struct layer_info *info_copy;
|
||||||
|
|
||||||
|
g_return_val_if_fail(GDS_RENDER_IS_LAYER_SETTINGS(settings), -1);
|
||||||
|
if (!info)
|
||||||
|
return -2;
|
||||||
|
|
||||||
|
/* Copy layer info */
|
||||||
|
info_copy = layer_info_copy(info);
|
||||||
|
|
||||||
|
/* Append to list */
|
||||||
|
settings->layer_infos = g_list_append(settings->layer_infos, info_copy);
|
||||||
|
|
||||||
|
return (settings->layer_infos ? 0 : -3);
|
||||||
|
}
|
||||||
|
|
||||||
|
void layer_settings_clear(LayerSettings *settings)
|
||||||
|
{
|
||||||
|
g_return_if_fail(GDS_RENDER_IS_LAYER_SETTINGS(settings));
|
||||||
|
|
||||||
|
/* Clear list and delete layer_info structs including the name field */
|
||||||
|
g_list_free_full(settings->layer_infos, (GDestroyNotify)layer_info_delete_with_name);
|
||||||
|
settings->layer_infos = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
int layer_settings_remove_layer(LayerSettings *settings, int layer)
|
||||||
|
{
|
||||||
|
GList *list_iter;
|
||||||
|
GList *found = NULL;
|
||||||
|
struct layer_info *inf;
|
||||||
|
|
||||||
|
g_return_val_if_fail(GDS_RENDER_IS_LAYER_SETTINGS(settings), -1);
|
||||||
|
|
||||||
|
/* Find in list */
|
||||||
|
for (list_iter = settings->layer_infos; list_iter; list_iter = list_iter->next) {
|
||||||
|
inf = (struct layer_info *)list_iter->data;
|
||||||
|
|
||||||
|
if (!inf)
|
||||||
|
continue;
|
||||||
|
if (inf->layer == layer)
|
||||||
|
found = list_iter;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (found) {
|
||||||
|
/* Free the layer_info struct */
|
||||||
|
layer_info_delete_with_name((struct layer_info *)found->data);
|
||||||
|
/* Delete the list element */
|
||||||
|
settings->layer_infos = g_list_delete_link(settings->layer_infos, found);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
return -2;
|
||||||
|
}
|
||||||
|
|
||||||
|
GList *layer_settings_get_layer_info_list(LayerSettings *settings)
|
||||||
|
{
|
||||||
|
g_return_val_if_fail(GDS_RENDER_IS_LAYER_SETTINGS(settings), NULL);
|
||||||
|
return settings->layer_infos;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Generate a layer mapping CSV line for a given layer_info struct
|
||||||
|
* @param string Buffer to write to
|
||||||
|
* @param linfo Layer information
|
||||||
|
*/
|
||||||
|
static void layer_settings_gen_csv_line(GString *string, struct layer_info *linfo)
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
|
||||||
|
g_string_printf(string, "%d:%lf:%lf:%lf:%lf:%d:%s\n",
|
||||||
|
linfo->layer, linfo->color.red, linfo->color.green,
|
||||||
|
linfo->color.blue, linfo->color.alpha, (linfo->render ? 1 : 0), linfo->name);
|
||||||
|
/* Fix broken locale settings */
|
||||||
|
for (i = 0; string->str[i]; i++) {
|
||||||
|
if (string->str[i] == ',')
|
||||||
|
string->str[i] = '.';
|
||||||
|
}
|
||||||
|
|
||||||
|
for (i = 0; string->str[i]; i++) {
|
||||||
|
if (string->str[i] == ':')
|
||||||
|
string->str[i] = ',';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
int layer_settings_to_csv(LayerSettings *settings, const char *path)
|
||||||
|
{
|
||||||
|
GFile *file;
|
||||||
|
GOutputStream *w_fstream;
|
||||||
|
GString *string;
|
||||||
|
GList *info_iter;
|
||||||
|
struct layer_info *linfo;
|
||||||
|
int ret = 0;
|
||||||
|
|
||||||
|
file = g_file_new_for_path(path);
|
||||||
|
w_fstream = G_OUTPUT_STREAM(g_file_replace(file, NULL, FALSE, G_FILE_CREATE_NONE, NULL, NULL));
|
||||||
|
if (!w_fstream) {
|
||||||
|
ret = -1;
|
||||||
|
goto ret_unref_file;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Allocate new working buffer string. A size bigger than 200 is unexpected, but possible
|
||||||
|
* 200 is a tradeoff between memory usage and preventing the necessity of realloc'ing the string
|
||||||
|
*/
|
||||||
|
string = g_string_new_len(NULL, 200);
|
||||||
|
if (!string) {
|
||||||
|
ret = -2;
|
||||||
|
goto ret_close_file;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Loop over layers and write CSV lines */
|
||||||
|
for (info_iter = settings->layer_infos; info_iter; info_iter = info_iter->next) {
|
||||||
|
linfo = (struct layer_info *)info_iter->data;
|
||||||
|
|
||||||
|
layer_settings_gen_csv_line(string, linfo);
|
||||||
|
g_output_stream_write(w_fstream, string->str, sizeof(gchar), NULL, NULL);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Delete string */
|
||||||
|
g_string_free(string, TRUE);
|
||||||
|
ret_close_file:
|
||||||
|
g_output_stream_flush(w_fstream, NULL, NULL);
|
||||||
|
g_output_stream_close(w_fstream, NULL, NULL);
|
||||||
|
g_object_unref(w_fstream);
|
||||||
|
ret_unref_file:
|
||||||
|
g_object_unref(file);
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Load a line from \p stream and parse try to parse it as layer information
|
||||||
|
* @param stream Input data stream
|
||||||
|
* @param linfo Layer info struct to fill
|
||||||
|
* @return 1 if malformatted line, 0 if parsing was successful and parameters are valid, -1 if file end
|
||||||
|
*/
|
||||||
|
static int layer_settings_load_csv_line_from_stream(GDataInputStream *stream, struct layer_info *linfo)
|
||||||
|
{
|
||||||
|
int ret;
|
||||||
|
gsize len;
|
||||||
|
gchar *line;
|
||||||
|
GRegex *regex;
|
||||||
|
GMatchInfo *mi;
|
||||||
|
char *match;
|
||||||
|
|
||||||
|
if (!linfo) {
|
||||||
|
ret = 1;
|
||||||
|
goto ret_direct;
|
||||||
|
}
|
||||||
|
|
||||||
|
regex = g_regex_new("^(?<layer>[0-9]+),(?<r>[0-9\\.]+),(?<g>[0-9\\.]+),(?<b>[0-9\\.]+),(?<a>[0-9\\.]+),(?<export>[01]),(?<name>.*)$", 0, 0, NULL);
|
||||||
|
|
||||||
|
line = g_data_input_stream_read_line(stream, &len, NULL, NULL);
|
||||||
|
if (!line) {
|
||||||
|
ret = -1;
|
||||||
|
goto destroy_regex;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Match line in CSV */
|
||||||
|
g_regex_match(regex, line, 0, &mi);
|
||||||
|
if (g_match_info_matches(mi)) {
|
||||||
|
/* Line is valid */
|
||||||
|
match = g_match_info_fetch_named(mi, "layer");
|
||||||
|
linfo->layer = (int)g_ascii_strtoll(match, NULL, 10);
|
||||||
|
g_free(match);
|
||||||
|
match = g_match_info_fetch_named(mi, "r");
|
||||||
|
linfo->color.red = g_ascii_strtod(match, NULL);
|
||||||
|
g_free(match);
|
||||||
|
match = g_match_info_fetch_named(mi, "g");
|
||||||
|
linfo->color.green = g_ascii_strtod(match, NULL);
|
||||||
|
g_free(match);
|
||||||
|
match = g_match_info_fetch_named(mi, "b");
|
||||||
|
linfo->color.blue = g_ascii_strtod(match, NULL);
|
||||||
|
g_free(match);
|
||||||
|
match = g_match_info_fetch_named(mi, "a");
|
||||||
|
linfo->color.alpha = g_ascii_strtod(match, NULL);
|
||||||
|
g_free(match);
|
||||||
|
match = g_match_info_fetch_named(mi, "export");
|
||||||
|
linfo->render = ((!strcmp(match, "1")) ? 1 : 0);
|
||||||
|
g_free(match);
|
||||||
|
match = g_match_info_fetch_named(mi, "name");
|
||||||
|
linfo->name = match;
|
||||||
|
|
||||||
|
ret = 0;
|
||||||
|
} else {
|
||||||
|
/* Line is malformatted */
|
||||||
|
printf("Could not recognize line in CSV as valid entry: %s\n", line);
|
||||||
|
ret = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
g_match_info_free(mi);
|
||||||
|
g_free(line);
|
||||||
|
destroy_regex:
|
||||||
|
g_regex_unref(regex);
|
||||||
|
ret_direct:
|
||||||
|
return ret;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
int layer_settings_load_from_csv(LayerSettings *settings, const char *path)
|
||||||
|
{
|
||||||
|
GFile *file;
|
||||||
|
int ret = 0;
|
||||||
|
GInputStream *in_stream;
|
||||||
|
GDataInputStream *data_stream;
|
||||||
|
int parser_ret;
|
||||||
|
struct layer_info linfo;
|
||||||
|
|
||||||
|
file = g_file_new_for_path(path);
|
||||||
|
in_stream = G_INPUT_STREAM(g_file_read(file, NULL, NULL));
|
||||||
|
if (!in_stream) {
|
||||||
|
ret = -1;
|
||||||
|
goto ret_destroy_file;
|
||||||
|
}
|
||||||
|
/* Delete old settings */
|
||||||
|
layer_settings_clear(settings);
|
||||||
|
|
||||||
|
data_stream = g_data_input_stream_new(in_stream);
|
||||||
|
|
||||||
|
while ((parser_ret = layer_settings_load_csv_line_from_stream(data_stream, &linfo)) >= 0) {
|
||||||
|
/* Line broken */
|
||||||
|
if (parser_ret == 1)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
layer_settings_append_layer_info(settings, &linfo);
|
||||||
|
/* Clear name to prevent memory leak */
|
||||||
|
if (linfo.name)
|
||||||
|
g_free(linfo.name);
|
||||||
|
}
|
||||||
|
|
||||||
|
g_object_unref(data_stream);
|
||||||
|
g_object_unref(in_stream);
|
||||||
|
ret_destroy_file:
|
||||||
|
g_object_unref(file);
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
823
layer/layer-selector.c
Normal file
823
layer/layer-selector.c
Normal file
@@ -0,0 +1,823 @@
|
|||||||
|
/*
|
||||||
|
* 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/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @file layer-selector.c
|
||||||
|
* @brief Implementation of the layer selector
|
||||||
|
* @author Mario Hüttel <mario.huettel@gmx.net>
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @addtogroup layer-selector
|
||||||
|
* @{
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <glib.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
|
||||||
|
#include <gds-render/layer/layer-selector.h>
|
||||||
|
#include <gds-render/layer/layer-info.h>
|
||||||
|
#include <gds-render/gds-utils/gds-parser.h>
|
||||||
|
#include <gds-render/widgets/layer-element.h>
|
||||||
|
#include <gds-render/layer/mapping-parser.h>
|
||||||
|
|
||||||
|
struct _LayerSelector {
|
||||||
|
/* Parent */
|
||||||
|
GObject parent;
|
||||||
|
/* Own fields */
|
||||||
|
GtkWidget *associated_load_button;
|
||||||
|
GtkWidget *associated_save_button;
|
||||||
|
GtkWindow *load_parent_window;
|
||||||
|
GtkWindow *save_parent_window;
|
||||||
|
GtkListBox *list_box;
|
||||||
|
|
||||||
|
GtkTargetEntry dnd_target;
|
||||||
|
|
||||||
|
gpointer dummy[4];
|
||||||
|
};
|
||||||
|
|
||||||
|
G_DEFINE_TYPE(LayerSelector, layer_selector, G_TYPE_OBJECT)
|
||||||
|
|
||||||
|
/* Drag and drop code
|
||||||
|
* Original code from https://blog.gtk.org/2017/06/01/drag-and-drop-in-lists-revisited/
|
||||||
|
*/
|
||||||
|
|
||||||
|
static void sel_layer_element_drag_begin(GtkWidget *widget, GdkDragContext *context, gpointer data)
|
||||||
|
{
|
||||||
|
GtkWidget *row;
|
||||||
|
GtkAllocation alloc;
|
||||||
|
cairo_surface_t *surface;
|
||||||
|
cairo_t *cr;
|
||||||
|
int x, y;
|
||||||
|
(void)data;
|
||||||
|
|
||||||
|
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);
|
||||||
|
|
||||||
|
g_object_set_data(G_OBJECT(gtk_widget_get_parent(row)), "drag-row", row);
|
||||||
|
gtk_style_context_add_class(gtk_widget_get_style_context(row), "drag-row");
|
||||||
|
}
|
||||||
|
|
||||||
|
static void sel_layer_element_drag_end(GtkWidget *widget, GdkDragContext *context, gpointer data)
|
||||||
|
{
|
||||||
|
GtkWidget *row;
|
||||||
|
(void)context;
|
||||||
|
(void)data;
|
||||||
|
|
||||||
|
row = gtk_widget_get_ancestor(widget, GTK_TYPE_LIST_BOX_ROW);
|
||||||
|
g_object_set_data(G_OBJECT(gtk_widget_get_parent(row)), "drag-row", NULL);
|
||||||
|
gtk_style_context_remove_class(gtk_widget_get_style_context(row), "drag-row");
|
||||||
|
gtk_style_context_remove_class(gtk_widget_get_style_context(row), "drag-hover");
|
||||||
|
}
|
||||||
|
|
||||||
|
static void sel_layer_element_drag_data_get(GtkWidget *widget, GdkDragContext *context,
|
||||||
|
GtkSelectionData *selection_data,
|
||||||
|
guint info, guint time, gpointer data)
|
||||||
|
{
|
||||||
|
(void)context;
|
||||||
|
(void)info;
|
||||||
|
(void)time;
|
||||||
|
(void)data;
|
||||||
|
GdkAtom atom;
|
||||||
|
|
||||||
|
atom = gdk_atom_intern_static_string("GTK_LIST_BOX_ROW");
|
||||||
|
|
||||||
|
gtk_selection_data_set(selection_data, atom,
|
||||||
|
32, (const guchar *)&widget, sizeof(gpointer));
|
||||||
|
}
|
||||||
|
|
||||||
|
static GtkListBoxRow *layer_selector_get_last_row (GtkListBox *list)
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
GtkListBoxRow *row;
|
||||||
|
|
||||||
|
row = NULL;
|
||||||
|
for (i = 0; ; i++) {
|
||||||
|
GtkListBoxRow *tmp;
|
||||||
|
tmp = gtk_list_box_get_row_at_index(list, i);
|
||||||
|
if (tmp == NULL)
|
||||||
|
break;
|
||||||
|
row = tmp;
|
||||||
|
}
|
||||||
|
|
||||||
|
return row;
|
||||||
|
}
|
||||||
|
|
||||||
|
static GtkListBoxRow *layer_selector_get_row_before (GtkListBox *list, GtkListBoxRow *row)
|
||||||
|
{
|
||||||
|
int pos;
|
||||||
|
|
||||||
|
pos = gtk_list_box_row_get_index (row);
|
||||||
|
return gtk_list_box_get_row_at_index (list, pos - 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
static GtkListBoxRow *layer_selector_get_row_after (GtkListBox *list, GtkListBoxRow *row)
|
||||||
|
{
|
||||||
|
int pos;
|
||||||
|
|
||||||
|
pos = gtk_list_box_row_get_index(row);
|
||||||
|
return gtk_list_box_get_row_at_index(list, pos + 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void layer_selector_drag_data_received(GtkWidget *widget, GdkDragContext *context, gint x, gint y,
|
||||||
|
GtkSelectionData *selection_data, guint info, guint32 time,
|
||||||
|
gpointer data)
|
||||||
|
{
|
||||||
|
GtkWidget *row_before, *row_after;
|
||||||
|
GtkWidget *row;
|
||||||
|
GtkWidget *source;
|
||||||
|
int pos;
|
||||||
|
|
||||||
|
row_before = GTK_WIDGET(g_object_get_data(G_OBJECT(widget), "row-before"));
|
||||||
|
row_after = GTK_WIDGET(g_object_get_data(G_OBJECT(widget), "row-after"));
|
||||||
|
|
||||||
|
g_object_set_data(G_OBJECT(widget), "row-before", NULL);
|
||||||
|
g_object_set_data(G_OBJECT(widget), "row-after", NULL);
|
||||||
|
|
||||||
|
if (row_before)
|
||||||
|
gtk_style_context_remove_class(gtk_widget_get_style_context(row_before), "drag-hover-bottom");
|
||||||
|
if (row_after)
|
||||||
|
gtk_style_context_remove_class(gtk_widget_get_style_context(row_after), "drag-hover-top");
|
||||||
|
|
||||||
|
row = (gpointer) *((gpointer *)gtk_selection_data_get_data(selection_data));
|
||||||
|
source = gtk_widget_get_ancestor(row, GTK_TYPE_LIST_BOX_ROW);
|
||||||
|
|
||||||
|
if (source == row_after)
|
||||||
|
return;
|
||||||
|
|
||||||
|
g_object_ref(source);
|
||||||
|
gtk_container_remove(GTK_CONTAINER(gtk_widget_get_parent(source)), source);
|
||||||
|
|
||||||
|
if (row_after)
|
||||||
|
pos = gtk_list_box_row_get_index(GTK_LIST_BOX_ROW(row_after));
|
||||||
|
else
|
||||||
|
pos = gtk_list_box_row_get_index(GTK_LIST_BOX_ROW(row_before)) + 1;
|
||||||
|
|
||||||
|
gtk_list_box_insert(GTK_LIST_BOX(widget), source, pos);
|
||||||
|
g_object_unref(source);
|
||||||
|
}
|
||||||
|
|
||||||
|
static gboolean layer_selector_drag_motion(GtkWidget *widget, GdkDragContext *context, int x, int y, guint time)
|
||||||
|
{
|
||||||
|
GtkAllocation alloc;
|
||||||
|
GtkWidget *row;
|
||||||
|
int hover_row_y;
|
||||||
|
int hover_row_height;
|
||||||
|
GtkWidget *drag_row;
|
||||||
|
GtkWidget *row_before;
|
||||||
|
GtkWidget *row_after;
|
||||||
|
|
||||||
|
row = GTK_WIDGET(gtk_list_box_get_row_at_y(GTK_LIST_BOX(widget), y));
|
||||||
|
|
||||||
|
drag_row = GTK_WIDGET(g_object_get_data(G_OBJECT(widget), "drag-row"));
|
||||||
|
row_after = GTK_WIDGET(g_object_get_data(G_OBJECT(widget), "row-after"));
|
||||||
|
row_before = GTK_WIDGET(g_object_get_data(G_OBJECT(widget), "row-before"));
|
||||||
|
|
||||||
|
gtk_style_context_remove_class(gtk_widget_get_style_context(drag_row), "drag-hover");
|
||||||
|
if (row_before)
|
||||||
|
gtk_style_context_remove_class(gtk_widget_get_style_context(row_before), "drag-hover-bottom");
|
||||||
|
if (row_after)
|
||||||
|
gtk_style_context_remove_class(gtk_widget_get_style_context(row_after), "drag-hover-top");
|
||||||
|
|
||||||
|
if (row) {
|
||||||
|
gtk_widget_get_allocation(row, &alloc);
|
||||||
|
hover_row_y = alloc.y;
|
||||||
|
hover_row_height = alloc.height;
|
||||||
|
|
||||||
|
if (y < hover_row_y + hover_row_height/2) {
|
||||||
|
row_after = row;
|
||||||
|
row_before = GTK_WIDGET(layer_selector_get_row_before(GTK_LIST_BOX(widget),
|
||||||
|
GTK_LIST_BOX_ROW(row)));
|
||||||
|
} else {
|
||||||
|
row_before = row;
|
||||||
|
row_after = GTK_WIDGET(layer_selector_get_row_after(GTK_LIST_BOX(widget),
|
||||||
|
GTK_LIST_BOX_ROW(row)));
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
row_before = GTK_WIDGET(layer_selector_get_last_row(GTK_LIST_BOX(widget)));
|
||||||
|
row_after = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
g_object_set_data(G_OBJECT(widget), "row-before", row_before);
|
||||||
|
g_object_set_data(G_OBJECT(widget), "row-after", row_after);
|
||||||
|
|
||||||
|
if (drag_row == row_before || drag_row == row_after) {
|
||||||
|
gtk_style_context_add_class(gtk_widget_get_style_context(drag_row), "drag-hover");
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (row_before)
|
||||||
|
gtk_style_context_add_class(gtk_widget_get_style_context(row_before), "drag-hover-bottom");
|
||||||
|
if (row_after)
|
||||||
|
gtk_style_context_add_class(gtk_widget_get_style_context(row_after), "drag-hover-top");
|
||||||
|
|
||||||
|
return TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void layer_selector_drag_leave(GtkWidget *widget, GdkDragContext *context, guint time)
|
||||||
|
{
|
||||||
|
GtkWidget *drag_row;
|
||||||
|
GtkWidget *row_before;
|
||||||
|
GtkWidget *row_after;
|
||||||
|
|
||||||
|
drag_row = GTK_WIDGET(g_object_get_data(G_OBJECT(widget), "drag-row"));
|
||||||
|
row_before = GTK_WIDGET(g_object_get_data(G_OBJECT(widget), "row-before"));
|
||||||
|
row_after = GTK_WIDGET(g_object_get_data(G_OBJECT(widget), "row-after"));
|
||||||
|
|
||||||
|
gtk_style_context_remove_class(gtk_widget_get_style_context(drag_row), "drag-hover");
|
||||||
|
if (row_before)
|
||||||
|
gtk_style_context_remove_class(gtk_widget_get_style_context(row_before), "drag-hover-bottom");
|
||||||
|
if (row_after)
|
||||||
|
gtk_style_context_remove_class(gtk_widget_get_style_context(row_after), "drag-hover-top");
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
static const char *dnd_additional_css =
|
||||||
|
".row:not(:first-child) { "
|
||||||
|
" border-top: 1px solid alpha(gray,0.5); "
|
||||||
|
" border-bottom: 1px solid transparent; "
|
||||||
|
"}"
|
||||||
|
".row:first-child { "
|
||||||
|
" border-top: 1px solid transparent; "
|
||||||
|
" border-bottom: 1px solid transparent; "
|
||||||
|
"}"
|
||||||
|
".row:last-child { "
|
||||||
|
" border-top: 1px solid alpha(gray,0.5); "
|
||||||
|
" border-bottom: 1px solid alpha(gray,0.5); "
|
||||||
|
"}"
|
||||||
|
".row.drag-icon { "
|
||||||
|
" background: #282828; "
|
||||||
|
" border: 1px solid blue; "
|
||||||
|
"}"
|
||||||
|
".row.drag-row { "
|
||||||
|
" color: gray; "
|
||||||
|
" background: alpha(gray,0.2); "
|
||||||
|
"}"
|
||||||
|
".row.drag-row.drag-hover { "
|
||||||
|
" border-top: 1px solid #4e9a06; "
|
||||||
|
" border-bottom: 1px solid #4e9a06; "
|
||||||
|
"}"
|
||||||
|
".row.drag-hover image, "
|
||||||
|
".row.drag-hover label { "
|
||||||
|
" color: #4e9a06; "
|
||||||
|
"}"
|
||||||
|
".row.drag-hover-top {"
|
||||||
|
" border-top: 1px solid #4e9a06; "
|
||||||
|
"}"
|
||||||
|
".row.drag-hover-bottom {"
|
||||||
|
" border-bottom: 1px solid #4e9a06; "
|
||||||
|
"}";
|
||||||
|
|
||||||
|
static void layer_selector_dispose(GObject *self)
|
||||||
|
{
|
||||||
|
LayerSelector *sel = LAYER_SELECTOR(self);
|
||||||
|
|
||||||
|
g_clear_object(&sel->list_box);
|
||||||
|
g_clear_object(&sel->load_parent_window);
|
||||||
|
g_clear_object(&sel->save_parent_window);
|
||||||
|
g_clear_object(&sel->associated_load_button);
|
||||||
|
g_clear_object(&sel->associated_save_button);
|
||||||
|
|
||||||
|
if (sel->dnd_target.target) {
|
||||||
|
g_free(sel->dnd_target.target);
|
||||||
|
sel->dnd_target.target = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Chain up to parent's dispose function */
|
||||||
|
G_OBJECT_CLASS(layer_selector_parent_class)->dispose(self);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void layer_selector_class_init(LayerSelectorClass *klass)
|
||||||
|
{
|
||||||
|
GObjectClass *object_class = G_OBJECT_CLASS(klass);
|
||||||
|
GtkCssProvider *provider;
|
||||||
|
|
||||||
|
/* Implement handles to virtual functions */
|
||||||
|
object_class->dispose = layer_selector_dispose;
|
||||||
|
|
||||||
|
/* Setup the CSS provider for the drag and drop animations once */
|
||||||
|
provider = gtk_css_provider_new();
|
||||||
|
gtk_css_provider_load_from_data(provider, dnd_additional_css, -1, NULL);
|
||||||
|
gtk_style_context_add_provider_for_screen(gdk_screen_get_default(), GTK_STYLE_PROVIDER(provider), 800);
|
||||||
|
|
||||||
|
g_object_unref(provider);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void layer_selector_setup_dnd(LayerSelector *self)
|
||||||
|
{
|
||||||
|
gtk_drag_dest_set(GTK_WIDGET(self->list_box), GTK_DEST_DEFAULT_MOTION | GTK_DEST_DEFAULT_DROP, &self->dnd_target, 1, GDK_ACTION_MOVE);
|
||||||
|
g_signal_connect(self->list_box, "drag-data-received", G_CALLBACK(layer_selector_drag_data_received), NULL);
|
||||||
|
g_signal_connect(self->list_box, "drag-motion", G_CALLBACK(layer_selector_drag_motion), NULL);
|
||||||
|
g_signal_connect(self->list_box, "drag-leave", G_CALLBACK(layer_selector_drag_leave), NULL);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Drag and drop end */
|
||||||
|
|
||||||
|
static void layer_selector_init(LayerSelector *self)
|
||||||
|
{
|
||||||
|
self->load_parent_window = NULL;
|
||||||
|
self->save_parent_window = NULL;
|
||||||
|
self->associated_load_button = NULL;
|
||||||
|
self->associated_save_button = NULL;
|
||||||
|
|
||||||
|
self->dnd_target.target = g_strdup_printf("LAYER_SELECTOR_DND_%p", self);
|
||||||
|
self->dnd_target.info = 0;
|
||||||
|
self->dnd_target.flags = GTK_TARGET_SAME_APP;
|
||||||
|
}
|
||||||
|
|
||||||
|
LayerSelector *layer_selector_new(GtkListBox *list_box)
|
||||||
|
{
|
||||||
|
LayerSelector *selector;
|
||||||
|
|
||||||
|
if (GTK_IS_LIST_BOX(list_box) == FALSE)
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
selector = LAYER_SELECTOR(g_object_new(TYPE_LAYER_SELECTOR, NULL));
|
||||||
|
selector->list_box = list_box;
|
||||||
|
layer_selector_setup_dnd(selector);
|
||||||
|
g_object_ref(G_OBJECT(list_box));
|
||||||
|
|
||||||
|
return selector;
|
||||||
|
}
|
||||||
|
|
||||||
|
GList *layer_selector_export_rendered_layer_info(LayerSelector *selector)
|
||||||
|
{
|
||||||
|
GList *info_list = NULL;
|
||||||
|
LayerElement *le;
|
||||||
|
struct layer_info *linfo;
|
||||||
|
GList *row_list;
|
||||||
|
GList *temp;
|
||||||
|
int i;
|
||||||
|
|
||||||
|
if (!selector)
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
row_list = gtk_container_get_children(GTK_CONTAINER(selector->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->name = (char *)layer_element_get_name(le);
|
||||||
|
|
||||||
|
/* Append to list */
|
||||||
|
info_list = g_list_append(info_list, (gpointer)linfo);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return info_list;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void layer_selector_clear_widgets(LayerSelector *self)
|
||||||
|
{
|
||||||
|
GList *list;
|
||||||
|
GList *temp;
|
||||||
|
|
||||||
|
list = gtk_container_get_children(GTK_CONTAINER(self->list_box));
|
||||||
|
for (temp = list; temp != NULL; temp = temp->next) {
|
||||||
|
gtk_container_remove(GTK_CONTAINER(self->list_box), GTK_WIDGET(temp->data));
|
||||||
|
}
|
||||||
|
/* Widgets are already destroyed when removed from box because they are only referenced inside the container */
|
||||||
|
|
||||||
|
g_list_free(list);
|
||||||
|
|
||||||
|
/* Deactivate buttons */
|
||||||
|
if (self->associated_load_button)
|
||||||
|
gtk_widget_set_sensitive(self->associated_load_button, FALSE);
|
||||||
|
if (self->associated_save_button)
|
||||||
|
gtk_widget_set_sensitive(self->associated_save_button, FALSE);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Check if a specific layer element with the given layer number is present in the layer selector
|
||||||
|
* @param self LayerSelector instance
|
||||||
|
* @param layer Layer number to check for
|
||||||
|
* @return TRUE if layer is present, else FALSE
|
||||||
|
*/
|
||||||
|
static gboolean layer_selector_check_if_layer_widget_exists(LayerSelector *self, int layer) {
|
||||||
|
GList *list;
|
||||||
|
GList *temp;
|
||||||
|
LayerElement *widget;
|
||||||
|
gboolean ret = FALSE;
|
||||||
|
|
||||||
|
list = gtk_container_get_children(GTK_CONTAINER(self->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;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Setup the necessary drag and drop callbacks of layer elements.
|
||||||
|
* @param self LayerSelector instance. Used to get the DnD target entry.
|
||||||
|
* @param element LayerElement instance to set the callbacks
|
||||||
|
*/
|
||||||
|
static void sel_layer_element_setup_dnd_callbacks(LayerSelector *self, LayerElement *element)
|
||||||
|
{
|
||||||
|
struct layer_element_dnd_data dnd_data;
|
||||||
|
|
||||||
|
if (!self || !element)
|
||||||
|
return;
|
||||||
|
|
||||||
|
dnd_data.entries = &self->dnd_target;
|
||||||
|
dnd_data.entry_count = 1;
|
||||||
|
dnd_data.drag_end = sel_layer_element_drag_end;
|
||||||
|
dnd_data.drag_begin = sel_layer_element_drag_begin;
|
||||||
|
dnd_data.drag_data_get = sel_layer_element_drag_data_get;
|
||||||
|
|
||||||
|
layer_element_set_dnd_callbacks(element, &dnd_data);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Analyze \p cell layers and append detected layers to layer selector \p self
|
||||||
|
* @param self LayerSelector instance
|
||||||
|
* @param cell Cell to analyze
|
||||||
|
*/
|
||||||
|
static void layer_selector_analyze_cell_layers(LayerSelector *self, struct gds_cell *cell)
|
||||||
|
{
|
||||||
|
GList *graphics;
|
||||||
|
struct gds_graphics *gfx;
|
||||||
|
int layer;
|
||||||
|
GtkWidget *le;
|
||||||
|
|
||||||
|
for (graphics = cell->graphic_objs; graphics != NULL; graphics = graphics->next) {
|
||||||
|
gfx = (struct gds_graphics *)graphics->data;
|
||||||
|
layer = (int)gfx->layer;
|
||||||
|
if (layer_selector_check_if_layer_widget_exists(self, layer) == FALSE) {
|
||||||
|
le = layer_element_new();
|
||||||
|
sel_layer_element_setup_dnd_callbacks(self, LAYER_ELEMENT(le));
|
||||||
|
layer_element_set_layer(LAYER_ELEMENT(le), layer);
|
||||||
|
gtk_list_box_insert(self->list_box, le, -1);
|
||||||
|
gtk_widget_show(le);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief sort_func Sort callback for list box
|
||||||
|
* @param row1
|
||||||
|
* @param row2
|
||||||
|
* @param unused
|
||||||
|
* @note Do not use this function. This is an internal callback
|
||||||
|
* @return See sort function documentation of GTK+
|
||||||
|
*/
|
||||||
|
static gint layer_selector_sort_func(GtkListBoxRow *row1, GtkListBoxRow *row2, gpointer unused)
|
||||||
|
{
|
||||||
|
LayerElement *le1, *le2;
|
||||||
|
gint ret;
|
||||||
|
static const enum layer_selector_sort_algo default_sort = LAYER_SELECTOR_SORT_DOWN;
|
||||||
|
const enum layer_selector_sort_algo *algo = (const enum layer_selector_sort_algo *)unused;
|
||||||
|
|
||||||
|
/* Assume downward sorting */
|
||||||
|
/* TODO: This is nasty. Find a better way */
|
||||||
|
if (!algo)
|
||||||
|
algo = &default_sort;
|
||||||
|
|
||||||
|
le1 = LAYER_ELEMENT(row1);
|
||||||
|
le2 = LAYER_ELEMENT(row2);
|
||||||
|
|
||||||
|
/* Determine sort fow downward sort */
|
||||||
|
ret = layer_element_get_layer(le1) - layer_element_get_layer(le2);
|
||||||
|
|
||||||
|
/* Change order if upward sort is requested */
|
||||||
|
ret *= (*algo == LAYER_SELECTOR_SORT_DOWN ? 1 : -1);
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
void layer_selector_generate_layer_widgets(LayerSelector *selector, GList *libs)
|
||||||
|
{
|
||||||
|
GList *cell_list = NULL;
|
||||||
|
struct gds_library *lib;
|
||||||
|
|
||||||
|
layer_selector_clear_widgets(selector);
|
||||||
|
|
||||||
|
for (; libs != NULL; libs = libs->next) {
|
||||||
|
lib = (struct gds_library *)libs->data;
|
||||||
|
for (cell_list = lib->cells; cell_list != NULL; cell_list = cell_list->next) {
|
||||||
|
layer_selector_analyze_cell_layers(selector, (struct gds_cell *)cell_list->data);
|
||||||
|
} /* For Cell List */
|
||||||
|
} /* For libs */
|
||||||
|
|
||||||
|
/* Sort the layers */
|
||||||
|
layer_selector_force_sort(selector, LAYER_SELECTOR_SORT_DOWN);
|
||||||
|
|
||||||
|
/* Activate Buttons */
|
||||||
|
if (selector->associated_load_button)
|
||||||
|
gtk_widget_set_sensitive(selector->associated_load_button, TRUE);
|
||||||
|
if (selector->associated_save_button)
|
||||||
|
gtk_widget_set_sensitive(selector->associated_save_button, TRUE);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Find LayerElement in list with specified layer number
|
||||||
|
* @param el_list List with elements of type LayerElement
|
||||||
|
* @param layer Layer number
|
||||||
|
* @return Found LayerElement. If nothing is found, NULL.
|
||||||
|
*/
|
||||||
|
static LayerElement *layer_selector_find_layer_element_in_list(GList *el_list, int layer)
|
||||||
|
{
|
||||||
|
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 ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Load the layer mapping from a CSV formatted file
|
||||||
|
*
|
||||||
|
* This function imports the layer specification from a file (see @ref lmf-spec).
|
||||||
|
* The layer ordering defined in the file is kept. All layers present in the
|
||||||
|
* current loaded library, which are not present in the layer mapping file
|
||||||
|
* are appended at the end of the layer selector list.
|
||||||
|
*
|
||||||
|
* @param self LayerSelector instance
|
||||||
|
* @param file_name File name to load from
|
||||||
|
*/
|
||||||
|
static void layer_selector_load_layer_mapping_from_file(LayerSelector *self, 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);
|
||||||
|
|
||||||
|
if (!stream)
|
||||||
|
goto destroy_file;
|
||||||
|
|
||||||
|
dstream = g_data_input_stream_new(G_INPUT_STREAM(stream));
|
||||||
|
|
||||||
|
rows = gtk_container_get_children(GTK_CONTAINER(self->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(self->list_box), GTK_WIDGET(le));
|
||||||
|
}
|
||||||
|
|
||||||
|
while((result = mapping_parser_load_line(dstream, &export, &name, &layer, &color)) >= 0) {
|
||||||
|
/* skip broken line */
|
||||||
|
if (result == 1)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
/* Add rows in the same order as in file */
|
||||||
|
if ((le = layer_selector_find_layer_element_in_list(rows, layer))) {
|
||||||
|
gtk_list_box_insert(self->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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 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(self->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);
|
||||||
|
destroy_file:
|
||||||
|
g_object_unref(file);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Callback for Load Mapping Button
|
||||||
|
* @param button
|
||||||
|
* @param user_data
|
||||||
|
*/
|
||||||
|
static void layer_selector_load_mapping_clicked(GtkWidget *button, gpointer user_data)
|
||||||
|
{
|
||||||
|
LayerSelector *sel;
|
||||||
|
GtkWidget *dialog;
|
||||||
|
gint res;
|
||||||
|
gchar *file_name;
|
||||||
|
|
||||||
|
sel = LAYER_SELECTOR(user_data);
|
||||||
|
|
||||||
|
dialog = gtk_file_chooser_dialog_new("Load Mapping File", GTK_WINDOW(sel->load_parent_window), GTK_FILE_CHOOSER_ACTION_OPEN,
|
||||||
|
"Cancel", GTK_RESPONSE_CANCEL, "Load Mapping", GTK_RESPONSE_ACCEPT, NULL);
|
||||||
|
res = gtk_dialog_run(GTK_DIALOG(dialog));
|
||||||
|
if (res == GTK_RESPONSE_ACCEPT) {
|
||||||
|
file_name = gtk_file_chooser_get_filename(GTK_FILE_CHOOSER(dialog));
|
||||||
|
layer_selector_load_layer_mapping_from_file(sel, file_name);
|
||||||
|
g_free(file_name);
|
||||||
|
}
|
||||||
|
gtk_widget_destroy(dialog);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Save layer mapping of selector \p self to a file
|
||||||
|
* @param self LayerSelector instance
|
||||||
|
* @param file_name File name to save to
|
||||||
|
*/
|
||||||
|
static void layer_selector_save_layer_mapping_data(LayerSelector *self, const gchar *file_name)
|
||||||
|
{
|
||||||
|
FILE *file;
|
||||||
|
char workbuff[512];
|
||||||
|
GList *le_list;
|
||||||
|
GList *temp;
|
||||||
|
|
||||||
|
/* Overwrite existing file */
|
||||||
|
file = fopen((const char *)file_name, "w");
|
||||||
|
|
||||||
|
le_list = gtk_container_get_children(GTK_CONTAINER(self->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;
|
||||||
|
mapping_parser_gen_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);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Callback for Save Layer Mapping Button
|
||||||
|
* @param button
|
||||||
|
* @param user_data
|
||||||
|
*/
|
||||||
|
static void layer_selector_save_mapping_clicked(GtkWidget *button, gpointer user_data)
|
||||||
|
{
|
||||||
|
GtkWidget *dialog;
|
||||||
|
gint res;
|
||||||
|
gchar *file_name;
|
||||||
|
LayerSelector *sel;
|
||||||
|
|
||||||
|
sel = LAYER_SELECTOR(user_data);
|
||||||
|
|
||||||
|
dialog = gtk_file_chooser_dialog_new("Save Mapping File", GTK_WINDOW(sel->save_parent_window), GTK_FILE_CHOOSER_ACTION_SAVE,
|
||||||
|
"Cancel", GTK_RESPONSE_CANCEL, "Save Mapping", GTK_RESPONSE_ACCEPT, NULL);
|
||||||
|
gtk_file_chooser_set_do_overwrite_confirmation(GTK_FILE_CHOOSER(dialog), TRUE);
|
||||||
|
|
||||||
|
res = gtk_dialog_run(GTK_DIALOG(dialog));
|
||||||
|
if (res == GTK_RESPONSE_ACCEPT) {
|
||||||
|
file_name = gtk_file_chooser_get_filename(GTK_FILE_CHOOSER(dialog));
|
||||||
|
layer_selector_save_layer_mapping_data(sel, file_name);
|
||||||
|
g_free(file_name);
|
||||||
|
}
|
||||||
|
gtk_widget_destroy(dialog);
|
||||||
|
}
|
||||||
|
|
||||||
|
void layer_selector_set_load_mapping_button(LayerSelector *selector, GtkWidget *button, GtkWindow *main_window)
|
||||||
|
{
|
||||||
|
g_clear_object(&selector->load_parent_window);
|
||||||
|
g_clear_object(&selector->associated_load_button);
|
||||||
|
|
||||||
|
g_object_ref(G_OBJECT(button));
|
||||||
|
g_object_ref(G_OBJECT(main_window));
|
||||||
|
selector->associated_load_button = button;
|
||||||
|
selector->load_parent_window = main_window;
|
||||||
|
g_signal_connect(button, "clicked", G_CALLBACK(layer_selector_load_mapping_clicked), selector);
|
||||||
|
}
|
||||||
|
|
||||||
|
void layer_selector_set_save_mapping_button(LayerSelector *selector, GtkWidget *button, GtkWindow *main_window)
|
||||||
|
{
|
||||||
|
g_clear_object(&selector->save_parent_window);
|
||||||
|
g_clear_object(&selector->associated_save_button);
|
||||||
|
|
||||||
|
g_object_ref(G_OBJECT(button));
|
||||||
|
g_object_ref(G_OBJECT(main_window));
|
||||||
|
selector->associated_save_button = button;
|
||||||
|
selector->save_parent_window = main_window;
|
||||||
|
g_signal_connect(button, "clicked", G_CALLBACK(layer_selector_save_mapping_clicked), selector);
|
||||||
|
}
|
||||||
|
|
||||||
|
void layer_selector_force_sort(LayerSelector *selector, enum layer_selector_sort_algo sort_function)
|
||||||
|
{
|
||||||
|
GtkListBox *box;
|
||||||
|
|
||||||
|
if (!selector)
|
||||||
|
return;
|
||||||
|
|
||||||
|
box = selector->list_box;
|
||||||
|
if (!box)
|
||||||
|
return;
|
||||||
|
|
||||||
|
/* Set sorting function, sort, and disable sorting function */
|
||||||
|
gtk_list_box_set_sort_func(box, layer_selector_sort_func, (gpointer)&sort_function, NULL);
|
||||||
|
gtk_list_box_invalidate_sort(box);
|
||||||
|
gtk_list_box_set_sort_func(box, NULL, NULL, NULL);
|
||||||
|
}
|
||||||
|
|
||||||
|
void layer_selector_auto_color_layers(LayerSelector *layer_selector, ColorPalette *palette, double global_alpha)
|
||||||
|
{
|
||||||
|
GList *le_list;
|
||||||
|
GList *le_list_ptr;
|
||||||
|
LayerElement *le;
|
||||||
|
unsigned int color_index = 0;
|
||||||
|
unsigned int color_count;
|
||||||
|
GdkRGBA color;
|
||||||
|
|
||||||
|
if (GDS_RENDER_IS_COLOR_PALETTE(palette) == FALSE || LAYER_IS_SELECTOR(layer_selector) == FALSE)
|
||||||
|
return;
|
||||||
|
if (global_alpha <= 0)
|
||||||
|
return;
|
||||||
|
if (GTK_IS_LIST_BOX(layer_selector->list_box) == FALSE)
|
||||||
|
return;
|
||||||
|
|
||||||
|
le_list = gtk_container_get_children(GTK_CONTAINER(layer_selector->list_box));
|
||||||
|
|
||||||
|
/* iterate over layer elements and fill colors */
|
||||||
|
color_index = 0;
|
||||||
|
color_count = color_palette_get_color_count(palette);
|
||||||
|
if (color_count == 0)
|
||||||
|
goto ret_free_le_list;
|
||||||
|
|
||||||
|
for (le_list_ptr = le_list; le_list_ptr != NULL; le_list_ptr = le_list_ptr->next) {
|
||||||
|
le = LAYER_ELEMENT(le_list_ptr->data);
|
||||||
|
if (le) {
|
||||||
|
color_palette_get_color(palette, &color, color_index++);
|
||||||
|
color.alpha *= global_alpha;
|
||||||
|
layer_element_set_color(le, &color);
|
||||||
|
|
||||||
|
if (color_index >= color_count)
|
||||||
|
color_index = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ret_free_le_list:
|
||||||
|
g_list_free(le_list);
|
||||||
|
}
|
||||||
|
|
||||||
|
/** @} */
|
@@ -25,13 +25,13 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @addtogroup MainApplication
|
* @addtogroup Mapping-Parser
|
||||||
* @{
|
* @{
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include "mapping-parser.h"
|
#include <gds-render/layer/mapping-parser.h>
|
||||||
|
|
||||||
int load_csv_line(GDataInputStream *stream, gboolean *export, char **name, int *layer, GdkRGBA *color)
|
int mapping_parser_load_line(GDataInputStream *stream, gboolean *export, char **name, int *layer, GdkRGBA *color)
|
||||||
{
|
{
|
||||||
int ret;
|
int ret;
|
||||||
gsize len;
|
gsize len;
|
||||||
@@ -94,5 +94,51 @@ ret_direct:
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void mapping_parser_gen_csv_line(LayerElement *layer_element, char *line_buffer, size_t max_len)
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
GString *string;
|
||||||
|
gboolean export;
|
||||||
|
const gchar *name;
|
||||||
|
int layer;
|
||||||
|
GdkRGBA color;
|
||||||
|
|
||||||
|
string = g_string_new_len(NULL, max_len-1);
|
||||||
|
|
||||||
|
/* Extract values */
|
||||||
|
export = layer_element_get_export(layer_element);
|
||||||
|
name = (const gchar*)layer_element_get_name(layer_element);
|
||||||
|
layer = layer_element_get_layer(layer_element);
|
||||||
|
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,
|
||||||
|
color.blue, color.alpha, (export == TRUE ? 1 : 0), name);
|
||||||
|
/* Fix broken locale settings */
|
||||||
|
for (i = 0; string->str[i]; i++) {
|
||||||
|
if (string->str[i] == ',')
|
||||||
|
string->str[i] = '.';
|
||||||
|
}
|
||||||
|
|
||||||
|
for (i = 0; string->str[i]; i++) {
|
||||||
|
if (string->str[i] == ':')
|
||||||
|
string->str[i] = ',';
|
||||||
|
}
|
||||||
|
|
||||||
|
if (string->len > (max_len-1)) {
|
||||||
|
printf("Layer Definition too long. Please shorten Layer Name!!\n");
|
||||||
|
line_buffer[0] = 0x0;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* copy max_len bytes of string */
|
||||||
|
strncpy(line_buffer, (char *)string->str, max_len-1);
|
||||||
|
line_buffer[max_len-1] = 0;
|
||||||
|
|
||||||
|
/* Completely remove string */
|
||||||
|
g_string_free(string, TRUE);
|
||||||
|
}
|
||||||
|
|
||||||
/** @} */
|
/** @} */
|
||||||
|
|
391
main-window.c
391
main-window.c
@@ -1,391 +0,0 @@
|
|||||||
/*
|
|
||||||
* 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/>.
|
|
||||||
*/
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @file main-window.c
|
|
||||||
* @brief Handling of GUI
|
|
||||||
* @author Mario Hüttel <mario.huettel@gmx.net>
|
|
||||||
*/
|
|
||||||
|
|
||||||
/** @addtogroup MainApplication
|
|
||||||
* @{
|
|
||||||
*/
|
|
||||||
|
|
||||||
#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"
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief User data supplied to callback function of the open button
|
|
||||||
*/
|
|
||||||
struct open_button_data {
|
|
||||||
GtkWindow *main_window;
|
|
||||||
GList **list_ptr;
|
|
||||||
GtkTreeStore *cell_store;
|
|
||||||
GtkListBox *layer_box;
|
|
||||||
GtkSearchEntry *search_entry;
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief User data supplied to callback function of the convert button
|
|
||||||
*/
|
|
||||||
struct convert_button_data {
|
|
||||||
GtkTreeView *tree_view;
|
|
||||||
GtkWindow *main_window;
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief Window close event of main window
|
|
||||||
*
|
|
||||||
* Closes the main window. This leads to the termination of the whole application
|
|
||||||
* @param window main window
|
|
||||||
* @param user not used
|
|
||||||
* @return TRUE. This indicates that the event has been fully handled
|
|
||||||
*/
|
|
||||||
static gboolean on_window_close(gpointer window, gpointer user)
|
|
||||||
{
|
|
||||||
gtk_widget_destroy(GTK_WIDGET(window));
|
|
||||||
return TRUE;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief generate string from gds_time_field
|
|
||||||
* @param date Date to convert
|
|
||||||
* @return String with date
|
|
||||||
*/
|
|
||||||
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;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief Callback function of Load GDS button
|
|
||||||
* @param button
|
|
||||||
* @param user Necessary Data
|
|
||||||
*/
|
|
||||||
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;
|
|
||||||
GdkRGBA cell_text_color;
|
|
||||||
|
|
||||||
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);
|
|
||||||
|
|
||||||
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;
|
|
||||||
|
|
||||||
/* Add cell to tree store model
|
|
||||||
* CELL_SEL_CELL_COLOR will always be green,
|
|
||||||
* because no cell cehcker is implemented, yet.
|
|
||||||
*/
|
|
||||||
gtk_tree_store_set (store, &celliter,
|
|
||||||
CELL_SEL_CELL, gds_c,
|
|
||||||
CELL_SEL_MODDATE, mod_date->str,
|
|
||||||
CELL_SEL_ACCESSDATE, acc_date->str,
|
|
||||||
CELL_SEL_CELL_COLOR, &cell_text_color, // TODO: implement cell checker
|
|
||||||
-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);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief Convert button callback
|
|
||||||
* @param button
|
|
||||||
* @param user
|
|
||||||
*/
|
|
||||||
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();
|
|
||||||
switch (sett.renderer) {
|
|
||||||
case RENDERER_LATEX_TIKZ:
|
|
||||||
gtk_file_filter_add_pattern(filter, "*.tex");
|
|
||||||
gtk_file_filter_set_name(filter, "LaTeX-Files");
|
|
||||||
break;
|
|
||||||
case RENDERER_CAIROGRAPHICS_PDF:
|
|
||||||
gtk_file_filter_add_pattern(filter, "*.pdf");
|
|
||||||
gtk_file_filter_set_name(filter, "PDF-Files");
|
|
||||||
break;
|
|
||||||
case RENDERER_CAIROGRAPHICS_SVG:
|
|
||||||
gtk_file_filter_add_pattern(filter, "*.svg");
|
|
||||||
gtk_file_filter_set_name(filter, "SVG-Files");
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
gtk_file_chooser_add_filter(GTK_FILE_CHOOSER(dialog), filter);
|
|
||||||
|
|
||||||
gtk_file_chooser_set_do_overwrite_confirmation(GTK_FILE_CHOOSER(dialog), TRUE);
|
|
||||||
|
|
||||||
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_SVG:
|
|
||||||
case RENDERER_CAIROGRAPHICS_PDF:
|
|
||||||
cairo_render_cell_to_vector_file(cell_to_render, layer_list,
|
|
||||||
(sett.renderer == RENDERER_CAIROGRAPHICS_PDF ? file_name : NULL),
|
|
||||||
(sett.renderer == RENDERER_CAIROGRAPHICS_SVG ? file_name : NULL),
|
|
||||||
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);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief Callback for cell-selection change event
|
|
||||||
*
|
|
||||||
* This function activates/deactivates the convert button depending on whether
|
|
||||||
* a cell is selected for conversion or not
|
|
||||||
* @param sel
|
|
||||||
* @param convert_button
|
|
||||||
*/
|
|
||||||
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;
|
|
||||||
GtkWidget *listbox;
|
|
||||||
GtkWidget *conv_button;
|
|
||||||
GtkWidget *search_entry;
|
|
||||||
static GList *gds_libs;
|
|
||||||
static struct open_button_data open_data;
|
|
||||||
static struct convert_button_data conv_data;
|
|
||||||
struct tree_stores *cell_selector_stores;
|
|
||||||
|
|
||||||
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"));
|
|
||||||
search_entry = GTK_WIDGET(gtk_builder_get_object(main_builder, "cell-search"));
|
|
||||||
open_data.search_entry = GTK_SEARCH_ENTRY(search_entry);
|
|
||||||
cell_selector_stores = setup_cell_selector(cell_tree, GTK_ENTRY(search_entry));
|
|
||||||
|
|
||||||
open_data.cell_store = cell_selector_stores->base_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);
|
|
||||||
|
|
||||||
g_object_unref(main_builder);
|
|
||||||
|
|
||||||
return (conv_data.main_window);
|
|
||||||
}
|
|
||||||
|
|
||||||
/** @} */
|
|
234
main.c
234
main.c
@@ -17,66 +17,171 @@
|
|||||||
* along with GDSII-Converter. If not, see <http://www.gnu.org/licenses/>.
|
* along with GDSII-Converter. If not, see <http://www.gnu.org/licenses/>.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @file main.c
|
||||||
|
* @brief main.c
|
||||||
|
* @author Mario Hüttel <mario.huettel@gmx.net>
|
||||||
|
*/
|
||||||
|
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <gtk/gtk.h>
|
#include <gtk/gtk.h>
|
||||||
#include <glib.h>
|
#include <glib.h>
|
||||||
#include "main-window.h"
|
|
||||||
#include "command-line.h"
|
|
||||||
#include "external-renderer.h"
|
|
||||||
|
|
||||||
|
#include <gds-render/gds-render-gui.h>
|
||||||
|
#include <gds-render/command-line.h>
|
||||||
|
#include <gds-render/output-renderers/external-renderer.h>
|
||||||
|
#include <gds-render/version.h>
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Structure containing The GtkApplication and a list containing the GdsRenderGui objects.
|
||||||
|
*/
|
||||||
struct application_data {
|
struct application_data {
|
||||||
GtkApplication *app;
|
GtkApplication *app;
|
||||||
GtkWindow *main_window;
|
GList *gui_list;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Callback for the menu entry 'Quit'
|
||||||
|
*
|
||||||
|
* Destroys all GUIs contained in the application_data structure
|
||||||
|
* provided by \p user_data.
|
||||||
|
*
|
||||||
|
* The complete suspension of all main windows leads to the termination of the
|
||||||
|
* GApplication.
|
||||||
|
*
|
||||||
|
* @param action unused
|
||||||
|
* @param parameter unused
|
||||||
|
* @param user_data application_data structure
|
||||||
|
*/
|
||||||
static void app_quit(GSimpleAction *action, GVariant *parameter, gpointer user_data)
|
static void app_quit(GSimpleAction *action, GVariant *parameter, gpointer user_data)
|
||||||
{
|
{
|
||||||
struct application_data *appdata = (struct application_data *)user_data;
|
struct application_data * const appdata = (struct application_data *)user_data;
|
||||||
(void)action;
|
(void)action;
|
||||||
(void)parameter;
|
(void)parameter;
|
||||||
|
GList *list_iter;
|
||||||
|
GdsRenderGui *gui;
|
||||||
|
|
||||||
gtk_widget_destroy(GTK_WIDGET(appdata->main_window));
|
/* Dispose all GUIs */
|
||||||
|
for (list_iter = appdata->gui_list; list_iter != NULL; list_iter = g_list_next(list_iter)) {
|
||||||
|
gui = RENDERER_GUI(list_iter->data);
|
||||||
|
g_object_unref(gui);
|
||||||
|
}
|
||||||
|
|
||||||
|
g_list_free(appdata->gui_list);
|
||||||
|
appdata->gui_list = NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Callback for the 'About' menu entry
|
||||||
|
*
|
||||||
|
* This function shows the about dialog.
|
||||||
|
*
|
||||||
|
* @param action GSimpleAction, unused
|
||||||
|
* @param parameter Unused.
|
||||||
|
* @param user_data Unused
|
||||||
|
*/
|
||||||
static void app_about(GSimpleAction *action, GVariant *parameter, gpointer user_data)
|
static void app_about(GSimpleAction *action, GVariant *parameter, gpointer user_data)
|
||||||
{
|
{
|
||||||
GtkBuilder *builder;
|
GtkBuilder *builder;
|
||||||
GtkDialog *dialog;
|
GtkDialog *dialog;
|
||||||
struct application_data *appdata = (struct application_data *)user_data;
|
GdkPixbuf *logo_buf;
|
||||||
|
GError *error = NULL;
|
||||||
|
(void)user_data;
|
||||||
(void)action;
|
(void)action;
|
||||||
(void)parameter;
|
(void)parameter;
|
||||||
|
|
||||||
builder = gtk_builder_new_from_resource("/about.glade");
|
builder = gtk_builder_new_from_resource("/gui/about.glade");
|
||||||
dialog = GTK_DIALOG(gtk_builder_get_object(builder, "about-dialog"));
|
dialog = GTK_DIALOG(gtk_builder_get_object(builder, "about-dialog"));
|
||||||
gtk_window_set_transient_for(GTK_WINDOW(dialog), appdata->main_window);
|
gtk_window_set_transient_for(GTK_WINDOW(dialog), NULL);
|
||||||
|
gtk_about_dialog_set_version(GTK_ABOUT_DIALOG(dialog), _app_version_string);
|
||||||
|
|
||||||
|
/* Load icon from resource */
|
||||||
|
logo_buf = gdk_pixbuf_new_from_resource_at_scale("/images/logo.svg", 100, 100, TRUE, &error);
|
||||||
|
if (logo_buf) {
|
||||||
|
/* Set logo */
|
||||||
|
gtk_about_dialog_set_logo(GTK_ABOUT_DIALOG(dialog), logo_buf);
|
||||||
|
|
||||||
|
/* Pixbuf is now owned by about dialog. Unref */
|
||||||
|
g_object_unref(logo_buf);
|
||||||
|
} else if (error) {
|
||||||
|
fprintf(stderr, "Logo could not be displayed: %s\n", error->message);
|
||||||
|
g_error_free(error);
|
||||||
|
}
|
||||||
|
|
||||||
gtk_dialog_run(dialog);
|
gtk_dialog_run(dialog);
|
||||||
|
|
||||||
gtk_widget_destroy(GTK_WIDGET(dialog));
|
gtk_widget_destroy(GTK_WIDGET(dialog));
|
||||||
g_object_unref(builder);
|
g_object_unref(builder);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Contains the application menu entries
|
||||||
|
*/
|
||||||
const static GActionEntry app_actions[] = {
|
const static GActionEntry app_actions[] = {
|
||||||
{ "quit", app_quit },
|
{"quit", app_quit, NULL, NULL, NULL, {0}},
|
||||||
{ "about", app_about }
|
{"about", app_about, NULL, NULL, NULL, {0}}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Called when a GUI main window is closed
|
||||||
|
*
|
||||||
|
* The GdsRenderGui object associated with the closed main window
|
||||||
|
* is removed from the list of open GUIs (\p user_data) and unreferenced.
|
||||||
|
*
|
||||||
|
* @param gui The GUI instance the closed main window belongs to
|
||||||
|
* @param user_data List of GUIs
|
||||||
|
*/
|
||||||
|
static void gui_window_closed_callback(GdsRenderGui *gui, gpointer user_data)
|
||||||
|
{
|
||||||
|
GList **gui_list = (GList **)user_data;
|
||||||
|
|
||||||
|
/* Dispose of Gui element */
|
||||||
|
*gui_list = g_list_remove(*gui_list, gui);
|
||||||
|
g_object_unref(gui);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Activation of the GUI
|
||||||
|
* @param app The GApplication reference
|
||||||
|
* @param user_data Used to store the individual GUI instances.
|
||||||
|
*/
|
||||||
static void gapp_activate(GApplication *app, gpointer user_data)
|
static void gapp_activate(GApplication *app, gpointer user_data)
|
||||||
{
|
{
|
||||||
GtkWindow *main_window;
|
GtkWindow *main_window;
|
||||||
struct application_data *appdata = (struct application_data *)user_data;
|
GdsRenderGui *gui;
|
||||||
|
|
||||||
|
struct application_data * const appdata = (struct application_data *)user_data;
|
||||||
|
|
||||||
|
gui = gds_render_gui_new();
|
||||||
|
appdata->gui_list = g_list_append(appdata->gui_list, gui);
|
||||||
|
|
||||||
|
g_signal_connect(gui, "window-closed", G_CALLBACK(gui_window_closed_callback), &appdata->gui_list);
|
||||||
|
|
||||||
|
main_window = gds_render_gui_get_main_window(gui);
|
||||||
|
|
||||||
main_window = create_main_window();
|
|
||||||
appdata->main_window = main_window;
|
|
||||||
gtk_application_add_window(GTK_APPLICATION(app), main_window);
|
gtk_application_add_window(GTK_APPLICATION(app), main_window);
|
||||||
gtk_widget_show(GTK_WIDGET(main_window));
|
gtk_widget_show(GTK_WIDGET(main_window));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Start the graphical interface.
|
||||||
|
*
|
||||||
|
* This function starts the GUI. If there's already a
|
||||||
|
* running instance of this program, a second window will be
|
||||||
|
* created in that instance and the second one is terminated.
|
||||||
|
*
|
||||||
|
* @param argc
|
||||||
|
* @param argv
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
static int start_gui(int argc, char **argv)
|
static int start_gui(int argc, char **argv)
|
||||||
{
|
{
|
||||||
|
|
||||||
GtkApplication *gapp;
|
GtkApplication *gapp;
|
||||||
int app_status;
|
int app_status;
|
||||||
static struct application_data appdata;
|
static struct application_data appdata = {
|
||||||
|
.gui_list = NULL
|
||||||
|
};
|
||||||
GMenu *menu;
|
GMenu *menu;
|
||||||
GMenu *m_quit;
|
GMenu *m_quit;
|
||||||
GMenu *m_about;
|
GMenu *m_about;
|
||||||
@@ -85,6 +190,12 @@ static int start_gui(int argc, char **argv)
|
|||||||
g_application_register(G_APPLICATION(gapp), NULL, NULL);
|
g_application_register(G_APPLICATION(gapp), NULL, NULL);
|
||||||
g_signal_connect(gapp, "activate", G_CALLBACK(gapp_activate), &appdata);
|
g_signal_connect(gapp, "activate", G_CALLBACK(gapp_activate), &appdata);
|
||||||
|
|
||||||
|
if (g_application_get_is_remote(G_APPLICATION(gapp)) == TRUE) {
|
||||||
|
g_application_activate(G_APPLICATION(gapp));
|
||||||
|
printf("There is already an open instance. Will open second window in said instance.\n");
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
menu = g_menu_new();
|
menu = g_menu_new();
|
||||||
m_quit = g_menu_new();
|
m_quit = g_menu_new();
|
||||||
m_about = g_menu_new();
|
m_about = g_menu_new();
|
||||||
@@ -100,41 +211,55 @@ static int start_gui(int argc, char **argv)
|
|||||||
g_object_unref(m_about);
|
g_object_unref(m_about);
|
||||||
g_object_unref(menu);
|
g_object_unref(menu);
|
||||||
|
|
||||||
|
|
||||||
app_status = g_application_run(G_APPLICATION(gapp), argc, argv);
|
app_status = g_application_run(G_APPLICATION(gapp), argc, argv);
|
||||||
g_object_unref(gapp);
|
g_object_unref(gapp);
|
||||||
|
|
||||||
|
g_list_free(appdata.gui_list);
|
||||||
|
|
||||||
return app_status;
|
return app_status;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Print the application version string to stdout
|
||||||
|
*/
|
||||||
|
static void print_version(void)
|
||||||
|
{
|
||||||
|
printf("This is gds-render, version: %s\n\nFor a list of supported commands execute with --help option.\n",
|
||||||
|
_app_version_string);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief The "entry point" of the application
|
||||||
|
* @param argc Number of command line parameters
|
||||||
|
* @param argv Command line parameters
|
||||||
|
* @return Execution status of the application
|
||||||
|
*/
|
||||||
int main(int argc, char **argv)
|
int main(int argc, char **argv)
|
||||||
{
|
{
|
||||||
|
int i;
|
||||||
GError *error = NULL;
|
GError *error = NULL;
|
||||||
GOptionContext *context;
|
GOptionContext *context;
|
||||||
gchar *gds_name;
|
gchar *gds_name;
|
||||||
gchar *basename;
|
gchar **output_paths = NULL;
|
||||||
gchar *pdfname = NULL, *texname = NULL, *mappingname = NULL, *cellname = NULL, *svgname = NULL;
|
gchar *mappingname = NULL;
|
||||||
gboolean tikz = FALSE, pdf = FALSE, pdf_layers = FALSE, pdf_standalone = FALSE, svg = FALSE;
|
gchar *cellname = NULL;
|
||||||
|
gchar **renderer_args = NULL;
|
||||||
|
gboolean version = FALSE, pdf_standalone = FALSE, pdf_layers = FALSE;
|
||||||
gchar *custom_library_path = NULL;
|
gchar *custom_library_path = NULL;
|
||||||
gchar *custom_library_file_name = NULL;
|
|
||||||
int scale = 1000;
|
int scale = 1000;
|
||||||
int app_status;
|
int app_status = 0;
|
||||||
|
|
||||||
GOptionEntry entries[] = {
|
GOptionEntry entries[] = {
|
||||||
{"tikz", 't', 0, G_OPTION_ARG_NONE, &tikz, "Output TikZ code", NULL },
|
{"version", 'v', 0, G_OPTION_ARG_NONE, &version, "Print version", NULL},
|
||||||
{"pdf", 'p', 0, G_OPTION_ARG_NONE, &pdf, "Output PDF document", NULL },
|
{"renderer", 'r', 0, G_OPTION_ARG_STRING_ARRAY, &renderer_args, "Renderer to use. Can be used multiple times.", "pdf|svg|tikz|ext"},
|
||||||
//{"svg", 'S', 0, G_OPTION_ARG_NONE, &svg, "Output SVG image", NULL },
|
|
||||||
{"scale", 's', 0, G_OPTION_ARG_INT, &scale, "Divide output coordinates by <SCALE>", "<SCALE>" },
|
{"scale", 's', 0, G_OPTION_ARG_INT, &scale, "Divide output coordinates by <SCALE>", "<SCALE>" },
|
||||||
{"tex-output", 'o', 0, G_OPTION_ARG_FILENAME, &texname, "Optional path for TeX file", "PATH" },
|
{"output-file", 'o', 0, G_OPTION_ARG_FILENAME_ARRAY, &output_paths, "Output file path. Can be used multiple times.", "PATH" },
|
||||||
{"pdf-output", 'O', 0, G_OPTION_ARG_FILENAME, &pdfname, "Optional path for PDF file", "PATH" },
|
|
||||||
//{"svg-output", 0, 0, G_OPTION_ARG_FILENAME, &svgname, "Optional path for PDF file", "PATH"},
|
|
||||||
{"mapping", 'm', 0, G_OPTION_ARG_FILENAME, &mappingname, "Path for Layer Mapping File", "PATH" },
|
{"mapping", 'm', 0, G_OPTION_ARG_FILENAME, &mappingname, "Path for Layer Mapping File", "PATH" },
|
||||||
{"cell", 'c', 0, G_OPTION_ARG_STRING, &cellname, "Cell to render", "NAME" },
|
{"cell", 'c', 0, G_OPTION_ARG_STRING, &cellname, "Cell to render", "NAME" },
|
||||||
{"tex-standalone", 'a', 0, G_OPTION_ARG_NONE, &pdf_standalone, "Create standalone PDF", NULL },
|
{"tex-standalone", 'a', 0, G_OPTION_ARG_NONE, &pdf_standalone, "Create standalone PDF", NULL },
|
||||||
{"tex-layers", 'l', 0, G_OPTION_ARG_NONE, &pdf_layers, "Create PDF Layers (OCG)", NULL },
|
{"tex-layers", 'l', 0, G_OPTION_ARG_NONE, &pdf_layers, "Create PDF Layers (OCG)", NULL },
|
||||||
{"custom-render-lib", 'P', 0, G_OPTION_ARG_FILENAME, &custom_library_path, "Path to a custom shared object, that implements the " EXTERNAL_LIBRARY_FUNCTION " function", "PATH"},
|
{"custom-render-lib", 'P', 0, G_OPTION_ARG_FILENAME, &custom_library_path, "Path to a custom shared object, that implements the " EXTERNAL_LIBRARY_FUNCTION " function", "PATH"},
|
||||||
{"external-lib-output", 'e', 0, G_OPTION_ARG_FILENAME, &custom_library_file_name, "Output path for external render library", "PATH"},
|
{NULL}
|
||||||
{ NULL }
|
|
||||||
};
|
};
|
||||||
|
|
||||||
context = g_option_context_new(" FILE - Convert GDS file <FILE> to graphic");
|
context = g_option_context_new(" FILE - Convert GDS file <FILE> to graphic");
|
||||||
@@ -146,49 +271,46 @@ int main(int argc, char **argv)
|
|||||||
exit(1);
|
exit(1);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (version) {
|
||||||
|
print_version();
|
||||||
|
goto ret_status;
|
||||||
|
}
|
||||||
|
|
||||||
if (argc >= 2) {
|
if (argc >= 2) {
|
||||||
if (scale < 1) {
|
if (scale < 1) {
|
||||||
printf("Scale < 1 not allowed. Setting to 1\n");
|
printf("Scale < 1 not allowed. Setting to 1\n");
|
||||||
scale = 1;
|
scale = 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* No format selected */
|
|
||||||
if (!(tikz || pdf || svg))
|
|
||||||
tikz = TRUE;
|
|
||||||
|
|
||||||
/* Get gds name */
|
/* Get gds name */
|
||||||
gds_name = argv[1];
|
gds_name = argv[1];
|
||||||
|
|
||||||
/* Check if PDF/TeX names are supplied. if not generate */
|
/* Print out additional arguments as ignored */
|
||||||
basename = g_path_get_basename(gds_name);
|
for (i = 2; i < argc; i++) {
|
||||||
|
printf("Ignored argument: %s", argv[i]);
|
||||||
|
}
|
||||||
|
|
||||||
if (!texname)
|
app_status =
|
||||||
texname = g_strdup_printf("./%s.tex", basename);
|
command_line_convert_gds(gds_name, cellname, renderer_args, output_paths, mappingname,
|
||||||
|
custom_library_path, pdf_standalone, pdf_layers, scale);
|
||||||
|
|
||||||
if (!pdfname)
|
|
||||||
pdfname = g_strdup_printf("./%s.pdf", basename);
|
|
||||||
|
|
||||||
if (!pdfname)
|
|
||||||
pdfname = g_strdup_printf("./%s.svg", basename);
|
|
||||||
|
|
||||||
command_line_convert_gds(gds_name, pdfname, texname, pdf, tikz,
|
|
||||||
mappingname, cellname, (double)scale,
|
|
||||||
pdf_layers, pdf_standalone, svg, svgname,
|
|
||||||
custom_library_path, custom_library_file_name);
|
|
||||||
/* Clean up */
|
|
||||||
g_free(pdfname);
|
|
||||||
g_free(texname);
|
|
||||||
g_free(svgname);
|
|
||||||
g_free(basename);
|
|
||||||
if (mappingname)
|
|
||||||
g_free(mappingname);
|
|
||||||
if (cellname)
|
|
||||||
g_free(cellname);
|
|
||||||
app_status = 0;
|
|
||||||
} else {
|
} else {
|
||||||
app_status = start_gui(argc, argv);
|
app_status = start_gui(argc, argv);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ret_status:
|
||||||
|
/* If necessary, free command line parameters */
|
||||||
|
if (output_paths)
|
||||||
|
g_strfreev(output_paths);
|
||||||
|
if (renderer_args)
|
||||||
|
g_strfreev(renderer_args);
|
||||||
|
if (mappingname)
|
||||||
|
g_free(mappingname);
|
||||||
|
if (cellname)
|
||||||
|
free(cellname);
|
||||||
|
if (custom_library_path)
|
||||||
|
free(custom_library_path);
|
||||||
|
|
||||||
return app_status;
|
return app_status;
|
||||||
}
|
}
|
||||||
|
@@ -22,17 +22,27 @@
|
|||||||
* @author Mario Hüttel <mario.huettel@gmx.net>
|
* @author Mario Hüttel <mario.huettel@gmx.net>
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/** @addtogroup Cairo-Renderer
|
/** @addtogroup CairoRenderer
|
||||||
* @{
|
* @{
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include "cairo-output.h"
|
|
||||||
#include <math.h>
|
#include <math.h>
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <cairo.h>
|
#include <cairo.h>
|
||||||
#include <cairo-pdf.h>
|
#include <cairo-pdf.h>
|
||||||
#include <cairo-svg.h>
|
#include <cairo-svg.h>
|
||||||
|
|
||||||
|
#include <gds-render/output-renderers/cairo-renderer.h>
|
||||||
|
#include <sys/wait.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
|
||||||
|
struct _CairoRenderer {
|
||||||
|
GdsOutputRenderer parent;
|
||||||
|
gboolean svg; /**< @brief TRUE: SVG output, FALSE: PDF output */
|
||||||
|
};
|
||||||
|
|
||||||
|
G_DEFINE_TYPE(CairoRenderer, cairo_renderer, GDS_RENDER_TYPE_OUTPUT_RENDERER)
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief The cairo_layer struct
|
* @brief The cairo_layer struct
|
||||||
* Each rendered layer is represented by this struct.
|
* Each rendered layer is represented by this struct.
|
||||||
@@ -64,7 +74,7 @@ static void revert_inherited_transform(struct cairo_layer *layers)
|
|||||||
* @param origin Origin translation
|
* @param origin Origin translation
|
||||||
* @param magnification Scaling
|
* @param magnification Scaling
|
||||||
* @param flipping Mirror image on x-axis before rotating
|
* @param flipping Mirror image on x-axis before rotating
|
||||||
* @param rotation Rotattion in degrees
|
* @param rotation Rotation in degrees
|
||||||
* @param scale Scale the image down by. Only used for sclaing origin coordinates. Not applied to layer.
|
* @param scale Scale the image down by. Only used for sclaing origin coordinates. Not applied to layer.
|
||||||
*/
|
*/
|
||||||
static void apply_inherited_transform_to_all_layers(struct cairo_layer *layers,
|
static void apply_inherited_transform_to_all_layers(struct cairo_layer *layers,
|
||||||
@@ -130,7 +140,9 @@ static void render_cell(struct gds_cell *cell, struct cairo_layer *layers, doubl
|
|||||||
/* Get layer renderer */
|
/* Get layer renderer */
|
||||||
if (gfx->layer >= MAX_LAYERS)
|
if (gfx->layer >= MAX_LAYERS)
|
||||||
continue;
|
continue;
|
||||||
if ((cr = layers[gfx->layer].cr) == NULL)
|
|
||||||
|
cr = layers[gfx->layer].cr;
|
||||||
|
if (cr == NULL)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
/* Apply settings */
|
/* Apply settings */
|
||||||
@@ -157,7 +169,6 @@ static void render_cell(struct gds_cell *cell, struct cairo_layer *layers, doubl
|
|||||||
cairo_move_to(cr, vertex->x/scale, vertex->y/scale);
|
cairo_move_to(cr, vertex->x/scale, vertex->y/scale);
|
||||||
else
|
else
|
||||||
cairo_line_to(cr, vertex->x/scale, vertex->y/scale);
|
cairo_line_to(cr, vertex->x/scale, vertex->y/scale);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Create graphics object */
|
/* Create graphics object */
|
||||||
@@ -173,15 +184,23 @@ static void render_cell(struct gds_cell *cell, struct cairo_layer *layers, doubl
|
|||||||
cairo_fill(cr);
|
cairo_fill(cr);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
} /* for gfx list */
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void cairo_render_cell_to_vector_file(struct gds_cell *cell, GList *layer_infos, char *pdf_file, char *svg_file, double scale)
|
/**
|
||||||
|
* @brief Render \p cell to a PDF file specified by \p pdf_file
|
||||||
|
* @param cell Toplevel cell to @ref Cairo-Renderer
|
||||||
|
* @param layer_infos List of layer information. Specifies color and layer stacking
|
||||||
|
* @param pdf_file PDF output file. Set to NULL if no PDF file has to be generated
|
||||||
|
* @param svg_file SVG output file. Set to NULL if no SVG file has to be generated
|
||||||
|
* @param scale Scale the output image down by \p scale
|
||||||
|
* @return Error
|
||||||
|
*/
|
||||||
|
static int cairo_renderer_render_cell_to_vector_file(struct gds_cell *cell, GList *layer_infos, const char *pdf_file,
|
||||||
|
const char *svg_file, double scale)
|
||||||
{
|
{
|
||||||
cairo_surface_t *pdf_surface, *svg_surface;
|
cairo_surface_t *pdf_surface = NULL, *svg_surface = NULL;
|
||||||
cairo_t *pdf_cr, *svg_cr;
|
cairo_t *pdf_cr = NULL, *svg_cr = NULL;
|
||||||
struct layer_info *linfo;
|
struct layer_info *linfo;
|
||||||
struct cairo_layer *layers;
|
struct cairo_layer *layers;
|
||||||
struct cairo_layer *lay;
|
struct cairo_layer *lay;
|
||||||
@@ -189,10 +208,24 @@ void cairo_render_cell_to_vector_file(struct gds_cell *cell, GList *layer_infos,
|
|||||||
int i;
|
int i;
|
||||||
double rec_x0, rec_y0, rec_width, rec_height;
|
double rec_x0, rec_y0, rec_width, rec_height;
|
||||||
double xmin = INT32_MAX, xmax = INT32_MIN, ymin = INT32_MAX, ymax = INT32_MIN;
|
double xmin = INT32_MAX, xmax = INT32_MIN, ymin = INT32_MAX, ymax = INT32_MIN;
|
||||||
|
pid_t process_id;
|
||||||
|
|
||||||
if (pdf_file == NULL && svg_file == NULL) {
|
if (pdf_file == NULL && svg_file == NULL) {
|
||||||
/* No output specified */
|
/* No output specified */
|
||||||
return;
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Fork to a new child process. This ensures the memory leaks (see issue #16) in Cairo don't
|
||||||
|
* brick everything.
|
||||||
|
*
|
||||||
|
* And by the way: This now bricks all Windows compatibility. Deal with it.
|
||||||
|
*/
|
||||||
|
process_id = fork();
|
||||||
|
if (process_id < 0) {
|
||||||
|
/* Well... shit... We have to run it in our process. */
|
||||||
|
} else if (process_id > 0) {
|
||||||
|
/* Woohoo... Successfully dumped the shitty code to an unknowing victim */
|
||||||
|
goto ret_parent;
|
||||||
}
|
}
|
||||||
|
|
||||||
layers = (struct cairo_layer *)calloc(MAX_LAYERS, sizeof(struct cairo_layer));
|
layers = (struct cairo_layer *)calloc(MAX_LAYERS, sizeof(struct cairo_layer));
|
||||||
@@ -206,7 +239,7 @@ void cairo_render_cell_to_vector_file(struct gds_cell *cell, GList *layer_infos,
|
|||||||
/* Create recording surface for each layer */
|
/* Create recording surface for each layer */
|
||||||
for (info_list = layer_infos; info_list != NULL; info_list = g_list_next(info_list)) {
|
for (info_list = layer_infos; info_list != NULL; info_list = g_list_next(info_list)) {
|
||||||
linfo = (struct layer_info *)info_list->data;
|
linfo = (struct layer_info *)info_list->data;
|
||||||
if (linfo->layer < MAX_LAYERS) {
|
if (linfo->layer < MAX_LAYERS && linfo->render) {
|
||||||
lay = &(layers[(unsigned int)linfo->layer]);
|
lay = &(layers[(unsigned int)linfo->layer]);
|
||||||
lay->linfo = linfo;
|
lay->linfo = linfo;
|
||||||
lay->rec = cairo_recording_surface_create(CAIRO_CONTENT_COLOR_ALPHA,
|
lay->rec = cairo_recording_surface_create(CAIRO_CONTENT_COLOR_ALPHA,
|
||||||
@@ -232,11 +265,18 @@ void cairo_render_cell_to_vector_file(struct gds_cell *cell, GList *layer_infos,
|
|||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (!linfo->render)
|
||||||
|
continue;
|
||||||
|
|
||||||
/* Print size */
|
/* Print size */
|
||||||
cairo_recording_surface_ink_extents(layers[linfo->layer].rec, &rec_x0, &rec_y0,
|
cairo_recording_surface_ink_extents(layers[linfo->layer].rec, &rec_x0, &rec_y0,
|
||||||
&rec_width, &rec_height);
|
&rec_width, &rec_height);
|
||||||
printf("Size of layer %d: %lf -- %lf\n", linfo->layer,
|
printf("Size of layer %d%s%s%s: <%lf x %lf> @ (%lf | %lf)\n",
|
||||||
rec_width, rec_height);
|
linfo->layer,
|
||||||
|
(linfo->name && linfo->name[0] ? " (" : ""),
|
||||||
|
(linfo->name && linfo->name[0] ? linfo->name : ""),
|
||||||
|
(linfo->name && linfo->name[0] ? ")" : ""),
|
||||||
|
rec_width, rec_height, rec_x0, rec_y0);
|
||||||
|
|
||||||
/* update bounding box */
|
/* update bounding box */
|
||||||
xmin = MIN(xmin, rec_x0);
|
xmin = MIN(xmin, rec_x0);
|
||||||
@@ -250,7 +290,7 @@ void cairo_render_cell_to_vector_file(struct gds_cell *cell, GList *layer_infos,
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
printf("Bounding box: (%lf,%lf) -- (%lf,%lf)\n", xmin, ymin, xmax, ymax);
|
printf("Cell bounding box: (%lf | %lf) -- (%lf | %lf)\n", xmin, ymin, xmax, ymax);
|
||||||
|
|
||||||
if (pdf_file) {
|
if (pdf_file) {
|
||||||
pdf_surface = cairo_pdf_surface_create(pdf_file, xmax-xmin, ymax-ymin);
|
pdf_surface = cairo_pdf_surface_create(pdf_file, xmax-xmin, ymax-ymin);
|
||||||
@@ -271,16 +311,18 @@ void cairo_render_cell_to_vector_file(struct gds_cell *cell, GList *layer_infos,
|
|||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (pdf_file) {
|
if (!linfo->render)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
if (pdf_file && pdf_cr) {
|
||||||
cairo_set_source_surface(pdf_cr, layers[linfo->layer].rec, -xmin, -ymin);
|
cairo_set_source_surface(pdf_cr, layers[linfo->layer].rec, -xmin, -ymin);
|
||||||
cairo_paint_with_alpha(pdf_cr, linfo->color.alpha);
|
cairo_paint_with_alpha(pdf_cr, linfo->color.alpha);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (svg_file) {
|
if (svg_file && svg_cr) {
|
||||||
cairo_set_source_surface(svg_cr, layers[linfo->layer].rec, -xmin, -ymin);
|
cairo_set_source_surface(svg_cr, layers[linfo->layer].rec, -xmin, -ymin);
|
||||||
cairo_paint_with_alpha(svg_cr, linfo->color.alpha);
|
cairo_paint_with_alpha(svg_cr, linfo->color.alpha);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (pdf_file) {
|
if (pdf_file) {
|
||||||
@@ -305,7 +347,85 @@ ret_clear_layers:
|
|||||||
}
|
}
|
||||||
free(layers);
|
free(layers);
|
||||||
|
|
||||||
printf("cairo export finished. It might still be buggy!\n");
|
printf("Cairo export finished. It might still be buggy!\n");
|
||||||
|
|
||||||
|
/* If forked, suspend process */
|
||||||
|
if (process_id == 0)
|
||||||
|
exit(0);
|
||||||
|
|
||||||
|
/* Fork didn't work. Just return here */
|
||||||
|
return 0;
|
||||||
|
ret_parent:
|
||||||
|
waitpid(process_id, NULL, 0);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void cairo_renderer_init(CairoRenderer *self)
|
||||||
|
{
|
||||||
|
/* PDF default */
|
||||||
|
self->svg = FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int cairo_renderer_render_output(GdsOutputRenderer *renderer,
|
||||||
|
struct gds_cell *cell,
|
||||||
|
double scale)
|
||||||
|
{
|
||||||
|
CairoRenderer *c_renderer = GDS_RENDER_CAIRO_RENDERER(renderer);
|
||||||
|
const char *pdf_file = NULL;
|
||||||
|
const char *svg_file = NULL;
|
||||||
|
LayerSettings *settings;
|
||||||
|
GList *layer_infos = NULL;
|
||||||
|
const char *output_file;
|
||||||
|
int ret;
|
||||||
|
|
||||||
|
if (!c_renderer)
|
||||||
|
return -2000;
|
||||||
|
|
||||||
|
output_file = gds_output_renderer_get_output_file(renderer);
|
||||||
|
settings = gds_output_renderer_get_and_ref_layer_settings(renderer);
|
||||||
|
|
||||||
|
/* Set layer info list. In case of failure it remains NULL */
|
||||||
|
if (settings)
|
||||||
|
layer_infos = layer_settings_get_layer_info_list(settings);
|
||||||
|
|
||||||
|
if (c_renderer->svg == TRUE)
|
||||||
|
svg_file = output_file;
|
||||||
|
else
|
||||||
|
pdf_file = output_file;
|
||||||
|
|
||||||
|
ret = cairo_renderer_render_cell_to_vector_file(cell, layer_infos, pdf_file, svg_file, scale);
|
||||||
|
|
||||||
|
if (settings)
|
||||||
|
g_object_unref(settings);
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void cairo_renderer_class_init(CairoRendererClass *klass)
|
||||||
|
{
|
||||||
|
GdsOutputRendererClass *renderer_class = GDS_RENDER_OUTPUT_RENDERER_CLASS(klass);
|
||||||
|
|
||||||
|
renderer_class->render_output = cairo_renderer_render_output;
|
||||||
|
}
|
||||||
|
|
||||||
|
CairoRenderer *cairo_renderer_new_pdf()
|
||||||
|
{
|
||||||
|
CairoRenderer *renderer;
|
||||||
|
|
||||||
|
renderer = GDS_RENDER_CAIRO_RENDERER(g_object_new(GDS_RENDER_TYPE_CAIRO_RENDERER, NULL));
|
||||||
|
renderer->svg = FALSE;
|
||||||
|
|
||||||
|
return renderer;
|
||||||
|
}
|
||||||
|
|
||||||
|
CairoRenderer *cairo_renderer_new_svg()
|
||||||
|
{
|
||||||
|
CairoRenderer *renderer;
|
||||||
|
|
||||||
|
renderer = GDS_RENDER_CAIRO_RENDERER(g_object_new(GDS_RENDER_TYPE_CAIRO_RENDERER, NULL));
|
||||||
|
renderer->svg = TRUE;
|
||||||
|
|
||||||
|
return renderer;
|
||||||
}
|
}
|
||||||
|
|
||||||
/** @} */
|
/** @} */
|
213
output-renderers/external-renderer.c
Normal file
213
output-renderers/external-renderer.c
Normal file
@@ -0,0 +1,213 @@
|
|||||||
|
/*
|
||||||
|
* 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/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @file external-renderer.c
|
||||||
|
* @brief This file implements the dynamic library loading for the external rendering feature
|
||||||
|
* @author Mario Hüttel <mario.huettel@gmx.net>
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @addtogroup ExternalRenderer
|
||||||
|
* @{
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <dlfcn.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
|
||||||
|
#include <gds-render/output-renderers/external-renderer.h>
|
||||||
|
|
||||||
|
struct _ExternalRenderer {
|
||||||
|
GdsOutputRenderer parent;
|
||||||
|
char *shared_object_path;
|
||||||
|
};
|
||||||
|
|
||||||
|
enum {
|
||||||
|
PROP_SO_PATH = 1, /**< @brief Shared object path property */
|
||||||
|
N_PROPERTIES /**< @brief Used to get property count */
|
||||||
|
};
|
||||||
|
|
||||||
|
G_DEFINE_TYPE(ExternalRenderer, external_renderer, GDS_RENDER_TYPE_OUTPUT_RENDERER)
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Execute render function in shared object to render the supplied cell
|
||||||
|
* @param toplevel_cell Cell to render
|
||||||
|
* @param layer_info_list Layer information (Color etc.)
|
||||||
|
* @param output_file Destination file
|
||||||
|
* @param so_path Path to shared object
|
||||||
|
* @return 0 if successful
|
||||||
|
*/
|
||||||
|
static int external_renderer_render_cell(struct gds_cell *toplevel_cell, GList *layer_info_list,
|
||||||
|
const char *output_file, double scale, const char *so_path)
|
||||||
|
{
|
||||||
|
int (*so_render_func)(struct gds_cell *, GList *, const char *, double) = NULL;
|
||||||
|
void *so_handle = NULL;
|
||||||
|
char *error_msg;
|
||||||
|
int ret = 0;
|
||||||
|
|
||||||
|
if (!so_path) {
|
||||||
|
fprintf(stderr, "Path to shared object not set!\n");
|
||||||
|
return -3000;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Check parameter sanity */
|
||||||
|
if (!output_file || !toplevel_cell || !layer_info_list)
|
||||||
|
return -3000;
|
||||||
|
|
||||||
|
/* Load shared object */
|
||||||
|
so_handle = dlopen(so_path, RTLD_LAZY);
|
||||||
|
if (!so_handle) {
|
||||||
|
fprintf(stderr, "Could not load external library '%s'\nDetailed error is:\n%s\n", so_path, dlerror());
|
||||||
|
return -2000;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Load symbol from library */
|
||||||
|
so_render_func = (int (*)(struct gds_cell *, GList *, const char *, double))dlsym(so_handle, EXTERNAL_LIBRARY_FUNCTION);
|
||||||
|
error_msg = dlerror();
|
||||||
|
if (error_msg != NULL) {
|
||||||
|
fprintf(stderr, "Rendering function not found in library:\n%s\n", error_msg);
|
||||||
|
goto ret_close_so_handle;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Execute */
|
||||||
|
if (so_render_func) {
|
||||||
|
g_message("Calling external renderer.");
|
||||||
|
ret = so_render_func(toplevel_cell, layer_info_list, output_file, scale);
|
||||||
|
g_message("External renderer finished.");
|
||||||
|
}
|
||||||
|
|
||||||
|
ret_close_so_handle:
|
||||||
|
dlclose(so_handle);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int external_renderer_render_output(GdsOutputRenderer *renderer,
|
||||||
|
struct gds_cell *cell,
|
||||||
|
double scale)
|
||||||
|
{
|
||||||
|
ExternalRenderer *ext_renderer = GDS_RENDER_EXTERNAL_RENDERER(renderer);
|
||||||
|
LayerSettings *settings;
|
||||||
|
GList *layer_infos = NULL;
|
||||||
|
const char *output_file;
|
||||||
|
int ret;
|
||||||
|
|
||||||
|
output_file = gds_output_renderer_get_output_file(renderer);
|
||||||
|
settings = gds_output_renderer_get_and_ref_layer_settings(renderer);
|
||||||
|
|
||||||
|
/* Set layer info list. In case of failure it remains NULL */
|
||||||
|
if (settings)
|
||||||
|
layer_infos = layer_settings_get_layer_info_list(settings);
|
||||||
|
|
||||||
|
ret = external_renderer_render_cell(cell, layer_infos, output_file, scale, ext_renderer->shared_object_path);
|
||||||
|
if (settings)
|
||||||
|
g_object_unref(settings);
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void external_renderer_get_property(GObject *obj, guint property_id, GValue *value, GParamSpec *pspec)
|
||||||
|
{
|
||||||
|
ExternalRenderer *self;
|
||||||
|
|
||||||
|
self = GDS_RENDER_EXTERNAL_RENDERER(obj);
|
||||||
|
|
||||||
|
switch (property_id) {
|
||||||
|
case PROP_SO_PATH:
|
||||||
|
g_value_set_string(value, self->shared_object_path);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
G_OBJECT_WARN_INVALID_PROPERTY_ID (obj, property_id, pspec);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void external_renderer_set_property(GObject *obj, guint property_id, const GValue *value, GParamSpec *pspec)
|
||||||
|
{
|
||||||
|
ExternalRenderer *self;
|
||||||
|
|
||||||
|
self = GDS_RENDER_EXTERNAL_RENDERER(obj);
|
||||||
|
|
||||||
|
switch (property_id) {
|
||||||
|
case PROP_SO_PATH:
|
||||||
|
if (self->shared_object_path)
|
||||||
|
g_free(self->shared_object_path);
|
||||||
|
self->shared_object_path = g_value_dup_string(value);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
G_OBJECT_WARN_INVALID_PROPERTY_ID(obj, property_id, pspec);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void external_renderer_dispose(GObject *self_obj)
|
||||||
|
{
|
||||||
|
ExternalRenderer *self = GDS_RENDER_EXTERNAL_RENDERER(self_obj);
|
||||||
|
|
||||||
|
if (self->shared_object_path) {
|
||||||
|
g_free(self->shared_object_path);
|
||||||
|
self->shared_object_path = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
G_OBJECT_CLASS(external_renderer_parent_class)->dispose(self_obj);
|
||||||
|
}
|
||||||
|
|
||||||
|
static GParamSpec *external_renderer_properties[N_PROPERTIES] = {NULL};
|
||||||
|
|
||||||
|
static void external_renderer_class_init(ExternalRendererClass *klass)
|
||||||
|
{
|
||||||
|
GdsOutputRendererClass *inherited_parent_class;
|
||||||
|
GObjectClass *oclass;
|
||||||
|
|
||||||
|
inherited_parent_class = GDS_RENDER_OUTPUT_RENDERER_CLASS(klass);
|
||||||
|
oclass = G_OBJECT_CLASS(klass);
|
||||||
|
|
||||||
|
/* Override virtual function */
|
||||||
|
inherited_parent_class->render_output = external_renderer_render_output;
|
||||||
|
|
||||||
|
/* Setup Gobject callbacks */
|
||||||
|
oclass->set_property = external_renderer_set_property;
|
||||||
|
oclass->get_property = external_renderer_get_property;
|
||||||
|
oclass->dispose = external_renderer_dispose;
|
||||||
|
|
||||||
|
/* Setup properties */
|
||||||
|
external_renderer_properties[PROP_SO_PATH] =
|
||||||
|
g_param_spec_string("shared-object-path",
|
||||||
|
"Shared object file path",
|
||||||
|
"Path to the shared object to search rendering function in.",
|
||||||
|
NULL,
|
||||||
|
G_PARAM_READWRITE);
|
||||||
|
g_object_class_install_properties(oclass, N_PROPERTIES, external_renderer_properties);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void external_renderer_init(ExternalRenderer *self)
|
||||||
|
{
|
||||||
|
self->shared_object_path = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
ExternalRenderer *external_renderer_new()
|
||||||
|
{
|
||||||
|
return g_object_new(GDS_RENDER_TYPE_EXTERNAL_RENDERER, NULL);
|
||||||
|
}
|
||||||
|
|
||||||
|
ExternalRenderer *external_renderer_new_with_so(const char *so_path)
|
||||||
|
{
|
||||||
|
return g_object_new(GDS_RENDER_TYPE_EXTERNAL_RENDERER, "shared-object-path", so_path, NULL);
|
||||||
|
}
|
||||||
|
|
||||||
|
/** @} */
|
322
output-renderers/gds-output-renderer.c
Normal file
322
output-renderers/gds-output-renderer.c
Normal file
@@ -0,0 +1,322 @@
|
|||||||
|
/*
|
||||||
|
* GDSII-Converter
|
||||||
|
* Copyright (C) 2019 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/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @file gds-output-renderer.c
|
||||||
|
* @brief Base GObject class for output renderers
|
||||||
|
*
|
||||||
|
* All output renderers are derived from this class
|
||||||
|
*
|
||||||
|
* @author Mario Hüttel <mario.huettel@gmx.net>
|
||||||
|
*/
|
||||||
|
|
||||||
|
/** @addtogroup GdsOutputRenderer
|
||||||
|
* @{
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <gds-render/output-renderers/gds-output-renderer.h>
|
||||||
|
#include <gds-render/layer/layer-info.h>
|
||||||
|
|
||||||
|
struct renderer_params {
|
||||||
|
struct gds_cell *cell;
|
||||||
|
double scale;
|
||||||
|
};
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
gchar *output_file;
|
||||||
|
LayerSettings *layer_settings;
|
||||||
|
GMutex settings_lock;
|
||||||
|
gboolean mutex_init_status;
|
||||||
|
GThread *thread;
|
||||||
|
struct renderer_params async_params;
|
||||||
|
gpointer padding[11];
|
||||||
|
} GdsOutputRendererPrivate;
|
||||||
|
|
||||||
|
enum {
|
||||||
|
PROP_OUTPUT_FILE = 1,
|
||||||
|
PROP_LAYER_SETTINGS,
|
||||||
|
N_PROPERTIES
|
||||||
|
};
|
||||||
|
|
||||||
|
G_DEFINE_TYPE_WITH_PRIVATE(GdsOutputRenderer, gds_output_renderer, G_TYPE_OBJECT)
|
||||||
|
|
||||||
|
enum gds_output_renderer_signal_ids {THREAD_JOINED = 0, GDS_OUTPUT_RENDERER_SIGNAL_COUNT};
|
||||||
|
static guint gds_output_renderer_signals[GDS_OUTPUT_RENDERER_SIGNAL_COUNT];
|
||||||
|
|
||||||
|
static int gds_output_renderer_render_dummy(GdsOutputRenderer *renderer,
|
||||||
|
struct gds_cell *cell,
|
||||||
|
double scale)
|
||||||
|
{
|
||||||
|
(void)renderer;
|
||||||
|
(void)cell;
|
||||||
|
(void)scale;
|
||||||
|
|
||||||
|
g_warning("Output renderer does not define a render_output function!");
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void gds_output_renderer_dispose(GObject *self_obj)
|
||||||
|
{
|
||||||
|
GdsOutputRenderer *renderer = GDS_RENDER_OUTPUT_RENDERER(self_obj);
|
||||||
|
GdsOutputRendererPrivate *priv;
|
||||||
|
|
||||||
|
priv = gds_output_renderer_get_instance_private(renderer);
|
||||||
|
|
||||||
|
if (priv->mutex_init_status) {
|
||||||
|
/* Try locking the mutex, to test if it's free */
|
||||||
|
g_mutex_lock(&priv->settings_lock);
|
||||||
|
g_mutex_unlock(&priv->settings_lock);
|
||||||
|
g_mutex_clear(&priv->settings_lock);
|
||||||
|
priv->mutex_init_status = FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (priv->output_file)
|
||||||
|
g_free(priv->output_file);
|
||||||
|
|
||||||
|
g_clear_object(&priv->layer_settings);
|
||||||
|
|
||||||
|
/* Chain up to parent class */
|
||||||
|
G_OBJECT_CLASS(gds_output_renderer_parent_class)->dispose(self_obj);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void gds_output_renderer_get_property(GObject *obj, guint property_id, GValue *value, GParamSpec *pspec)
|
||||||
|
{
|
||||||
|
GdsOutputRenderer *self = GDS_RENDER_OUTPUT_RENDERER(obj);
|
||||||
|
GdsOutputRendererPrivate *priv;
|
||||||
|
|
||||||
|
priv = gds_output_renderer_get_instance_private(self);
|
||||||
|
|
||||||
|
switch (property_id) {
|
||||||
|
case PROP_OUTPUT_FILE:
|
||||||
|
g_value_set_string(value, priv->output_file);
|
||||||
|
break;
|
||||||
|
case PROP_LAYER_SETTINGS:
|
||||||
|
g_value_set_object(value, priv->layer_settings);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
G_OBJECT_WARN_INVALID_PROPERTY_ID(obj, property_id, pspec);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void gds_output_renderer_set_property(GObject *obj, guint property_id, const GValue *value, GParamSpec *pspec)
|
||||||
|
{
|
||||||
|
GdsOutputRenderer *self = GDS_RENDER_OUTPUT_RENDERER(obj);
|
||||||
|
GdsOutputRendererPrivate *priv;
|
||||||
|
|
||||||
|
priv = gds_output_renderer_get_instance_private(self);
|
||||||
|
|
||||||
|
switch (property_id) {
|
||||||
|
case PROP_OUTPUT_FILE:
|
||||||
|
g_mutex_lock(&priv->settings_lock);
|
||||||
|
if (priv->output_file)
|
||||||
|
g_free(priv->output_file);
|
||||||
|
priv->output_file = g_strdup(g_value_get_string(value));
|
||||||
|
g_mutex_unlock(&priv->settings_lock);
|
||||||
|
break;
|
||||||
|
case PROP_LAYER_SETTINGS:
|
||||||
|
g_mutex_lock(&priv->settings_lock);
|
||||||
|
g_clear_object(&priv->layer_settings);
|
||||||
|
priv->layer_settings = g_value_get_object(value);
|
||||||
|
g_object_ref(priv->layer_settings);
|
||||||
|
g_mutex_unlock(&priv->settings_lock);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
G_OBJECT_WARN_INVALID_PROPERTY_ID(obj, property_id, pspec);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static GParamSpec *gds_output_renderer_properties[N_PROPERTIES] = {NULL};
|
||||||
|
|
||||||
|
static void gds_output_renderer_class_init(GdsOutputRendererClass *klass)
|
||||||
|
{
|
||||||
|
GObjectClass *oclass = G_OBJECT_CLASS(klass);
|
||||||
|
|
||||||
|
klass->render_output = gds_output_renderer_render_dummy;
|
||||||
|
|
||||||
|
oclass->dispose = gds_output_renderer_dispose;
|
||||||
|
oclass->set_property = gds_output_renderer_set_property;
|
||||||
|
oclass->get_property = gds_output_renderer_get_property;
|
||||||
|
|
||||||
|
/* Setup properties */
|
||||||
|
gds_output_renderer_properties[PROP_OUTPUT_FILE] =
|
||||||
|
g_param_spec_string("output-file", "output file", "Output file for renderer",
|
||||||
|
NULL, G_PARAM_READWRITE);
|
||||||
|
gds_output_renderer_properties[PROP_LAYER_SETTINGS] =
|
||||||
|
g_param_spec_object("layer-settings", "Layer Settings object",
|
||||||
|
"Object containing the layer rendering information",
|
||||||
|
GDS_RENDER_TYPE_LAYER_SETTINGS, G_PARAM_READWRITE);
|
||||||
|
g_object_class_install_properties(oclass, N_PROPERTIES, gds_output_renderer_properties);
|
||||||
|
|
||||||
|
/* Setup output signals */
|
||||||
|
gds_output_renderer_signals[THREAD_JOINED] =
|
||||||
|
g_signal_newv("thread-joined", GDS_RENDER_TYPE_OUTPUT_RENDERER,
|
||||||
|
G_SIGNAL_RUN_LAST | G_SIGNAL_NO_RECURSE,
|
||||||
|
NULL,
|
||||||
|
NULL,
|
||||||
|
NULL,
|
||||||
|
NULL,
|
||||||
|
G_TYPE_NONE,
|
||||||
|
0,
|
||||||
|
NULL);
|
||||||
|
}
|
||||||
|
|
||||||
|
void gds_output_renderer_init(GdsOutputRenderer *self)
|
||||||
|
{
|
||||||
|
GdsOutputRendererPrivate *priv;
|
||||||
|
|
||||||
|
priv = gds_output_renderer_get_instance_private(self);
|
||||||
|
|
||||||
|
priv->layer_settings = NULL;
|
||||||
|
priv->output_file = NULL;
|
||||||
|
priv->thread = NULL;
|
||||||
|
priv->mutex_init_status = TRUE;
|
||||||
|
g_mutex_init(&priv->settings_lock);
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
GdsOutputRenderer *gds_output_renderer_new()
|
||||||
|
{
|
||||||
|
return GDS_RENDER_OUTPUT_RENDERER(g_object_new(GDS_RENDER_TYPE_OUTPUT_RENDERER, NULL));
|
||||||
|
}
|
||||||
|
|
||||||
|
GdsOutputRenderer *gds_output_renderer_new_with_props(const char *output_file, LayerSettings *layer_settings)
|
||||||
|
{
|
||||||
|
return GDS_RENDER_OUTPUT_RENDERER(g_object_new(GDS_RENDER_TYPE_OUTPUT_RENDERER,
|
||||||
|
"layer-settings", layer_settings,
|
||||||
|
"output-file", output_file,
|
||||||
|
NULL));
|
||||||
|
}
|
||||||
|
|
||||||
|
void gds_output_renderer_set_output_file(GdsOutputRenderer *renderer, const gchar *file_name)
|
||||||
|
{
|
||||||
|
g_return_if_fail(GDS_RENDER_IS_OUTPUT_RENDERER(renderer));
|
||||||
|
|
||||||
|
/* Check if the filename is actually filled */
|
||||||
|
if (!file_name || !file_name[0])
|
||||||
|
return;
|
||||||
|
g_object_set(renderer, "output-file", file_name, NULL);
|
||||||
|
}
|
||||||
|
|
||||||
|
const char *gds_output_renderer_get_output_file(GdsOutputRenderer *renderer)
|
||||||
|
{
|
||||||
|
const char *file = NULL;
|
||||||
|
|
||||||
|
g_object_get(renderer, "output-file", &file, NULL);
|
||||||
|
return file;
|
||||||
|
}
|
||||||
|
|
||||||
|
LayerSettings *gds_output_renderer_get_and_ref_layer_settings(GdsOutputRenderer *renderer)
|
||||||
|
{
|
||||||
|
LayerSettings *ret = NULL;
|
||||||
|
GdsOutputRendererPrivate *priv;
|
||||||
|
|
||||||
|
priv = gds_output_renderer_get_instance_private(renderer);
|
||||||
|
|
||||||
|
/* Acquire settings lock */
|
||||||
|
g_mutex_lock(&priv->settings_lock);
|
||||||
|
|
||||||
|
g_object_get(renderer, "layer-settings", &ret, NULL);
|
||||||
|
/* Reference it, so it is not cleared by another thread overwriting the property */
|
||||||
|
g_object_ref(ret);
|
||||||
|
|
||||||
|
/* It is now safe to clear the lock */
|
||||||
|
g_mutex_unlock(&priv->settings_lock);
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
void gds_output_renderer_set_layer_settings(GdsOutputRenderer *renderer, LayerSettings *settings)
|
||||||
|
{
|
||||||
|
g_return_if_fail(GDS_RENDER_IS_LAYER_SETTINGS(settings));
|
||||||
|
|
||||||
|
g_object_set(renderer, "layer_settings", settings, NULL);
|
||||||
|
}
|
||||||
|
|
||||||
|
int gds_output_renderer_render_output(GdsOutputRenderer *renderer, struct gds_cell *cell, double scale)
|
||||||
|
{
|
||||||
|
int ret;
|
||||||
|
GdsOutputRendererClass *klass;
|
||||||
|
GdsOutputRendererPrivate *priv = gds_output_renderer_get_instance_private(renderer);
|
||||||
|
|
||||||
|
if (GDS_RENDER_IS_OUTPUT_RENDERER(renderer) == FALSE) {
|
||||||
|
g_error("Output Renderer not valid.");
|
||||||
|
return GDS_OUTPUT_RENDERER_GEN_ERR;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!priv->output_file || !priv->output_file[0]) {
|
||||||
|
g_error("No/invalid output file set.");
|
||||||
|
return GDS_OUTPUT_RENDERER_GEN_ERR;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!priv->layer_settings) {
|
||||||
|
g_error("No layer specification supplied.");
|
||||||
|
return GDS_OUTPUT_RENDERER_GEN_ERR;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!cell) {
|
||||||
|
g_error("Output renderer called without cell to render.");
|
||||||
|
return GDS_OUTPUT_RENDERER_PARAM_ERR;
|
||||||
|
}
|
||||||
|
|
||||||
|
klass = GDS_RENDER_OUTPUT_RENDERER_GET_CLASS(renderer);
|
||||||
|
if (klass->render_output == NULL) {
|
||||||
|
g_critical("Output Renderer: Rendering function broken. This is a bug.");
|
||||||
|
return GDS_OUTPUT_RENDERER_GEN_ERR;
|
||||||
|
}
|
||||||
|
|
||||||
|
ret = klass->render_output(renderer, cell, scale);
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int gds_output_renderer_async_wrapper(gpointer data)
|
||||||
|
{
|
||||||
|
GdsOutputRenderer *renderer;
|
||||||
|
GdsOutputRendererPrivate *priv;
|
||||||
|
int ret;
|
||||||
|
|
||||||
|
renderer = GDS_RENDER_OUTPUT_RENDERER(data);
|
||||||
|
priv = gds_output_renderer_get_instance_private(renderer);
|
||||||
|
if (!priv)
|
||||||
|
return -1000;
|
||||||
|
|
||||||
|
if(!priv->mutex_init_status)
|
||||||
|
return -1001;
|
||||||
|
|
||||||
|
g_mutex_lock(&priv->settings_lock);
|
||||||
|
ret = gds_output_renderer_render_output(renderer, priv->async_params.cell, priv->async_params.scale);
|
||||||
|
g_mutex_unlock(&priv->settings_lock);
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
int gds_output_renderer_render_output_async(GdsOutputRenderer *renderer, struct gds_cell *cell, double scale)
|
||||||
|
{
|
||||||
|
GdsOutputRendererPrivate *priv;
|
||||||
|
int ret = -1;
|
||||||
|
|
||||||
|
priv = gds_output_renderer_get_instance_private(renderer);
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** @} */
|
@@ -23,15 +23,34 @@
|
|||||||
* @author Mario Hüttel <mario.huettel@gmx.net>
|
* @author Mario Hüttel <mario.huettel@gmx.net>
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include "latex-output.h"
|
|
||||||
#include <math.h>
|
#include <math.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <gds-render/output-renderers/latex-renderer.h>
|
||||||
|
#include <gdk/gdk.h>
|
||||||
|
#include <gds-render/layer/layer-info.h>
|
||||||
/**
|
/**
|
||||||
* @addtogroup LaTeX-Renderer
|
* @addtogroup LatexRenderer
|
||||||
* @{
|
* @{
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/** @brief Writes a GString \p buffer to the fixed file tex_file */
|
struct _LatexRenderer {
|
||||||
|
GdsOutputRenderer parent;
|
||||||
|
gboolean tex_standalone;
|
||||||
|
gboolean pdf_layers;
|
||||||
|
};
|
||||||
|
|
||||||
|
G_DEFINE_TYPE(LatexRenderer, latex_renderer, GDS_RENDER_TYPE_OUTPUT_RENDERER)
|
||||||
|
|
||||||
|
enum {
|
||||||
|
PROP_STANDALONE = 1,
|
||||||
|
PROP_PDF_LAYERS,
|
||||||
|
N_PROPERTIES
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Writes a GString \p buffer to the fixed file tex_file
|
||||||
|
* @note This is a convinience macro. Do not use this anywhere else. It might change behavior in futurtre releases
|
||||||
|
*/
|
||||||
#define WRITEOUT_BUFFER(buff) fwrite((buff)->str, sizeof(char), (buff)->len, tex_file)
|
#define WRITEOUT_BUFFER(buff) fwrite((buff)->str, sizeof(char), (buff)->len, tex_file)
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -50,10 +69,13 @@ static void write_layer_definitions(FILE *tex_file, GList *layer_infos, GString
|
|||||||
{
|
{
|
||||||
GList *list;
|
GList *list;
|
||||||
struct layer_info *lifo;
|
struct layer_info *lifo;
|
||||||
char *end_str;
|
|
||||||
|
|
||||||
for (list = layer_infos; list != NULL; list = list->next) {
|
for (list = layer_infos; list != NULL; list = list->next) {
|
||||||
lifo = (struct layer_info *)list->data;
|
lifo = (struct layer_info *)list->data;
|
||||||
|
|
||||||
|
if (!lifo->render)
|
||||||
|
continue;
|
||||||
|
|
||||||
g_string_printf(buffer, "\\pgfdeclarelayer{l%d}\n\\definecolor{c%d}{rgb}{%lf,%lf,%lf}\n",
|
g_string_printf(buffer, "\\pgfdeclarelayer{l%d}\n\\definecolor{c%d}{rgb}{%lf,%lf,%lf}\n",
|
||||||
lifo->layer, lifo->layer,
|
lifo->layer, lifo->layer,
|
||||||
lifo->color.red, lifo->color.green, lifo->color.blue);
|
lifo->color.red, lifo->color.green, lifo->color.blue);
|
||||||
@@ -66,14 +88,14 @@ static void write_layer_definitions(FILE *tex_file, GList *layer_infos, GString
|
|||||||
for (list = layer_infos; list != NULL; list = list->next) {
|
for (list = layer_infos; list != NULL; list = list->next) {
|
||||||
lifo = (struct layer_info *)list->data;
|
lifo = (struct layer_info *)list->data;
|
||||||
|
|
||||||
if (list->next == NULL)
|
if (!lifo->render)
|
||||||
end_str = ",main}";
|
continue;
|
||||||
else
|
|
||||||
end_str = ",";
|
g_string_printf(buffer, "l%d,", lifo->layer);
|
||||||
g_string_printf(buffer, "l%d%s", lifo->layer, end_str);
|
|
||||||
WRITEOUT_BUFFER(buffer);
|
WRITEOUT_BUFFER(buffer);
|
||||||
}
|
}
|
||||||
fwrite("\n", sizeof(char), 1, tex_file);
|
g_string_printf(buffer, "main}\n");
|
||||||
|
WRITEOUT_BUFFER(buffer);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -109,7 +131,7 @@ static gboolean write_layer_env(FILE *tex_file, GdkRGBA *color, int layer, GList
|
|||||||
|
|
||||||
for (temp = linfo; temp != NULL; temp = temp->next) {
|
for (temp = linfo; temp != NULL; temp = temp->next) {
|
||||||
inf = (struct layer_info *)temp->data;
|
inf = (struct layer_info *)temp->data;
|
||||||
if (inf->layer == layer) {
|
if (inf->layer == layer && inf->render) {
|
||||||
color->alpha = inf->color.alpha;
|
color->alpha = inf->color.alpha;
|
||||||
color->red = inf->color.red;
|
color->red = inf->color.red;
|
||||||
color->green = inf->color.green;
|
color->green = inf->color.green;
|
||||||
@@ -248,14 +270,14 @@ static void render_cell(struct gds_cell *cell, GList *layer_infos, FILE *tex_fil
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void latex_render_cell_to_code(struct gds_cell *cell, GList *layer_infos, FILE *tex_file, double scale,
|
static int latex_render_cell_to_code(struct gds_cell *cell, GList *layer_infos, FILE *tex_file, double scale,
|
||||||
gboolean create_pdf_layers, gboolean standalone_document)
|
gboolean create_pdf_layers, gboolean standalone_document)
|
||||||
{
|
{
|
||||||
GString *working_line;
|
GString *working_line;
|
||||||
|
|
||||||
|
|
||||||
if (!tex_file || !layer_infos || !cell)
|
if (!tex_file || !layer_infos || !cell)
|
||||||
return;
|
return -1;
|
||||||
|
|
||||||
/* 10 kB Line working buffer should be enough */
|
/* 10 kB Line working buffer should be enough */
|
||||||
working_line = g_string_new_len(NULL, LATEX_LINE_BUFFER_KB*1024);
|
working_line = g_string_new_len(NULL, LATEX_LINE_BUFFER_KB*1024);
|
||||||
@@ -297,6 +319,125 @@ void latex_render_cell_to_code(struct gds_cell *cell, GList *layer_infos, FILE *
|
|||||||
|
|
||||||
fflush(tex_file);
|
fflush(tex_file);
|
||||||
g_string_free(working_line, TRUE);
|
g_string_free(working_line, TRUE);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int latex_renderer_render_output(GdsOutputRenderer *renderer,
|
||||||
|
struct gds_cell *cell,
|
||||||
|
double scale)
|
||||||
|
{
|
||||||
|
LatexRenderer *l_renderer = GDS_RENDER_LATEX_RENDERER(renderer);
|
||||||
|
FILE *tex_file;
|
||||||
|
int ret = -2;
|
||||||
|
LayerSettings *settings;
|
||||||
|
GList *layer_infos = NULL;
|
||||||
|
const char *output_file;
|
||||||
|
|
||||||
|
output_file = gds_output_renderer_get_output_file(renderer);
|
||||||
|
settings = gds_output_renderer_get_and_ref_layer_settings(renderer);
|
||||||
|
|
||||||
|
/* Set layer info list. In case of failure it remains NULL */
|
||||||
|
if (settings)
|
||||||
|
layer_infos = layer_settings_get_layer_info_list(settings);
|
||||||
|
|
||||||
|
tex_file = fopen(output_file, "w");
|
||||||
|
if (tex_file) {
|
||||||
|
ret = latex_render_cell_to_code(cell, layer_infos, tex_file, scale,
|
||||||
|
l_renderer->pdf_layers, l_renderer->tex_standalone);
|
||||||
|
fclose(tex_file);
|
||||||
|
} else {
|
||||||
|
g_error("Could not open LaTeX output file");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (settings) {
|
||||||
|
g_object_unref(settings);
|
||||||
|
}
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void latex_renderer_init(LatexRenderer *self)
|
||||||
|
{
|
||||||
|
self->pdf_layers = FALSE;
|
||||||
|
self->tex_standalone = FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void latex_renderer_get_property(GObject *obj, guint property_id, GValue *value, GParamSpec *pspec)
|
||||||
|
{
|
||||||
|
LatexRenderer *self = GDS_RENDER_LATEX_RENDERER(obj);
|
||||||
|
|
||||||
|
switch (property_id) {
|
||||||
|
case PROP_STANDALONE:
|
||||||
|
g_value_set_boolean(value, self->tex_standalone);
|
||||||
|
break;
|
||||||
|
case PROP_PDF_LAYERS:
|
||||||
|
g_value_set_boolean(value, self->pdf_layers);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
G_OBJECT_WARN_INVALID_PROPERTY_ID(obj, property_id, pspec);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void latex_renderer_set_property(GObject *obj, guint property_id, const GValue *value, GParamSpec *pspec)
|
||||||
|
{
|
||||||
|
LatexRenderer *self = GDS_RENDER_LATEX_RENDERER(obj);
|
||||||
|
|
||||||
|
switch (property_id) {
|
||||||
|
case PROP_STANDALONE:
|
||||||
|
self->tex_standalone = g_value_get_boolean(value);
|
||||||
|
break;
|
||||||
|
case PROP_PDF_LAYERS:
|
||||||
|
self->pdf_layers = g_value_get_boolean(value);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
G_OBJECT_WARN_INVALID_PROPERTY_ID(obj, property_id, pspec);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static GParamSpec *latex_renderer_properties[N_PROPERTIES] = {NULL};
|
||||||
|
|
||||||
|
static void latex_renderer_class_init(LatexRendererClass *klass)
|
||||||
|
{
|
||||||
|
GdsOutputRendererClass *render_class = GDS_RENDER_OUTPUT_RENDERER_CLASS(klass);
|
||||||
|
GObjectClass *oclass = G_OBJECT_CLASS(klass);
|
||||||
|
|
||||||
|
/* Overwrite virtual function */
|
||||||
|
render_class->render_output = latex_renderer_render_output;
|
||||||
|
|
||||||
|
/* Property stuff */
|
||||||
|
oclass->get_property = latex_renderer_get_property;
|
||||||
|
oclass->set_property = latex_renderer_set_property;
|
||||||
|
|
||||||
|
latex_renderer_properties[PROP_STANDALONE] =
|
||||||
|
g_param_spec_boolean("standalone",
|
||||||
|
"Standalone TeX file",
|
||||||
|
"Generate a standalone LaTeX file.",
|
||||||
|
FALSE,
|
||||||
|
G_PARAM_READWRITE);
|
||||||
|
latex_renderer_properties[PROP_PDF_LAYERS] =
|
||||||
|
g_param_spec_boolean("pdf-layers",
|
||||||
|
"PDF OCR layers",
|
||||||
|
"Generate OCR layers",
|
||||||
|
FALSE,
|
||||||
|
G_PARAM_READWRITE);
|
||||||
|
|
||||||
|
g_object_class_install_properties(oclass, N_PROPERTIES, latex_renderer_properties);
|
||||||
|
}
|
||||||
|
|
||||||
|
LatexRenderer *latex_renderer_new()
|
||||||
|
{
|
||||||
|
return GDS_RENDER_LATEX_RENDERER(g_object_new(GDS_RENDER_TYPE_LATEX_RENDERER, NULL));
|
||||||
|
}
|
||||||
|
|
||||||
|
LatexRenderer *latex_renderer_new_with_options(gboolean pdf_layers, gboolean standalone)
|
||||||
|
{
|
||||||
|
GObject *obj;
|
||||||
|
|
||||||
|
obj = g_object_new(GDS_RENDER_TYPE_LATEX_RENDERER, "standalone", standalone, "pdf-layers", pdf_layers, NULL);
|
||||||
|
return GDS_RENDER_LATEX_RENDERER(obj);
|
||||||
}
|
}
|
||||||
|
|
||||||
/** @} */
|
/** @} */
|
@@ -1,6 +1,8 @@
|
|||||||
add_custom_target(glib-resources DEPENDS ${CMAKE_CURRENT_BINARY_DIR}/resources.c)
|
add_custom_target(glib-resources DEPENDS ${CMAKE_CURRENT_BINARY_DIR}/resources.c)
|
||||||
add_custom_command(DEPENDS
|
add_custom_command(DEPENDS
|
||||||
${CMAKE_CURRENT_SOURCE_DIR}/*.glade
|
${CMAKE_CURRENT_SOURCE_DIR}/*.glade
|
||||||
|
${CMAKE_CURRENT_SOURCE_DIR}/resources.xml
|
||||||
|
${CMAKE_CURRENT_SOURCE_DIR}/color-palette.txt
|
||||||
OUTPUT
|
OUTPUT
|
||||||
${CMAKE_CURRENT_BINARY_DIR}/resources.c
|
${CMAKE_CURRENT_BINARY_DIR}/resources.c
|
||||||
COMMAND
|
COMMAND
|
@@ -10,7 +10,7 @@
|
|||||||
<property name="website">https://git.shimatta.de/mhu/gds-render</property>
|
<property name="website">https://git.shimatta.de/mhu/gds-render</property>
|
||||||
<property name="website_label" translatable="yes">Git Repository</property>
|
<property name="website_label" translatable="yes">Git Repository</property>
|
||||||
<property name="authors">Mario Hüttel <mario.huettel@gmx.net></property>
|
<property name="authors">Mario Hüttel <mario.huettel@gmx.net></property>
|
||||||
<property name="logo_icon_name">gds-render</property>
|
<property name="logo_icon_name"/>
|
||||||
<property name="license_type">gpl-2-0-only</property>
|
<property name="license_type">gpl-2-0-only</property>
|
||||||
<child>
|
<child>
|
||||||
<placeholder/>
|
<placeholder/>
|
255
resources/color-palette.txt
Normal file
255
resources/color-palette.txt
Normal file
@@ -0,0 +1,255 @@
|
|||||||
|
800000
|
||||||
|
008000
|
||||||
|
808000
|
||||||
|
000080
|
||||||
|
800080
|
||||||
|
008080
|
||||||
|
c0c0c0
|
||||||
|
808080
|
||||||
|
ff0000
|
||||||
|
00ff00
|
||||||
|
ffff00
|
||||||
|
0000ff
|
||||||
|
ff00ff
|
||||||
|
00ffff
|
||||||
|
f105f5
|
||||||
|
000000
|
||||||
|
00005f
|
||||||
|
000087
|
||||||
|
0000af
|
||||||
|
0000d7
|
||||||
|
0000ff
|
||||||
|
005f00
|
||||||
|
005f5f
|
||||||
|
005f87
|
||||||
|
005faf
|
||||||
|
005fd7
|
||||||
|
005fff
|
||||||
|
008700
|
||||||
|
00875f
|
||||||
|
008787
|
||||||
|
0087af
|
||||||
|
0087d7
|
||||||
|
0087ff
|
||||||
|
00af00
|
||||||
|
00af5f
|
||||||
|
00af87
|
||||||
|
00afaf
|
||||||
|
00afd7
|
||||||
|
00afff
|
||||||
|
00d700
|
||||||
|
00d75f
|
||||||
|
00d787
|
||||||
|
00d7af
|
||||||
|
00d7d7
|
||||||
|
00d7ff
|
||||||
|
00ff00
|
||||||
|
00ff5f
|
||||||
|
00ff87
|
||||||
|
00ffaf
|
||||||
|
00ffd7
|
||||||
|
00ffff
|
||||||
|
5f0000
|
||||||
|
5f005f
|
||||||
|
5f0087
|
||||||
|
5f00af
|
||||||
|
5f00d7
|
||||||
|
5f00ff
|
||||||
|
5f5f00
|
||||||
|
5f5f5f
|
||||||
|
5f5f87
|
||||||
|
5f5faf
|
||||||
|
5f5fd7
|
||||||
|
5f5fff
|
||||||
|
5f8700
|
||||||
|
5f875f
|
||||||
|
5f8787
|
||||||
|
5f87af
|
||||||
|
5f87d7
|
||||||
|
5f87ff
|
||||||
|
5faf00
|
||||||
|
5faf5f
|
||||||
|
5faf87
|
||||||
|
5fafaf
|
||||||
|
5fafd7
|
||||||
|
5fafff
|
||||||
|
5fd700
|
||||||
|
5fd75f
|
||||||
|
5fd787
|
||||||
|
5fd7af
|
||||||
|
5fd7d7
|
||||||
|
5fd7ff
|
||||||
|
5fff00
|
||||||
|
5fff5f
|
||||||
|
5fff87
|
||||||
|
5fffaf
|
||||||
|
5fffd7
|
||||||
|
5fffff
|
||||||
|
870000
|
||||||
|
87005f
|
||||||
|
870087
|
||||||
|
8700af
|
||||||
|
8700d7
|
||||||
|
8700ff
|
||||||
|
875f00
|
||||||
|
875f5f
|
||||||
|
875f87
|
||||||
|
875faf
|
||||||
|
875fd7
|
||||||
|
875fff
|
||||||
|
878700
|
||||||
|
87875f
|
||||||
|
878787
|
||||||
|
8787af
|
||||||
|
8787d7
|
||||||
|
8787ff
|
||||||
|
87af00
|
||||||
|
87af5f
|
||||||
|
87af87
|
||||||
|
87afaf
|
||||||
|
87afd7
|
||||||
|
87afff
|
||||||
|
87d700
|
||||||
|
87d75f
|
||||||
|
87d787
|
||||||
|
87d7af
|
||||||
|
87d7d7
|
||||||
|
87d7ff
|
||||||
|
87ff00
|
||||||
|
87ff5f
|
||||||
|
87ff87
|
||||||
|
87ffaf
|
||||||
|
87ffd7
|
||||||
|
87ffff
|
||||||
|
af0000
|
||||||
|
af005f
|
||||||
|
af0087
|
||||||
|
af00af
|
||||||
|
af00d7
|
||||||
|
af00ff
|
||||||
|
af5f00
|
||||||
|
af5f5f
|
||||||
|
af5f87
|
||||||
|
af5faf
|
||||||
|
af5fd7
|
||||||
|
af5fff
|
||||||
|
af8700
|
||||||
|
af875f
|
||||||
|
af8787
|
||||||
|
af87af
|
||||||
|
af87d7
|
||||||
|
af87ff
|
||||||
|
afaf00
|
||||||
|
afaf5f
|
||||||
|
afaf87
|
||||||
|
afafaf
|
||||||
|
afafd7
|
||||||
|
afafff
|
||||||
|
afd700
|
||||||
|
afd75f
|
||||||
|
afd787
|
||||||
|
afd7af
|
||||||
|
afd7d7
|
||||||
|
afd7ff
|
||||||
|
afff00
|
||||||
|
afff5f
|
||||||
|
afff87
|
||||||
|
afffaf
|
||||||
|
afffd7
|
||||||
|
afffff
|
||||||
|
d70000
|
||||||
|
d7005f
|
||||||
|
d70087
|
||||||
|
d700af
|
||||||
|
d700d7
|
||||||
|
d700ff
|
||||||
|
d75f00
|
||||||
|
d75f5f
|
||||||
|
d75f87
|
||||||
|
d75faf
|
||||||
|
d75fd7
|
||||||
|
d75fff
|
||||||
|
d78700
|
||||||
|
d7875f
|
||||||
|
d78787
|
||||||
|
d787af
|
||||||
|
d787d7
|
||||||
|
d787ff
|
||||||
|
d7af00
|
||||||
|
d7af5f
|
||||||
|
d7af87
|
||||||
|
d7afaf
|
||||||
|
d7afd7
|
||||||
|
d7afff
|
||||||
|
d7d700
|
||||||
|
d7d75f
|
||||||
|
d7d787
|
||||||
|
d7d7af
|
||||||
|
d7d7d7
|
||||||
|
d7d7ff
|
||||||
|
d7ff00
|
||||||
|
d7ff5f
|
||||||
|
d7ff87
|
||||||
|
d7ffaf
|
||||||
|
d7ffd7
|
||||||
|
d7ffff
|
||||||
|
ff0000
|
||||||
|
ff005f
|
||||||
|
ff0087
|
||||||
|
ff00af
|
||||||
|
ff00d7
|
||||||
|
ff00ff
|
||||||
|
ff5f00
|
||||||
|
ff5f5f
|
||||||
|
ff5f87
|
||||||
|
ff5faf
|
||||||
|
ff5fd7
|
||||||
|
ff5fff
|
||||||
|
ff8700
|
||||||
|
ff875f
|
||||||
|
ff8787
|
||||||
|
ff87af
|
||||||
|
ff87d7
|
||||||
|
ff87ff
|
||||||
|
ffaf00
|
||||||
|
ffaf5f
|
||||||
|
ffaf87
|
||||||
|
ffafaf
|
||||||
|
ffafd7
|
||||||
|
ffafff
|
||||||
|
ffd700
|
||||||
|
ffd75f
|
||||||
|
ffd787
|
||||||
|
ffd7af
|
||||||
|
ffd7d7
|
||||||
|
ffd7ff
|
||||||
|
ffff00
|
||||||
|
ffff5f
|
||||||
|
ffff87
|
||||||
|
ffffaf
|
||||||
|
ffffd7
|
||||||
|
ffffff
|
||||||
|
080808
|
||||||
|
121212
|
||||||
|
1c1c1c
|
||||||
|
262626
|
||||||
|
303030
|
||||||
|
3a3a3a
|
||||||
|
444444
|
||||||
|
4e4e4e
|
||||||
|
585858
|
||||||
|
626262
|
||||||
|
6c6c6c
|
||||||
|
767676
|
||||||
|
808080
|
||||||
|
8a8a8a
|
||||||
|
949494
|
||||||
|
9e9e9e
|
||||||
|
a8a8a8
|
||||||
|
b2b2b2
|
||||||
|
bcbcbc
|
||||||
|
c6c6c6
|
||||||
|
d0d0d0
|
||||||
|
dadada
|
||||||
|
e4e4e4
|
||||||
|
eeeeee
|
@@ -4,7 +4,7 @@
|
|||||||
<requires lib="gtk+" version="3.20"/>
|
<requires lib="gtk+" version="3.20"/>
|
||||||
<object class="GtkAdjustment" id="adjustment1">
|
<object class="GtkAdjustment" id="adjustment1">
|
||||||
<property name="lower">1</property>
|
<property name="lower">1</property>
|
||||||
<property name="upper">3000</property>
|
<property name="upper">4000</property>
|
||||||
<property name="value">1000</property>
|
<property name="value">1000</property>
|
||||||
<property name="step_increment">10</property>
|
<property name="step_increment">10</property>
|
||||||
<property name="page_increment">1000</property>
|
<property name="page_increment">1000</property>
|
||||||
@@ -16,7 +16,6 @@
|
|||||||
<child>
|
<child>
|
||||||
<object class="GtkRadioButton" id="latex-radio">
|
<object class="GtkRadioButton" id="latex-radio">
|
||||||
<property name="label" translatable="yes">Generate LaTeX/TikZ output</property>
|
<property name="label" translatable="yes">Generate LaTeX/TikZ output</property>
|
||||||
<property name="use_action_appearance">True</property>
|
|
||||||
<property name="visible">True</property>
|
<property name="visible">True</property>
|
||||||
<property name="can_focus">True</property>
|
<property name="can_focus">True</property>
|
||||||
<property name="receives_default">False</property>
|
<property name="receives_default">False</property>
|
||||||
@@ -32,11 +31,9 @@
|
|||||||
<child>
|
<child>
|
||||||
<object class="GtkRadioButton" id="cairo-pdf-radio">
|
<object class="GtkRadioButton" id="cairo-pdf-radio">
|
||||||
<property name="label" translatable="yes">Render PDF using Cairographics</property>
|
<property name="label" translatable="yes">Render PDF using Cairographics</property>
|
||||||
<property name="use_action_appearance">True</property>
|
|
||||||
<property name="visible">True</property>
|
<property name="visible">True</property>
|
||||||
<property name="can_focus">True</property>
|
<property name="can_focus">True</property>
|
||||||
<property name="receives_default">False</property>
|
<property name="receives_default">False</property>
|
||||||
<property name="active">True</property>
|
|
||||||
<property name="draw_indicator">True</property>
|
<property name="draw_indicator">True</property>
|
||||||
<property name="group">latex-radio</property>
|
<property name="group">latex-radio</property>
|
||||||
</object>
|
</object>
|
||||||
@@ -49,12 +46,10 @@
|
|||||||
<child>
|
<child>
|
||||||
<object class="GtkRadioButton" id="cairo-svg-radio">
|
<object class="GtkRadioButton" id="cairo-svg-radio">
|
||||||
<property name="label" translatable="yes">Render SVG using Cairographics (too buggy at the moment)</property>
|
<property name="label" translatable="yes">Render SVG using Cairographics (too buggy at the moment)</property>
|
||||||
<property name="use_action_appearance">True</property>
|
|
||||||
<property name="visible">True</property>
|
<property name="visible">True</property>
|
||||||
<property name="sensitive">False</property>
|
<property name="sensitive">False</property>
|
||||||
<property name="can_focus">True</property>
|
<property name="can_focus">True</property>
|
||||||
<property name="receives_default">False</property>
|
<property name="receives_default">False</property>
|
||||||
<property name="active">True</property>
|
|
||||||
<property name="draw_indicator">True</property>
|
<property name="draw_indicator">True</property>
|
||||||
<property name="group">latex-radio</property>
|
<property name="group">latex-radio</property>
|
||||||
</object>
|
</object>
|
||||||
@@ -69,6 +64,7 @@
|
|||||||
<property name="visible">True</property>
|
<property name="visible">True</property>
|
||||||
<property name="can_focus">True</property>
|
<property name="can_focus">True</property>
|
||||||
<property name="adjustment">adjustment1</property>
|
<property name="adjustment">adjustment1</property>
|
||||||
|
<property name="fill_level">4000</property>
|
||||||
<property name="round_digits">0</property>
|
<property name="round_digits">0</property>
|
||||||
<property name="digits">0</property>
|
<property name="digits">0</property>
|
||||||
</object>
|
</object>
|
||||||
@@ -106,5 +102,83 @@
|
|||||||
<property name="position">5</property>
|
<property name="position">5</property>
|
||||||
</packing>
|
</packing>
|
||||||
</child>
|
</child>
|
||||||
|
<child>
|
||||||
|
<object class="GtkDrawingArea" id="shape-drawer">
|
||||||
|
<property name="height_request">200</property>
|
||||||
|
<property name="visible">True</property>
|
||||||
|
<property name="can_focus">False</property>
|
||||||
|
</object>
|
||||||
|
<packing>
|
||||||
|
<property name="expand">True</property>
|
||||||
|
<property name="fill">True</property>
|
||||||
|
<property name="position">6</property>
|
||||||
|
</packing>
|
||||||
|
</child>
|
||||||
|
<child>
|
||||||
|
<object class="GtkBox">
|
||||||
|
<property name="visible">True</property>
|
||||||
|
<property name="can_focus">False</property>
|
||||||
|
<child>
|
||||||
|
<object class="GtkLabel" id="x-label">
|
||||||
|
<property name="visible">True</property>
|
||||||
|
<property name="can_focus">False</property>
|
||||||
|
</object>
|
||||||
|
<packing>
|
||||||
|
<property name="expand">True</property>
|
||||||
|
<property name="fill">True</property>
|
||||||
|
<property name="position">0</property>
|
||||||
|
</packing>
|
||||||
|
</child>
|
||||||
|
<child>
|
||||||
|
<object class="GtkLabel" id="y-label">
|
||||||
|
<property name="visible">True</property>
|
||||||
|
<property name="can_focus">False</property>
|
||||||
|
</object>
|
||||||
|
<packing>
|
||||||
|
<property name="expand">True</property>
|
||||||
|
<property name="fill">True</property>
|
||||||
|
<property name="position">1</property>
|
||||||
|
</packing>
|
||||||
|
</child>
|
||||||
|
</object>
|
||||||
|
<packing>
|
||||||
|
<property name="expand">False</property>
|
||||||
|
<property name="fill">True</property>
|
||||||
|
<property name="position">7</property>
|
||||||
|
</packing>
|
||||||
|
</child>
|
||||||
|
<child>
|
||||||
|
<object class="GtkBox">
|
||||||
|
<property name="visible">True</property>
|
||||||
|
<property name="can_focus">False</property>
|
||||||
|
<child>
|
||||||
|
<object class="GtkLabel" id="x-output-label">
|
||||||
|
<property name="visible">True</property>
|
||||||
|
<property name="can_focus">False</property>
|
||||||
|
</object>
|
||||||
|
<packing>
|
||||||
|
<property name="expand">True</property>
|
||||||
|
<property name="fill">True</property>
|
||||||
|
<property name="position">0</property>
|
||||||
|
</packing>
|
||||||
|
</child>
|
||||||
|
<child>
|
||||||
|
<object class="GtkLabel" id="y-output-label">
|
||||||
|
<property name="visible">True</property>
|
||||||
|
<property name="can_focus">False</property>
|
||||||
|
</object>
|
||||||
|
<packing>
|
||||||
|
<property name="expand">True</property>
|
||||||
|
<property name="fill">True</property>
|
||||||
|
<property name="position">1</property>
|
||||||
|
</packing>
|
||||||
|
</child>
|
||||||
|
</object>
|
||||||
|
<packing>
|
||||||
|
<property name="expand">False</property>
|
||||||
|
<property name="fill">True</property>
|
||||||
|
<property name="position">8</property>
|
||||||
|
</packing>
|
||||||
|
</child>
|
||||||
</object>
|
</object>
|
||||||
</interface>
|
</interface>
|
283
resources/main.glade
Normal file
283
resources/main.glade
Normal file
@@ -0,0 +1,283 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<!-- Generated with glade 3.22.1 -->
|
||||||
|
<interface>
|
||||||
|
<requires lib="gtk+" version="3.20"/>
|
||||||
|
<object class="GtkImage" id="color-img">
|
||||||
|
<property name="visible">True</property>
|
||||||
|
<property name="can_focus">False</property>
|
||||||
|
<property name="stock">gtk-select-color</property>
|
||||||
|
</object>
|
||||||
|
<object class="GtkImage" id="load-mapping-img">
|
||||||
|
<property name="visible">True</property>
|
||||||
|
<property name="can_focus">False</property>
|
||||||
|
<property name="stock">gtk-open</property>
|
||||||
|
</object>
|
||||||
|
<object class="GtkImage" id="save-mapping-img">
|
||||||
|
<property name="visible">True</property>
|
||||||
|
<property name="can_focus">False</property>
|
||||||
|
<property name="stock">gtk-save-as</property>
|
||||||
|
</object>
|
||||||
|
<object class="GtkWindow" id="main-window">
|
||||||
|
<property name="height_request">250</property>
|
||||||
|
<property name="can_focus">False</property>
|
||||||
|
<property name="icon_name">gds-render</property>
|
||||||
|
<child type="titlebar">
|
||||||
|
<object class="GtkHeaderBar" id="header-bar">
|
||||||
|
<property name="name">header</property>
|
||||||
|
<property name="visible">True</property>
|
||||||
|
<property name="can_focus">False</property>
|
||||||
|
<property name="title" translatable="yes">GDS Renderer</property>
|
||||||
|
<property name="show_close_button">True</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>
|
||||||
|
</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>
|
||||||
|
<property name="image">load-mapping-img</property>
|
||||||
|
<property name="always_show_image">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>
|
||||||
|
<property name="image">save-mapping-img</property>
|
||||||
|
<property name="always_show_image">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>
|
||||||
|
<object class="GtkBox">
|
||||||
|
<property name="visible">True</property>
|
||||||
|
<property name="can_focus">False</property>
|
||||||
|
<property name="orientation">vertical</property>
|
||||||
|
<child>
|
||||||
|
<object class="GtkBox">
|
||||||
|
<property name="visible">True</property>
|
||||||
|
<property name="can_focus">False</property>
|
||||||
|
<child>
|
||||||
|
<object class="GtkBox">
|
||||||
|
<property name="visible">True</property>
|
||||||
|
<property name="can_focus">False</property>
|
||||||
|
<property name="orientation">vertical</property>
|
||||||
|
<child>
|
||||||
|
<object class="GtkSearchEntry" id="cell-search">
|
||||||
|
<property name="visible">True</property>
|
||||||
|
<property name="can_focus">True</property>
|
||||||
|
<property name="primary_icon_name">edit-find-symbolic</property>
|
||||||
|
<property name="primary_icon_activatable">False</property>
|
||||||
|
<property name="primary_icon_sensitive">False</property>
|
||||||
|
</object>
|
||||||
|
<packing>
|
||||||
|
<property name="expand">False</property>
|
||||||
|
<property name="fill">True</property>
|
||||||
|
<property name="position">0</property>
|
||||||
|
</packing>
|
||||||
|
</child>
|
||||||
|
<child>
|
||||||
|
<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="GtkTreeView" id="cell-tree">
|
||||||
|
<property name="visible">True</property>
|
||||||
|
<property name="can_focus">True</property>
|
||||||
|
<property name="enable_search">False</property>
|
||||||
|
<property name="enable_grid_lines">both</property>
|
||||||
|
<child internal-child="selection">
|
||||||
|
<object class="GtkTreeSelection"/>
|
||||||
|
</child>
|
||||||
|
</object>
|
||||||
|
</child>
|
||||||
|
</object>
|
||||||
|
<packing>
|
||||||
|
<property name="expand">True</property>
|
||||||
|
<property name="fill">True</property>
|
||||||
|
<property name="position">1</property>
|
||||||
|
</packing>
|
||||||
|
</child>
|
||||||
|
</object>
|
||||||
|
<packing>
|
||||||
|
<property name="expand">True</property>
|
||||||
|
<property name="fill">True</property>
|
||||||
|
<property name="position">0</property>
|
||||||
|
</packing>
|
||||||
|
</child>
|
||||||
|
<child>
|
||||||
|
<object class="GtkBox">
|
||||||
|
<property name="visible">True</property>
|
||||||
|
<property name="can_focus">False</property>
|
||||||
|
<property name="orientation">vertical</property>
|
||||||
|
<child>
|
||||||
|
<object class="GtkBox">
|
||||||
|
<property name="visible">True</property>
|
||||||
|
<property name="can_focus">False</property>
|
||||||
|
<child>
|
||||||
|
<object class="GtkButton" id="button-up-sort">
|
||||||
|
<property name="visible">True</property>
|
||||||
|
<property name="can_focus">True</property>
|
||||||
|
<property name="receives_default">True</property>
|
||||||
|
<property name="image">sort-up-img</property>
|
||||||
|
<property name="always_show_image">True</property>
|
||||||
|
</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-down-sort">
|
||||||
|
<property name="visible">True</property>
|
||||||
|
<property name="can_focus">True</property>
|
||||||
|
<property name="receives_default">True</property>
|
||||||
|
<property name="image">sort-down-img</property>
|
||||||
|
<property name="always_show_image">True</property>
|
||||||
|
</object>
|
||||||
|
<packing>
|
||||||
|
<property name="expand">False</property>
|
||||||
|
<property name="fill">True</property>
|
||||||
|
<property name="position">1</property>
|
||||||
|
</packing>
|
||||||
|
</child>
|
||||||
|
<child>
|
||||||
|
<object class="GtkButton" id="auto-color-button">
|
||||||
|
<property name="visible">True</property>
|
||||||
|
<property name="can_focus">True</property>
|
||||||
|
<property name="receives_default">True</property>
|
||||||
|
<property name="image">color-img</property>
|
||||||
|
<property name="always_show_image">True</property>
|
||||||
|
</object>
|
||||||
|
<packing>
|
||||||
|
<property name="expand">False</property>
|
||||||
|
<property name="fill">True</property>
|
||||||
|
<property name="position">2</property>
|
||||||
|
</packing>
|
||||||
|
</child>
|
||||||
|
</object>
|
||||||
|
<packing>
|
||||||
|
<property name="expand">False</property>
|
||||||
|
<property name="fill">False</property>
|
||||||
|
<property name="position">0</property>
|
||||||
|
</packing>
|
||||||
|
</child>
|
||||||
|
<child>
|
||||||
|
<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">
|
||||||
|
<property name="visible">True</property>
|
||||||
|
<property name="can_focus">False</property>
|
||||||
|
<child>
|
||||||
|
<object class="GtkListBox" id="layer-list">
|
||||||
|
<property name="visible">True</property>
|
||||||
|
<property name="can_focus">False</property>
|
||||||
|
<property name="selection_mode">none</property>
|
||||||
|
</object>
|
||||||
|
</child>
|
||||||
|
</object>
|
||||||
|
</child>
|
||||||
|
</object>
|
||||||
|
<packing>
|
||||||
|
<property name="expand">True</property>
|
||||||
|
<property name="fill">True</property>
|
||||||
|
<property name="position">1</property>
|
||||||
|
</packing>
|
||||||
|
</child>
|
||||||
|
</object>
|
||||||
|
<packing>
|
||||||
|
<property name="expand">True</property>
|
||||||
|
<property name="fill">True</property>
|
||||||
|
<property name="position">1</property>
|
||||||
|
</packing>
|
||||||
|
</child>
|
||||||
|
</object>
|
||||||
|
<packing>
|
||||||
|
<property name="expand">True</property>
|
||||||
|
<property name="fill">True</property>
|
||||||
|
<property name="position">0</property>
|
||||||
|
</packing>
|
||||||
|
</child>
|
||||||
|
<child>
|
||||||
|
<object class="GtkBox" id="activity-bar">
|
||||||
|
<property name="visible">True</property>
|
||||||
|
<property name="can_focus">False</property>
|
||||||
|
<property name="orientation">vertical</property>
|
||||||
|
<child>
|
||||||
|
<placeholder/>
|
||||||
|
</child>
|
||||||
|
</object>
|
||||||
|
<packing>
|
||||||
|
<property name="expand">False</property>
|
||||||
|
<property name="fill">False</property>
|
||||||
|
<property name="position">1</property>
|
||||||
|
</packing>
|
||||||
|
</child>
|
||||||
|
</object>
|
||||||
|
</child>
|
||||||
|
</object>
|
||||||
|
<object class="GtkImage" id="sort-down-img">
|
||||||
|
<property name="visible">True</property>
|
||||||
|
<property name="can_focus">False</property>
|
||||||
|
<property name="stock">gtk-sort-ascending</property>
|
||||||
|
</object>
|
||||||
|
<object class="GtkImage" id="sort-up-img">
|
||||||
|
<property name="visible">True</property>
|
||||||
|
<property name="can_focus">False</property>
|
||||||
|
<property name="stock">gtk-sort-descending</property>
|
||||||
|
</object>
|
||||||
|
</interface>
|
17
resources/resources.xml
Normal file
17
resources/resources.xml
Normal file
@@ -0,0 +1,17 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<gresources>
|
||||||
|
<gresource prefix="/gui">
|
||||||
|
<file compressed="true">main.glade</file>
|
||||||
|
<file compressed="true">about.glade</file>
|
||||||
|
<file>layer-widget.glade</file>
|
||||||
|
<file>dialog.glade</file>
|
||||||
|
</gresource>
|
||||||
|
<gresource prefix="/data">
|
||||||
|
<file compressed="true">color-palette.txt</file>
|
||||||
|
</gresource>
|
||||||
|
<gresource prefix="/images">
|
||||||
|
<file compressed="true" alias="logo.svg">../icon/gds-render.svg</file>
|
||||||
|
</gresource>
|
||||||
|
</gresources>
|
||||||
|
|
||||||
|
|
5
version/CMakeLists.txt
Normal file
5
version/CMakeLists.txt
Normal file
@@ -0,0 +1,5 @@
|
|||||||
|
add_library(version STATIC "version.c")
|
||||||
|
execute_process(COMMAND bash ./generate-version-string.sh
|
||||||
|
WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}
|
||||||
|
OUTPUT_VARIABLE GIT_VER)
|
||||||
|
target_compile_definitions(version PUBLIC PROJECT_GIT_VERSION=${GIT_VER})
|
1
version/generate-version-string.sh
Executable file
1
version/generate-version-string.sh
Executable file
@@ -0,0 +1 @@
|
|||||||
|
git describe --tags --dirty
|
36
version/version.c
Normal file
36
version/version.c
Normal file
@@ -0,0 +1,36 @@
|
|||||||
|
/*
|
||||||
|
* 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/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @defgroup version Version Number
|
||||||
|
* See @ref git-version-num
|
||||||
|
* @addtogroup version
|
||||||
|
* @{
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifdef PROJECT_GIT_VERSION
|
||||||
|
#define xstr(a) str(a)
|
||||||
|
#define str(a) #a
|
||||||
|
const char *_app_version_string = xstr(PROJECT_GIT_VERSION);
|
||||||
|
#else
|
||||||
|
const char *_app_version_string = "! version not set !";
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/** @} */
|
109
widgets/activity-bar.c
Normal file
109
widgets/activity-bar.c
Normal file
@@ -0,0 +1,109 @@
|
|||||||
|
/*
|
||||||
|
* GDSII-Converter
|
||||||
|
* Copyright (C) 2019 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/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
* The drag and drop implementation is adapted from
|
||||||
|
* https://gitlab.gnome.org/GNOME/gtk/blob/gtk-3-22/tests/testlist3.c
|
||||||
|
*
|
||||||
|
* Thanks to the GTK3 people for creating these examples.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @file activity-bar.c
|
||||||
|
* @brief Status bar indicating activity of the program
|
||||||
|
* @author Mario Hüttel <mario.huettel@gmx.net>
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @addtogroup ActivityBar
|
||||||
|
* @ingroup Widgets
|
||||||
|
* @{
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <gds-render/widgets/activity-bar.h>
|
||||||
|
|
||||||
|
/** @brief Opaque ActivityBar object. Not viewable outside this source file. */
|
||||||
|
struct _ActivityBar {
|
||||||
|
GtkBox super;
|
||||||
|
/* Private stuff */
|
||||||
|
GtkWidget *spinner;
|
||||||
|
GtkWidget *label;
|
||||||
|
};
|
||||||
|
|
||||||
|
G_DEFINE_TYPE(ActivityBar, activity_bar, GTK_TYPE_BOX)
|
||||||
|
|
||||||
|
static void activity_bar_dispose(GObject *obj)
|
||||||
|
{
|
||||||
|
ActivityBar *bar;
|
||||||
|
|
||||||
|
bar = ACTIVITY_BAR(obj);
|
||||||
|
|
||||||
|
/* Clear references on owned objects */
|
||||||
|
g_clear_object(&bar->label);
|
||||||
|
g_clear_object(&bar->spinner);
|
||||||
|
|
||||||
|
/* Chain up */
|
||||||
|
G_OBJECT_CLASS(activity_bar_parent_class)->dispose(obj);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void activity_bar_class_init(ActivityBarClass *klass)
|
||||||
|
{
|
||||||
|
GObjectClass *oclass = G_OBJECT_CLASS(klass);
|
||||||
|
|
||||||
|
oclass->dispose = activity_bar_dispose;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void activity_bar_init(ActivityBar *self)
|
||||||
|
{
|
||||||
|
GtkContainer *box = GTK_CONTAINER(self);
|
||||||
|
|
||||||
|
/* Create Widgets */
|
||||||
|
self->label = gtk_label_new("");
|
||||||
|
self->spinner = gtk_spinner_new();
|
||||||
|
|
||||||
|
/* Add to this widget and show */
|
||||||
|
gtk_container_add(box, self->spinner);
|
||||||
|
gtk_container_add(box, self->label);
|
||||||
|
gtk_widget_show(self->label);
|
||||||
|
gtk_widget_show(self->spinner);
|
||||||
|
|
||||||
|
g_object_ref(self->spinner);
|
||||||
|
g_object_ref(self->label);
|
||||||
|
}
|
||||||
|
|
||||||
|
ActivityBar *activity_bar_new()
|
||||||
|
{
|
||||||
|
ActivityBar *bar;
|
||||||
|
|
||||||
|
bar = ACTIVITY_BAR(g_object_new(TYPE_ACTIVITY_BAR, "orientation", GTK_ORIENTATION_HORIZONTAL, NULL));
|
||||||
|
if (bar)
|
||||||
|
activity_bar_set_ready(bar);
|
||||||
|
|
||||||
|
return bar;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* TODO: Complete this once the task list is fully implemented */
|
||||||
|
void activity_bar_set_ready(ActivityBar *bar)
|
||||||
|
{
|
||||||
|
gtk_label_set_text(GTK_LABEL(bar->label), "Ready");
|
||||||
|
gtk_spinner_stop(GTK_SPINNER(bar->spinner));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/** @} */
|
@@ -18,17 +18,18 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @file conv-settings-dilaog.c
|
* @file conv-settings-dialog.c
|
||||||
* @brief Implementation of the setting dialog
|
* @brief Implementation of the setting dialog
|
||||||
* @author Mario Hüttel <mario.huettel@gmx.net>
|
* @author Mario Hüttel <mario.huettel@gmx.net>
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @addtogroup Widgets
|
* @addtogroup RendererSettingsDialog
|
||||||
|
* @ingroup Widgets
|
||||||
* @{
|
* @{
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include "conv-settings-dialog.h"
|
#include <gds-render/widgets/conv-settings-dialog.h>
|
||||||
|
|
||||||
struct _RendererSettingsDialog {
|
struct _RendererSettingsDialog {
|
||||||
GtkDialog parent;
|
GtkDialog parent;
|
||||||
@@ -39,16 +40,74 @@ struct _RendererSettingsDialog {
|
|||||||
GtkWidget *scale;
|
GtkWidget *scale;
|
||||||
GtkWidget *layer_check;
|
GtkWidget *layer_check;
|
||||||
GtkWidget *standalone_check;
|
GtkWidget *standalone_check;
|
||||||
|
GtkDrawingArea *shape_drawing;
|
||||||
|
GtkLabel *x_label;
|
||||||
|
GtkLabel *y_label;
|
||||||
|
|
||||||
|
GtkLabel *x_output_label;
|
||||||
|
GtkLabel *y_output_label;
|
||||||
|
|
||||||
|
unsigned int cell_height;
|
||||||
|
unsigned int cell_width;
|
||||||
|
double unit_in_meters;
|
||||||
};
|
};
|
||||||
|
|
||||||
G_DEFINE_TYPE(RendererSettingsDialog, renderer_settings_dialog, GTK_TYPE_DIALOG)
|
G_DEFINE_TYPE(RendererSettingsDialog, renderer_settings_dialog, GTK_TYPE_DIALOG)
|
||||||
|
|
||||||
|
enum {
|
||||||
|
PROP_CELL_NAME = 1,
|
||||||
|
PROP_COUNT
|
||||||
|
};
|
||||||
|
|
||||||
|
static GParamSpec *properties[PROP_COUNT];
|
||||||
|
|
||||||
|
static void renderer_settings_dialog_set_property(GObject *object, guint property_id,
|
||||||
|
const GValue *value, GParamSpec *pspec)
|
||||||
|
{
|
||||||
|
const gchar *title = NULL;
|
||||||
|
|
||||||
|
switch (property_id) {
|
||||||
|
case PROP_CELL_NAME:
|
||||||
|
title = g_value_get_string(value);
|
||||||
|
if (title)
|
||||||
|
gtk_window_set_title(GTK_WINDOW(object), title);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
G_OBJECT_WARN_INVALID_PROPERTY_ID(object, property_id, pspec);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void renderer_settings_dialog_get_property(GObject *object, guint property_id,
|
||||||
|
GValue *value, GParamSpec *pspec)
|
||||||
|
{
|
||||||
|
const gchar *title;
|
||||||
|
|
||||||
|
switch (property_id) {
|
||||||
|
case PROP_CELL_NAME:
|
||||||
|
title = gtk_window_get_title(GTK_WINDOW(object));
|
||||||
|
g_value_set_string(value, title);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
G_OBJECT_WARN_INVALID_PROPERTY_ID(object, property_id, pspec);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
static void renderer_settings_dialog_class_init(RendererSettingsDialogClass *klass)
|
static void renderer_settings_dialog_class_init(RendererSettingsDialogClass *klass)
|
||||||
{
|
{
|
||||||
/* No special code needed. Child cells are destroyed automatically due to reference counter */
|
GObjectClass *oclass = G_OBJECT_CLASS(klass);
|
||||||
return;
|
|
||||||
|
/* Override virtual functions */
|
||||||
|
oclass->set_property = renderer_settings_dialog_set_property;
|
||||||
|
oclass->get_property = renderer_settings_dialog_get_property;
|
||||||
|
|
||||||
|
properties[PROP_CELL_NAME] = g_param_spec_string("cell-name",
|
||||||
|
"cell-name",
|
||||||
|
"Cell name to be displayed in header bar",
|
||||||
|
"",
|
||||||
|
G_PARAM_READWRITE);
|
||||||
|
g_object_class_install_properties(oclass, PROP_COUNT, properties);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void show_tex_options(RendererSettingsDialog *self)
|
static void show_tex_options(RendererSettingsDialog *self)
|
||||||
@@ -72,16 +131,146 @@ static void latex_render_callback(GtkToggleButton *radio, RendererSettingsDialog
|
|||||||
hide_tex_options(dialog);
|
hide_tex_options(dialog);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static gboolean shape_drawer_drawing_callback(GtkWidget *widget, cairo_t *cr, gpointer data)
|
||||||
|
{
|
||||||
|
int width;
|
||||||
|
int height;
|
||||||
|
GtkStyleContext *style_context;
|
||||||
|
GdkRGBA foreground_color;
|
||||||
|
RendererSettingsDialog *dialog = (RendererSettingsDialog *)data;
|
||||||
|
double usable_width;
|
||||||
|
double usable_height;
|
||||||
|
double height_scale;
|
||||||
|
double width_scale;
|
||||||
|
double final_scale_value;
|
||||||
|
|
||||||
|
style_context = gtk_widget_get_style_context(widget);
|
||||||
|
width = gtk_widget_get_allocated_width(widget);
|
||||||
|
height = gtk_widget_get_allocated_height(widget);
|
||||||
|
|
||||||
|
gtk_render_background(style_context, cr, 0, 0, width, height);
|
||||||
|
|
||||||
|
gtk_style_context_get_color(style_context, gtk_style_context_get_state(style_context),
|
||||||
|
&foreground_color);
|
||||||
|
|
||||||
|
gdk_cairo_set_source_rgba(cr, &foreground_color);
|
||||||
|
|
||||||
|
cairo_save(cr);
|
||||||
|
|
||||||
|
/* Tranform coordiante system */
|
||||||
|
cairo_scale(cr, 1, -1);
|
||||||
|
cairo_translate(cr, (double)width/2.0, -(double)height/2.0);
|
||||||
|
|
||||||
|
/* Define usable drawing area */
|
||||||
|
usable_width = (0.95*(double)width) - 15.0;
|
||||||
|
usable_height = (0.95*(double)height) - 15.0;
|
||||||
|
|
||||||
|
width_scale = usable_width/(double)dialog->cell_width;
|
||||||
|
height_scale = usable_height/(double)dialog->cell_height;
|
||||||
|
|
||||||
|
final_scale_value = (width_scale < height_scale ? width_scale : height_scale);
|
||||||
|
|
||||||
|
cairo_rectangle(cr, -(double)dialog->cell_width*final_scale_value/2.0, -(double)dialog->cell_height*final_scale_value/2.0,
|
||||||
|
(double)dialog->cell_width*final_scale_value, (double)dialog->cell_height*final_scale_value);
|
||||||
|
cairo_stroke(cr);
|
||||||
|
cairo_restore(cr);
|
||||||
|
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
static double convert_number_to_engineering(double input, const char **out_prefix)
|
||||||
|
{
|
||||||
|
const char *selected_prefix = NULL;
|
||||||
|
double return_val = 0.0;
|
||||||
|
int idx;
|
||||||
|
const static char * prefixes[] = {"y", "z", "a", "f", "p", "n", "u", "m", "c", "d", /* < 1 */
|
||||||
|
"", /* 1 */
|
||||||
|
"h", "k", "M", "G", "T", "P", "E", "Z", "Y"}; /* > 1 */
|
||||||
|
const static double scale[] = {1E-24, 1E-21, 1E-18, 1E-15, 1E-12, 1E-9, 1E-6, 1E-3, 1E-2, 1E-1,
|
||||||
|
1,
|
||||||
|
1E2, 1E3, 1E6, 1E9, 1E12, 1E15, 1E18, 1E21, 1E24};
|
||||||
|
const int prefix_count = (int)(sizeof(prefixes)/sizeof(char *));
|
||||||
|
|
||||||
|
/* If pointer is invalid, return NaN */
|
||||||
|
if (!out_prefix)
|
||||||
|
return 0.0 / 0.0;
|
||||||
|
|
||||||
|
/* Start with the 2nd smallest prefix */
|
||||||
|
for (idx = 1; idx < prefix_count; idx++) {
|
||||||
|
if (input < scale[idx]) {
|
||||||
|
/* This prefix is bigger than the number. Take the previous one */
|
||||||
|
selected_prefix = prefixes[idx-1];
|
||||||
|
return_val = input / scale[idx-1];
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Check if prefix was set by loop. Else take the largest in the list */
|
||||||
|
if (selected_prefix == NULL) {
|
||||||
|
selected_prefix = prefixes[prefix_count-1];
|
||||||
|
return_val = input / scale[prefix_count-1];
|
||||||
|
}
|
||||||
|
|
||||||
|
if (out_prefix)
|
||||||
|
*out_prefix = selected_prefix;
|
||||||
|
|
||||||
|
return return_val;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void renderer_settings_dialog_update_labels(RendererSettingsDialog *self)
|
||||||
|
{
|
||||||
|
char default_buff[100];
|
||||||
|
double scale;
|
||||||
|
double width_meters;
|
||||||
|
double height_meters;
|
||||||
|
double width_engineering;
|
||||||
|
const char *width_prefix;
|
||||||
|
double height_engineering;
|
||||||
|
const char *height_prefix;
|
||||||
|
|
||||||
|
if (!self)
|
||||||
|
return;
|
||||||
|
|
||||||
|
width_meters = (double)self->cell_width * self->unit_in_meters;
|
||||||
|
height_meters = (double)self->cell_height * self->unit_in_meters;
|
||||||
|
|
||||||
|
width_engineering = convert_number_to_engineering(width_meters, &width_prefix);
|
||||||
|
height_engineering = convert_number_to_engineering(height_meters, &height_prefix);
|
||||||
|
|
||||||
|
snprintf(default_buff, sizeof(default_buff), "Width: %.3lf %sm", width_engineering, width_prefix);
|
||||||
|
gtk_label_set_text(self->x_label, default_buff);
|
||||||
|
snprintf(default_buff, sizeof(default_buff), "Height: %.3lf %sm", height_engineering, height_prefix);
|
||||||
|
gtk_label_set_text(self->y_label, default_buff);
|
||||||
|
|
||||||
|
scale = gtk_range_get_value(GTK_RANGE(self->scale));
|
||||||
|
|
||||||
|
/* Set the pixel sizes */
|
||||||
|
snprintf(default_buff, sizeof(default_buff), "Output Width: %u px",
|
||||||
|
(unsigned int)((double)self->cell_width / scale));
|
||||||
|
gtk_label_set_text(self->x_output_label, default_buff);
|
||||||
|
snprintf(default_buff, sizeof(default_buff), "Output Height: %u px",
|
||||||
|
(unsigned int)((double)self->cell_height / scale));
|
||||||
|
gtk_label_set_text(self->y_output_label, default_buff);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void scale_value_changed(GtkRange *range, gpointer user_data)
|
||||||
|
{
|
||||||
|
(void)range;
|
||||||
|
RendererSettingsDialog *dialog;
|
||||||
|
|
||||||
|
dialog = RENDERER_SETTINGS_DIALOG(user_data);
|
||||||
|
renderer_settings_dialog_update_labels(dialog);
|
||||||
|
}
|
||||||
|
|
||||||
static void renderer_settings_dialog_init(RendererSettingsDialog *self)
|
static void renderer_settings_dialog_init(RendererSettingsDialog *self)
|
||||||
{
|
{
|
||||||
GtkBuilder *builder;
|
GtkBuilder *builder;
|
||||||
GtkWidget *box;
|
GtkWidget *box;
|
||||||
GtkDialog *dialog;
|
GtkDialog *dialog;
|
||||||
|
|
||||||
|
dialog = &self->parent;
|
||||||
|
|
||||||
dialog = &(self->parent);
|
builder = gtk_builder_new_from_resource("/gui/dialog.glade");
|
||||||
|
|
||||||
builder = gtk_builder_new_from_resource("/dialog.glade");
|
|
||||||
box = GTK_WIDGET(gtk_builder_get_object(builder, "dialog-box"));
|
box = GTK_WIDGET(gtk_builder_get_object(builder, "dialog-box"));
|
||||||
self->radio_latex = GTK_WIDGET(gtk_builder_get_object(builder, "latex-radio"));
|
self->radio_latex = GTK_WIDGET(gtk_builder_get_object(builder, "latex-radio"));
|
||||||
self->radio_cairo_pdf = GTK_WIDGET(gtk_builder_get_object(builder, "cairo-pdf-radio"));
|
self->radio_cairo_pdf = GTK_WIDGET(gtk_builder_get_object(builder, "cairo-pdf-radio"));
|
||||||
@@ -89,12 +278,27 @@ static void renderer_settings_dialog_init(RendererSettingsDialog *self)
|
|||||||
self->scale = GTK_WIDGET(gtk_builder_get_object(builder, "dialog-scale"));
|
self->scale = GTK_WIDGET(gtk_builder_get_object(builder, "dialog-scale"));
|
||||||
self->standalone_check = GTK_WIDGET(gtk_builder_get_object(builder, "standalone-check"));
|
self->standalone_check = GTK_WIDGET(gtk_builder_get_object(builder, "standalone-check"));
|
||||||
self->layer_check = GTK_WIDGET(gtk_builder_get_object(builder, "layer-check"));
|
self->layer_check = GTK_WIDGET(gtk_builder_get_object(builder, "layer-check"));
|
||||||
|
self->shape_drawing = GTK_DRAWING_AREA(gtk_builder_get_object(builder, "shape-drawer"));
|
||||||
|
self->x_label = GTK_LABEL(gtk_builder_get_object(builder, "x-label"));
|
||||||
|
self->y_label = GTK_LABEL(gtk_builder_get_object(builder, "y-label"));
|
||||||
|
self->x_output_label = GTK_LABEL(gtk_builder_get_object(builder, "x-output-label"));
|
||||||
|
self->y_output_label = GTK_LABEL(gtk_builder_get_object(builder, "y-output-label"));
|
||||||
|
|
||||||
gtk_dialog_add_buttons(dialog, "Cancel", GTK_RESPONSE_CANCEL, "OK", GTK_RESPONSE_OK, NULL);
|
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_container_add(GTK_CONTAINER(gtk_dialog_get_content_area(dialog)), box);
|
||||||
gtk_window_set_title(GTK_WINDOW(self), "Renderer Settings");
|
gtk_window_set_title(GTK_WINDOW(self), "Renderer Settings");
|
||||||
|
|
||||||
g_signal_connect(self->radio_latex, "toggled", G_CALLBACK(latex_render_callback), (gpointer)self);
|
g_signal_connect(self->radio_latex, "toggled", G_CALLBACK(latex_render_callback), (gpointer)self);
|
||||||
|
g_signal_connect(G_OBJECT(self->shape_drawing),
|
||||||
|
"draw", G_CALLBACK(shape_drawer_drawing_callback), (gpointer)self);
|
||||||
|
|
||||||
|
g_signal_connect(self->scale, "value-changed", G_CALLBACK(scale_value_changed), (gpointer)self);
|
||||||
|
|
||||||
|
/* Default values */
|
||||||
|
self->cell_width = 1;
|
||||||
|
self->cell_height = 1;
|
||||||
|
self->unit_in_meters = 1E-6;
|
||||||
|
renderer_settings_dialog_update_labels(self);
|
||||||
|
|
||||||
g_object_unref(builder);
|
g_object_unref(builder);
|
||||||
}
|
}
|
||||||
@@ -112,10 +316,7 @@ RendererSettingsDialog *renderer_settings_dialog_new(GtkWindow *parent)
|
|||||||
|
|
||||||
void renderer_settings_dialog_get_settings(RendererSettingsDialog *dialog, struct render_settings *settings)
|
void renderer_settings_dialog_get_settings(RendererSettingsDialog *dialog, struct render_settings *settings)
|
||||||
{
|
{
|
||||||
/*GList *radio_buttons;
|
|
||||||
*GList *temp_button_list;
|
|
||||||
*GtkToggleButton *temp_button = NULL;
|
|
||||||
*/
|
|
||||||
if (!settings || !dialog)
|
if (!settings || !dialog)
|
||||||
return;
|
return;
|
||||||
settings->scale = gtk_range_get_value(GTK_RANGE(dialog->scale));
|
settings->scale = gtk_range_get_value(GTK_RANGE(dialog->scale));
|
||||||
@@ -155,9 +356,43 @@ void renderer_settings_dialog_set_settings(RendererSettingsDialog *dialog, struc
|
|||||||
hide_tex_options(dialog);
|
hide_tex_options(dialog);
|
||||||
gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(dialog->radio_cairo_svg), TRUE);
|
gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(dialog->radio_cairo_svg), TRUE);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void renderer_settings_dialog_set_cell_width(RendererSettingsDialog *dialog, unsigned int width)
|
||||||
|
{
|
||||||
|
if (!dialog)
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (width == 0)
|
||||||
|
width = 1;
|
||||||
|
|
||||||
|
dialog->cell_width = width;
|
||||||
|
renderer_settings_dialog_update_labels(dialog);
|
||||||
|
}
|
||||||
|
|
||||||
|
void renderer_settings_dialog_set_cell_height(RendererSettingsDialog *dialog, unsigned int height)
|
||||||
|
{
|
||||||
|
if (!dialog)
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (height == 0)
|
||||||
|
height = 1;
|
||||||
|
|
||||||
|
dialog->cell_height = height;
|
||||||
|
renderer_settings_dialog_update_labels(dialog);
|
||||||
|
}
|
||||||
|
|
||||||
|
void renderer_settings_dialog_set_database_unit_scale(RendererSettingsDialog *dialog, double unit_in_meters)
|
||||||
|
{
|
||||||
|
if (!dialog)
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (unit_in_meters < 0)
|
||||||
|
unit_in_meters *= -1;
|
||||||
|
|
||||||
|
dialog->unit_in_meters = unit_in_meters;
|
||||||
|
renderer_settings_dialog_update_labels(dialog);
|
||||||
|
}
|
||||||
|
|
||||||
/** @} */
|
/** @} */
|
||||||
|
@@ -17,18 +17,26 @@
|
|||||||
* along with GDSII-Converter. If not, see <http://www.gnu.org/licenses/>.
|
* along with GDSII-Converter. If not, see <http://www.gnu.org/licenses/>.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
* The drag and drop implementation is adapted from
|
||||||
|
* https://gitlab.gnome.org/GNOME/gtk/blob/gtk-3-22/tests/testlist3.c
|
||||||
|
*
|
||||||
|
* Thanks to the GTK3 people for creating these examples.
|
||||||
|
*/
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @file layer-element.c
|
* @file layer-element.c
|
||||||
* @brief Omplementation of the layer element used for configuring layer colors etc.
|
* @brief Implementation of the layer element used for configuring layer colors etc.
|
||||||
* @author Mario Hüttel <mario.huettel@gmx.net>
|
* @author Mario Hüttel <mario.huettel@gmx.net>
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @addtogroup Widgets
|
* @addtogroup LayerElement
|
||||||
|
* @ingroup Widgets
|
||||||
* @{
|
* @{
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include "layer-element.h"
|
#include <gds-render/widgets/layer-element.h>
|
||||||
|
|
||||||
G_DEFINE_TYPE(LayerElement, layer_element, GTK_TYPE_LIST_BOX_ROW)
|
G_DEFINE_TYPE(LayerElement, layer_element, GTK_TYPE_LIST_BOX_ROW)
|
||||||
|
|
||||||
@@ -50,82 +58,11 @@ static void layer_element_class_init(LayerElementClass *klass)
|
|||||||
oclass->constructed = layer_element_constructed;
|
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)
|
static void layer_element_init(LayerElement *self)
|
||||||
{
|
{
|
||||||
GtkBuilder *builder;
|
GtkBuilder *builder;
|
||||||
GtkWidget *glade_box;
|
GtkWidget *glade_box;
|
||||||
builder = gtk_builder_new_from_resource("/layer-widget.glade");
|
builder = gtk_builder_new_from_resource("/gui/layer-widget.glade");
|
||||||
glade_box = GTK_WIDGET(gtk_builder_get_object(builder, "box"));
|
glade_box = GTK_WIDGET(gtk_builder_get_object(builder, "box"));
|
||||||
gtk_container_add(GTK_CONTAINER(self), glade_box);
|
gtk_container_add(GTK_CONTAINER(self), glade_box);
|
||||||
|
|
||||||
@@ -136,13 +73,6 @@ static void layer_element_init(LayerElement *self)
|
|||||||
self->priv.name = GTK_ENTRY(gtk_builder_get_object(builder, "entry"));
|
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"));
|
self->priv.event_handle = GTK_EVENT_BOX(gtk_builder_get_object(builder, "event-box"));
|
||||||
|
|
||||||
/* 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);
|
g_object_unref(builder);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -191,12 +121,30 @@ void layer_element_get_color(LayerElement *elem, GdkRGBA *rgba)
|
|||||||
{
|
{
|
||||||
if (!rgba)
|
if (!rgba)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
gtk_color_chooser_get_rgba(GTK_COLOR_CHOOSER(elem->priv.color), rgba);
|
gtk_color_chooser_get_rgba(GTK_COLOR_CHOOSER(elem->priv.color), rgba);
|
||||||
}
|
}
|
||||||
|
|
||||||
void layer_element_set_color(LayerElement *elem, GdkRGBA *rgba)
|
void layer_element_set_color(LayerElement *elem, GdkRGBA *rgba)
|
||||||
{
|
{
|
||||||
|
if (!elem || !rgba)
|
||||||
|
return;
|
||||||
|
|
||||||
gtk_color_chooser_set_rgba(GTK_COLOR_CHOOSER(elem->priv.color), rgba);
|
gtk_color_chooser_set_rgba(GTK_COLOR_CHOOSER(elem->priv.color), rgba);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void layer_element_set_dnd_callbacks(LayerElement *elem, struct layer_element_dnd_data *data)
|
||||||
|
{
|
||||||
|
if (!elem || !data)
|
||||||
|
return;
|
||||||
|
|
||||||
|
/* Setup drag and drop */
|
||||||
|
gtk_style_context_add_class (gtk_widget_get_style_context(GTK_WIDGET(elem)), "row");
|
||||||
|
gtk_drag_source_set(GTK_WIDGET(elem->priv.event_handle), GDK_BUTTON1_MASK, data->entries, data->entry_count, GDK_ACTION_MOVE);
|
||||||
|
g_signal_connect(elem->priv.event_handle, "drag-begin", G_CALLBACK(data->drag_begin), NULL);
|
||||||
|
g_signal_connect(elem->priv.event_handle, "drag-data-get", G_CALLBACK(data->drag_data_get), NULL);
|
||||||
|
g_signal_connect(elem->priv.event_handle, "drag-end", G_CALLBACK(data->drag_end), NULL);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
/** @} */
|
/** @} */
|
||||||
|
Reference in New Issue
Block a user