96 Commits

Author SHA1 Message Date
33deba8ca4 Command line: Fix auto-guessing of SVG file name. 2019-03-15 18:03:29 +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
c28da2ab71 Update doxygen color 2019-02-05 20:54:29 +01:00
6937d24699 Remove old search and implement new search using filtering. 2019-02-05 20:38:52 +01:00
1d67424bc9 Tree storage modified to use combination struct 2019-02-05 19:45:02 +01:00
c7ffcf68ed Add readme 2019-02-04 21:52:50 +01:00
8306c34292 Implement first draft of cell search 2019-02-04 20:02:10 +01:00
af031acc38 Merge branch 'master' into dev 2019-02-03 22:56:47 +01:00
9f2544ee94 fix double 0 in layer mapping 2019-02-03 22:50:34 +01:00
1f281119df Fix the better solution. This makes it an even better solution 2019-02-03 22:47:54 +01:00
bdb06c4d6e Fix segfault and implement better *cough* fix for locale problems 2019-02-03 22:44:03 +01:00
1fa2d75abd Fix broken layer mapping if locale is different than english 2019-02-03 22:29:06 +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
a3be13bc7c Update doyygen look 2018-12-15 00:21:01 +01:00
4cc519a661 Update usage page 2018-12-15 00:13:01 +01:00
f3968bee48 fix file tag in doxygen header 2018-12-15 00:08:37 +01:00
f54ff7ded6 Add support for external shared object renderer 2018-12-15 00:05:34 +01:00
f025a0233d fix doxygen header 2018-12-15 00:04:53 +01:00
bbdc6c9049 remove unused variable warnings 2018-12-15 00:03:40 +01:00
03a5aea335 Edit Doxygen config. Add image to latex output 2018-12-11 00:19:25 +01:00
3e1a4c7d92 Fixed style and warnings 2018-12-11 00:06:27 +01:00
fc6756b1fb Add doxygen to build system 2018-12-10 23:53:57 +01:00
d7293de1dc Fix doxygen foo 2018-12-10 23:37:00 +01:00
37c21ced04 Fix typo 2018-12-10 21:30:07 +01:00
179dfa0724 Add description to bounding box 2018-12-10 21:28:43 +01:00
3c1f4f9c97 Doxygen Docu 2018-12-10 21:24:52 +01:00
d4ba826474 Update doxygen 2018-12-10 19:36:00 +01:00
8b1626c111 Revert previous commit, fix typos 2018-12-10 19:23:54 +01:00
2a860ab949 Update doxygen 2018-12-10 19:16:07 +01:00
eaf692e046 Add .buildconfig to gitignore 2018-12-06 23:05:56 +01:00
2fe6358815 remove buildconfig 2018-12-06 23:05:19 +01:00
e8b7bd65ac Add static to global variable 2018-09-22 23:32:22 +02:00
d69082a676 Fix CmakeLists File. Project command has to be first to prevent errors 2018-09-22 23:29:31 +02:00
47 changed files with 2226 additions and 400 deletions

View File

@@ -1,10 +0,0 @@
[default]
name=Default
runtime=host
config-opts=
run-opts=
prefix=/home/mari/.cache/gnome-builder/install/gds-render/host
app-id=
postbuild=
prebuild=
default=true

2
.gitignore vendored
View File

@@ -72,3 +72,5 @@ Thumbs.db
*.exe
*.user
*.user*
*.buildconfig

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

@@ -1,25 +1,27 @@
project(gds-render)
cmake_minimum_required(VERSION 2.8)
find_package(PkgConfig REQUIRED)
pkg_search_module(GLIB REQUIRED glib-2.0)
pkg_check_modules(GTK3 REQUIRED gtk+-3.0)
pkg_check_modules(CAIRO REQUIRED cairo)
project(gds-render)
add_subdirectory(glade)
add_subdirectory(doxygen)
add_subdirectory(version)
include_directories(${GLIB_INCLUDE_DIRS} ${GTK3_INCLUDE_DIRS} ${CAIRO_INCLUDE_DIRS})
link_directories(${GLIB_LINK_DIRS} ${GTK3_LINK_DIRS} ${CAIRO_LINK_DIRS})
add_definitions(${GLIB2_CFLAGS_OTHER})
aux_source_directory("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")
aux_source_directory("layer-selector" LAYER_SELECTOR_SOURCES)
set(SOURCE "main.c" "mapping-parser.c" "command-line.c" "main-window.c" "external-renderer.c")
set(SOURCE
${SOURCE}
@@ -29,13 +31,16 @@ set(SOURCE
${LATEX_SOURCES}
${CAIRO_SOURCES}
${TRIG_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)
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)

21
README.MD Normal file
View File

@@ -0,0 +1,21 @@
# GDS-Render
This software is a rendering programm for GDS2 layout files.
The GDS2 format is mainly used in integrated circuit development.
This program allows the conversion of a GDS file to a vector graphics file.
## Output Formats
* Export GDS Layout to LaTeX (using TikZ).
* Export to PDF (Cairographics).
# Features
Note: Due to various size limitations of both TikZ and the PDF export, the layout might not render correctly. In this case adjust the scale value. A higher scale value scales down your design.
* Configurable layer stack-up.
* Layer colors configurable as ARGB color values.
* Command line interface.
* ~~Awesome~~ Somehow usable GUI.
# License and Other Stuff
* Free software (GPLv2 _only_)
* Coded in plain C using GTK+3.0, Glib2, and Cairographics

1
c-style-checker Submodule

Submodule c-style-checker added at 3a58e3dd1c

View File

@@ -24,7 +24,7 @@
#ifndef __CAIRO_OUTPUT_H__
#define __CAIRO_OUTPUT_H__
#include "../layer-selector.h"
#include "../layer-selector/layer-selector.h"
#include "../gds-parser/gds-types.h"
/** @addtogroup Cairo-Renderer
@@ -35,7 +35,7 @@
/**
* @brief Render \p cell to a PDF file specified by \p pdf_file
* @param cell Toplevel cell to render
* @param cell Toplevel cell to @ref Cairo-Renderer
* @param layer_infos List of layer information. Specifies color and layer stacking
* @param pdf_file PDF output file. Set to NULL if no PDF file has to be generated
* @param svg_file SVG output file. Set to NULL if no SVG file has to be generated

View File

@@ -34,12 +34,15 @@
#include "mapping-parser.h"
#include "cairo-output/cairo-output.h"
#include "latex-output/latex-output.h"
#include "external-renderer.h"
#include "gds-parser/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)
{
@@ -52,7 +55,7 @@ static void delete_layer_info_with_name(struct layer_info *info)
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,
gboolean pdf_standalone, gboolean svg, char *svg_name)
gboolean pdf_standalone, gboolean svg, char *svg_name, char *so_name, char *so_out_file)
{
GList *libs = NULL;
FILE *tex_file;
@@ -68,10 +71,12 @@ 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 || !tex_name || !layer_file || !cell_name) {
if (!gds_name || (!pdf_name && pdf) || (!tex_name && tex) || !layer_file || !cell_name) {
printf("Probably missing argument. Check --help option\n");
return;
}
@@ -80,14 +85,14 @@ 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;
@@ -99,7 +104,7 @@ void command_line_convert_gds(char *gds_name, char *pdf_name, char *tex_name, gb
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;
@@ -115,9 +120,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;
@@ -127,9 +138,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),
@@ -139,20 +172,31 @@ 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);
}
ret_clear_list:
if (so_name && so_out_file) {
if (strlen(so_name) == 0 || strlen(so_out_file) == 0)
goto ret_clear_layer_list;
/* Render output using external renderer */
printf("Invoking external renderer!\n");
external_renderer_render_cell(toplevel_cell, layer_info_list, so_out_file, so_name);
printf("External renderer finished!\n");
}
ret_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

