113 Commits

Author SHA1 Message Date
d08cd3626d Update Usage page and application screenshot 2019-05-14 19:59:43 +02:00
ef180f3ea2 Add version generation script to doxygen generation script 2019-05-14 19:58:52 +02:00
74ecde9807 Revert "gds-parser: Remove unnecessary code. Fix #13"
Code wasn't unnecessary. Oops.

This reverts commit aa413732f1.
2019-05-14 19:46:17 +02:00
cd2cf8c5c7 Add versioning scheme to documentation 2019-05-14 19:39:29 +02:00
63eb65a3c4 Fix #12: Wrong markdown in usage page. 2019-05-14 19:37:23 +02:00
aa413732f1 gds-parser: Remove unnecessary code. Fix #13 2019-05-14 18:35:40 +02:00
54165a8475 conv-settings-dialog: harden number2eng function against null pointer 2019-05-12 14:16:36 +02:00
c3c4636334 Add cell name to renderer settings dialog title bar 2019-04-08 19:05:07 +02:00
f4de9c4402 Code rework 2019-04-08 18:23:30 +02:00
a016a18587 Improve doxygen 2019-03-30 19:55:47 +01:00
a3626e7b33 Improve doxygen documentation 2019-03-30 19:51:56 +01:00
4dcafeed3f Update doxygen reference 2019-03-28 22:14:11 +01:00
03e2b15571 Add dirty flag to git describe command used for the version string. 2019-03-28 22:02:00 +01:00
e278ad6d94 Move each GTK Widget to its own documentation group 2019-03-26 21:12:37 +01:00
8d8af8d211 Add compiler warnings to documentation 2019-03-26 21:12:05 +01:00
4bed016f01 Update documentation: Add compilation page, fix additional mistake in cell-geometrics.h 2019-03-26 21:00:05 +01:00
e8c7f78af4 Update include file hierarchy: Move include file to central include tree 2019-03-26 19:57:19 +01:00
60e20f45cc Merge branch 'master' into dev 2019-03-25 19:06:26 +01:00
cd55137951 Grouped widgets into GUI group 2019-03-25 19:05:57 +01:00
d6fb6ba6b0 Remove SVG output from GUI, fixes issue #9 2019-03-25 18:57:48 +01:00
829c9a2386 Restructure code, improve doxygen documentation 2019-03-25 18:47:12 +01:00
a99a469cf0 Rename functions of mapping parser 2019-03-25 17:56:57 +01:00
f237004e6c Remove useless function call 2019-03-22 22:43:24 +01:00
188086de52 Rework code: simplify if 2019-03-22 22:24:48 +01:00
38f18009fc Rework Cairo-Render output messages 2019-03-22 22:15:56 +01:00
ff3f692f2c Make renderer settings dialog settings unique for each window 2019-03-22 21:59:43 +01:00
5537c076a8 Add logo as resource and configure about dialog to use logo from resource 2019-03-21 22:22:35 +01:00
b43b142a75 Coding improvements in conversion settings dialog 2019-03-21 21:48:11 +01:00
4c0df56386 cast unused variables 2019-03-21 21:26:31 +01:00
008fe52cb2 Rename gds-parser folder to gds-utils because it no longer contains only the parser 2019-03-21 21:24:59 +01:00
67f9d9b4ee Add source for ListBox Drag and Drop 2019-03-18 21:12:47 +01:00
e289e7b301 fix compiler warnings 2019-03-16 16:24:39 +01:00
b9cc8570ac Use signal for gui disposement. Whena gui is closed, the library data is relesed 2019-03-16 16:09:29 +01:00
5357aff1b8 Fix bug which allowd moving layer elements between different windows. 2019-03-15 23:46:06 +01:00
64508104bc Move drag and drop code from layer element to layer selector. 2019-03-15 23:17:03 +01:00
60f54e2240 Typo 2019-03-15 23:16:39 +01:00
19b26a3c26 Fix bugs in closing gds render windows 2019-03-15 20:36:23 +01:00
28734a797a Merge branch 'master' into rework-main-window-gui 2019-03-15 20:02:53 +01:00
31d9d26aa4 Implement multiple GUI per process feature. Still buggy. 2019-03-15 20:02:03 +01:00
45f0d90a87 remove layer-selector-dnd.h file 2019-03-15 18:23:25 +01:00
33deba8ca4 Command line: Fix auto-guessing of SVG file name. 2019-03-15 18:03:29 +01:00
587b79dc31 Command line: print out unprocessed parameters 2019-03-15 17:57:59 +01:00
67e5023c1e Command line: Fix auto-guessing of SVG file name. 2019-03-15 17:56:53 +01:00
c94c3d591e rework layer selector. This commit is compilable. Layer selector is now a separate GObject 2019-03-14 23:40:26 +01:00
c9e2c2a76d Rename layer selector functions. Attention. This commit breaks the code. Compile a later commit, that implements the full feature set, This starts the reworking of the cell selector as a gobject class 2019-03-14 21:40:53 +01:00
bb2a4f7f04 Rename layer info deletion function 2019-03-14 21:39:12 +01:00
6b03695824 Restructured Code
* Move layer info struct and associated functions to dedicated c/h files.
* Rename layer selector folder more generic "layer"

Besides from restructuring nothing changes
2019-03-14 21:30:37 +01:00
b0c25a4bcf Add version number to about dialog 2019-03-14 21:01:16 +01:00
899c8daf81 Add documentation target, which at the moment is only an alias for the
doxygen target
2019-03-14 19:24:17 +01:00
a9c7b9f61f Gui: Menubar: GActionEntry definition expanded to set unused values to zero, especially pointers 2019-03-14 19:10:06 +01:00
55fd080796 Fix Issue #11
* Set NON_UNIQUE Flag of GApplication. When opening a second program instance, Glib will not try to open a second window inside the first instance, which was the feature, that caused problems
2019-03-14 19:02:17 +01:00
178ef2d5b2 Insert quick fix, that prevents starting multiple instances in GUI mode the same time 2019-03-13 22:54:52 +01:00
6a78e0df15 Fix background color of drag element in Drag and Drop code for the layer
selector.