@@ -18,7 +18,7 @@
*/
/**
* @file command-line.c
* @file command-line.h
* @brief Render according to command line parameters
* @author Mario Hüttel <mario.huettel@gmx.net>
*/
@@ -45,11 +45,13 @@
* @param pdf_layers TikZ creates OCG layers
* @param pdf_standalone LaTeX document is standalone7
* @param svg Render to SVG file
* @param so_name Path to shared object of custom renderer
* @param so_out_file Output file path for custom renderer
* @param svg_name SVG file name
*/
void command_line_convert_gds(char *gds_name, char *pdf_name, char *tex_name, gboolean pdf, gboolean tex,
char *layer_file, char *cell_name, double scale, gboolean pdf_layers,
gboolean pdf_standalone, gboolean svg, char *svg_name);
gboolean pdf_standalone, gboolean svg, char *svg_name, char *so_name, char *so_out_file);
#endif /* _COMMAND_LINE_H_ */

10
doxygen/CMakeLists.txt Normal file
View File

@@ -0,0 +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

@@ -1,4 +1,4 @@
# Doxyfile 1.8.14
# Doxyfile 1.8.15
# This file describes the settings to be used by the documentation system
# doxygen (www.doxygen.org) for a project.
@@ -17,10 +17,10 @@
# Project related configuration options
#---------------------------------------------------------------------------
# This tag specifies the encoding used for all characters in the config file
# that follow. The default is UTF-8 which is also the encoding used for all text
# before the first occurrence of this tag. Doxygen uses libiconv (or the iconv
# built into libc) for the transcoding. See
# This tag specifies the encoding used for all characters in the configuration
# file that follow. The default is UTF-8 which is also the encoding used for all
# text before the first occurrence of this tag. Doxygen uses libiconv (or the
# iconv built into libc) for the transcoding. See
# https://www.gnu.org/software/libiconv/ for the list of possible encodings.
# The default value is: UTF-8.
@@ -38,7 +38,7 @@ PROJECT_NAME = GDS-Render
# could be handy for archiving the generated documentation or if some version
# control system is used.
PROJECT_NUMBER =
PROJECT_NUMBER = $(PROJECT_NUMBER)
# Using the PROJECT_BRIEF tag one can provide an optional one line description
# for a project that appears at the top of each page and should give viewer a
@@ -58,7 +58,7 @@ PROJECT_LOGO = ../icon/gds-render.svg
# entered, it will be relative to the location where doxygen was started. If
# left blank the current directory will be used.
OUTPUT_DIRECTORY = ./output
OUTPUT_DIRECTORY = $(OUTPUT_DIRECTORY)
# If the CREATE_SUBDIRS tag is set to YES then doxygen will create 4096 sub-
# directories (in 2 levels) under the output directory of each output format and
@@ -93,6 +93,14 @@ ALLOW_UNICODE_NAMES = NO
OUTPUT_LANGUAGE = English
# The OUTPUT_TEXT_DIRECTION tag is used to specify the direction in which all
# documentation generated by doxygen is written. Doxygen will use this
# information to generate all generated output in the proper direction.
# Possible values are: None, LTR, RTL and Context.
# The default value is: None.
OUTPUT_TEXT_DIRECTION = None
# If the BRIEF_MEMBER_DESC tag is set to YES, doxygen will include brief member
# descriptions after the members that are listed in the file and class
# documentation (similar to Javadoc). Set to NO to disable this.
@@ -238,6 +246,10 @@ TAB_SIZE = 4
# "Side Effects:". You can put \n's in the value part of an alias to insert
# newlines (in the resulting output). You can put ^^ in the value part of an
# alias to insert a newline as if a physical newline was in the original file.
# When you need a literal { or } or , in the value part of an alias you have to
# escape them by means of a backslash (\), this can lead to conflicts with the
# commands \{ and \} for these it is advised to use the version @{ and @} or use
# a double escape (\\{ and \\})
ALIASES =
@@ -275,17 +287,26 @@ OPTIMIZE_FOR_FORTRAN = NO
OPTIMIZE_OUTPUT_VHDL = NO
# Set the OPTIMIZE_OUTPUT_SLICE tag to YES if your project consists of Slice
# sources only. Doxygen will then generate output that is more tailored for that
# language. For instance, namespaces will be presented as modules, types will be
# separated into more groups, etc.
# The default value is: NO.
OPTIMIZE_OUTPUT_SLICE = NO
# Doxygen selects the parser to use depending on the extension of the files it
# parses. With this tag you can assign which parser to use for a given
# extension. Doxygen has a built-in mapping, but you can override or extend it
# using this tag. The format is ext=language, where ext is a file extension, and
# language is one of the parsers supported by doxygen: IDL, Java, Javascript,
# C#, C, C++, D, PHP, Objective-C, Python, Fortran (fixed format Fortran:
# FortranFixed, free formatted Fortran: FortranFree, unknown formatted Fortran:
# Fortran. In the later case the parser tries to guess whether the code is fixed
# or free formatted code, this is the default for Fortran type files), VHDL. For
# instance to make doxygen treat .inc files as Fortran files (default is PHP),
# and .f files as C (default is Fortran), use: inc=Fortran f=C.
# Csharp (C#), C, C++, D, PHP, md (Markdown), Objective-C, Python, Slice,
# Fortran (fixed format Fortran: FortranFixed, free formatted Fortran:
# FortranFree, unknown formatted Fortran: Fortran. In the later case the parser
# tries to guess whether the code is fixed or free formatted code, this is the
# default for Fortran type files), VHDL, tcl. For instance to make doxygen treat
# .inc files as Fortran files (default is PHP), and .f files as C (default is
# Fortran), use: inc=Fortran f=C.
#
# Note: For files without extension you can use no_extension as a placeholder.
#
@@ -296,7 +317,7 @@ EXTENSION_MAPPING =
# If the MARKDOWN_SUPPORT tag is enabled then doxygen pre-processes all comments
# according to the Markdown format, which allows for more readable
# documentation. See http://daringfireball.net/projects/markdown/ for details.
# documentation. See https://daringfireball.net/projects/markdown/ for details.
# The output of markdown processing is further processed by doxygen, so you can
# mix doxygen, HTML, and XML commands with Markdown formatting. Disable only in
# case of backward compatibilities issues.
@@ -754,7 +775,8 @@ WARN_IF_DOC_ERROR = YES
# This WARN_NO_PARAMDOC option can be enabled to get warnings for functions that
# are documented, but have no documentation for their parameters or return
# value. If set to NO, doxygen will only warn about wrong or incomplete
# parameter documentation, but not about the absence of documentation.
# parameter documentation, but not about the absence of documentation. If
# EXTRACT_ALL is set to YES then this flag will automatically be disabled.
# The default value is: NO.
WARN_NO_PARAMDOC = NO
@@ -814,7 +836,7 @@ INPUT_ENCODING = UTF-8
# *.c++, *.java, *.ii, *.ixx, *.ipp, *.i++, *.inl, *.idl, *.ddl, *.odl, *.h,
# *.hh, *.hxx, *.hpp, *.h++, *.cs, *.d, *.php, *.php4, *.php5, *.phtml, *.inc,
# *.m, *.markdown, *.md, *.mm, *.dox, *.py, *.pyw, *.f90, *.f95, *.f03, *.f08,
# *.f, *.for, *.tcl, *.vhd, *.vhdl, *.ucf and *.qsf.
# *.f, *.for, *.tcl, *.vhd, *.vhdl, *.ucf, *.qsf and *.ice.
FILE_PATTERNS = *.c \
*.cc \
@@ -1012,7 +1034,7 @@ INLINE_SOURCES = NO
STRIP_CODE_COMMENTS = YES
# If the REFERENCED_BY_RELATION tag is set to YES then for each documented
# function all documented functions referencing it will be listed.
# entity all documented functions referencing it will be listed.
# The default value is: NO.
REFERENCED_BY_RELATION = NO
@@ -1049,7 +1071,7 @@ SOURCE_TOOLTIPS = YES
#
# To use it do the following:
# - Install the latest version of global
# - Enable SOURCE_BROWSER and USE_HTAGS in the config file
# - Enable SOURCE_BROWSER and USE_HTAGS in the configuration file
# - Make sure the INPUT points to the root of the source tree
# - Run doxygen as normal
#
@@ -1195,7 +1217,7 @@ HTML_EXTRA_FILES =
# Minimum value: 0, maximum value: 359, default value: 220.
# This tag requires that the tag GENERATE_HTML is set to YES.
HTML_COLORSTYLE_HUE = 220
HTML_COLORSTYLE_HUE = 49
# The HTML_COLORSTYLE_SAT tag controls the purity (or saturation) of the colors
# in the HTML output. For a value of 0 the output will use grayscales only. A
@@ -1203,7 +1225,7 @@ HTML_COLORSTYLE_HUE = 220
# Minimum value: 0, maximum value: 255, default value: 100.
# This tag requires that the tag GENERATE_HTML is set to YES.
HTML_COLORSTYLE_SAT = 100
HTML_COLORSTYLE_SAT = 155
# The HTML_COLORSTYLE_GAMMA tag controls the gamma correction applied to the
# luminance component of the colors in the HTML output. Values below 100
@@ -1214,7 +1236,7 @@ HTML_COLORSTYLE_SAT = 100
# Minimum value: 40, maximum value: 240, default value: 80.
# This tag requires that the tag GENERATE_HTML is set to YES.
HTML_COLORSTYLE_GAMMA = 80
HTML_COLORSTYLE_GAMMA = 240
# If the HTML_TIMESTAMP tag is set to YES then the footer of each generated HTML
# page will contain the date and time when the page was generated. Setting this
@@ -1259,13 +1281,13 @@ HTML_INDEX_NUM_ENTRIES = 100
# If the GENERATE_DOCSET tag is set to YES, additional index files will be
# generated that can be used as input for Apple's Xcode 3 integrated development
# environment (see: https://developer.apple.com/tools/xcode/), introduced with
# OSX 10.5 (Leopard). To create a documentation set, doxygen will generate a
# environment (see: https://developer.apple.com/xcode/), introduced with OSX
# 10.5 (Leopard). To create a documentation set, doxygen will generate a
# Makefile in the HTML output directory. Running make will produce the docset in
# that directory and running make install will install the docset in
# ~/Library/Developer/Shared/Documentation/DocSets so that Xcode will find it at
# startup. See https://developer.apple.com/tools/creatingdocsetswithdoxygen.html
# for more information.
# startup. See https://developer.apple.com/library/archive/featuredarticles/Doxy
# genXcode/_index.html for more information.
# The default value is: NO.
# This tag requires that the tag GENERATE_HTML is set to YES.
@@ -1304,7 +1326,7 @@ DOCSET_PUBLISHER_NAME = Publisher
# If the GENERATE_HTMLHELP tag is set to YES then doxygen generates three
# additional HTML index files: index.hhp, index.hhc, and index.hhk. The
# index.hhp is a project file that can be read by Microsoft's HTML Help Workshop
# (see: http://www.microsoft.com/en-us/download/details.aspx?id=21138) on
# (see: https://www.microsoft.com/en-us/download/details.aspx?id=21138) on
# Windows.
#
# The HTML Help Workshop contains a compiler that can convert all HTML output
@@ -1380,7 +1402,7 @@ QCH_FILE =
# The QHP_NAMESPACE tag specifies the namespace to use when generating Qt Help
# Project output. For more information please see Qt Help Project / Namespace
# (see: http://doc.qt.io/qt-4.8/qthelpproject.html#namespace).
# (see: http://doc.qt.io/archives/qt-4.8/qthelpproject.html#namespace).
# The default value is: org.doxygen.Project.
# This tag requires that the tag GENERATE_QHP is set to YES.
@@ -1388,7 +1410,8 @@ QHP_NAMESPACE = org.doxygen.Project
# The QHP_VIRTUAL_FOLDER tag specifies the namespace to use when generating Qt
# Help Project output. For more information please see Qt Help Project / Virtual
# Folders (see: http://doc.qt.io/qt-4.8/qthelpproject.html#virtual-folders).
# Folders (see: http://doc.qt.io/archives/qt-4.8/qthelpproject.html#virtual-
# folders).
# The default value is: doc.
# This tag requires that the tag GENERATE_QHP is set to YES.
@@ -1396,21 +1419,23 @@ QHP_VIRTUAL_FOLDER = doc
# If the QHP_CUST_FILTER_NAME tag is set, it specifies the name of a custom
# filter to add. For more information please see Qt Help Project / Custom
# Filters (see: http://doc.qt.io/qt-4.8/qthelpproject.html#custom-filters).
# Filters (see: http://doc.qt.io/archives/qt-4.8/qthelpproject.html#custom-
# filters).
# This tag requires that the tag GENERATE_QHP is set to YES.
QHP_CUST_FILTER_NAME =
# The QHP_CUST_FILTER_ATTRS tag specifies the list of the attributes of the
# custom filter to add. For more information please see Qt Help Project / Custom
# Filters (see: http://doc.qt.io/qt-4.8/qthelpproject.html#custom-filters).
# Filters (see: http://doc.qt.io/archives/qt-4.8/qthelpproject.html#custom-
# filters).
# This tag requires that the tag GENERATE_QHP is set to YES.
QHP_CUST_FILTER_ATTRS =
# The QHP_SECT_FILTER_ATTRS tag specifies the list of the attributes this
# project's filter section matches. Qt Help Project / Filter Attributes (see:
# http://doc.qt.io/qt-4.8/qthelpproject.html#filter-attributes).
# http://doc.qt.io/archives/qt-4.8/qthelpproject.html#filter-attributes).
# This tag requires that the tag GENERATE_QHP is set to YES.
QHP_SECT_FILTER_ATTRS =
@@ -1468,7 +1493,7 @@ DISABLE_INDEX = NO
# The default value is: NO.
# This tag requires that the tag GENERATE_HTML is set to YES.
GENERATE_TREEVIEW = NO
GENERATE_TREEVIEW = YES
# The ENUM_VALUES_PER_LINE tag can be used to set the number of enum values that
# doxygen will group on one line in the generated HTML documentation.
@@ -1523,7 +1548,7 @@ FORMULA_TRANSPARENT = YES
# The default value is: NO.
# This tag requires that the tag GENERATE_HTML is set to YES.
USE_MATHJAX = NO
USE_MATHJAX = YES
# When MathJax is enabled you can set the default output format to be used for
# the MathJax output. See the MathJax site (see:
@@ -1543,7 +1568,7 @@ MATHJAX_FORMAT = HTML-CSS
# Content Delivery Network so you can quickly see the result without installing
# MathJax. However, it is strongly recommended to install a local copy of
# MathJax from https://www.mathjax.org before deployment.
# The default value is: https://cdnjs.cloudflare.com/ajax/libs/mathjax/2.7.2/.
# The default value is: https://cdnjs.cloudflare.com/ajax/libs/mathjax/2.7.5/.
# This tag requires that the tag USE_MATHJAX is set to YES.
MATHJAX_RELPATH = https://cdnjs.cloudflare.com/ajax/libs/mathjax/2.7.2/
@@ -1669,21 +1694,34 @@ LATEX_OUTPUT = latex
# The LATEX_CMD_NAME tag can be used to specify the LaTeX command name to be
# invoked.
#
# Note that when enabling USE_PDFLATEX this option is only used for generating
# bitmaps for formulas in the HTML output, but not in the Makefile that is
# written to the output directory.
# The default file is: latex.
# Note that when not enabling USE_PDFLATEX the default is latex when enabling
# USE_PDFLATEX the default is pdflatex and when in the later case latex is
# chosen this is overwritten by pdflatex. For specific output languages the
# default can have been set differently, this depends on the implementation of
# the output language.
# This tag requires that the tag GENERATE_LATEX is set to YES.
LATEX_CMD_NAME = latex
# The MAKEINDEX_CMD_NAME tag can be used to specify the command name to generate
# index for LaTeX.
# Note: This tag is used in the Makefile / make.bat.
# See also: LATEX_MAKEINDEX_CMD for the part in the generated output file
# (.tex).
# The default file is: makeindex.
# This tag requires that the tag GENERATE_LATEX is set to YES.
MAKEINDEX_CMD_NAME = makeindex
# The LATEX_MAKEINDEX_CMD tag can be used to specify the command name to
# generate index for LaTeX.
# Note: This tag is used in the generated output file (.tex).
# See also: MAKEINDEX_CMD_NAME for the part in the Makefile / make.bat.
# The default value is: \makeindex.
# This tag requires that the tag GENERATE_LATEX is set to YES.
LATEX_MAKEINDEX_CMD = \makeindex
# If the COMPACT_LATEX tag is set to YES, doxygen generates more compact LaTeX
# documents. This may be useful for small projects and may help to save some
# trees in general.
@@ -1800,7 +1838,7 @@ LATEX_HIDE_INDICES = NO
# The default value is: NO.
# This tag requires that the tag GENERATE_LATEX is set to YES.
LATEX_SOURCE_CODE = NO
LATEX_SOURCE_CODE = YES
# The LATEX_BIB_STYLE tag can be used to specify the style to use for the
# bibliography, e.g. plainnat, or ieeetr. See
@@ -1818,6 +1856,14 @@ LATEX_BIB_STYLE = plain
LATEX_TIMESTAMP = NO
# The LATEX_EMOJI_DIRECTORY tag is used to specify the (relative or absolute)
# path from which the emoji images will be read. If a relative path is entered,
# it will be relative to the LATEX_OUTPUT directory. If left blank the
# LATEX_OUTPUT directory will be used.
# This tag requires that the tag GENERATE_LATEX is set to YES.
LATEX_EMOJI_DIRECTORY =
#---------------------------------------------------------------------------
# Configuration options related to the RTF output
#---------------------------------------------------------------------------
@@ -1857,9 +1903,9 @@ COMPACT_RTF = NO
RTF_HYPERLINKS = NO
# Load stylesheet definitions from file. Syntax is similar to doxygen's config
# file, i.e. a series of assignments. You only have to provide replacements,
# missing definitions are set to their default value.
# Load stylesheet definitions from file. Syntax is similar to doxygen's
# configuration file, i.e. a series of assignments. You only have to provide
# replacements, missing definitions are set to their default value.
#
# See also section "Doxygen usage" for information on how to generate the
# default style sheet that doxygen normally uses.
@@ -1868,8 +1914,8 @@ RTF_HYPERLINKS = NO
RTF_STYLESHEET_FILE =
# Set optional variables used in the generation of an RTF document. Syntax is
# similar to doxygen's config file. A template extensions file can be generated
# using doxygen -e rtf extensionFile.
# similar to doxygen's configuration file. A template extensions file can be
# generated using doxygen -e rtf extensionFile.
# This tag requires that the tag GENERATE_RTF is set to YES.
RTF_EXTENSIONS_FILE =
@@ -1955,6 +2001,13 @@ XML_OUTPUT = xml
XML_PROGRAMLISTING = YES
# If the XML_NS_MEMB_FILE_SCOPE tag is set to YES, doxygen will include
# namespace members in file scope as well, matching the HTML output.
# The default value is: NO.
# This tag requires that the tag GENERATE_XML is set to YES.
XML_NS_MEMB_FILE_SCOPE = NO
#---------------------------------------------------------------------------
# Configuration options related to the DOCBOOK output
#---------------------------------------------------------------------------