With this commit Issue #8 is fixed.
2019-03-13 21:01:49 +01:00
1e6d0bd1b9 Restructured code for layer selector 2019-03-13 20:32:09 +01:00
658e681c38 Implement a more convenient drag and drop 2019-03-13 20:22:11 +01:00
e24b4a8367 implement layer sorting buttons, This fixes #5 2019-03-12 19:47:39 +01:00
960a773ed1 Implement fucntion to force sort of the layer selector 2019-03-12 19:39:36 +01:00
ab23be1cfc Make enum in sorting function const 2019-03-12 19:28:17 +01:00
72d5352b09 Change sorting function in order to add capability to sort both ways 2019-03-12 19:26:31 +01:00
3f198f870a Add buttons for layer sorting to glade file 2019-03-12 19:10:43 +01:00
2a204640bd Add warning to probably misunderstandable function 2019-03-12 19:02:34 +01:00
a237a89ecf Feature: Double click on cells now also opens the convert settings menu. Same callback as for the convert button is used. 2019-03-11 23:33:51 +01:00
1ec0f9b297 Merge branch 'master' of git.shimatta.de:mhu/gds-render 2019-03-11 10:38:35 +01:00
2f2eb90b69 Add automatic version numbering to command line and GUI 2019-03-11 10:36:02 +01:00
bbf08a4d6e style fix, convert dialog size preview in SI units 2019-03-08 20:46:48 +01:00
34a19fa11d Fix style in external renderer 2019-03-07 20:35:23 +01:00
b4ae8eee37 fix style issues in main-window.c 2019-03-07 20:32:55 +01:00
6e1b7d3f61 Update style checker to new version 2019-03-07 20:26:03 +01:00
d1e6e7b05a fix style issues in main.c 2019-03-07 20:14:44 +01:00
187ae2a74b Add style checker as submodule 2019-03-07 20:00:54 +01:00
eeae61ad47 Check cells before displaying them and color the cells accordingly. Fixes #4 2019-03-06 20:07:26 +01:00
3146ca801f Add functions for checking cell reference loops 2019-03-06 20:06:01 +01:00
43fdab4533 Improve GDS parser 2019-03-06 20:04:49 +01:00
59835018af Edit colors 2019-03-06 19:58:26 +01:00
d81c6d1037 Make gds-parser more robust 2019-03-06 18:16:14 +01:00
ba53a1151e Add cell recursion cehck to command line interface 2019-03-06 18:15:50 +01:00
fdf2c9a42b fix style issue 2019-03-06 18:15:11 +01:00
34c113517b Fox doxygen file header 2019-03-06 18:14:53 +01:00
5291b682c7 remove braces around scale to prevent doxygen from interpreting this as HTML tag 2019-03-06 17:38:47 +01:00
e76f2cbb9d Merge branch 'master' into dev 2019-03-05 21:48:26 +01:00
586339cac1 fix doxygen 2019-03-05 21:46:29 +01:00
3882f3944e Change selction filter function. Now only cells without major errors are selectable. Warnings are okay because the renderers can handle these (unresolved references etc...) 2019-03-05 21:03:27 +01:00
00b47d7ded Add lib cell renderer to main window. It is needed for the Error level defines of the cells 2019-03-05 20:55:04 +01:00
e9b67fe1bc Implement error level indicator for cells 2019-03-05 20:52:00 +01:00
976bdd9854 Fix function description 2019-03-05 20:21:49 +01:00
73e4806e65 Implenment child cell resolve checker 2019-03-05 20:14:07 +01:00
0b17c25ecc Add defualt value for check results 2019-03-05 20:08:10 +01:00
0ef6d2f40f update trigonometric library doxygen 2019-03-05 19:50:01 +01:00
58bb74b905 Add checks to cell structure 2019-03-05 19:48:03 +01:00
cd9030a24e Create GDS Tree checking functions. Renamed doxygen section of GDS Parser to GDS-Utilities so the cheking function fit into this section 2019-03-05 19:38:07 +01:00
546332a9c2 Merge branch 'dev' 2019-03-04 20:20:15 +01:00
68e7d52cd8 Changed settings dialog api to use database units. Implement render output size preview 2019-03-04 20:14:21 +01:00
91a3e8f983 Fix style 2019-03-04 19:35:25 +01:00
f74e2d5cf5 Fix bug 2019-03-04 19:35:04 +01:00
8ffb1d42b6 Fix bug of wrong bounding box calculation: Replace DBL_MIN with -DBL_MAX 2019-02-28 21:21:00 +01:00
845da756b7 Fix bug of wrong bounding box calculation: Replace DBL_MIN with -DBL_MAX 2019-02-28 21:17:54 +01:00
531634b55a Fix bug in bounding box 2d translation 2019-02-27 21:42:54 +01:00
2e1cf456c7 Add pointer to parent library to cells, implement first draft of cell size/shape preview 2019-02-27 21:33:12 +01:00
bce47f11fc Fix formatting 2019-02-27 20:28:53 +01:00
5573ceb46b Fix formatting in GDS-Parser 2019-02-27 20:28:06 +01:00
7124c9a5cc Add fallthrough mark, correct Typo 2019-02-27 20:27:01 +01:00
d5997ab5f2 Merge branch 'master' into dev 2019-02-22 20:04:27 +01:00
e692129477 fix minor code style stuff 2019-02-22 19:54:08 +01:00
af031acc38 Merge branch 'master' into dev 2019-02-03 22:56:47 +01:00
199833d603 Updated code for cell size calculation 2018-12-29 01:13:33 +01:00
b0acbda6e3 Temporarily re-enabled SVG output (from GUI only)
* Cairo version: 1.16.0-1
* SVG output doens't seem as broken as before with the current cairo version
* Transparency doesn't work. Transparent layers aren't rendered at all.
2018-12-22 21:30:16 +01:00
7e4b915961 Remove useless empty lines 2018-12-22 21:06:52 +01:00
1fe70422db Update size labels when size is set 2018-12-22 21:04:34 +01:00
b5087769ee Add cell size preview to dialog 2018-12-22 20:54:02 +01:00
4f9e5ca0b4 Add drawing area for size demonstartion 2018-12-22 19:37:57 +01:00
a2b83c37a9 Edit trigonometric functions 2018-12-22 19:31:36 +01:00
15ff68ea74 Fix invalid conversion 2018-12-22 19:13:33 +01:00
6bb05890b9 Add database unit parsing 2018-12-22 19:11:09 +01:00
72 changed files with 3355 additions and 3275 deletions

3
.gitmodules vendored Normal file
View File

@@ -0,0 +1,3 @@
[submodule "c-style-checker"]
path = c-style-checker
url = https://git.shimatta.de/mhu/c-style-checker

View File

@@ -8,34 +8,39 @@ pkg_check_modules(CAIRO REQUIRED cairo)
add_subdirectory(glade)
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})
add_definitions(${GLIB2_CFLAGS_OTHER})
aux_source_directory("widgets" LAYER_SOURCES)
aux_source_directory("tree-renderer" RENDERER_SOURCES)
aux_source_directory("gds-parser" PARSER_SOURCES)
aux_source_directory("latex-output" LATEX_SOURCES)
aux_source_directory("cairo-output" CAIRO_SOURCES)
aux_source_directory("trigonometric" TRIG_SOURCES)
set(SOURCE "main.c" "layer-selector.c" "mapping-parser.c" "command-line.c" "main-window.c" "external-renderer.c")
aux_source_directory("gds-utils" GDS_SOURCES)
aux_source_directory("latex-renderer" LATEX_SOURCES)
aux_source_directory("cairo-renderer" CAIRO_SOURCES)
aux_source_directory("geometric" GEOMETRIC_SOURCES)
aux_source_directory("layer" LAYER_SELECTOR_SOURCES)
set(SOURCE "main.c" "command-line.c" "gds-render-gui.c" "external-renderer.c")
set(SOURCE
${SOURCE}
${LAYER_SOURCES}
${RENDERER_SOURCES}
${PARSER_SOURCES}
${GDS_SOURCES}
${LATEX_SOURCES}
${CAIRO_SOURCES}
${TRIG_SOURCES}
${GEOMETRIC_SOURCES}
${LAYER_SELECTOR_SOURCES}
)
add_compile_options(-Wall)
add_executable(${PROJECT_NAME} ${SOURCE} ${CMAKE_CURRENT_BINARY_DIR}/glade/resources.c)
add_dependencies(${PROJECT_NAME} glib-resources)
add_dependencies(${PROJECT_NAME} version)
SET_SOURCE_FILES_PROPERTIES(${CMAKE_CURRENT_BINARY_DIR}/glade/resources.c PROPERTIES GENERATED 1)
target_link_libraries(${PROJECT_NAME} ${GLIB_LDFLAGS} ${GTK3_LDFLAGS} ${CAIRO_LDFLAGS} m ${CMAKE_DL_LIBS})
target_link_libraries(${PROJECT_NAME} ${GLIB_LDFLAGS} ${GTK3_LDFLAGS} ${CAIRO_LDFLAGS} m version ${CMAKE_DL_LIBS})
install (TARGETS ${PROJECT_NAME} DESTINATION bin)
add_custom_target(documentation DEPENDS doxygen)