20
doxygen/build-doxygen.sh Executable file
View File

@@ -0,0 +1,20 @@
#!/bin/bash
SOURCE="${BASH_SOURCE[0]}"
while [ -h "$SOURCE" ]; do # resolve $SOURCE until the file is no longer a symlink
DIR="$( cd -P "$( dirname "$SOURCE" )" >/dev/null && pwd )"
SOURCE="$(readlink "$SOURCE")"
[[ $SOURCE != /* ]] && SOURCE="$DIR/$SOURCE" # if $SOURCE was a relative symlink, we need to resolve it relative to the path where the symlink file was located
done
DIR="$( cd -P "$( dirname "$SOURCE" )" >/dev/null && pwd )"
cd "$DIR"
export PROJECT_NUMBER=`git describe --tags`
if [ $# != 1 ]; then
export OUTPUT_DIRECTORY="./output"
else
export OUTPUT_DIRECTORY="$1"
fi
doxygen Doxyconfig

View File

@@ -5,7 +5,7 @@ File Format
-----------
The layer mapping file contains information on how to render the layers.
The information is stored in CSV format.
The information is stored in CSV format -- *True CSV*; not that rubbish with semicolons that Excel calls CSV.
Each line representing a layer consists of following fields:

View File

@@ -0,0 +1,8 @@
/* This file only contains help information for doxygen */
/**
* @defgroup trigonometric Trigonometric Helper Functions
*
* The trigonometric helper function are used to calculate bounding boxes
* @warning Code is incomplete. Please double check for functionality!
*/

View File

@@ -3,16 +3,20 @@
@section cmd Command Line Interface
To use the application on the command line check 'gds-render --help'.
Application options:
Application Options:
- -t, --tikz Output TikZ code
- -p, --pdf Output PDF document
- -s, --scale=<SCALE> Divide output coordinates by <SCALE>
- -s, --scale=SCALE Divide output coordinates by SCALE
- -o, --tex-output=PATH Optional path for TeX file
- -O, --pdf-output=PATH Optional path for PDF file
- -m, --mapping=PATH Path for Layer Mapping File (see @ref lmf-spec)
- -m, --mapping=PATH Path for Layer Mapping File
- -c, --cell=NAME Cell to render
- -a, --tex-standalone Configure TeX Code standalone
- -l, --tex-layers configure TeX code to create PDF Layers (OCG)
- -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
@@ -21,5 +25,6 @@ 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
*/

71
external-renderer.c Normal file
View File

@@ -0,0 +1,71 @@
/*
* GDSII-Converter
* Copyright (C) 2018 Mario Hüttel <mario.huettel@gmx.net>
*
* This file is part of GDSII-Converter.
*
* GDSII-Converter is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*
* GDSII-Converter is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with GDSII-Converter. If not, see <http://www.gnu.org/licenses/>.
*/
/**
* @file external-renderer.c
* @brief This file implements the dynamic library loading for the external rendering feature
* @author Mario Hüttel <mario.huettel@gmx.net>
*/
/**
* @addtogroup MainApplication
* @{
*/
#include "external-renderer.h"
#include <dlfcn.h>
#include <stdio.h>
int external_renderer_render_cell(struct gds_cell *toplevel_cell, GList *layer_info_list,
char *output_file, char *so_path)
{
int (*so_render_func)(struct gds_cell *, GList *, char *) = NULL;
void *so_handle = NULL;
char *error_msg;
int ret = 0;
/* Check parameter sanity */
if (!output_file || !so_path || !toplevel_cell || !layer_info_list)
return -3000;
/* Load shared object */
so_handle = dlopen(so_path, RTLD_LAZY);
if (!so_handle) {
printf("Could not load external library '%s'\nDetailed error is:\n%s\n", so_path, dlerror());
return -2000;
}
/* Load symbol from library */
so_render_func = (int (*)(struct gds_cell *, GList *, char *))dlsym(so_handle, EXTERNAL_LIBRARY_FUNCTION);
error_msg = dlerror();
if (error_msg != NULL) {
printf("Rendering function not found in library:\n%s\n", error_msg);
goto ret_close_so_handle;
}
/* Execute */
if (so_render_func)
so_render_func(toplevel_cell, layer_info_list, output_file);
ret_close_so_handle:
dlclose(so_handle);
return ret;
}
/** @} */

59
external-renderer.h Normal file
View File

@@ -0,0 +1,59 @@
/*
* GDSII-Converter
* Copyright (C) 2018 Mario Hüttel <mario.huettel@gmx.net>
*
* This file is part of GDSII-Converter.
*
* GDSII-Converter is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*
* GDSII-Converter is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with GDSII-Converter. If not, see <http://www.gnu.org/licenses/>.
*/
/**
* @file external-renderer.h
* @brief Render according to command line parameters
* @author Mario Hüttel <mario.huettel@gmx.net>
*/
/**
* @addtogroup MainApplication
* @{
*/
#ifndef _EXTERNAL_RENDERER_H_
#define _EXTERNAL_RENDERER_H_
#include "gds-parser/gds-types.h"
#include <glib.h>
/**
* @brief function name expected to be found in external library.
*
* The function has to be defined as follows:
* @code
* int function_name(gds_cell *toplevel, GList *layer_info_list, char *output_file_name)
* @endcode
*/
#define EXTERNAL_LIBRARY_FUNCTION "render_cell_to_file"
/**
* @brief external_renderer_render_cell
* @param toplevel_cell The toplevel cell to render
* @param layer_info_list The layer information. Contains #layer_info elements
* @param output_file Output file
* @param so_path Path to the shared object file containing #EXTERNAL_LIBRARY_FUNCTION
* @return 0 on success
*/
int external_renderer_render_cell(struct gds_cell *toplevel_cell, GList *layer_info_list, char *output_file, char *so_path);
#endif /* _EXTERNAL_RENDERER_H_ */
/** @} */

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,7 +30,7 @@
*/
/**
* @addtogroup GDS-Parser
* @addtogroup GDS-Utilities
* @{
*/
@@ -48,11 +43,17 @@
#include <math.h>
#include <cairo.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,6 +898,7 @@ int parse_gds_from_file(const char *filename, GList **library_list)
*/
static void delete_cell_inst_element(struct gds_cell_instance *cell_inst)
{
if (cell_inst)
free(cell_inst);
}
@@ -879,6 +908,7 @@ static void delete_cell_inst_element(struct gds_cell_instance *cell_inst)
*/
static void delete_vertex(struct gds_point *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

@@ -24,7 +24,7 @@
*/
/**
* @addtogroup GDS-Parser
* @addtogroup GDS-Utilities
* @{
*/
@@ -39,7 +39,7 @@
int parse_gds_from_file(const char *filename, GList **library_array);
/**
* @brief Deletes all libraries including cells, references etc.
* @param Pointer to a list of #gds_library. Is set to NULL after completion.
* @param library_list Pointer to a list of #gds_library. Is set to NULL after completion.
* @return 0
*/
int clear_lib_list(GList **library_list);

View File

@@ -0,0 +1,200 @@
/*
* 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 "gds-tree-checker.h"
#include <stdio.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

@@ -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-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: 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: 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

@@ -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>
@@ -51,7 +51,6 @@
<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>
@@ -69,6 +68,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 +106,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">
@@ -81,6 +90,25 @@
<object class="GtkBox">
<property name="visible">True</property>
<property name="can_focus">False</property>
<child>
<object class="GtkBox">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="orientation">vertical</property>
<child>
<object class="GtkSearchEntry" id="cell-search">
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="primary_icon_name">edit-find-symbolic</property>
<property name="primary_icon_activatable">False</property>
<property name="primary_icon_sensitive">False</property>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="position">0</property>
</packing>
</child>
<child>
<object class="GtkScrolledWindow">
<property name="visible">True</property>
@@ -91,6 +119,9 @@
<object class="GtkTreeView" id="cell-tree">
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="headers_clickable">False</property>
<property name="enable_search">False</property>
<property name="enable_grid_lines">both</property>
<child internal-child="selection">
<object class="GtkTreeSelection"/>
</child>
@@ -100,6 +131,57 @@
<packing>
<property name="expand">True</property>
<property name="fill">True</property>
<property name="position">1</property>
</packing>
</child>
</object>
<packing>
<property name="expand">True</property>
<property name="fill">True</property>
<property name="position">0</property>
</packing>
</child>
<child>
<object class="GtkBox">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="orientation">vertical</property>
<child>
<object class="GtkBox">
<property name="visible">True</property>
<property name="can_focus">False</property>
<child>
<object class="GtkButton" id="button-up-sort">
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="receives_default">True</property>
<property name="image">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>
@@ -130,6 +212,13 @@
</packing>
</child>
</object>
<packing>
<property name="expand">True</property>
<property name="fill">True</property>
<property name="position">1</property>
</packing>
</child>
</object>
</child>
</object>
</interface>

View File

@@ -0,0 +1,231 @@
/*
* 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/>.
*/
/*
* Original Drag and Drop Code taken from:
* https://gitlab.gnome.org/GNOME/gtk/blob/gtk-3-22/tests/testlist3.c
*/
/**
* @file layer-selector-dnd.c
* @brief This file implements the drag and drop functions regarding the list box containing the layer elements
* @author Mario Hüttel <mario.huettel@gmx.net>
*/
#include "layer-selector-dnd.h"
static GtkTargetEntry entries[] = {
{ "GTK_LIST_BOX_ROW", GTK_TARGET_SAME_APP, 0 }
};
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; "
"}";
void layer_selector_list_box_setup_dnd(GtkListBox *box)
{
GtkCssProvider *provider;
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);
gtk_drag_dest_set(GTK_WIDGET(box), GTK_DEST_DEFAULT_MOTION | GTK_DEST_DEFAULT_DROP, entries, 1, GDK_ACTION_MOVE);
g_signal_connect(box, "drag-data-received", G_CALLBACK(layer_selector_drag_data_received), NULL);
g_signal_connect(box, "drag-motion", G_CALLBACK(layer_selector_drag_motion), NULL);
g_signal_connect(box, "drag-leave", G_CALLBACK(layer_selector_drag_leave), NULL);
}

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-selector-dnd.h
* @brief Header for drag and drop of layer selector
* @author Mario Hüttel <mario.huettel@gmx.net>
*/
#ifndef _LAYER_SELECTOR_DND_H_
#define _LAYER_SELECTOR_DND_H_
#include <gtk/gtk.h>
void layer_selector_list_box_setup_dnd(GtkListBox *box);
#endif /* _LAYER_SELECTOR_DND_H_ */

View File

@@ -18,7 +18,7 @@
*/
/**
* @file layer-selection.c
* @file layer-selector.c
* @brief Implementation of the layer selector
* @author Mario Hüttel <mario.huettel@gmx.net>
*/
@@ -29,8 +29,8 @@
*/
#include "layer-selector.h"
#include "gds-parser/gds-parser.h"
#include "widgets/layer-element.h"
#include "../gds-parser/gds-parser.h"
#include "../widgets/layer-element.h"
#include <glib.h>
#include <string.h>
#include <stdio.h>
@@ -155,19 +155,30 @@ static void analyze_cell_layers(GtkListBox *listbox, struct gds_cell *cell)
* @param row1
* @param row2
* @param unused
* @note Do not use this function
* @return
* @note Do not use this function. This is an internal callback
* @return See sort function documentation of GTK+
*/
static gint 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;
}
@@ -179,7 +190,6 @@ void generate_layer_widgets(GtkListBox *listbox, GList *libs)
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;
@@ -188,11 +198,8 @@ void generate_layer_widgets(GtkListBox *listbox, GList *libs)
} /* 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);
/* Sort the layers */
layer_selector_force_sort(LAYER_SELECTOR_SORT_DOWN);
/* Activate Buttons */
gtk_widget_set_sensitive(global_load_button, TRUE);
@@ -321,6 +328,7 @@ static void load_mapping_clicked(GtkWidget *button, gpointer user_data)
*/
static void create_csv_line(LayerElement *layer_element, char *line_buffer, size_t max_len)
{
int i;
GString *string;
gboolean export;
const gchar *name;
@@ -336,9 +344,19 @@ static void create_csv_line(LayerElement *layer_element, char *line_buffer, size
layer_element_get_color(layer_element, &color);
/* print values to line */
g_string_printf(string, "%d,%lf,%lf,%lf,%lf,%d,%s\n",
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");
@@ -424,4 +442,15 @@ void setup_save_mapping_callback(GtkWidget *button, GtkWindow *main_window)
g_signal_connect(button, "clicked", G_CALLBACK(save_mapping_clicked), main_window);
}
void layer_selector_force_sort(enum layer_selector_sort_algo sort_function)
{
if (!global_list_box)
return;
/* Set dorting function, sort, and disable sorting function */
gtk_list_box_set_sort_func(global_list_box, sort_func, (gpointer)&sort_function, NULL);
gtk_list_box_invalidate_sort(global_list_box);
gtk_list_box_set_sort_func(global_list_box, NULL, NULL, NULL);
}
/** @} */

View File

@@ -28,7 +28,12 @@
#include <gtk/gtk.h>
#include <glib.h>
#include "mapping-parser.h"
#include "../mapping-parser.h"
/**
* @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 Generate layer widgets in \p listbox
@@ -64,4 +69,14 @@ GList *export_rendered_layer_info();
* @note The layer_info::name Element has to be freed manually
*/
void delete_layer_info_struct(struct layer_info *info);
/**
* @brief Force sorting of the layer selector in a specified way
*
* If the layer selector is not yet set up, this function has no effect.
*
* @param sort_function Sorting direction
*/
void layer_selector_force_sort(enum layer_selector_sort_algo sort_function);
#endif /* __LAYER_SELECTOR_H__ */

View File

@@ -31,12 +31,16 @@
#include <stdio.h>
#include "gds-parser/gds-parser.h"
#include <gtk/gtk.h>
#include "layer-selector.h"
#include "layer-selector/layer-selector.h"
#include "layer-selector/layer-selector-dnd.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"
#include "trigonometric/cell-trigonometrics.h"
#include "version/version.h"
#include "tree-renderer/lib-cell-renderer.h"
#include "gds-parser/gds-tree-checker.h"
/**
* @brief User data supplied to callback function of the open button
*/
@@ -45,6 +49,7 @@ struct open_button_data {
GList **list_ptr;
GtkTreeStore *cell_store;
GtkListBox *layer_box;
GtkSearchEntry *search_entry;
};
/**
@@ -112,9 +117,13 @@ static void on_load_gds(gpointer button, gpointer user)
char *filename;
GString *mod_date;
GString *acc_date;
unsigned int cell_error_level;
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);
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();
@@ -159,6 +168,10 @@ static void on_load_gds(gpointer button, gpointer user)
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);
@@ -172,10 +185,21 @@ static void on_load_gds(gpointer button, gpointer user)
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(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. */
@@ -201,8 +225,9 @@ end_destroy:
*/
static void on_convert_clicked(gpointer button, gpointer user)
{
(void)button;
static struct render_settings sett = {
.scale = 1000.0f,
.scale = 1000.0,
.renderer = RENDERER_LATEX_TIKZ,
};
struct convert_button_data *data = (struct convert_button_data *)user;
@@ -217,6 +242,11 @@ static void on_convert_clicked(gpointer button, gpointer user)
GtkFileFilter *filter;
gint res;
char *file_name;
union bounding_box cell_box;
unsigned int height, width;
if (!data)
return;
/* Get selected cell */
selection = gtk_tree_view_get_selection(data->tree_view);
@@ -231,8 +261,24 @@ static void on_convert_clicked(gpointer button, gpointer user)
/* Get layers that are rendered */
layer_list = export_rendered_layer_info();
/* 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 asbsolutely 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(data->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);
res = gtk_dialog_run(GTK_DIALOG(settings));
if (res == GTK_RESPONSE_OK) {
renderer_settings_dialog_get_settings(settings, &sett);
@@ -242,8 +288,6 @@ static void on_convert_clicked(gpointer button, gpointer user)
goto ret_layer_destroy;
}
/* save file dialog */
dialog = gtk_file_chooser_dialog_new((sett.renderer == RENDERER_LATEX_TIKZ
? "Save LaTeX File" : "Save PDF"),
@@ -285,8 +329,12 @@ static void on_convert_clicked(gpointer button, gpointer user)
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.renderer == RENDERER_CAIROGRAPHICS_PDF
? file_name
: NULL),
(sett.renderer == RENDERER_CAIROGRAPHICS_SVG
? file_name
: NULL),
sett.scale);
break;
}
@@ -299,6 +347,21 @@ ret_layer_destroy:
g_list_free_full(layer_list, (GDestroyNotify)delete_layer_info_struct);
}
/**
* @brief cell_tree_view_activated
* @param tree_view Not used
* @param user convert button data
*/
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
@@ -321,27 +384,46 @@ static void cell_selection_changed(GtkTreeSelection *sel, GtkWidget *convert_but
}
}
static void sort_up_callback(GtkWidget *widget, gpointer user)
{
(void)widget;
(void)user;
layer_selector_force_sort(LAYER_SELECTOR_SORT_UP);
}
static void sort_down_callback(GtkWidget *widget, gpointer user)
{
(void)widget;
(void)user;
layer_selector_force_sort(LAYER_SELECTOR_SORT_DOWN);
}
GtkWindow *create_main_window()
{
GtkBuilder *main_builder;
GtkTreeView *cell_tree;
GtkTreeStore *cell_store;
GtkWidget *listbox;
GtkWidget *conv_button;
GtkWidget *search_entry;
GtkHeaderBar *header_bar;
static GList *gds_libs;
static struct open_button_data open_data;
static struct convert_button_data conv_data;
struct tree_stores *cell_selector_stores;
GtkWidget *sort_up_button;
GtkWidget *sort_down_button;
main_builder = gtk_builder_new_from_resource("/main.glade");
gtk_builder_connect_signals(main_builder, NULL);
cell_tree = GTK_TREE_VIEW(gtk_builder_get_object(main_builder, "cell-tree"));
cell_store = setup_cell_selector(cell_tree);
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_store;
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")),
@@ -359,6 +441,9 @@ GtkWindow *create_main_window()
g_signal_connect(conv_button, "clicked", G_CALLBACK(on_convert_clicked), &conv_data);
listbox = GTK_WIDGET(gtk_builder_get_object(main_builder, "layer-list"));
/* Set up the list box sided callbacks for drag and drop */
layer_selector_list_box_setup_dnd(GTK_LIST_BOX(listbox));
open_data.layer_box = GTK_LIST_BOX(listbox);
/* Set buttons fpr layer mapping GUI */
@@ -370,8 +455,22 @@ GtkWindow *create_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_signal_connect(cell_tree, "row-activated", G_CALLBACK(cell_tree_view_activated), &conv_data);
return (conv_data.main_window);
/* 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), NULL);
g_signal_connect(sort_down_button, "clicked", G_CALLBACK(sort_down_callback), NULL);
g_object_unref(main_builder);
return conv_data.main_window;
}
/** @} */

80
main.c
View File

@@ -22,16 +22,20 @@
#include <glib.h>
#include "main-window.h"
#include "command-line.h"
#include "external-renderer.h"
#include "version/version.h"
struct application_data {
GtkApplication *app;
GtkWindow *main_window;
};
static void app_quit(GSimpleAction *action, GVariant *parameter, gpointer user_data)
{
struct application_data *appdata = (struct application_data *)user_data;
const struct application_data * const appdata = (const struct application_data *)user_data;
(void)action;
(void)parameter;
gtk_widget_destroy(GTK_WIDGET(appdata->main_window));
}
@@ -39,26 +43,29 @@ static void app_about(GSimpleAction *action, GVariant *parameter, gpointer user_
{
GtkBuilder *builder;
GtkDialog *dialog;
struct application_data *appdata = (struct application_data *)user_data;
const struct application_data * const appdata = (const struct application_data *)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_about_dialog_set_version(GTK_ABOUT_DIALOG(dialog), _app_version_string);
gtk_dialog_run(dialog);
gtk_widget_destroy(GTK_WIDGET(dialog));
g_object_unref(builder);
}
const GActionEntry app_actions[] = {
{ "quit", app_quit },
{ "about", app_about }
const static GActionEntry app_actions[] = {
{"quit", app_quit, NULL, NULL, NULL, {0}},
{"about", app_about, NULL, NULL, NULL, {0}}
};
static void gapp_activate(GApplication *app, gpointer user_data)
{
GtkWindow *main_window;
struct application_data *appdata = (struct application_data *)user_data;
struct application_data * const appdata = (struct application_data *)user_data;
main_window = create_main_window();
appdata->main_window = main_window;
@@ -76,13 +83,10 @@ static int start_gui(int argc, char **argv)
GMenu *m_quit;
GMenu *m_about;
gapp = gtk_application_new("de.shimatta.gds-render", G_APPLICATION_FLAGS_NONE);
gapp = gtk_application_new("de.shimatta.gds-render", G_APPLICATION_NON_UNIQUE);
g_application_register(G_APPLICATION(gapp), NULL, NULL);
//g_action_map_add_action_entries(G_ACTION_MAP(gapp), app_actions, G_N_ELEMENTS(app_actions), &appdata);
g_signal_connect(gapp, "activate", G_CALLBACK(gapp_activate), &appdata);
menu = g_menu_new();
m_quit = g_menu_new();
m_about = g_menu_new();
@@ -90,20 +94,26 @@ static int start_gui(int argc, char **argv)
g_menu_append(m_about, "About", "app.about");
g_menu_append_section(menu, NULL, G_MENU_MODEL(m_about));
g_menu_append_section(menu, NULL, G_MENU_MODEL(m_quit));
g_action_map_add_action_entries(G_ACTION_MAP(gapp), app_actions, G_N_ELEMENTS(app_actions), &appdata);
g_action_map_add_action_entries(G_ACTION_MAP(gapp), app_actions,
G_N_ELEMENTS(app_actions), &appdata);
gtk_application_set_app_menu(GTK_APPLICATION(gapp), G_MENU_MODEL(menu));
g_object_unref(m_quit);
g_object_unref(m_about);
g_object_unref(menu);
app_status = g_application_run(G_APPLICATION(gapp), argc, argv);
g_object_unref(gapp);
return app_status;
}
static void print_version()
{
printf("This is gds-render, version: %s\n\nFor a list of supported commands execute with --help option.\n",
_app_version_string);
}
int main(int argc, char **argv)
{
GError *error = NULL;
@@ -112,12 +122,14 @@ int main(int argc, char **argv)
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[] =
{
GOptionEntry entries[] = {
{"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 },
@@ -129,18 +141,25 @@ int main(int argc, char **argv)
{"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");
g_option_context_add_main_entries(context, entries, NULL);
g_option_context_add_group(context, gtk_get_option_group(TRUE));
if (!g_option_context_parse (context, &argc, &argv, &error))
{
if (!g_option_context_parse(context, &argc, &argv, &error)) {
g_print("Option parsing failed: %s\n", error->message);
exit(1);
}
if (version) {
print_version();
goto ret_status;
}
if (argc >= 2) {
if (scale < 1) {
printf("Scale < 1 not allowed. Setting to 1\n");
@@ -148,9 +167,8 @@ int main(int argc, char **argv)
}
/* No format selected */
if (!(tikz || pdf || svg)) {
if (!(tikz || pdf || svg))
tikz = TRUE;
}
/* Get gds name */
gds_name = argv[1];
@@ -158,21 +176,19 @@ int main(int argc, char **argv)
/* Check if PDF/TeX names are supplied. if not generate */
basename = g_path_get_basename(gds_name);
if (!texname) {
if (!texname)
texname = g_strdup_printf("./%s.tex", basename);
}
if (!pdfname) {
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);
command_line_convert_gds(gds_name, pdfname, texname, pdf, tikz,
mappingname, cellname, (double)scale,
pdf_layers, pdf_standalone, svg, svgname,
custom_library_path, custom_library_file_name);
/* Clean up */
g_free(pdfname);
g_free(texname);
@@ -187,6 +203,6 @@ int main(int argc, char **argv)
app_status = start_gui(argc, argv);
}
ret_status:
return app_status;
}

View File

@@ -25,6 +25,7 @@ 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 +39,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;
@@ -89,6 +122,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);
}

View File

@@ -27,6 +27,9 @@ 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())
#define LIB_CELL_RENDERER_ERROR_WARN (1U<<0)
#define LIB_CELL_RENDERER_ERROR_ERR (1U<<1)
typedef struct _LibCellRenderer {
/* Inheritance */
GtkCellRendererText super;

View File

@@ -49,64 +49,111 @@ static gboolean tree_sel_func(GtkTreeSelection *selection,
{
GtkTreeIter iter;
struct gds_cell *cell;
unsigned int error_level;
gboolean ret = FALSE;
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;
}
/**
* @brief cell_store_filter_visible_func Decides whether an element of the tree model @p model is visible.
* @param model Tree model
* @param iter Current element / iter in Model to check
* @param data Data. Set to static stores variable
* @return TRUE if visible, else FALSE
* @note TODO: Maybe implement Damerau-Levenshtein distance matching
*/
static gboolean cell_store_filter_visible_func(GtkTreeModel *model, GtkTreeIter *iter, gpointer data)
{
struct tree_stores *stores = (struct tree_stores *)data;
struct gds_cell *cell;
struct gds_library *lib;
gboolean result = FALSE;
const char *search_string;
if (!model || !iter || !stores)
goto exit_filter;
gtk_tree_model_get(model, iter, CELL_SEL_CELL, &cell, CELL_SEL_LIBRARY, &lib, -1);
if (lib) {
result = TRUE;
goto exit_filter;
}
if (!cell)
goto exit_filter;
search_string = gtk_entry_get_text(stores->search_entry);
/* Show all, if field is empty */
if (!strlen(search_string))
result = TRUE;
if (strstr(cell->name, search_string))
result = TRUE;
gtk_tree_view_expand_all(stores->base_tree_view);
exit_filter:
return result;
}
static void change_filter(GtkWidget *entry, gpointer data)
{
struct tree_stores *stores = (struct tree_stores *)data;
gtk_tree_model_filter_refilter(stores->filter);
}
/**
* @brief Setup a GtkTreeView with the necessary columns
* @param view Tree view to set up
* @return TreeStore for storing data inside the GtkTreeView
* @param search_entry Entry field for search
* @return Tree stores for storing data inside the GtkTreeView
*/
GtkTreeStore *setup_cell_selector(GtkTreeView* view)
struct tree_stores *setup_cell_selector(GtkTreeView* view, GtkEntry *search_entry)
{
GtkTreeStore *cell_store;
static struct tree_stores stores;
GtkCellRenderer *render_dates;
GtkCellRenderer *render_cell;
GtkCellRenderer *render_lib;
GtkTreeViewColumn *column;
GdkRGBA cell_text_color;
GValue val = G_VALUE_INIT;
cell_store = gtk_tree_store_new(CELL_SEL_COLUMN_COUNT, G_TYPE_POINTER, G_TYPE_POINTER, G_TYPE_STRING, G_TYPE_STRING);
gtk_tree_view_set_model(view, GTK_TREE_MODEL(cell_store));
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, G_TYPE_UINT, G_TYPE_STRING, G_TYPE_STRING);
/* Searching */
if (search_entry) {
stores.filter = GTK_TREE_MODEL_FILTER(gtk_tree_model_filter_new(GTK_TREE_MODEL(stores.base_store), NULL));
gtk_tree_model_filter_set_visible_func (stores.filter,
(GtkTreeModelFilterVisibleFunc)cell_store_filter_visible_func,
&stores, NULL);
g_signal_connect(GTK_SEARCH_ENTRY(search_entry), "search-changed", G_CALLBACK(change_filter), &stores);
}
gtk_tree_view_set_model(view, GTK_TREE_MODEL(stores.filter));
render_dates = gtk_cell_renderer_text_new();
render_cell = lib_cell_renderer_new();
render_lib = lib_cell_renderer_new();
/* Set foreground color for cell column */
cell_text_color.alpha = 1;
cell_text_color.red = (double)61.0/(double)255.0;
cell_text_color.green = (double)152.0/(double)255.0;
cell_text_color.blue = 0.0;
g_value_init(&val, G_TYPE_BOOLEAN);
g_value_set_boolean(&val, TRUE);
g_object_set_property(G_OBJECT(render_cell), "foreground-set", &val);
g_value_unset(&val);
g_value_init(&val, GDK_TYPE_RGBA);
g_value_set_boxed(&val, &cell_text_color);
g_object_set_property(G_OBJECT(render_cell), "foreground-rgba", &val);
g_value_unset(&val);
column = gtk_tree_view_column_new_with_attributes("Library", render_lib, "gds-lib", CELL_SEL_LIBRARY, NULL);
gtk_tree_view_append_column(view, column);
/* Cell color: #3D9801 */
column = gtk_tree_view_column_new_with_attributes("Cell", render_cell, "gds-cell", CELL_SEL_CELL, NULL);
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);
@@ -119,6 +166,6 @@ GtkTreeStore *setup_cell_selector(GtkTreeView* view)
* This prevents selecting a library */
gtk_tree_selection_set_select_function(gtk_tree_view_get_selection(view), tree_sel_func, NULL, NULL);
return cell_store;
return &stores;
}
/** @} */

View File

@@ -37,12 +37,20 @@
enum cell_store_columns {
CELL_SEL_LIBRARY = 0,
CELL_SEL_CELL,
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 */
};
GtkTreeStore *setup_cell_selector(GtkTreeView* view);
struct tree_stores {
GtkTreeView *base_tree_view;
GtkTreeStore *base_store;
GtkTreeModelFilter *filter;
GtkEntry *search_entry;
};
struct tree_stores *setup_cell_selector(GtkTreeView* view, GtkEntry *search_entry);
#endif /* __TREE_STORE_H__ */

View File

@@ -23,6 +23,11 @@
* @author Mario Hüttel <mario.huettel@gmx.net>
*/
/**
* @addtogroup trigonometric
* @{
*/
#include <stdio.h>
#include "bounding-box.h"
#include <math.h>
@@ -33,7 +38,7 @@
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;
@@ -81,8 +86,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,
@@ -128,12 +133,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);
}
}
/** @} */

View File

@@ -23,12 +23,19 @@
* @author Mario Hüttel <mario.huettel@gmx.net>
*/
/**
* @addtogroup trigonometric
* @{
*/
#ifndef _BOUNDING_BOX_H_
#define _BOUNDING_BOX_H_
#include <glib.h>
#include "vector-operations.h"
#include <stdbool.h>
union bounding_box {
/** Coordinate System is (y up | x right) */
struct _vectors {
struct vector_2d lower_left;
struct vector_2d upper_right;
@@ -42,4 +49,9 @@ 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,119 @@
/*
* 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-trigonometrics.c
* @brief Calculation of gds_cell trigonometrics
* @author Mario Hüttel <mario.huettel@gmx.net>
*/
#include "cell-trigonometrics.h"
#include <math.h>
/**
* @addtogroup trigonometric
* @{
*/
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

@@ -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-trigonometrics.h
* @brief Calculation of gds_cell trigonometrics
* @author Mario Hüttel <mario.huettel@gmx.net>
*/
/**
* @addtogroup trigonometric
* @{
*/
#ifndef _CELL_TRIGONOMETRICS_H_
#define _CELL_TRIGONOMETRICS_H_
#include "bounding-box.h"
#include "../gds-parser/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_TRIGONOMETRICS_H_ */
/** @} */

View File

@@ -23,6 +23,11 @@
* @author Mario Hüttel <mario.huettel@gmx.net>
*/
/**
* @addtogroup trigonometric
* @{
*/
#include "vector-operations.h"
#include <math.h>
#include <stdlib.h>
@@ -71,19 +76,18 @@ 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;
}
}
struct vector_2d *vector_2d_alloc(void)
{
@@ -141,3 +145,5 @@ void vector_2d_add(struct vector_2d *res, struct vector_2d *a, struct vector_2d
res->y = a->y + b->y;
}
}
/** @} */

View File

@@ -23,6 +23,12 @@
* @author Mario Hüttel <mario.huettel@gmx.net>
*/
/**
* @addtogroup trigonometric
* @{
*/
#ifndef _VECTOR_OPERATIONS_H_
#define _VECTOR_OPERATIONS_H_
@@ -48,3 +54,5 @@ void vector_2d_subtract(struct vector_2d *res, struct vector_2d *a, struct vecto
void vector_2d_add(struct vector_2d *res, struct vector_2d *a, struct vector_2d *b);
#endif /* _VECTOR_OPERATIONS_H_ */
/** @} */

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

34
version/version.c Normal file
View File

@@ -0,0 +1,34 @@
/*
* 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/>.
*/
/**
* @addtogroup MainApplication
* @{
*/
#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
/** @} */

28
version/version.h Normal file
View File

@@ -0,0 +1,28 @@
/*
* 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/>.
*/
/**
* @addtogroup MainApplication
* @{
*/
/** @brief This string holds the 'git describe' version of the app */
extern char *_app_version_string;
/** @} */

View File

@@ -18,7 +18,7 @@
*/
/**
* @file conv-settings-dilaog.c
* @file conv-settings-dialog.c
* @brief Implementation of the setting dialog
* @author Mario Hüttel <mario.huettel@gmx.net>
*/
@@ -39,12 +39,20 @@ 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)
static void renderer_settings_dialog_class_init(RendererSettingsDialogClass *klass)
{
/* No special code needed. Child cells are destroyed automatically due to reference counter */
@@ -72,13 +80,138 @@ 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 *));
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);
builder = gtk_builder_new_from_resource("/dialog.glade");
@@ -89,12 +222,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 +260,10 @@ 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;
/*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 +303,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

@@ -75,6 +75,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

@@ -17,9 +17,16 @@
* 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>
*/
@@ -63,6 +70,7 @@ static void layer_element_drag_begin(GtkWidget *widget,
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);
@@ -79,48 +87,35 @@ static void layer_element_drag_begin(GtkWidget *widget,
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 layer_element_drag_data_get(GtkWidget *widget,
GdkDragContext *context,
GtkSelectionData *selection_data,
guint info,
guint time,
gpointer data)
static void 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 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;
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;
@@ -137,11 +132,11 @@ static void layer_element_init(LayerElement *self)
self->priv.event_handle = GTK_EVENT_BOX(gtk_builder_get_object(builder, "event-box"));
/* Setup drag and drop */
gtk_style_context_add_class (gtk_widget_get_style_context(GTK_WIDGET(self)), "row");
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_signal_connect(self->priv.event_handle, "drag-end", G_CALLBACK(layer_element_drag_end), NULL);
g_object_unref(builder);
}