View File

@@ -1,4 +1,4 @@
# GDS-Render
# GDS-Render Readme
This software is a rendering programm for GDS2 layout files.
The GDS2 format is mainly used in integrated circuit development.

1
c-style-checker Submodule

Submodule c-style-checker added at 3a58e3dd1c

View File

@@ -26,13 +26,14 @@
* @{
*/
#include "cairo-output.h"
#include <math.h>
#include <stdlib.h>
#include <cairo.h>
#include <cairo-pdf.h>
#include <cairo-svg.h>
#include <gds-render/cairo-renderer/cairo-output.h>
/**
* @brief The cairo_layer struct
* Each rendered layer is represented by this struct.
@@ -235,8 +236,12 @@ void cairo_render_cell_to_vector_file(struct gds_cell *cell, GList *layer_infos,
/* Print size */
cairo_recording_surface_ink_extents(layers[linfo->layer].rec, &rec_x0, &rec_y0,
&rec_width, &rec_height);
printf("Size of layer %d: %lf -- %lf\n", linfo->layer,
rec_width, rec_height);
printf("Size of layer %d%s%s%s: <%lf x %lf> @ (%lf | %lf)\n",
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 */
xmin = MIN(xmin, rec_x0);
@@ -250,7 +255,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) {
pdf_surface = cairo_pdf_surface_create(pdf_file, xmax-xmin, ymax-ymin);

View File

@@ -24,23 +24,27 @@
*/
/**
* @addtogroup MainApplication
* @addtogroup cmdline
* @{
*/
#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>
#include <gds-render/gds-utils/gds-parser.h>
#include <gds-render/layer/mapping-parser.h>
#include <gds-render/layer/layer-info.h>
#include <gds-render/cairo-renderer/cairo-output.h>
#include <gds-render/latex-renderer/latex-output.h>
#include <gds-render/external-renderer.h>
#include <gds-render/gds-utils/gds-tree-checker.h>
/**
* @brief Delete layer_info and free nem element.
*
* Like delete_layer_info_struct() but also frees layer_info::name
* @param info
* @warning This function must not be used if the layer_info::name field references the internal storage strings if e.g. an entry field
*/
static void delete_layer_info_with_name(struct layer_info *info)
{
@@ -69,8 +73,10 @@ void command_line_convert_gds(char *gds_name, char *pdf_name, char *tex_name, gb
GList *layer_info_list = NULL;
GList *cell_list;
struct layer_info *linfo_temp;
struct gds_library *first_lib;
struct gds_cell *toplevel_cell = NULL, *temp_cell;
/* Check if parameters are valid */
if (!gds_name || (!pdf_name && pdf) || (!tex_name && tex) || !layer_file || !cell_name) {
printf("Probably missing argument. Check --help option\n");
@@ -81,26 +87,26 @@ void command_line_convert_gds(char *gds_name, char *pdf_name, char *tex_name, gb
clear_lib_list(&libs);
res = parse_gds_from_file(gds_name, &libs);
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;
goto ret_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);
res = mapping_parser_load_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;
goto ret_clear_layer_list;
}
linfo_temp->color.alpha = layer_color.alpha;
linfo_temp->color.red = layer_color.red;
@@ -116,9 +122,15 @@ void command_line_convert_gds(char *gds_name, char *pdf_name, char *tex_name, gb
/* find_cell in first library. */
if (!libs)
goto ret_clear_list;
goto ret_clear_layer_list;
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;
if (!first_lib) {
fprintf(stderr, "No library in library list. This should not happen.\n");
goto ret_clear_layer_list;
}
for (cell_list = first_lib->cells; cell_list != NULL; cell_list = g_list_next(cell_list)) {
temp_cell = (struct gds_cell *)cell_list->data;
if (!strcmp(temp_cell->name, cell_name)) {
toplevel_cell = temp_cell;
@@ -128,9 +140,31 @@ void command_line_convert_gds(char *gds_name, char *pdf_name, char *tex_name, gb
if (!toplevel_cell) {
printf("Couldn't find cell in first library!\n");
goto ret_clear_list;
goto ret_clear_layer_list;
}
/* Check if cell passes vital checks */
res = gds_tree_check_reference_loops(toplevel_cell->parent_library);
if (res < 0) {
fprintf(stderr, "Checking library %s failed.\n", first_lib->name);
goto ret_clear_layer_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_clear_layer_list;
}
}
if (toplevel_cell->checks.affected_by_reference_loop == GDS_CELL_CHECK_NOT_RUN)
fprintf(stderr, "Cell was not checked. This should not happen. Please report this issue. Will continue either way.\n");
/* Note: unresolved references are not an abort condition.
* Deal with it.
*/
/* Render outputs */
if (pdf == TRUE || svg == TRUE) {
cairo_render_cell_to_vector_file(toplevel_cell, layer_info_list, (pdf == TRUE ? pdf_name : NULL),
@@ -140,14 +174,14 @@ void command_line_convert_gds(char *gds_name, char *pdf_name, char *tex_name, gb
if (tex == TRUE) {
tex_file = fopen(tex_name, "w");
if (!tex_file)
goto ret_clear_list;
goto ret_clear_layer_list;
latex_render_cell_to_code(toplevel_cell, layer_info_list, tex_file, scale, pdf_layers, pdf_standalone);
fclose(tex_file);
}
if (so_name && so_out_file) {
if (strlen(so_name) == 0 || strlen(so_out_file) == 0)
goto ret_clear_list;
goto ret_clear_layer_list;
/* Render output using external renderer */
printf("Invoking external renderer!\n");
@@ -155,15 +189,16 @@ void command_line_convert_gds(char *gds_name, char *pdf_name, char *tex_name, gb
printf("External renderer finished!\n");
}
ret_clear_list:
ret_clear_layer_list:
g_list_free_full(layer_info_list, (GDestroyNotify)delete_layer_info_with_name);
g_object_unref(dstream);
g_object_unref(stream);
destroy_file:
ret_destroy_file:
g_object_unref(file);
/* Delete all allocated libraries */
ret_destroy_library_list:
clear_lib_list(&libs);
}
/** @} */

View File

@@ -1,10 +1,10 @@
find_package(Doxygen)
if (DOXYGEN_FOUND)
add_custom_target(doxygen
COMMAND ./build-doxygen.sh "${PROJECT_BINARY_DIR}"
WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}
COMMENT "Generating documentation with Doxygen")
else (DOXYGEN_FOUND)
message("Doxygen need to be installed to generate the doxygen documentation")
endif (DOXYGEN_FOUND)

View File

@@ -9,7 +9,7 @@ done
DIR="$( cd -P "$( dirname "$SOURCE" )" >/dev/null && pwd )"
cd "$DIR"
export PROJECT_NUMBER=`git describe --tags`
export PROJECT_NUMBER=`../version/generate-version-string.sh`
if [ $# != 1 ]; then
export OUTPUT_DIRECTORY="./output"

View File

@@ -0,0 +1,4 @@
/**
* @defgroup Cairo-Renderer Cairo Renderer
* @ingroup renderers
*/

3
doxygen/command-line.dox Normal file
View File

@@ -0,0 +1,3 @@
/**
* @defgroup cmdline Command Line Interface
*/

67
doxygen/compilation.dox Normal file
View File

@@ -0,0 +1,67 @@
/**
@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 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. |
*/

View File

@@ -0,0 +1,4 @@
/**
* @defgroup external-renderer External Shared Object Renderer
* @ingroup renderers
*/

8
doxygen/geometric.dox Normal file
View 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!
*/

View File

@@ -1,6 +1,5 @@
/* 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

Binary file not shown.

After

Width:  |  Height:  |  Size: 35 KiB

File diff suppressed because it is too large Load Diff

Before

Width:  |  Height:  |  Size: 114 KiB

View File

@@ -0,0 +1,4 @@
/**
* @defgroup LaTeX-Renderer LaTeX/TikZ Renderer
* @ingroup renderers
*/

View 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.
*/

View 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.
*
*/

View File

@@ -6,10 +6,7 @@ This programm converts GDS layout files to
- PDF Files using the @ref Cairo-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
View 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.
*/

View File

@@ -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!
*/

View File

@@ -1,21 +1,21 @@
/**
@page usage Usage
@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'.
Application Options:
- -t, --tikz Output TikZ code
- -p, --pdf Output PDF document
- -s, --scale=<SCALE> Divide output coordinates by <SCALE>
- -o, --tex-output=PATH Optional path for TeX file
- -O, --pdf-output=PATH Optional path for PDF file
- -m, --mapping=PATH Path for Layer Mapping File
- -c, --cell=NAME Cell to render
- -a, --tex-standalone Create standalone PDF
- -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
- -e, --external-lib-output=PATH Output path for external render library
- --display=DISPLAY X display to use
- -t, `--`tikz Output TikZ code
- -p, `--`pdf Output PDF document
- -s, `--`scale=SCALE Divide output coordinates by SCALE
- -o, `--`tex-output=PATH Optional path for TeX file
- -O, `--`pdf-output=PATH Optional path for PDF file
- -m, `--`mapping=PATH Path for Layer Mapping File
- -c, `--`cell=NAME Cell to render
- -a, `--`tex-standalone Create standalone PDF
- -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
- -e, `--`external-lib-output=PATH Output path for external render library
- `--`display=DISPLAY X display to use
@section gui Graphical User Interface
@@ -24,7 +24,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
@image html gui.svg
@image latex gui.pdf
@image html gui.png
@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
View 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 doxumentation 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.
**/

View File

@@ -2,5 +2,5 @@
/**
* @defgroup Widgets Custom GTK Widgets
*
* @ingroup GUI
*/

View File

@@ -24,15 +24,17 @@
*/
/**
* @addtogroup MainApplication
* @addtogroup external-renderer
* @{
*/
#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)
#include <gds-render/external-renderer.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;
@@ -40,9 +42,8 @@ int external_renderer_render_cell(struct gds_cell *toplevel_cell, GList *layer_i
int ret = 0;
/* Check parameter sanity */
if (!output_file || !so_path || !toplevel_cell || !layer_info_list) {
if (!output_file || !so_path || !toplevel_cell || !layer_info_list)
return -3000;
}
/* Load shared object */
so_handle = dlopen(so_path, RTLD_LAZY);
@@ -53,7 +54,8 @@ int external_renderer_render_cell(struct gds_cell *toplevel_cell, GList *layer_i
/* Load symbol from library */
so_render_func = (int (*)(struct gds_cell *, GList *, char *))dlsym(so_handle, EXTERNAL_LIBRARY_FUNCTION);
if ((error_msg = dlerror()) != NULL) {
error_msg = dlerror();
if (error_msg != NULL) {
printf("Rendering function not found in library:\n%s\n", error_msg);
goto ret_close_so_handle;
}

559
gds-render-gui.c Normal file
View File

@@ -0,0 +1,559 @@
/*
* 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/tree-renderer/tree-store.h>
#include <gds-render/tree-renderer/lib-cell-renderer.h>
#include <gds-render/latex-renderer/latex-output.h>
#include <gds-render/cairo-renderer/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;
struct render_settings render_dialog_settings;
};
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 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);
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;
main_builder = gtk_builder_new_from_resource("/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));
/* 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);
g_object_unref(main_builder);
/* 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;
/* Reference all objects referenced by this object */
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);
}
GdsRenderGui *gds_render_gui_new()
{
return RENDERER_GUI(g_object_new(RENDERER_TYPE_GUI, NULL));
}
/** @} */

View File

@@ -17,11 +17,6 @@
* along with GDSII-Converter. If not, see <http://www.gnu.org/licenses/>.
*/
/*
*/
/**
* @file gds-parser.c
* @brief Implementation of the GDS-Parser
@@ -35,12 +30,10 @@
*/
/**
* @addtogroup GDS-Parser
* @addtogroup GDS-Utilities
* @{
*/
#include "gds-parser.h"
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
@@ -48,11 +41,19 @@
#include <math.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_WARN(fmt, ...) printf("[PARSE_WARNING] " fmt "\n", ##__VA_ARGS__) /**< @brief Print GDS warning */
#if GDS_PRINT_DEBUG_INFOS
#define GDS_INF(fmt, ...) printf(fmt, ##__VA_ARGS__) /**< @brief standard printf. But cna be disabled in code */
#define GDS_INF(fmt, ...) printf(fmt, ##__VA_ARGS__) /**< @brief standard printf. But can be disabled in code */
#else
#define GDS_INF(fmt, ...)
#endif
@@ -221,7 +222,7 @@ static GList *append_library(GList *curr_list, struct gds_library **library_ptr)
if (lib) {
lib->cells = NULL;
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;
} else
return NULL;
@@ -297,6 +298,9 @@ static GList *append_cell(GList *curr_list, struct gds_cell **cell_ptr)
cell->child_cells = NULL;
cell->graphic_objs = NULL;
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
return NULL;
/* return cell */
@@ -383,7 +387,7 @@ static int name_cell(struct gds_cell *cell, unsigned int bytes,
return -1;
}
data[bytes] = 0; // Append '0'
len = strlen(data);
len = (int)strlen(data);
if (len > CELL_NAME_MAX-1) {
GDS_ERROR("Cell name '%s' too long: %d\n", data, len);
return -1;
@@ -458,6 +462,7 @@ static void scan_cell_reference_dependencies(gpointer gcell, gpointer library)
static void scan_library_references(gpointer library_list_item, gpointer user)
{
struct gds_library *lib = (struct gds_library *)library_list_item;
(void)user;
GDS_INF("Scanning Library: %s\n", lib->name);
g_list_foreach(lib->cells, scan_cell_reference_dependencies, lib);
@@ -607,12 +612,20 @@ int parse_gds_from_file(const char *filename, GList **library_list)
GDS_INF("Leaving Library\n");
break;
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, &current_cell);
if (current_lib->cells == NULL) {
GDS_ERROR("Allocating memory failed");
run = -3;
break;
}
current_cell->parent_library = current_lib;
GDS_INF("Entering Cell\n");
break;
case ENDSTR:
@@ -649,7 +662,7 @@ int parse_gds_from_file(const char *filename, GList **library_list)
break;
case SREF:
if (current_cell == NULL) {
GDS_ERROR("Path outside of cell");
GDS_ERROR("Cell Reference outside of cell");
run = -3;
break;
}
@@ -710,6 +723,8 @@ int parse_gds_from_file(const char *filename, GList **library_list)
break;
case PATHTYPE:
break;
case UNITS:
break;
default:
//GDS_WARN("Record: %04x, len: %u", (unsigned int)rec_type, (unsigned int)rec_data_length);
break;
@@ -717,7 +732,7 @@ int parse_gds_from_file(const char *filename, GList **library_list)
/* 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);
@@ -731,7 +746,6 @@ int parse_gds_from_file(const char *filename, GList **library_list)
switch (rec_type) {
case HEADER:
case UNITS:
case ENDLIB:
case ENDSTR:
case BOUNDARY:
@@ -742,6 +756,20 @@ int parse_gds_from_file(const char *filename, GList **library_list)
case INVALID:
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:
/* Parse date record */
gds_parse_date(workbuff, read, &current_lib->mod_time, &current_lib->access_time);
@@ -782,7 +810,11 @@ int parse_gds_from_file(const char *filename, GList **library_list)
break;
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 {
GDS_ERROR("reference name set outside of cell reference.\n");
}
break;
case WIDTH:
if (!current_graphics) {
@@ -835,7 +867,7 @@ int parse_gds_from_file(const char *filename, GList **library_list)
break;
}
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);
} else {
GDS_WARN("Path type defined inside non-path graphics object. Ignoring");
@@ -848,15 +880,11 @@ int parse_gds_from_file(const char *filename, GList **library_list)
fclose(gds_file);
if (!run) {
/* Iterate and find references to cells */
g_list_foreach(lib_list, scan_library_references, NULL);
}
*library_list = lib_list;
free(workbuff);
@@ -870,7 +898,8 @@ int parse_gds_from_file(const char *filename, GList **library_list)
*/
static void delete_cell_inst_element(struct gds_cell_instance *cell_inst)
{
free(cell_inst);
if (cell_inst)
free(cell_inst);
}
/**
@@ -879,7 +908,8 @@ static void delete_cell_inst_element(struct gds_cell_instance *cell_inst)
*/
static void delete_vertex(struct gds_point *vertex)
{
free(vertex);
if (vertex)
free(vertex);
}
/**
@@ -888,6 +918,9 @@ static void delete_vertex(struct gds_point *vertex)
*/
static void delete_graphics_obj(struct gds_graphics *gfx)
{
if (!gfx)
return;
g_list_free_full(gfx->vertices, (GDestroyNotify)delete_vertex);
free(gfx);
}
@@ -898,6 +931,9 @@ static void delete_graphics_obj(struct gds_graphics *gfx)
*/
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->graphic_objs, (GDestroyNotify)delete_graphics_obj);
free(cell);
@@ -909,6 +945,9 @@ static void delete_cell_element(struct gds_cell *cell)
*/
static void delete_library_element(struct gds_library *lib)
{
if (!lib)
return;
g_list_free(lib->cell_names);
g_list_free_full(lib->cells, (GDestroyNotify)delete_cell_element);
free(lib);
@@ -916,8 +955,12 @@ static void delete_library_element(struct gds_library *lib)
int clear_lib_list(GList **library_list)
{
if (!library_list)
return 0;
if (*library_list == NULL)
return 0;
g_list_free_full(*library_list, (GDestroyNotify)delete_library_element);
*library_list = NULL;
return 0;

View File

@@ -0,0 +1,201 @@
/*
* 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 cehcking 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 (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;
}
}
if (visited_cells) {
fprintf(stderr, "Visited cell list should be empty. This is a bug. Please report this.\n");
g_list_free(visited_cells);
}
return loop_count;
}
/** @} */

View File

@@ -24,21 +24,22 @@
*/
/**
* @addtogroup trigonometric
* @addtogroup geometric
* @{
*/
#include <stdio.h>
#include "bounding-box.h"
#include <math.h>
#include <gds-render/geometric/bounding-box.h>
#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 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)
{
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;
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.y = DBL_MAX;
box->vectors.upper_right.x = DBL_MIN;
box->vectors.upper_right.y = DBL_MIN;
box->vectors.upper_right.x = -DBL_MAX;
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,
@@ -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);
}
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)
{
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
View 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(&current_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,
&current_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,
&current_box);
break;
default:
/* Unknown graphics object. */
/* Print error? Nah.. */
break;
}
/* Update box with results */
bounding_box_update_box(box, &current_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);
}
}
/** @} */

View File

@@ -24,14 +24,15 @@
*/
/**
* @addtogroup trigonometric
* @addtogroup geometric
* @{
*/
#include "vector-operations.h"
#include <math.h>
#include <stdlib.h>
#include <gds-render/geometric/vector-operations.h>
#define ABS_DBL(a) ((a) < 0 ? -(a) : (a))
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)
return NULL;
if (opt_res) {
opt_res->x = vec->x;
opt_res->y = vec->y;
return opt_res;
} else {
if (opt_res)
res = opt_res;
else
res = vector_2d_alloc();
if (res) {
res->x = vec->x;
res->y = vec->y;
}
return res;
if (res) {
res->x = vec->x;
res->y = vec->y;
}
return res;
}
struct vector_2d *vector_2d_alloc(void)

View File

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

View File

@@ -10,7 +10,7 @@
<property name="website">https://git.shimatta.de/mhu/gds-render</property>
<property name="website_label" translatable="yes">Git Repository</property>
<property name="authors">Mario Hüttel &lt;mario.huettel@gmx.net&gt;</property>
<property name="logo_icon_name">gds-render</property>
<property name="logo_icon_name"/>
<property name="license_type">gpl-2-0-only</property>
<child>
<placeholder/>

View File

@@ -4,7 +4,7 @@
<requires lib="gtk+" version="3.20"/>
<object class="GtkAdjustment" id="adjustment1">
<property name="lower">1</property>
<property name="upper">3000</property>
<property name="upper">4000</property>
<property name="value">1000</property>
<property name="step_increment">10</property>
<property name="page_increment">1000</property>
@@ -16,7 +16,6 @@
<child>
<object class="GtkRadioButton" id="latex-radio">
<property name="label" translatable="yes">Generate LaTeX/TikZ output</property>
<property name="use_action_appearance">True</property>
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="receives_default">False</property>
@@ -32,11 +31,9 @@
<child>
<object class="GtkRadioButton" id="cairo-pdf-radio">
<property name="label" translatable="yes">Render PDF using Cairographics</property>
<property name="use_action_appearance">True</property>
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="receives_default">False</property>
<property name="active">True</property>
<property name="draw_indicator">True</property>
<property name="group">latex-radio</property>
</object>
@@ -49,12 +46,10 @@
<child>
<object class="GtkRadioButton" id="cairo-svg-radio">
<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="sensitive">False</property>
<property name="can_focus">True</property>
<property name="receives_default">False</property>
<property name="active">True</property>
<property name="draw_indicator">True</property>
<property name="group">latex-radio</property>
</object>
@@ -69,6 +64,7 @@
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="adjustment">adjustment1</property>
<property name="fill_level">4000</property>
<property name="round_digits">0</property>
<property name="digits">0</property>
</object>
@@ -106,5 +102,83 @@
<property name="position">5</property>
</packing>
</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>
</interface>

View File

@@ -2,17 +2,26 @@
<!-- Generated with glade 3.22.1 -->
<interface>
<requires lib="gtk+" version="3.20"/>
<object class="GtkImage" id="image1">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="stock">gtk-go-up</property>
</object>
<object class="GtkImage" id="image2">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="stock">gtk-go-down</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">
<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="subtitle" translatable="yes">GDSII to PDF/TikZ Converter</property>
<property name="show_close_button">True</property>
<child>
<object class="GtkButton" id="button-load-gds">
@@ -133,23 +142,74 @@
</packing>
</child>
<child>
<object class="GtkScrolledWindow">
<object class="GtkBox">
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="hscrollbar_policy">never</property>
<property name="shadow_type">in</property>
<property name="can_focus">False</property>
<property name="orientation">vertical</property>
<child>
<object class="GtkViewport">
<object class="GtkBox">
<property name="visible">True</property>
<property name="can_focus">False</property>
<child>
<object class="GtkListBox" id="layer-list">
<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">image1</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">image2</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>
</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>
<property name="selection_mode">none</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>

View File

@@ -5,6 +5,7 @@
<file compressed="true">about.glade</file>
<file>layer-widget.glade</file>
<file>dialog.glade</file>
<file compressed="true" alias="logo.svg">../icon/gds-render.svg</file>
</gresource>
</gresources>

View File

@@ -21,11 +21,11 @@
* @brief Header File for Cairo output renderer
* @author Mario Hüttel <mario.huettel@gmx.net>
*/
#ifndef __CAIRO_OUTPUT_H__
#define __CAIRO_OUTPUT_H__
#ifndef _CAIRO_OUTPUT_H_
#define _CAIRO_OUTPUT_H_
#include "../layer-selector.h"
#include "../gds-parser/gds-types.h"
#include <gds-render/gds-utils/gds-types.h>
#include <gds-render/layer/layer-info.h>
/** @addtogroup Cairo-Renderer
* @{
@@ -45,4 +45,4 @@ void cairo_render_cell_to_vector_file(struct gds_cell *cell, GList *layer_infos,
/** @} */
#endif /* __CAIRO_OUTPUT_H__ */
#endif /* _CAIRO_OUTPUT_H_ */

View File

@@ -24,12 +24,13 @@
*/
/**
* @addtogroup MainApplication
* @addtogroup cmdline
* @{
*/
#ifndef _COMMAND_LINE_H_
#define _COMMAND_LINE_H_
#include <glib.h>
/**
@@ -48,6 +49,8 @@
* @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
*
* @note This function is pretty damn retarded (Lots of parameters). Will be reworked when generating GObjects for renderers.
*/
void command_line_convert_gds(char *gds_name, char *pdf_name, char *tex_name, gboolean pdf, gboolean tex,
char *layer_file, char *cell_name, double scale, gboolean pdf_layers,

View File

@@ -24,19 +24,20 @@
*/
/**
* @addtogroup MainApplication
* @addtogroup external-renderer
* @{
*/
#ifndef _EXTERNAL_RENDERER_H_
#define _EXTERNAL_RENDERER_H_
#include "gds-parser/gds-types.h"
#include <gds-render/gds-utils/gds-types.h>
#include <glib.h>
/**
* @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
* int function_name(gds_cell *toplevel, GList *layer_info_list, char *output_file_name)
* @endcode

View 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_ */

View File

@@ -24,15 +24,16 @@
*/
/**
* @addtogroup GDS-Parser
* @addtogroup GDS-Utilities
* @{
*/
#ifndef __GDSPARSE_H__
#define __GDSPARSE_H__
#ifndef _GDSPARSER_H_
#define _GDSPARSER_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 */
@@ -46,4 +47,4 @@ int clear_lib_list(GList **library_list);
/** @} */
#endif /* __GDSPARSE_H__ */
#endif /* _GDSPARSE_H_ */

View 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_ */
/** @} */

View File

@@ -24,7 +24,7 @@
*/
/**
* @addtogroup GDS-Parser
* @addtogroup GDS-Utilities
* @{
*/
@@ -35,9 +35,15 @@
#include <glib.h>
#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 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 */
enum graphics_type
{
@@ -59,6 +65,21 @@ struct gds_point {
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
*/
@@ -104,6 +125,8 @@ struct gds_cell {
struct gds_time_field access_time;
GList *child_cells; /**< @brief List of #gds_cell_instance elements */
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];
struct gds_time_field mod_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 *cell_names /**< List of strings that contains all cell names */;
};

View File

@@ -24,14 +24,16 @@
*/
/**
* @addtogroup trigonometric
* @addtogroup geometric
* @{
*/
#ifndef _BOUNDING_BOX_H_
#define _BOUNDING_BOX_H_
#include <glib.h>
#include "vector-operations.h"
#include <gds-render/geometric/vector-operations.h>
#include <stdbool.h>
union bounding_box {
/** 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_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_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_ */

View 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_ */
/** @} */

View File

@@ -24,7 +24,7 @@
*/
/**
* @addtogroup trigonometric
* @addtogroup geometric
* @{
*/

View File

@@ -31,10 +31,11 @@
* @{
*/
#include "../gds-parser/gds-types.h"
#include <glib.h>
#include <stdio.h>
#include "../mapping-parser.h"
#include "gds-render/layer/layer-info.h"
#include <gds-render/gds-utils/gds-types.h>
#define LATEX_LINE_BUFFER_KB (10) /**< @brief Buffer for LaTeX Code line in KiB */

View File

@@ -0,0 +1,51 @@
/*
* 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 Helper functions and definition of layer info struct
* @author Mario Hüttel <mario.huettel@gmx.net>
*/
#ifndef _LAYER_INFO_H_
#define _LAYER_INFO_H_
#include <gtk/gtk.h>
/**
* @brief Layer information.
*
* 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 Delete a layer_info struct
* @param info Struct to be deleted.
* @note The layer_info::name Element has to be freed manually
*/
void layer_info_delete_struct(struct layer_info *info);
#endif // _LAYER_INFO_H_

View File

@@ -0,0 +1,97 @@
/*
* 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>
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);
G_END_DECLS
#endif /* __LAYER_SELECTOR_H__ */
/** @} */

View File

@@ -27,24 +27,13 @@
#define __MAPPING_PARSER_H__
/**
* @addtogroup MainApplication
* @addtogroup Mapping-Parser
* @{
*/
#include <gtk/gtk.h>
#include <glib.h>
/**
* @brief Layer information.
*
* 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 */
};
#include <gds-render/widgets/layer-element.h>
/**
* @brief Load a line from \p stream and parse try to parse it as layer information
@@ -55,7 +44,15 @@ struct layer_info
* @param color RGBA color.
* @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);
/** @} */

View File

@@ -17,6 +17,17 @@
* 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__
#define __LIB_CELL_RENDERER_H__
@@ -27,15 +38,33 @@ G_BEGIN_DECLS
G_DECLARE_FINAL_TYPE(LibCellRenderer, lib_cell_renderer, LIB_CELL, RENDERER, GtkCellRendererText)
#define TYPE_LIB_CELL_RENDERER (lib_cell_renderer_get_type())
/** @{
* Error levels
*/
#define LIB_CELL_RENDERER_ERROR_WARN (1U<<0)
#define LIB_CELL_RENDERER_ERROR_ERR (1U<<1)
/** @} */
typedef struct _LibCellRenderer {
/* Inheritance */
GtkCellRendererText super;
/* Custom Elements */
} LibCellRenderer;
/**
* @brief lib_cell_renderer_get_type
* @return GObject Type
*/
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);
G_END_DECLS
#endif /* __LIB_CELL_RENDERER_H__ */
/** @} */

View File

@@ -24,7 +24,7 @@
*/
/**
* @addtogroup MainApplication
* @addtogroup GUI
* @{
*/
@@ -37,10 +37,10 @@
enum cell_store_columns {
CELL_SEL_LIBRARY = 0,
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_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 {

View File

@@ -18,29 +18,11 @@
*/
/**
* @file main-window.h
* @brief Header for main-window
* @author Mario Hüttel <mario.huettel@gmx.net>
*/
#ifndef _MAIN_WINDOW_H_
#define _MAIN_WINDOW_H_
/**
* @addtogroup MainApplication
* @addtogroup version
* @{
*/
#include <gtk/gtk.h>
/**
* @brief Create main window
*
* This function creates the main window and sets the necessary callback routines.
* @return
*/
GtkWindow *create_main_window();
/** @brief This string holds the @ref git-version-num of the app */
extern const char *_app_version_string;
/** @} */
#endif /* _MAIN_WINDOW_H_ */

View File

@@ -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);
/**
* @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__ */
/** @} */

View File

@@ -24,7 +24,8 @@
*/
/**
* @addtogroup Widgets
* @addtogroup LayerElement
* @ingroup Widgets
* @{
*/
@@ -56,6 +57,22 @@ struct _LayerElement {
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
* @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);
/**
* @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
#endif /* __LAYER_ELEMENT_H__ */

View File

@@ -23,9 +23,10 @@
* @author Mario Hüttel <mario.huettel@gmx.net>
*/
#include "latex-output.h"
#include <math.h>
#include <gds-render/latex-renderer/latex-output.h>
/**
* @addtogroup LaTeX-Renderer
* @{

View File

@@ -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);
}
/** @} */

View File

@@ -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__ */

33
layer/layer-info.c Normal file
View File

@@ -0,0 +1,33 @@
/*
* 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 Helper functions for layer info struct
* @author Mario Hüttel <mario.huettel@gmx.net>
*/
#include <gds-render/layer/layer-info.h>
void layer_info_delete_struct(struct layer_info *info)
{
if (info)
free(info);
}

784
layer/layer-selector.c Normal file
View File

@@ -0,0 +1,784 @@
/*
* 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->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;
}
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);
}
/** @} */

View File

@@ -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;
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);
}
/** @} */

View File

@@ -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);
}
/** @} */

214
main.c
View File

@@ -17,66 +17,171 @@
* 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 <gtk/gtk.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/external-renderer.h>
#include <gds-render/version.h>
/**
* @brief Structure containing The GtkApplication and a list containing the GdsRenderGui objects.
*/
struct application_data {
GtkApplication *app;
GtkWindow *main_window;
GtkApplication *app;
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)
{
struct application_data *appdata = (struct application_data *)user_data;
struct application_data * const appdata = (struct application_data *)user_data;
(void)action;
(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)
{
GtkBuilder *builder;
GtkDialog *dialog;
struct application_data *appdata = (struct application_data *)user_data;
GdkPixbuf *logo_buf;
GError *error = NULL;
(void)user_data;
(void)action;
(void)parameter;
builder = gtk_builder_new_from_resource("/about.glade");
dialog = GTK_DIALOG(gtk_builder_get_object(builder, "about-dialog"));
gtk_window_set_transient_for(GTK_WINDOW(dialog), appdata->main_window);
gtk_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("/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_widget_destroy(GTK_WIDGET(dialog));
g_object_unref(builder);
}
/**
* @brief Contains the application menu entries
*/
const static GActionEntry app_actions[] = {
{ "quit", app_quit },
{ "about", app_about }
{"quit", app_quit, NULL, NULL, NULL, {0}},
{"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)
{
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_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)
{
GtkApplication *gapp;
int app_status;
static struct application_data appdata;
static struct application_data appdata = {
.gui_list = NULL
};
GMenu *menu;
GMenu *m_quit;
GMenu *m_about;
@@ -85,6 +190,12 @@ static int start_gui(int argc, char **argv)
g_application_register(G_APPLICATION(gapp), NULL, NULL);
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();
m_quit = g_menu_new();
m_about = g_menu_new();
@@ -100,41 +211,60 @@ static int start_gui(int argc, char **argv)
g_object_unref(m_about);
g_object_unref(menu);
app_status = g_application_run(G_APPLICATION(gapp), argc, argv);
g_object_unref(gapp);
g_list_free(appdata.gui_list);
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 i;
GError *error = NULL;
GOptionContext *context;
gchar *gds_name;
gchar *basename;
gchar *pdfname = NULL, *texname = NULL, *mappingname = NULL, *cellname = NULL, *svgname = NULL;
gboolean tikz = FALSE, pdf = FALSE, pdf_layers = FALSE, pdf_standalone = FALSE, svg = FALSE;
gboolean version = FALSE;
gchar *custom_library_path = NULL;
gchar *custom_library_file_name = NULL;
int scale = 1000;
int app_status;
int app_status = 0;
GOptionEntry entries[] = {
{"tikz", 't', 0, G_OPTION_ARG_NONE, &tikz, "Output TikZ code", NULL },
{"pdf", 'p', 0, G_OPTION_ARG_NONE, &pdf, "Output PDF document", NULL },
//{"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>" },
{"tex-output", 'o', 0, G_OPTION_ARG_FILENAME, &texname, "Optional path for TeX file", "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" },
{"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-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"},
{"external-lib-output", 'e', 0, G_OPTION_ARG_FILENAME, &custom_library_file_name, "Output path for external render library", "PATH"},
{ NULL }
{"version", 'v', 0, G_OPTION_ARG_NONE, &version, "Print version", NULL},
{"tikz", 't', 0, G_OPTION_ARG_NONE, &tikz, "Output TikZ code", NULL },
{"pdf", 'p', 0, G_OPTION_ARG_NONE, &pdf, "Output PDF document", NULL },
//{"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>" },
{"tex-output", 'o', 0, G_OPTION_ARG_FILENAME, &texname, "Optional path for TeX file", "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" },
{"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-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"},
{"external-lib-output", 'e', 0, G_OPTION_ARG_FILENAME, &custom_library_file_name, "Output path for external render library", "PATH"},
{NULL}
};
context = g_option_context_new(" FILE - Convert GDS file <FILE> to graphic");
@@ -146,6 +276,11 @@ int main(int argc, char **argv)
exit(1);
}
if (version) {
print_version();
goto ret_status;
}
if (argc >= 2) {
if (scale < 1) {
printf("Scale < 1 not allowed. Setting to 1\n");
@@ -159,6 +294,11 @@ int main(int argc, char **argv)
/* Get gds name */
gds_name = argv[1];
/* Print out additional arguments as ignored */
for (i = 2; i < argc; i++) {
printf("Ignored argument: %s", argv[i]);
}
/* Check if PDF/TeX names are supplied. if not generate */
basename = g_path_get_basename(gds_name);
@@ -168,13 +308,13 @@ int main(int argc, char **argv)
if (!pdfname)
pdfname = g_strdup_printf("./%s.pdf", basename);
if (!pdfname)
pdfname = g_strdup_printf("./%s.svg", basename);
if (!svgname)
svgname = 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);
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);
@@ -189,6 +329,6 @@ int main(int argc, char **argv)
app_status = start_gui(argc, argv);
}
ret_status:
return app_status;
}

View File

@@ -17,14 +17,26 @@
* 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/tree-renderer/lib-cell-renderer.h>
#include <gds-render/gds-utils/gds-types.h>
G_DEFINE_TYPE(LibCellRenderer, lib_cell_renderer, GTK_TYPE_CELL_RENDERER_TEXT)
enum {
PROP_LIB = 1,
PROP_CELL,
PROP_ERROR_LEVEL,
PROP_COUNT
};
@@ -38,24 +50,56 @@ static void lib_cell_renderer_constructed(GObject *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,
guint param_id,
const GValue *value,
GParamSpec *pspec)
{
GValue val = G_VALUE_INIT;
g_value_init(&val, G_TYPE_STRING);
GdkRGBA color;
switch (param_id) {
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_object_set_property(object, "text", &val);
break;
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_object_set_property(object, "text", &val);
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:
G_OBJECT_WARN_INVALID_PROPERTY_ID(object, param_id, pspec);
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)
{
GObjectClass *oclass = G_OBJECT_CLASS(klass);
oclass->constructed = lib_cell_renderer_constructed;
oclass->set_property = lib_cell_renderer_set_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",
"Cell reference to be displayed",
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);
}
@@ -97,3 +144,5 @@ GtkCellRenderer *lib_cell_renderer_new()
{
return GTK_CELL_RENDERER(g_object_new(TYPE_LIB_CELL_RENDERER, NULL));
}
/** @} */

View File

@@ -24,13 +24,13 @@
*/
/**
* @addtogroup MainApplication
* @addtogroup GUI
* @{
*/
#include "tree-store.h"
#include "lib-cell-renderer.h"
#include "../gds-parser/gds-types.h"
#include <gds-render/tree-renderer/tree-store.h>
#include <gds-render/tree-renderer/lib-cell-renderer.h>
#include <gds-render/gds-utils/gds-types.h>
/**
* @brief this function olny allows cells to be selected
@@ -49,15 +49,23 @@ static gboolean tree_sel_func(GtkTreeSelection *selection,
{
GtkTreeIter iter;
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(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 */
if (cell)
return TRUE;
else
return FALSE;
/* Allow only rows with _valid_ cell to be selected */
if (cell) {
/* Cell available. Check if it passed the critical checks */
if (!(error_level & LIB_CELL_RENDERER_ERROR_ERR))
ret = TRUE;
}
return ret;
}
/**
@@ -107,6 +115,8 @@ exit_filter:
static void change_filter(GtkWidget *entry, gpointer data)
{
struct tree_stores *stores = (struct tree_stores *)data;
(void)entry;
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.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 */
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);
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, "foreground-rgba", CELL_SEL_CELL_COLOR, NULL);
column = gtk_tree_view_column_new_with_attributes("Cell", render_cell, "gds-cell", CELL_SEL_CELL,
"error-level", CELL_SEL_CELL_ERROR_STATE, NULL);
gtk_tree_view_append_column(view, column);
column = gtk_tree_view_column_new_with_attributes("Mod. Date", render_dates, "text", CELL_SEL_MODDATE, NULL);

5
version/CMakeLists.txt Normal file
View 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})

View File

@@ -0,0 +1 @@
git describe --tags --dirty

36
version/version.c Normal file
View 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
/** @} */

View File

@@ -18,17 +18,18 @@
*/
/**
* @file conv-settings-dilaog.c
* @file conv-settings-dialog.c
* @brief Implementation of the setting dialog
* @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 {
GtkDialog parent;
@@ -39,16 +40,74 @@ struct _RendererSettingsDialog {
GtkWidget *scale;
GtkWidget *layer_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)
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)
{
/* No special code needed. Child cells are destroyed automatically due to reference counter */
return;
GObjectClass *oclass = G_OBJECT_CLASS(klass);
/* 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)
@@ -72,14 +131,144 @@ static void latex_render_callback(GtkToggleButton *radio, RendererSettingsDialog
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)
{
GtkBuilder *builder;
GtkWidget *box;
GtkDialog *dialog;
dialog = &(self->parent);
dialog = &self->parent;
builder = gtk_builder_new_from_resource("/dialog.glade");
box = GTK_WIDGET(gtk_builder_get_object(builder, "dialog-box"));
@@ -89,12 +278,27 @@ static void renderer_settings_dialog_init(RendererSettingsDialog *self)
self->scale = GTK_WIDGET(gtk_builder_get_object(builder, "dialog-scale"));
self->standalone_check = GTK_WIDGET(gtk_builder_get_object(builder, "standalone-check"));
self->layer_check = GTK_WIDGET(gtk_builder_get_object(builder, "layer-check"));
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_container_add(GTK_CONTAINER(gtk_dialog_get_content_area(dialog)), box);
gtk_window_set_title(GTK_WINDOW(self), "Renderer Settings");
g_signal_connect(self->radio_latex, "toggled", G_CALLBACK(latex_render_callback), (gpointer)self);
g_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);
}
@@ -112,10 +316,7 @@ RendererSettingsDialog *renderer_settings_dialog_new(GtkWindow *parent)
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)
return;
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);
gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(dialog->radio_cairo_svg), TRUE);
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);
}
/** @} */

View File

@@ -17,18 +17,26 @@
* 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
* @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>
*/
/**
* @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)
@@ -50,77 +58,6 @@ static void layer_element_class_init(LayerElementClass *klass)
oclass->constructed = layer_element_constructed;
}
static GtkTargetEntry entries[] = {
{ "GTK_LIST_BOX_ROW", GTK_TARGET_SAME_APP, 0 }
};
static void layer_element_drag_begin(GtkWidget *widget,
GdkDragContext *context,
gpointer data)
{
GtkWidget *row;
GtkAllocation alloc;
cairo_surface_t *surface;
cairo_t *cr;
int x, y;
row = gtk_widget_get_ancestor (widget, GTK_TYPE_LIST_BOX_ROW);
gtk_widget_get_allocation (row, &alloc);
surface = cairo_image_surface_create (CAIRO_FORMAT_ARGB32, alloc.width, alloc.height);
cr = cairo_create (surface);
gtk_style_context_add_class (gtk_widget_get_style_context (row), "drag-icon");
gtk_widget_draw (row, cr);
gtk_style_context_remove_class (gtk_widget_get_style_context (row), "drag-icon");
gtk_widget_translate_coordinates (widget, row, 0, 0, &x, &y);
cairo_surface_set_device_offset (surface, -x, -y);
gtk_drag_set_icon_surface (context, surface);
cairo_destroy (cr);
cairo_surface_destroy (surface);
}
static void layer_element_drag_data_get(GtkWidget *widget,
GdkDragContext *context,
GtkSelectionData *selection_data,
guint info,
guint time,
gpointer data)
{
gtk_selection_data_set(selection_data, gdk_atom_intern_static_string("GTK_LIST_BOX_ROW"),
32, (const guchar *)&widget, sizeof(gpointer));
}
static void layer_element_drag_data_received(GtkWidget *widget,
GdkDragContext *context,
gint x,
gint y,
GtkSelectionData *selection_data,
guint info,
guint32 time,
gpointer data)
{
GtkWidget *target;
GtkWidget *row;
GtkWidget *source;
int pos;
target = widget;
pos = gtk_list_box_row_get_index (GTK_LIST_BOX_ROW (target));
row = (gpointer) *(gpointer *)gtk_selection_data_get_data (selection_data);
source = gtk_widget_get_ancestor (row, GTK_TYPE_LIST_BOX_ROW);
if (source == target)
return;
g_object_ref (source);
gtk_container_remove (GTK_CONTAINER (gtk_widget_get_parent (source)), source);
gtk_list_box_insert (GTK_LIST_BOX (gtk_widget_get_parent (target)), source, pos);
g_object_unref (source);
}
static void layer_element_init(LayerElement *self)
{
GtkBuilder *builder;
@@ -136,13 +73,6 @@ static void layer_element_init(LayerElement *self)
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"));
/* 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);
}
@@ -191,12 +121,30 @@ void layer_element_get_color(LayerElement *elem, GdkRGBA *rgba)
{
if (!rgba)
return;
gtk_color_chooser_get_rgba(GTK_COLOR_CHOOSER(elem->priv.color), 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);
}
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);
}
/** @} */