459 Commits

Author SHA1 Message Date
1ca04aaa71 Doxygen: Update image of Gui and its description. Fix #31 2019-12-16 22:09:14 +01:00
b8fc904af5 Fix typos 2019-12-16 22:00:59 +01:00
fdfa478fed Add full German translation 2019-12-16 21:58:18 +01:00
c0182220f1 Translations: Generate only one PO template file for all input files. Include glade files into translation, delete previous German Translation 2019-12-16 18:29:28 +01:00
798262383e Update the POT files 2019-12-12 21:39:08 +01:00
0bfe8df92f Update POT files 2019-12-12 21:24:19 +01:00
de9066f181 Add translation markers to all messages except for the gds parser's messages 2019-12-12 21:22:14 +01:00
87bc60bed0 Fix style issue in version.c 2019-12-12 20:36:17 +01:00
20d72a5edb Remove outdated TODO from source file 2019-12-12 20:34:41 +01:00
9e8d0b4611 include/gds-utils/gds-types.h: Fix typo in comment 2019-12-11 08:25:24 +01:00
4550815901 Fix code style 2019-12-07 19:07:52 +01:00
e3b6ee66ef Fix typo in comment 2019-11-28 17:59:06 +01:00
f3786cf282 Gui: Add library name to all cells in cell selector 2019-11-25 20:48:09 +01:00
c085a62036 GUI: Remove access and modification date from cell selector
Fix #28
2019-11-25 20:45:57 +01:00
55799b2266 Merge branch 'master' into dev 2019-11-19 01:33:56 +01:00
4970585cee Remove call to g_task_set(). It is not available under debian 2019-11-19 01:33:44 +01:00
c6483dbebd Merge branch 'master' into dev 2019-11-18 22:30:51 +01:00
86342da2a2 Remove unneeded comments 2019-11-18 22:30:05 +01:00
ce8386799b external renderer: Rename FUNC_DECL to EXPORTED_FUNC_DECL to show that it also exports a function 2019-11-18 21:59:42 +01:00
374e3b54c0 plugins: example plugin: Make all functions invisible except for the explicitly exported ones
* Add target parameters to compile all symbols invisible to the outside by default.
* Edit FUNC_DECL() macro to set attribute that exports the function
2019-11-18 21:56:22 +01:00
3651296c3a Merge branch 'master' into dev 2019-11-17 22:31:47 +01:00
5fe21f1d73 bounding box: Fix doxygen documentation typo 2019-11-17 22:31:31 +01:00
2d7103abbb Fix doxygen 2019-11-17 14:49:00 +01:00
392d7e1b3c plugins: Add license header and doxygen file 2019-11-17 14:09:53 +01:00
2fddfa475b Merge branch 'master' into dev 2019-11-17 01:52:05 +01:00
e6603d4c13 Fix broken latex generation 2019-11-16 16:16:01 +01:00
80730ab9c4 Merge branch 'master' into dev 2019-11-16 16:02:51 +01:00
2b0e2095e6 Update documentation and implementations of bounding box calculations. Rename functions to fit their behavior 2019-11-16 16:02:33 +01:00
0c20db39bd Update documentation and implementations of bounding box calculations. Rename functions to fit their behavior 2019-11-16 15:54:56 +01:00
1b1f742ae1 Fix doxygen for command line header 2019-11-15 21:39:33 +01:00
3b6837b886 Rename python renderer to plugin example and leave it be as a template 2019-11-15 21:34:13 +01:00
efb1af7ee0 Complete chain of passing command line parameters to external renderer 2019-11-15 21:11:41 +01:00
fa1a78e54c Edit comments 2019-11-15 21:06:41 +01:00
0417784877 Add property for command line parameters to external renderer 2019-11-15 21:04:59 +01:00
c186d3cdb3 Pass command line parameters for shared object renderer to command line convert struct 2019-11-15 20:50:46 +01:00
f02a720f99 Uodate translations of main.c 2019-11-15 20:35:36 +01:00
374a893dda Add W option to command line parser for external renderer parameters 2019-11-15 20:31:57 +01:00
83a7848c14 Merge branch 'dev' into external-renderer-rework 2019-11-14 23:39:40 +01:00
7977ee7c8b Merge branch 'master' into dev 2019-11-14 23:39:29 +01:00
e7f0f904e8 main: Free command line option context, add comment for freeing all the command line parameter data 2019-11-14 23:39:12 +01:00
48eb2c296f Merge branch 'dev' into external-renderer-rework 2019-11-14 19:36:59 +01:00
3d5c4daad9 Doxygen: Rework documentation make targets
* new target doxygen-pdf which build the latex output
* Add doxygen-pdf to documentation target
* Move documentaiton target definition to doxygen's CMakeLists.txt
2019-11-14 19:32:54 +01:00
9899b94db6 cmake: rework source list for generated files 2019-11-14 19:31:57 +01:00
f153485996 Implement base construct of new external renderer. CLI parameters still not implemented. Currently NULL is passed to init func. Forking implemented but not tested 2019-11-12 21:15:36 +01:00
f15e82b5dc Modify External Renderer: External renderer docu updated for future changes, restructuring. Not that the changes in the documentation are not yet implemented in code 2019-11-12 20:52:42 +01:00
daf12a7d8c Merge branch 'dev' into python-renderer 2019-11-12 19:55:01 +01:00
11f2068b76 Improve Cmake target for translations. Still not perfect. 2019-11-12 19:53:16 +01:00
24d66e74fe Merge commit '866d36873a4adef0ef8505de25740c03ec92a2e0' into dev 2019-11-12 19:53:02 +01:00
58a0bd85c4 Improve Cmake target for translations. Still not perfect. 2019-11-12 19:50:34 +01:00
f8de3468de Merge branch 'translations' into python-renderer 2019-11-12 19:16:12 +01:00
4cc31c81e3 Move plugins in CMakeLists.txt so they don't need to fullfil all warnign restrictions of the main application 2019-11-12 19:14:58 +01:00
74dfbd9b34 Add preliminary construct for plugin renderers (shared object renderers) 2019-11-12 19:12:57 +01:00
40a7e5a650 Compilation: Add -Wextra to compile arguments + Fix minor resulting warnings 2019-11-12 18:14:07 +01:00
d8f6981fe6 Gui: Only promt overwrite message of auto-naming tool when there are actual elements in the layer selector 2019-11-09 02:21:57 +01:00
4e38d8f452 LayerSelector: Add layer_selector_contains_elements() function 2019-11-09 02:18:53 +01:00
866d36873a Merge branch 'dev' into translations 2019-11-09 01:52:00 +01:00
74eb17b2dc Merge branch 'dev' 2019-11-09 01:50:37 +01:00
0304c0d08b Adapt Header bar to show title correctly 2019-11-03 21:07:56 +01:00
70ea6a8901 Merge branch 'master' into translations 2019-10-29 00:03:30 +01:00
529b49ee2e Fix coding style problems in bounding-box.c 2019-10-28 23:57:54 +01:00
6d31193123 Fix coding style in vector-operations.c 2019-10-28 23:55:22 +01:00
e7bf59aa8c Merge branch 'master' into translations 2019-10-28 22:44:06 +01:00
188c6f5d87 Fix style of gds-tree-checker 2019-10-28 22:43:28 +01:00
92e40cb8ca Fix PKGBuild 2019-10-28 21:50:03 +01:00
8f788e262f Merge branch 'dev' into translations 2019-10-25 21:20:16 +02:00
2e8e258b49 Style improvements 2019-10-25 21:16:31 +02:00
547b002e57 style fixes in layer-element.c 2019-10-25 20:54:11 +02:00
c7ce62673f Style fixes in conv settings dialog 2019-10-25 20:52:22 +02:00
dd488c3105 Further style mprovements 2019-10-25 20:45:25 +02:00
be0d58c54e Fix coding style in main.c 2019-10-25 20:36:54 +02:00
4a6b0dc879 Update translation for German 2019-10-25 20:30:08 +02:00
f7b2a331ec Add German translations for command line interface 2019-10-22 23:13:09 +02:00
e90cd1313d remove useless tab at end of line in script 2019-10-22 22:59:05 +02:00
0fbbc1db64 Update package build 2019-10-20 14:26:46 +02:00
8005e8bcc7 Adapt install routines to install locales 2019-10-20 14:04:39 +02:00
31a47339f8 Update translations 2019-10-18 23:25:27 +02:00
7753e42078 Add translation output to Cmake 2019-10-18 22:51:31 +02:00
b2ffc709bb Started first translation approach 2019-10-18 21:19:38 +02:00
b6c6262662 Add helper scripts for gettext 2019-10-18 20:34:03 +02:00
c70f99a283 Remove uneeded empty line in CMakeLists.txt 2019-10-18 20:32:58 +02:00
592dcbae53 Use translations folder in binary dir when debugging 2019-10-18 19:39:54 +02:00
f1102162b7 Add dirty warning to version Cmake 2019-10-18 19:39:23 +02:00
8bef6bcb17 First inits for translations 2019-10-18 19:29:55 +02:00
dc40dec212 Add colors to cmake output 2019-10-18 19:29:04 +02:00
56591fb675 Merge branch 'dev' of git.shimatta.de:mhu/gds-render into dev 2019-10-18 18:13:05 +02:00
7fdd1f6c92 Add tooltips to main window's buttons 2019-10-18 18:12:21 +02:00
1f914d1218 Add version dependent application id. Multiple versions of htis program can now run at the same time 2019-10-03 11:57:53 +02:00
13e202424b Text improvements 2019-10-03 11:57:16 +02:00
a48fe9ab58 Merge branch 'master' into dev 2019-09-28 23:29:22 +02:00
9bd225b837 Merge branch 'Issue-28-new-gui-features' into dev 2019-09-28 23:20:14 +02:00
00d6710922 Doxygen error fixes 2019-09-28 23:16:48 +02:00
67b8dc2443 Doxygen fix 2019-09-28 23:16:48 +02:00
6eaf86dc1c Fix doxygen configuartion to handle __attribute__ correctly 2019-09-28 23:16:48 +02:00
1de96f501c Checked renderers for memory leaks 2019-09-28 23:16:48 +02:00
01e61a79fd Integrate cell selector to main gui class 2019-09-28 23:16:48 +02:00
dc30950df5 Tree store for cell selection moved to GUI file 2019-09-28 23:16:48 +02:00
23775b079a Code improvements 2019-09-28 23:16:48 +02:00
a65295fbeb remove now unneeded mapping parser completely 2019-09-28 23:16:48 +02:00
9245d68da1 LayerSelector: Use Layer Settings for CSV export. This makes the mapping parser unnecessary. It can be removed 2019-09-28 23:16:48 +02:00
0a04f2fed4 LayerSettings: Fix bug in CSV export function 2019-09-28 23:16:48 +02:00
62388e4053 Remove code from mapping parser that implements csv read. Use LayerSettings class instead. 2019-09-28 23:16:48 +02:00
c365c89908 LayerSelector: Make import of layer information from CSV independed from mapping-parser code. Use LayerSettings class instead. 2019-09-28 23:16:48 +02:00
f20826ccf7 LayerSettings: Fix layer_settings_load_from_csv()
* Add stacked position to layer settings
* Check if layer_settings instance is valid
2019-09-28 23:16:48 +02:00
94ef879a94 Refactoring: rename progress update func of output renderer to gds_output_renderer_update_async_progress() 2019-09-28 23:16:48 +02:00
977547d91d Enable status upgrades from Cairo renderer to activity bar. 2019-09-28 23:16:48 +02:00
0dc91c14de Add project entry to libversion CMAKE 2019-09-28 23:16:48 +02:00
5ec7832ac4 Cairo Renderer: Add function that reads a line from a file descriptor (pipe) 2019-09-28 23:16:48 +02:00
52fb07bea6 Add warning for fallthrough to switch-case 2019-09-28 23:16:48 +02:00
eefe0df984 Remove warning about wrong bounding box calculation. Still wrong but the warning is annoying and problems are negligible. 2019-09-28 23:16:48 +02:00
e3e39a80ee Move compiler flags up in CMAKE, so they apply also for included subprojects 2019-09-28 23:16:48 +02:00
448de30b91 Doxygen fix 2019-09-28 23:01:12 +02:00
ec9a65cec5 Fix doxygen configuartion to handle __attribute__ correctly 2019-09-28 22:59:51 +02:00
7cbde0f30a Fixup round for doxygen 2019-09-28 22:57:31 +02:00
00d7691bda Code improvements 2019-09-28 20:46:41 +02:00
b8a02912b0 Merge branch 'master' into Issue-28-new-gui-features 2019-09-25 19:14:42 +02:00
e703d4427a Update image of GUI in documentation 2019-09-25 19:14:06 +02:00
f9e16fa4d7 Merge branch 'dev' into Issue-28-new-gui-features 2019-09-25 18:54:21 +02:00
1bf01a5cd2 Merge branch 'master' into dev 2019-09-25 18:50:03 +02:00
cd3ef452f1 Merge branch 'master' into Issue-28-new-gui-features 2019-09-25 18:49:38 +02:00
40edd21f0a Fix typo in application description 2019-09-25 18:47:28 +02:00
bcc8623382 remove now unneeded mapping parser completely 2019-09-25 18:25:12 +02:00
a9ccf6533d LayerSelector: Use Layer Settings for CSV export. This makes the mapping parser unnecessary. It can be removed 2019-09-25 18:21:02 +02:00
e16b7f9d25 LayerSettings: Fix bug in CSV export function 2019-09-25 18:20:03 +02:00
16b18fc5b3 Remove code from mapping parser that implements csv read. Use LayerSettings class instead. 2019-09-25 17:59:38 +02:00
941711129a LayerSelector: Make import of layer information from CSV independed from mapping-parser code. Use LayerSettings class instead. 2019-09-25 17:58:32 +02:00
d90c1b389e LayerSettings: Fix layer_settings_load_from_csv()
* Add stacked position to layer settings
* Check if layer_settings instance is valid
2019-09-25 17:54:26 +02:00
291ded0277 Refactoring: rename progress update func of output renderer to gds_output_renderer_update_async_progress() 2019-09-19 21:44:30 +02:00
5f6dbbed0e Enable status upgrades from Cairo renderer to activity bar. 2019-09-19 21:42:55 +02:00
8b1d3709b7 Add project entry to libversion CMAKE 2019-09-18 20:40:16 +02:00
4db8593e5b Cairo Renderer: Add function that reads a line from a file descriptor (pipe) 2019-09-18 20:39:42 +02:00
bea35bf952 Add warning for fallthrough to switch-case 2019-09-18 20:38:32 +02:00
ad5e0ebe11 Remove warning about wrong bounding box calculation. Still wrong but the warning is annoying and problems are negligible. 2019-09-18 20:37:51 +02:00
ee99e50656 Move compiler flags up in CMAKE, so they apply also for included subprojects 2019-09-18 20:36:50 +02:00
c016a5e96e Revert "Add benchmark for GDS-rendering. Will be removed later"
This reverts commit bd97ccf44f.
2019-09-15 13:28:40 +02:00
cfc156c1c0 Improve performance by prepending to list inststead of appending. O(n^2) -> O(1) 2019-09-15 13:28:05 +02:00
bd97ccf44f Add benchmark for GDS-rendering. Will be removed later 2019-09-15 13:11:38 +02:00
df7cc6d0fc Fix typo in name of function 2019-09-15 13:04:30 +02:00
8be5bd230b Fix #26: Implement callback function for auto naming button 2019-08-29 18:31:53 +02:00
3a72796b2f Fix docu for layer_selector_auto_color_layers 2019-08-29 18:20:19 +02:00
9f7e1e1696 Issue #26: Add layer_selector_auto_name_layers() function 2019-08-29 18:19:28 +02:00
27f5a5e3d2 Issue #26: Setup callback for auto naming button 2019-08-29 17:58:39 +02:00
ec72fb2aa1 Issue #26: Add auto naming button to gui 2019-08-29 17:52:49 +02:00
4968492eee Fix unnecessary space in string after newline 2019-08-29 17:49:23 +02:00
4d6d2e6734 Make C style checker submodule track its master branch by default 2019-08-26 21:07:16 +02:00
eba4238855 Update doxygen compilation instructions 2019-08-26 20:53:39 +02:00
7492764666 Enable XML output of doxygen 2019-08-26 20:40:54 +02:00
6c840b8bd1 Fixup doxygen groups and LaTeX symbol 2019-08-26 20:37:48 +02:00
3489b74027 Add warning about unused parameters to CMake config and fix code accordingly 2019-08-26 20:01:32 +02:00
f60150e8c7 Add full git commit to About dialog 2019-08-26 00:05:45 +02:00
91633edc78 Add docu for on_select_all_layers_clicked 2019-08-25 23:26:59 +02:00
1dc23afa9a implement callback for all layer select button. Fix issue #25 2019-08-25 23:24:24 +02:00
7fd8768fd0 Issue #25: Add layer_selector_select_all_layers() function 2019-08-25 23:21:45 +02:00
c77c08299f Issue #25: Add select all button to GUI and connect callback. 2019-08-25 22:11:36 +02:00
dc0520e9d3 Add additional uninitialized varibale warning to compile options 2019-08-25 21:56:21 +02:00
2af859b136 Fix bug of color palette not working properly, due to uninitialized variable 2019-08-25 21:52:22 +02:00
b102d90d33 Add old style wwarning to compile flags. Fix code accordingly 2019-08-25 21:51:44 +02:00
c5e697b366 Add quiatation marks to CMake file 2019-08-25 21:44:26 +02:00
ea27443b39 Fix #21: Rename layer-info files to layer-settings 2019-08-24 14:17:24 +02:00
5dbafcb8d5 Merge branch 'multithread-dev' into dev 2019-08-24 14:08:04 +02:00
7a0d61020b Merge branch 'master' into dev 2019-08-24 14:02:43 +02:00
74bdbe6d79 Update doxyfile and enable timestanp in Latex 2019-08-24 14:02:29 +02:00
8d57d63cf3 Update doxyfile and enable timestanp in Latex 2019-08-24 13:59:05 +02:00
a2bcda6752 Update doxygen 2019-08-24 13:50:55 +02:00
17af08b04d GdsOutputrenderer: progress-changed signal: Status message is now freed inside the GdsOutputRenderer.
This is safe because the signals are handled back to back inside the emit function. Therefore, it can be freed directly after emission. This solves the problem of the status message not being freed if no handler is connected to the signal.
2019-08-24 13:49:33 +02:00
8a3721dc53 Fix reference counting issue of the LayerSettings inside the
GdsOutputRenderer class.

The LayerSettings element is now disposed of properly.
2019-08-23 21:58:02 +02:00
94ac44ddc5 Set task name of rendering GTask 2019-08-23 21:50:16 +02:00
1cbacef56c Fix reference counting issue of the LayerSettings inside the
GdsOutputRenderer class.

The LayerSettings element is now disposed of properly.
2019-08-23 21:40:21 +02:00
cae6a9c6c3 LayerSettings: Fix memory leak: GList of layer infos was not freed. Add
dispose to LayerSettings which takes care of this task.
2019-08-23 21:38:59 +02:00
fe98499ce7 Enable Release build in PKGBUILD and also use this configuration in the compilation guide 2019-08-23 18:21:25 +02:00
d5dde3658d Enable Release build in PKGBUILD and also use this configuration in the compilation guide 2019-08-23 18:19:46 +02:00
b6bf0c30bf Fix uninitialized variable warning 2019-08-22 19:37:26 +02:00
c908a8be47 Fix bug in progress update from rendering thread which results in the creation of multipe idel callbacks at the same time. 2019-08-22 19:31:47 +02:00
7aa7a0c773 Fix unnecessary whitespace 2019-08-22 19:01:45 +02:00
a10c09c674 Add preliminary status upograde outputs to cairo and latex renderers 2019-08-22 18:56:18 +02:00
a0d19bee39 Add progress updated callback to gui to update titlebar 2019-08-22 18:55:56 +02:00
4115fd97af Add progress updated signal to gds output renderer that can be used when called asynchronously 2019-08-22 18:55:14 +02:00
32b8c4ccd3 Add simple multithreading support. Activity bar is not yet used for rendering status updates 2019-08-21 19:30:52 +02:00
1584769a51 fix deadlock in mutex usage 2019-08-21 19:30:19 +02:00
dc4b377b13 Add preliminary set_busy fuinction to activity bar 2019-08-21 19:29:22 +02:00
08722cd6f9 Add function in GUI to determine the current button states to prevent multiple triggers for rendering/reloading the library during rendering 2019-08-21 18:34:40 +02:00
4b238c55ea Replace 0 by 0.0 for double value comparison. This is nicer. 2019-08-20 22:42:44 +02:00
1b62427770 Merge branch 'multithread-dev' into dev
Current progess: Changed output renderers to GObjects derived from a base class. Furthermore, added base structure for future multithreading
2019-08-20 19:05:58 +02:00
85f037ce59 Fix #19: Renderers are now implemented as objects. Implementation of asynchronous functionality can begin. Feature needs further testing to be considered stable 2019-08-20 19:05:14 +02:00
92506485e0 Output renderer base class: Fix wrong assigned property name 2019-08-20 19:03:59 +02:00
3ec91ab322 Cairo Renderer: Fix bug introduced in 3ffd63115f due to the introduction of the LayerSettings class 2019-08-20 19:01:03 +02:00
92da653368 Merge branch 'dev' of git.shimatta.de:mhu/gds-render into dev 2019-08-20 18:14:32 +02:00
a38946b803 LayerSelector: Rewrite layer_selector_export_rendered_layer_info() to return LayerSettings object. 2019-08-20 18:12:40 +02:00
943e924337 gds-parser.h: Fix typo 2019-08-20 18:12:09 +02:00
e0f2e7d605 gds-parser.h: Fix psoition of ifdef guards compared to doxygen group 2019-08-20 18:11:38 +02:00
bd64e13d87 GUI: render callback: Remove unnecessary variable layer_list 2019-08-20 18:09:15 +02:00
0123385b40 Command line: Improve code style in function 2019-08-20 18:08:15 +02:00
a4f9be1ef4 Add async rendering option. Not yet functional 2019-08-19 20:39:25 +02:00
731e377b6e Implement new layer rendering object and add it to the CLI. 2019-08-19 19:54:53 +02:00
0d0b692960 Fix memory leak in color palette due to missing dispose function 2019-08-19 19:52:50 +02:00
c2323ab43d Fix typo 2019-08-19 19:51:40 +02:00
7fa769806a Merge branch 'master' into dev 2019-07-26 22:05:17 +02:00
17c9d088cc Merge branch 'master' into output-renderer-rework 2019-07-03 21:35:18 +02:00
5f40f148b6 Update doxygen: Windows compilation 2019-07-03 21:33:16 +02:00
86566a038f Update version information in Compilation doxygen site 2019-07-03 21:14:17 +02:00
4ca1f75813 Fix typo 2019-06-22 14:20:00 +02:00
4d2f3b0d70 Issue #19: Restructure code 2019-06-22 14:17:08 +02:00
ed37fc0222 Issue #19: Fix bug in Latex renderer 2019-06-22 14:16:51 +02:00
d4f14c52ed Issue #19: Replace g_errors because these errors are not fatal 2019-06-22 14:04:11 +02:00
58d3f5c57c Fix function prototype description for external renderer 2019-06-22 14:03:33 +02:00
2510a54aac Fix compiler warning about uninitialized variable 2019-06-22 01:28:58 +02:00
02a59c4cc5 Merge branch 'dev' into output-renderer-rework 2019-06-22 01:27:25 +02:00
40c4c8b4fb Fix compiler warning about uninitialized variable 2019-06-22 01:27:03 +02:00
01c9701492 Issue #19: Implement first draft of command line rendering (synchronous-mode). Not yet fully tested!! 2019-06-22 01:21:26 +02:00
01ab56e07a Issue #19: Remove unused variable from layer settings 2019-06-22 01:20:45 +02:00
3ffd63115f Issue #19: Add LayerSettings Class
* Remove Command line and GUI rendering code
* Add LayerSettings Class with all options
* Prepare to remove mapping parser. Is now integrated in LayerSettings
* Adopt all renderers to check if the supplied layer_info struct has to be rendered.

Further todos:
* Implement correct command line parsing.
* Implement Layerselector and GUI to use new LayerSettings class
2019-06-21 21:41:38 +02:00
31c4efe99b Update GUI image in doxygen documentation to show new button style 2019-06-19 20:57:07 +02:00
f5bc8de86e Issue #19: Edit usage site in doxygen because the command line parameters have severly changed 2019-06-19 20:50:12 +02:00
d107954859 Issue #19: Finish integration of renderers to into command line interface 2019-06-19 20:47:19 +02:00
5c994f892a Issue #19: Implement CairoRenderer as GObject 2019-06-19 19:21:20 +02:00
96f1347b2c Issue #19: rename renderer source files and implement latex renderer new functions 2019-06-19 19:01:40 +02:00
2d2ca67c48 Issue #19: Move LaTeX Renderer to GObject 2019-06-18 21:46:43 +02:00
d9282d8e5a Issue #19: Add dispose to ExternalRenderer class in order to free the path to the shared object 2019-06-18 21:46:02 +02:00
d5f1b2edf4 Issue #19: Implement external_renderer_new_with_so() 2019-06-18 21:10:53 +02:00
f224b28613 Issue #19: Add property shared-object-path to ExternalRenderer 2019-06-18 21:08:29 +02:00
7b10d41160 Issue #19: Convert external renderer to GObject. Not yet fully integrated 2019-06-18 19:43:00 +02:00
302d462cda Issue #19:
Create a base class GdsOutputRenderer with a virtual function render_output,
which can be derived by the different output renderers.
2019-06-17 22:59:27 +02:00
c146bcd094 Output renderers: Move existing renderers to common folder 2019-06-17 21:50:49 +02:00
e6abaddcd1 Cell selector: LibCellRenderer: Update doxygen 2019-06-17 21:40:41 +02:00
a35231b9ec Fix #20:
Move all cell selector specific code to a new folder "cell-selector".
2019-06-17 21:32:45 +02:00
24b70eec48 Merge branch 'master' into dev 2019-06-13 23:25:00 +02:00
8ffcba830d Fix #18: Segmentation fault due to a pointer pointing to already freed data. 2019-06-13 23:17:20 +02:00
022d9561db Remove temporary files of fot from doxygen output (DOT_CLEANUP) 2019-06-13 22:28:18 +02:00
f5f8509b91 Merge branch 'color-palette-feature' into dev 2019-06-13 22:25:54 +02:00
61f607ac94 Add autocoloring to layer selector. Auto coloring feature now fully implemented. Fix #14 2019-06-13 22:22:59 +02:00
ee1b55120f Gui: Add button callback for auto color button 2019-06-13 22:21:35 +02:00
b04788b7d4 Layer selector: Add prototype and empty function body for function that
fills all layers with colors from a given color palette.
2019-06-13 22:21:35 +02:00
3c05b50bc7 Gui: Add color palette object to gui. Will be used in button callback to
fill layer colors automatically.
2019-06-13 22:21:35 +02:00
dfadaa241e Color palette: Finish implementation
Color palette can now be loaded from a resource containing hexadecimal
RGB values.
2019-06-13 22:21:28 +02:00
4f02854401 Reclassify unhandled GDS records as information rather than a warning 2019-06-10 23:03:01 +02:00
f2b02c0c1f Code and spelling improvements 2019-06-10 23:00:05 +02:00
e739305f46 Gds Parser: Add support for array refrences (AREFs) 2019-06-10 22:59:18 +02:00
5729ef0db8 Doxygen: Change dot output to SVG 2019-06-09 14:17:52 +02:00
88cd834d13 Merge branch 'master' into dev
Incorporate urgent fixes
2019-06-08 13:33:16 +02:00
7f7b4cc7bf Fix #17: Reference loop detection fix. This will be part of v1.0-1 2019-06-08 13:32:42 +02:00
f625d2daba Reclassify unhandled GDS records as information rather than a warning 2019-06-08 12:53:57 +02:00
e42aa36520 Fix doxygen header in gds_parser.h 2019-06-08 12:43:42 +02:00
2ffa09d104 Code and spelling improvements 2019-06-08 12:43:01 +02:00
feb69b6d60 Gds Parser: Add support for array refrences (AREFs) 2019-06-08 12:41:15 +02:00
20ec6bd41b Fix doygen warning in Activity Bar 2019-06-08 12:37:29 +02:00
eef012fc4d Merge branch 'multithread-dev' into dev
Get newest changes in order to incorporate the fix for issue #16
2019-06-07 19:37:15 +02:00
e847e691bd Merge branch 'multithread-dev' into color-palette-feature
Get newest changes
2019-06-07 19:35:02 +02:00
0d6b2c7a36 Color palette: Cast unused function parameter 2019-06-07 19:33:53 +02:00
583f01faae Enhance formatting, fix typos 2019-06-07 19:32:38 +02:00
795d496949 GDS parser: Enhance doxygen headers 2019-06-07 19:30:37 +02:00
6ebd05007e Cairo Renderer: Fix Typos 2019-06-07 19:28:07 +02:00
906225f47f Fix Typos 2019-05-30 14:55:37 +02:00
dadafa43a3 Work around issue #16. This is not very beatiful. 2019-05-30 14:49:35 +02:00
2d3241d8b7 cairo-renderer: check for valid pointers of crs and surfaces 2019-05-30 14:45:36 +02:00
0ecc60d2a1 Fix Typo 2019-05-28 21:03:56 +02:00
9b0f268bbd Add ActivityBar widget 2019-05-28 20:59:16 +02:00
6ae316f459 Edit color palette code 2019-05-28 20:05:13 +02:00
082a823575 Add space for activity bar 2019-05-28 20:02:56 +02:00
1f7f3118fa Start development of color-palette class 2019-05-20 20:07:45 +02:00
5cfd93c18d Add color palette to resources, create gui, data and images groups for resources 2019-05-20 19:18:01 +02:00
6818357f64 Rename glade directory to more generic resource directory 2019-05-20 19:04:56 +02:00
b0fdb261e0 Remove text from auto-color button. A simple symbol is enough. 2019-05-19 16:54:49 +02:00
de8d6967c6 Update button images 2019-05-17 17:47:23 +02:00
493f787fd1 Doxygen: Tab width 4 -> 8, fixes #15 2019-05-17 17:36:42 +02:00
a7b7ba71e5 Add auto-color button to GUI 2019-05-15 20:46:13 +02:00
d08cd3626d Update Usage page and application screenshot 2019-05-14 19:59:43 +02:00
ef180f3ea2 Add version generation script to doxygen generation script 2019-05-14 19:58:52 +02:00
74ecde9807 Revert "gds-parser: Remove unnecessary code. Fix #13"
Code wasn't unnecessary. Oops.

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

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

With this commit Issue #8 is fixed.
2019-03-13 21:01:49 +01:00
1e6d0bd1b9 Restructured code for layer selector 2019-03-13 20:32:09 +01:00
658e681c38 Implement a more convenient drag and drop 2019-03-13 20:22:11 +01:00
e24b4a8367 implement layer sorting buttons, This fixes #5 2019-03-12 19:47:39 +01:00
960a773ed1 Implement fucntion to force sort of the layer selector 2019-03-12 19:39:36 +01:00
ab23be1cfc Make enum in sorting function const 2019-03-12 19:28:17 +01:00
72d5352b09 Change sorting function in order to add capability to sort both ways 2019-03-12 19:26:31 +01:00
3f198f870a Add buttons for layer sorting to glade file 2019-03-12 19:10:43 +01:00
2a204640bd Add warning to probably misunderstandable function 2019-03-12 19:02:34 +01:00
a237a89ecf Feature: Double click on cells now also opens the convert settings menu. Same callback as for the convert button is used. 2019-03-11 23:33:51 +01:00
1ec0f9b297 Merge branch 'master' of git.shimatta.de:mhu/gds-render 2019-03-11 10:38:35 +01:00
2f2eb90b69 Add automatic version numbering to command line and GUI 2019-03-11 10:36:02 +01:00
bbf08a4d6e style fix, convert dialog size preview in SI units 2019-03-08 20:46:48 +01:00
34a19fa11d Fix style in external renderer 2019-03-07 20:35:23 +01:00
b4ae8eee37 fix style issues in main-window.c 2019-03-07 20:32:55 +01:00
6e1b7d3f61 Update style checker to new version 2019-03-07 20:26:03 +01:00
d1e6e7b05a fix style issues in main.c 2019-03-07 20:14:44 +01:00
187ae2a74b Add style checker as submodule 2019-03-07 20:00:54 +01:00
eeae61ad47 Check cells before displaying them and color the cells accordingly. Fixes #4 2019-03-06 20:07:26 +01:00
3146ca801f Add functions for checking cell reference loops 2019-03-06 20:06:01 +01:00
43fdab4533 Improve GDS parser 2019-03-06 20:04:49 +01:00
59835018af Edit colors 2019-03-06 19:58:26 +01:00
d81c6d1037 Make gds-parser more robust 2019-03-06 18:16:14 +01:00
ba53a1151e Add cell recursion cehck to command line interface 2019-03-06 18:15:50 +01:00
fdf2c9a42b fix style issue 2019-03-06 18:15:11 +01:00
34c113517b Fox doxygen file header 2019-03-06 18:14:53 +01:00
5291b682c7 remove braces around scale to prevent doxygen from interpreting this as HTML tag 2019-03-06 17:38:47 +01:00
e76f2cbb9d Merge branch 'master' into dev 2019-03-05 21:48:26 +01:00
586339cac1 fix doxygen 2019-03-05 21:46:29 +01:00
3882f3944e Change selction filter function. Now only cells without major errors are selectable. Warnings are okay because the renderers can handle these (unresolved references etc...) 2019-03-05 21:03:27 +01:00
00b47d7ded Add lib cell renderer to main window. It is needed for the Error level defines of the cells 2019-03-05 20:55:04 +01:00
e9b67fe1bc Implement error level indicator for cells 2019-03-05 20:52:00 +01:00
976bdd9854 Fix function description 2019-03-05 20:21:49 +01:00
73e4806e65 Implenment child cell resolve checker 2019-03-05 20:14:07 +01:00
0b17c25ecc Add defualt value for check results 2019-03-05 20:08:10 +01:00
0ef6d2f40f update trigonometric library doxygen 2019-03-05 19:50:01 +01:00
58bb74b905 Add checks to cell structure 2019-03-05 19:48:03 +01:00
cd9030a24e Create GDS Tree checking functions. Renamed doxygen section of GDS Parser to GDS-Utilities so the cheking function fit into this section 2019-03-05 19:38:07 +01:00
546332a9c2 Merge branch 'dev' 2019-03-04 20:20:15 +01:00
68e7d52cd8 Changed settings dialog api to use database units. Implement render output size preview 2019-03-04 20:14:21 +01:00
91a3e8f983 Fix style 2019-03-04 19:35:25 +01:00
f74e2d5cf5 Fix bug 2019-03-04 19:35:04 +01:00
8ffb1d42b6 Fix bug of wrong bounding box calculation: Replace DBL_MIN with -DBL_MAX 2019-02-28 21:21:00 +01:00
845da756b7 Fix bug of wrong bounding box calculation: Replace DBL_MIN with -DBL_MAX 2019-02-28 21:17:54 +01:00
531634b55a Fix bug in bounding box 2d translation 2019-02-27 21:42:54 +01:00
2e1cf456c7 Add pointer to parent library to cells, implement first draft of cell size/shape preview 2019-02-27 21:33:12 +01:00
bce47f11fc Fix formatting 2019-02-27 20:28:53 +01:00
5573ceb46b Fix formatting in GDS-Parser 2019-02-27 20:28:06 +01:00
7124c9a5cc Add fallthrough mark, correct Typo 2019-02-27 20:27:01 +01:00
d5997ab5f2 Merge branch 'master' into dev 2019-02-22 20:04:27 +01:00
e692129477 fix minor code style stuff 2019-02-22 19:54:08 +01:00
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
b6ea48ba47 Merge branch 'master' of git.shimatta.de:mhu/gds-render 2018-08-24 16:15:42 +02:00
cf7e4ccad0 trigonometric operations added 2018-08-24 16:15:36 +02:00
1a6fdf59ab edit error handling 2018-08-01 12:42:41 +02:00
299d65aa6c cairo ouput svg modifications. Still doesn't work. Only for integer coordinates (scaling 1) it seems to work 2018-08-01 12:36:31 +02:00
54d5148c9d update doxygen 2018-07-30 12:44:37 +02:00
6a01d67594 Add cairo SVG export. However, cairo is buggy so it is on hold for the time being 2018-07-30 12:35:30 +02:00
01367af99c vector operations added 2018-07-28 10:37:00 +02:00
f04418376c add overwrite confirmation to file dialogs 2018-07-28 10:01:02 +02:00
74783f312a bounding box functions added 2018-07-27 21:08:45 +02:00
d4517aa493 add trigonometric sub library, add function to calculate bounding box of polygon 2018-07-27 21:00:30 +02:00
13676deb34 doxygen documentation, add image of GUI 2018-07-26 15:03:06 +02:00
f204d4c2e8 Fix bug in LaTeX renderer 2018-07-26 15:02:44 +02:00
7047315892 Describe layer mapping file 2018-07-26 14:44:52 +02:00
a56bec272b Doxygen documentation 2018-07-25 16:44:04 +02:00
8f9531d63f fix absolute paths in Doxygen documentation 2018-07-25 12:31:18 +02:00
5aaa4d85b8 fix PKGBUILD 2018-07-25 11:25:58 +02:00
6f9b23301e Add PKGBUILD to build Pacman package 2018-07-25 11:19:15 +02:00
7c47d7207f add preliminary icon, configure icon in widgets 2018-07-25 10:50:22 +02:00
c502b65297 Doxygen Header created 2018-07-24 18:47:29 +02:00
5526e403a3 Disable prints in GDS renderer. Wrote documentation 2018-07-24 17:45:16 +02:00
5c3b299eb0 minor fixes and doxygen Documentation started 2018-07-24 14:42:28 +02:00
6f7feb7aa9 Add doxygen 2018-07-24 10:21:55 +02:00
13aa2c8609 fix typo 2018-07-23 21:16:01 +02:00
942df1d971 fix typo 2018-07-23 21:14:35 +02:00
bb13993e34 Command line interface finished 2018-07-23 21:12:25 +02:00
b25f147707 command line progress 2018-07-23 20:17:18 +02:00
c60afedd6c start command line interface 2018-07-23 17:00:37 +02:00
a5d794461a Add license 2018-07-23 15:26:51 +02:00
6fb4d39fc8 Add application menu and about dialog 2018-07-23 15:10:40 +02:00
d0e1383861 reconstructed code to use g_application 2018-07-23 13:10:34 +02:00
6296627ac2 Merge branch 'master' of git.shimatta.de:mhu/gds-render 2018-07-23 09:59:26 +02:00
f79bab102b Remove Bounding box calculations from parser. They're not needed 2018-07-23 09:58:14 +02:00
e5300e60aa Color of Load layer mapping button changed to blue 2018-07-22 16:55:20 +02:00
4c5784c3a4 finished first version of Cairo export 2018-07-22 16:38:26 +02:00
f765e27ce8 fix rendering of box in cairo renderer 2018-07-20 23:29:27 +02:00
40760725b8 Merge branch 'master' into cairo-dev 2018-07-20 23:26:50 +02:00
dac834aef2 auto detect glade files 2018-07-20 23:22:47 +02:00
d4f2d6798e Merge branch 'master' into cairo-dev 2018-07-20 22:41:16 +02:00
f8cbf7e066 use enum name instead of pure integer value 2018-07-20 22:36:54 +02:00
59ec0c5a10 cairo layer renderer 2018-07-20 22:32:23 +02:00
2a615367d7 Add advanced export settings for LaTeX export 2018-07-19 22:09:58 +02:00
3167da4648 cairo output started 2018-07-19 18:45:37 +02:00
b72466957c Added variable scaling factor for Tex output 2018-07-19 17:54:05 +02:00
d9f0f3cdd5 settings dialog fully implemented 2018-07-19 17:49:33 +02:00
4c04ce3614 further implementation of settings dialog 2018-07-19 16:38:52 +02:00
a2bc980c64 dialog implementation 2018-07-19 15:47:57 +02:00
73ea4d6838 re-organized folder structure 2018-07-19 15:11:18 +02:00
526785cffd add dialog to compile resources 2018-07-19 15:07:20 +02:00
6a8b359f3d add dialog for conversion options 2018-07-19 15:05:44 +02:00
bbd731401d add support for boxes 2018-07-17 00:02:30 +02:00
7734467ea9 Use cairo for path bounding box 2018-07-11 12:24:15 +02:00
7d66ca1280 Support for magnification, bounding boxes fully implemented 2018-07-04 21:46:39 +02:00
542737622f smaller fixes, started boundary box scanner. Rotation, scaling and flipping is not handled correctly yet 2018-07-04 09:49:04 +02:00
101 changed files with 13663 additions and 1488 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

4
.gitmodules vendored Normal file
View File

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

40
AUR/PKGBUILD Normal file
View File

@@ -0,0 +1,40 @@
# Maintainer: Mario Hüttel <mario (dot) huettel (!) gmx (dot) net>
pkgname=gds-render
pkgver=20191020.403.448de30
pkgrel=1
pkgdesc="Conversion tool for converting GDS layout files into TikZ Code and PDF"
arch=('i686' 'x86_64')
url="https://git.shimatta.de/mhu/gds-render"
licence=('GPLv2')
depends=('glib2' 'gtk3' 'cairo')
makedepends=('cmake' 'git')
privides=('gds-render')
source=("${pkgname}-git"::"git+https://git.shimatta.de/mhu/gds-render.git")
sha1sums=('SKIP')
pkgver () {
_date=`date +"%Y%m%d"`
cd "${srcdir}/${pkgname}-git"
echo "$_date.$(git rev-list --count master).$(git rev-parse --short master)"
}
build () {
mkdir "$srcdir/$pkgname-git/build"
cd "$srcdir/$pkgname-git/build"
cmake -DCMAKE_BUILD_TYPE=Release ..
make
}
package () {
cd "$srcdir/$pkgname-git/build"
make DESTDIR="${pkgdir}" install
install -D -m664 "$srcdir/$pkgname-git/AUR/gds-render.desktop" \
"$pkgdir/usr/share/applications/gds-render.desktop"
install -D -m664 "$srcdir/$pkgname-git/icon/gds-render.svg" \
"$pkgdir/usr/share/icons/hicolor/scalable/apps/gds-render.svg"
install -D -m664 "$srcdir/$pkgname-git/icon/128x128/gds-render.png" \
"$pkgdir/usr/share/icons/hicolor/128x128/apps/gds-render.png"
(cd $srcdir/$pkgname-git/build/translations/output/ && tar cf - "locale" | (cd "$pkgdir/usr/share/" && tar xf -))
}

9
AUR/gds-render.desktop Normal file
View File

@@ -0,0 +1,9 @@
[Desktop Entry]
Version=1.0
Type=Application
Name=GDS-Render
Comment=Converter for GDS layout files
Icon=gds-render
Exec=gds-render
Categories=Graphics

View File

@@ -1,36 +1,88 @@
project(gds-render)
if(CMAKE_INSTALL_PREFIX_INITIALIZED_TO_DEFAULT)
set(CMAKE_INSTALL_PREFIX "/usr/" CACHE PATH "..." FORCE)
endif()
if(NOT WIN32)
string(ASCII 27 Esc)
set(ColorReset "${Esc}[m")
set(ColorBold "${Esc}[1m")
set(Red "${Esc}[31m")
set(Green "${Esc}[32m")
set(Yellow "${Esc}[33m")
set(Blue "${Esc}[34m")
set(Magenta "${Esc}[35m")
set(Cyan "${Esc}[36m")
set(White "${Esc}[37m")
set(BoldRed "${Esc}[1;31m")
set(BoldGreen "${Esc}[1;32m")
set(BoldYellow "${Esc}[1;33m")
set(BoldBlue "${Esc}[1;34m")
set(BoldMagenta "${Esc}[1;35m")
set(BoldCyan "${Esc}[1;36m")
set(BoldWhite "${Esc}[1;37m")
endif()
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)
include_directories(${GLIB_INCLUDE_DIRS} ${GTK3_INCLUDE_DIRS} ${CAIRO_INCLUDE_DIRS} ${CMAKE_CURRENT_SOURCE_DIR}/include)
add_subdirectory(plugins)
add_subdirectory(glade)
add_compile_options(-Wall -Wextra -Wold-style-declaration -Wuninitialized -Wmaybe-uninitialized -Wunused-parameter)
include_directories(${GLIB_INCLUDE_DIRS} ${GTK3_INCLUDE_DIRS})
link_directories(${GLIB_LINK_DIRS} ${GTK3_LINK_DIRS})
IF(CMAKE_BUILD_TYPE STREQUAL "Debug")
message("${Yellow}Debug mode for translations used!${ColorReset}")
add_definitions(-DGETTEXT_PACKAGE=\"gds-render\" -DLOCALEDATADIR=\"${CMAKE_CURRENT_BINARY_DIR}/translations/output\")
message("${BoldMagenta}${CMAKE_CURRENT_BINARY_DIR}/translations/output used as data dir${ColorReset}")
else(CMAKE_BUILD_TYPE STREQUAL "Debug")
message("Global locale directory used. Make sure files in /usr/share/locale are available")
add_definitions(-DGETTEXT_PACKAGE=\"gds-render\" -DLOCALEDATADIR=\"/usr/share\")
ENDIF(CMAKE_BUILD_TYPE STREQUAL "Debug")
add_subdirectory(resources)
add_subdirectory(doxygen)
add_subdirectory(translations)
add_subdirectory(version)
link_directories(${GLIB_LINK_DIRS} ${GTK3_LINK_DIRS} ${CAIRO_LINK_DIRS})
add_definitions(${GLIB2_CFLAGS_OTHER})
aux_source_directory("layer-widget" LAYER_SOURCES)
aux_source_directory("tree-renderer" RENDERER_SOURCES)
aux_source_directory("gds-parser" PARSER_SOURCES)
aux_source_directory("latex-output" LATEX_SOURCES)
set(SOURCE "main.c" "layer-selector.c")
aux_source_directory("widgets" LAYER_SOURCES)
aux_source_directory("cell-selector" CELL_SELECTOR_SOURCES)
aux_source_directory("gds-utils" GDS_SOURCES)
aux_source_directory("output-renderers" OUTPUT_RENDERER_SOURCES)
aux_source_directory("geometric" GEOMETRIC_SOURCES)
aux_source_directory("layer" LAYER_SELECTOR_SOURCES)
set(SOURCE "main.c" "command-line.c" "gds-render-gui.c")
set(SOURCE
${SOURCE}
${LAYER_SOURCES}
${RENDERER_SOURCES}
${PARSER_SOURCES}
${LATEX_SOURCES}
${CELL_SELECTOR_SOURCES}
${GDS_SOURCES}
${OUTPUT_RENDERER_SOURCES}
${GEOMETRIC_SOURCES}
${LAYER_SELECTOR_SOURCES}
)
add_compile_options(-Wall)
set(SOURCE_GENERATED
${CMAKE_CURRENT_BINARY_DIR}/resources/resources.c
)
add_executable(${PROJECT_NAME} ${SOURCE} ${CMAKE_CURRENT_BINARY_DIR}/glade/resources.c)
SET_SOURCE_FILES_PROPERTIES(${SOURCE_GENERATED} PROPERTIES GENERATED 1)
add_executable(${PROJECT_NAME} ${SOURCE} ${SOURCE_GENERATED})
add_dependencies(${PROJECT_NAME} glib-resources)
SET_SOURCE_FILES_PROPERTIES(${CMAKE_CURRENT_BINARY_DIR}/glade/resources.c PROPERTIES GENERATED 1)
target_link_libraries(${PROJECT_NAME} ${GLIB_LDFLAGS} ${GTK3_LDFLAGS} m)
add_dependencies(${PROJECT_NAME} version)
add_dependencies(${PROJECT_NAME} translations)
target_link_libraries(${PROJECT_NAME} ${GLIB_LDFLAGS} ${GTK3_LDFLAGS} ${CAIRO_LDFLAGS} m version ${CMAKE_DL_LIBS})
install (TARGETS ${PROJECT_NAME}
RUNTIME
DESTINATION bin
)

21
README.MD Normal file
View File

@@ -0,0 +1,21 @@
# GDS-Render Readme
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

@@ -17,19 +17,32 @@
* along with GDSII-Converter. If not, see <http://www.gnu.org/licenses/>.
*/
#include "lib-cell-renderer.h"
#include "../gds-parser/gds-types.h"
/**
* @file lib-cell-renderer.c
* @brief LibCellRenderer GObject Class
* @author Mario Hüttel <mario.huettel@gmx.net>
*/
/**
* @addtogroup LibCellRenderer
* @{
*/
#include <gds-render/cell-selector/lib-cell-renderer.h>
#include <gds-render/gds-utils/gds-types.h>
G_DEFINE_TYPE(LibCellRenderer, lib_cell_renderer, GTK_TYPE_CELL_RENDERER_TEXT)
enum {
PROP_LIB = 1,
PROP_CELL,
PROP_COUNT
PROP_LIB = 1, /**< @brief Library to display the name of */
PROP_CELL, /**< @brief Cell to display the name of */
PROP_ERROR_LEVEL, /**< @brief Error level of cell/library for coloring */
PROP_COUNT /**< @brief Sentinel */
};
void lib_cell_renderer_init(LibCellRenderer *self)
{
(void)self;
/* Nothing to do */
}
@@ -38,24 +51,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;
@@ -67,6 +112,8 @@ static void lib_cell_renderer_get_property(GObject *object,
GValue *value,
GParamSpec *pspec)
{
(void)value;
switch (param_id) {
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID(object, param_id, pspec);
@@ -74,11 +121,12 @@ static void lib_cell_renderer_get_property(GObject *object,
}
}
static GParamSpec *properties [PROP_COUNT];
static GParamSpec *properties[PROP_COUNT];
void lib_cell_renderer_class_init(LibCellRendererClass *klass)
{
GObjectClass *oclass = G_OBJECT_CLASS(klass);
oclass->constructed = lib_cell_renderer_constructed;
oclass->set_property = lib_cell_renderer_set_property;
oclass->get_property = lib_cell_renderer_get_property;
@@ -89,6 +137,8 @@ void lib_cell_renderer_class_init(LibCellRendererClass *klass)
properties[PROP_CELL] = g_param_spec_pointer("gds-cell", "gds-cell",
"Cell reference to be displayed",
G_PARAM_WRITABLE);
properties[PROP_ERROR_LEVEL] = g_param_spec_uint("error-level", "error-level",
"Error level of this cell", 0, 255, 0, G_PARAM_WRITABLE);
g_object_class_install_properties(oclass, PROP_COUNT, properties);
}
@@ -97,3 +147,5 @@ GtkCellRenderer *lib_cell_renderer_new()
{
return GTK_CELL_RENDERER(g_object_new(TYPE_LIB_CELL_RENDERER, NULL));
}
/** @} */

237
command-line.c Normal file
View File

@@ -0,0 +1,237 @@
/*
* 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 command-line.c
* @brief Function to render according to command line parameters
* @author Mario Hüttel <mario.huettel@gmx.net>
*/
/**
* @addtogroup cmdline
* @{
*/
#include <stdio.h>
#include <glib/gi18n.h>
#include <gds-render/command-line.h>
#include <gds-render/gds-utils/gds-parser.h>
#include <gds-render/layer/layer-settings.h>
#include <gds-render/output-renderers/cairo-renderer.h>
#include <gds-render/output-renderers/latex-renderer.h>
#include <gds-render/output-renderers/external-renderer.h>
#include <gds-render/gds-utils/gds-tree-checker.h>
static int string_array_count(char **string_array)
{
int count;
if (!string_array)
return 0;
for (count = 0; *string_array; string_array++)
count++;
return count;
}
static int create_renderers(char **renderers,
char **output_file_names,
gboolean tex_layers,
gboolean tex_standalone,
const struct external_renderer_params *ext_params,
GList **renderer_list,
LayerSettings *layer_settings)
{
char **renderer_iter;
char *current_renderer;
int idx;
char *current_out_file;
int count_render, count_out;
GdsOutputRenderer *output_renderer;
if (!renderer_list)
return -1;
if (!renderers || !output_file_names) {
fprintf(stderr, _("Please specify renderers and file names\n"));
return -1;
}
count_render = string_array_count(renderers);
count_out = string_array_count(output_file_names);
if (count_render != count_out) {
fprintf(stderr, _("Count of renderers %d does not match count of output file names %d\n"),
count_render, count_out);
return -1;
}
/* Parse cmd line parameters */
for (renderer_iter = renderers, idx = 0; *renderer_iter; renderer_iter++, idx++) {
current_renderer = *renderer_iter;
current_out_file = output_file_names[idx];
/* File valid ? */
if (!current_out_file || !current_out_file[0])
continue;
if (!strcmp(current_renderer, "tikz")) {
output_renderer = GDS_RENDER_OUTPUT_RENDERER(latex_renderer_new_with_options(tex_layers,
tex_standalone));
} else if (!strcmp(current_renderer, "pdf")) {
output_renderer = GDS_RENDER_OUTPUT_RENDERER(cairo_renderer_new_pdf());
} else if (!strcmp(current_renderer, "svg")) {
output_renderer = GDS_RENDER_OUTPUT_RENDERER(cairo_renderer_new_svg());
} else if (!strcmp(current_renderer, "ext")) {
if (!ext_params->so_path) {
fprintf(stderr, _("Please specify shared object for external renderer. Will ignore this renderer.\n"));
continue;
}
output_renderer = GDS_RENDER_OUTPUT_RENDERER(
external_renderer_new_with_so_and_param(ext_params->so_path,
ext_params->cli_params));
} else {
continue;
}
gds_output_renderer_set_output_file(output_renderer, current_out_file);
gds_output_renderer_set_layer_settings(output_renderer, layer_settings);
*renderer_list = g_list_append(*renderer_list, output_renderer);
}
return 0;
}
static struct gds_cell *find_gds_cell_in_lib(struct gds_library *lib, const char *cell_name)
{
GList *cell_list;
struct gds_cell *return_cell = NULL;
struct gds_cell *temp_cell;
for (cell_list = lib->cells; cell_list; cell_list = g_list_next(cell_list)) {
temp_cell = (struct gds_cell *)cell_list->data;
if (!strncmp(temp_cell->name, cell_name, CELL_NAME_MAX)) {
return_cell = temp_cell;
break;
}
}
return return_cell;
}
int command_line_convert_gds(const char *gds_name,
const char *cell_name,
char **renderers,
char **output_file_names,
const char *layer_file,
struct external_renderer_params *ext_param,
gboolean tex_standalone,
gboolean tex_layers,
double scale)
{
int ret = -1;
GList *libs = NULL;
int res;
GList *renderer_list = NULL;
GList *list_iter;
struct gds_library *first_lib;
struct gds_cell *toplevel_cell = NULL;
LayerSettings *layer_sett;
GdsOutputRenderer *current_renderer;
/* Check if parameters are valid */
if (!gds_name || !cell_name || !output_file_names || !layer_file || !renderers) {
printf(_("Probably missing argument. Check --help option\n"));
return -2;
}
/* Load layer_settings */
layer_sett = layer_settings_new();
layer_settings_load_from_csv(layer_sett, layer_file);
/* Create renderers */
if (create_renderers(renderers, output_file_names, tex_layers, tex_standalone,
ext_param, &renderer_list, layer_sett))
goto ret_destroy_layer_mapping;
/* Load GDS */
clear_lib_list(&libs);
res = parse_gds_from_file(gds_name, &libs);
if (res)
goto ret_destroy_library_list;
/* find_cell in first library. */
if (!libs)
goto ret_clear_renderers;
first_lib = (struct gds_library *)libs->data;
if (!first_lib) {
fprintf(stderr, _("No library in library list. This should not happen.\n"));
/* This is safe. Library destruction can handle an empty list element */
goto ret_destroy_library_list;
}
/* Find cell in first library */
toplevel_cell = find_gds_cell_in_lib(first_lib, cell_name);
if (!toplevel_cell) {
printf(_("Couldn't find cell in first library!\n"));
goto ret_destroy_library_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_destroy_library_list;
} else if (res > 0) {
fprintf(stderr, _("%d reference loops found.\n"), res);
/* do further checking if the specified cell and/or its subcells are affected */
if (toplevel_cell->checks.affected_by_reference_loop == 1) {
fprintf(stderr, _("Cell is affected by reference loop. Abort!\n"));
goto ret_destroy_library_list;
}
}
if (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.
*/
/* Execute all rendererer instances */
for (list_iter = renderer_list; list_iter; list_iter = list_iter->next) {
current_renderer = GDS_RENDER_OUTPUT_RENDERER(list_iter->data);
gds_output_renderer_render_output(current_renderer, toplevel_cell, scale);
}
ret_destroy_library_list:
clear_lib_list(&libs);
ret_clear_renderers:
for (list_iter = renderer_list; list_iter; list_iter = list_iter->next)
g_object_unref(list_iter->data);
ret_destroy_layer_mapping:
g_object_unref(layer_sett);
return ret;
}
/** @} */

19
doxygen/CMakeLists.txt Normal file
View File

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

2537
doxygen/Doxyconfig Normal file

File diff suppressed because it is too large Load Diff

6
doxygen/activity-bar.dox Normal file
View File

@@ -0,0 +1,6 @@
/**
* @defgroup ActivityBar Activity Bar
* @ingroup Widgets
*
* Activity Status Bar
*/

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=`../version/generate-version-string.sh`
if [ $# != 1 ]; then
export OUTPUT_DIRECTORY="./output"
else
export OUTPUT_DIRECTORY="$1"
fi
doxygen Doxyconfig

View File

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

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

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

88
doxygen/compilation.dox Normal file
View File

@@ -0,0 +1,88 @@
/**
@page compilation Compilation
@section Preface
GDS-Render is designed for UNIX-like, especially GNU/Linux based systems.
It was developed under a Linux system. Therefore, best performance is expected using a Linux operating system.
@section depencencies Dependencies
The dependencies of GDS-Render are:
@subsection run-deps Program Dependencies
- GLib2
- GTK3
- Cairographics
@subsection comp-deps Compilation Dependencies
These dependencies are not needed for running the program; just for compilation.
- Build System (GCC + binutils, make, etc...). Most distributions supply a "development" meta-package containing this stuff.
- cmake >= 2.8
- More or less optional: git. Used for extraction of the precise version number. It is strongly recommended to provide git!
- Optional: doxygen for this nice documentation.
The dependency list of GTK3 already includes Cairographics and GLib2. You should be on the safe side with a recent GTK3 version.
Development is done with the following library versions:
| Cairographics | GLib2 | GTK3 |
| ------------- | ---------- | --------- |
| 1.17.3 | 2.60.6-1 | 3.24.10-1 |
@section comp-instr Compilation Instructions
@subsection linux-build General Linux Build Instruction
Go to the build directory you want to compile in. This may be the gds-render project root.
Execute
@code
cmake -DCMAKE_BUILD_TYPE=Release <Path to gds-render root>
@endcode
for a build in release configuartion. Use `-DCMAKE_BUILD_TYPE=Debug` for debugging. Cmake will check the dependencies.
Once cmake has finished, type
@code
make
@endcode
to build the program and
@code
make documentation
@endcode
to build the doxygen documentation.
@subsection arch-makepkg Archlinux Package
The subfolder 'AUR' contains a PKGBUILD file to build an Archlinux/Pacman package.
@subsection comp-warnings Compiler Warnings
The compiler will throw the following warnings. Compiled with GCC 8.2.1.
| Warning | Assessment |
| ------- | ---------- |
| warning: calculate_path_miter_points defined but not used [-Wunused-function] | Ignore. Function will be used in later versions. |
@subsection windows-compilation Compilation for Windows
@warning Windows is not a target system for this application, considering that this program converts GDS files which are most likely generated under a Linux system. The tips shown in this section are a guidance for anyone trying to build this application for Windows.
@warning Note that the Windows compatibility may decrease in future releases and a simple compilation like with this version might not be possible anymore.
The current release of 'gds-render' does not compile under a windows system, due to incompatibilities in the external library renderer.
It is possible to comment out the code that causes the incompatibility. The external renderer will not be usable after this.
Steps:
- Go to file external-renderer.c
- Remove `#include` <dlfcn.h>
- comment out all code in #external_renderer_render_cell
The program should now compile.
@warning This guide is out of date. The Cairo renderer doesn't compile under windows anymore due to the usage of the fork() system call. It is possible to patch this out in order to restore Windows compatibility.
*/

View File

@@ -0,0 +1,26 @@
/**
* @defgroup ExternalRenderer External Shared Object Renderer
* @ingroup GdsOutputRenderer
*
* @section ExternalRendererProps Properties
* This class inherits all properties from its parent @ref GdsOutputRenderer.
* In addition to that, it implements the following properties:
*
* Property Name | Description
* -----------------|----------------------------------------------------------------
* shared-object-path | Path to the shared object used for rendering
* param-string | Command line parameters passed to external renderer's init function
*
* All these properties have to be set for rendering.
*
* @section ExternalRendererFuncs Necessary Functions
*
* The following functions and variables are necessary for an external renderer to implement:
*
* Code Define | Prototype | Description
* ---------------------------------------------|-----------------------------------------------------------------------------------------------------------------------------------------------|-----------------------------------------------------------------------------------------------------------------------------------
* @ref EXTERNAL_LIBRARY_RENDER_FUNCTION | int EXTERNAL_LIBRARY_RENDER_FUNCTION(struct gds_cell *toplevel, GList *layer_info_list, const char *output_file_name, double scale) | Render cell to output file
* @ref EXTERNAL_LIBRARY_INIT_FUNCTION | int EXTERNAL_LIBRARY_INIT_FUNCTION(const char *option_string, const char *version_string) | Init function. Executed before rendering. This is given the command line parameters specified for the external renderer and the version string of the currently running gds-render program.
* @ref EXTERNAL_LIBRARY_FORK_REQUEST | int EXTERNAL_LIBRARY_FORK_REQUEST; | The pure presence of this integer results in the execution inside a subprocess of hte whole shared object's code
*
*/

View File

@@ -0,0 +1,34 @@
/**
* @defgroup GdsOutputRenderer GDS Output Renderer base class
*
* The renderers are used to convert the cell structures read from the GDS layout file
* into different output formats.
*
* The GdsOutputRenderer base class is used to derive all renderers from.
*
* @warning Although the GdsOutputRenderer class provides compatibility for asynchronous rendering,
* the class is not thread safe / re-entrant. Only use it from a signle context. Not even the rendering function called is allowed to modifiy this object.
*
* A allowed function to be called from the async rendering thread is #gds_output_renderer_update_async_progress and the get functions for the properties.
*
* @note The context that owned the renderer has to ensure that only one rendering is active at a time for a single instance of a renderer.
*
* By default this class implements the following features:
*
* @section GdsOutputRendererProps Properties
* Property Name | Description
* -----------------|----------------------------------------------------------------
* layer-settings | LayerSettings object containing the layer rendering information
* output-file | Output file name for rendering
*
* All these properties have to be set for rendering.
*
* @section GdsOutputRendererSignals Signals / Events
* Signal Name | Description | Callback prototype
* -----------------|-------------------------------------------------|-----------------------------------------------------------
* async-finished | The asynchronous rendering is finished | void callback(GdsOutputRenderer *src, gpointer user_data)
* progress-changed | The asynchronous rendering progress changed | void callback(GdsOutputRenderer *src, const char *progress, gpointer user_data)
*
* @note The `char *progress` supplied to the callback function must not be modified or freed.
*
*/

8
doxygen/geometric.dox Normal file
View File

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

5
doxygen/gui.dox Normal file
View File

@@ -0,0 +1,5 @@
/* This file only contains help information for doxygen */
/**
* @defgroup GUI Graphical User Interface
*/

BIN
doxygen/images/gui.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 33 KiB

View File

@@ -0,0 +1,16 @@
/**
* @defgroup LaTeX-Renderer LaTeX / TikZ Renderer
* @ingroup GdsOutputRenderer
*
* This is the class implementing the \f$\mbox{\LaTeX}\f$ / TikZ output rendering
* @section LaTeXRendererProps Properties
* This class inherits all properties from its parent @ref GdsOutputRenderer.
* In addition to that, it implements the following properties:
*
* Property Name | Description
* -----------------|----------------------------------------------------------------
* standalone | Configure output LaTeX document to be standalone compilable (requires standalone documentclass)
* pdf-layers | Create OCG layers in LaTeX output
*
*/

View File

@@ -0,0 +1,7 @@
/**
* @defgroup layer-selector LayerSelector Object
* @ingroup GUI
*
* This objects implements the layer selector and displays the layers in a list box.
* It uses @ref LayerElement objects to display the individual layers inside the list box.
*/

View File

@@ -0,0 +1,18 @@
/**
* @defgroup LibCellRenderer LibCellRenderer GObject
* @ingroup GUI
*
* The LibCellRenderer Object is used to render @ref gds_cell and @ref gds_library elements
* to a GtkTreeView.
*
* The LibCellRenderer class is derived from a GtkCellRendererText and works the same way.
* The additinal features are three new properties:
*
* - *gds-lib*: This property can be used to set a @ref gds_library structure. The renderer will render the name of the library.
* - *gds-cell*: This property can be used to set a @ref gds_cell structure. The renderer will render the name of the cell.
* - *error-level*: Set the error level of the cell/library. This affects the foreground color of hte rendered output.
*
* Internally the class operates by setting the 'text' property, which is inherited form the base class to the library/cell name (gds_library::name and gds_cell::name fields).
* The error level (@ref LIB_CELL_RENDERER_ERROR_WARN and @ref LIB_CELL_RENDERER_ERROR_ERR) is translated to the inherited 'foreground-rgba' property.
*
*/

34
doxygen/lmf-spec.dox Normal file
View File

@@ -0,0 +1,34 @@
/**
@page lmf-spec Layer Mapping File Specification
File Format
-----------
The layer mapping file contains information on how to render the layers.
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:
> layer,r,g,b,a,export,name
- **layer**: Layer number identifiying this layer.
- **r**,**b**,**g**,**a**: RGBA color value uning double precision float values in the range from 0 to 1.
- **export**: Either '1' or '0'. Defining whether to render this layer into the output file.
- **name**: The name of the layer.
the order of the layers inside the layer mapping file defines the layer stack in the rendered output.
The first layer is at the bottom, the last at the top.
Handling Inside the GUI
-----------------------
The layer mapping file can be imported and exported inside the GUI.
### Export
During export, all layer configurations are written to the mapping file
### Import
During import, all layer configurations are loaded from the mapping file. This overwrites any configuration done to that layer. Layers that are not present in the layer mapping file are appended at the end of the list. This means, they are rendered on top of the other layers. Because the layer mapping file does not contain any information on these layers, their configuration is not reset during import.
*/

23
doxygen/main-page.dox Normal file
View File

@@ -0,0 +1,23 @@
/**
@mainpage
This programm converts GDS layout files to
- PDF Files using the @ref Cairo-Renderer
- Latex code (TikZ) using the @ref LaTeX-Renderer
See the @subpage usage page for details and @subpage compilation for building instructions and @subpage versioning for the versioning scheme of this program.
*/

3
doxygen/output/.gitignore vendored Normal file
View File

@@ -0,0 +1,3 @@
*
*/
!.gitignore

6
doxygen/plugins.dox Normal file
View File

@@ -0,0 +1,6 @@
/**
* @defgroup plugins External Renderer Plugins
*
* These plugins can be loaded with the @ref ExternalRenderer
*
*/

40
doxygen/usage.dox Normal file
View File

@@ -0,0 +1,40 @@
/**
@page usage Usage
@section cmd Command Line Interface
To use the application on the command line check 'gds-render `--`help'.
Usage:
gds-render [OPTION…] FILE - Convert GDS file `<FILE>` to graphic
Help Options:
-h, `--`help Show help options
`--`help-all Show all help options
`--`help-gtk Show GTK+ Options
Application Options:
-v, `--`version Print version
-r, `--`renderer=pdf|svg|tikz|ext Renderer to use
-s, `--`scale=`<SCALE>` Divide output coordinates by `<SCALE>`
-o, `--`output-file=PATH Output file path
-m, `--`mapping=PATH Path for Layer Mapping File
-c, `--`cell=NAME Cell to render
-a, `--`tex-standalone Create standalone PDF
-l, `--`tex-layers Create PDF Layers (OCG)
-P, `--`custom-render-lib=PATH Path to a custom shared object, that implements the render_cell_to_file function
`--`display=DISPLAY X display to use
@section gui Graphical User Interface
The graphical user interface (GUI) can be used to open GDS Files, configure the layer rendering (colors, order, transparency etc.), and convert cells.
It is possible to export the layer configurations so they can be used later on. Even in the @ref cmd
@image html gui.png
@image latex gui.png
The cell selector on the left shows the GDS Libraries and Cells. The cells are marked green if all references inside the cell could be found. If not all references could be found, the cell is marked orange. This doens't show if child cells have missing childs. Only one level of the hierarchy is checked in order to make it easier to spot an errorneous cell. Cells with missing child cells are still renderable but `--` obviously `--` faulty. If a cell or any sub-cell contains a reference loop, the cell is marked red. In this case it can't be selected for rendering.
In the above image one cell is green; so everything is okay. And the other one is red, which indicates a reference loop. This cell cannot be selected for rendering!
*/

36
doxygen/versioning.dox Normal file
View File

@@ -0,0 +1,36 @@
/**
@page versioning Version Number
@section main-version Main Versioning Scheme
The version number of this application consists of a given version in the format of 'v1.0'.
Where the first number indicates a major release and the second number indicates minor changes.
Versions, including release candidates and path-levels, are tagged in git.
@subsection rc Release Candidates
Release candidates are software versions that seem stable and functional to become a new version but testing is not fully finished. These versions are marked with an '-rcX', where X is the number of the release candidate.
The 3rd release candidate of version 4.2 would be '*v4.2-rc3*'.
Release candidates are in a frozen state. Only bugfixes that are necessary for functionality are applied to these versions before releasing the final version.
@subsection patch-level Patch Levels
If an already released version contains bugs that need to be fixed, the version number is not incremented. Insted a new version number with a patch-level is created. The patch-level is appended with a dash directly after the version number. The fist patch-level of version 3.5 would be: 'v3.5-1'.
@section git-version-num Git Based Version Number
The application and this documentation contain a git-based version number. With this version number not only released versions but all development points of the software can be uniquely identified.
An example for such a version number is: *v1.0-rc4-41-gaa41373-dirty*
It consists of the last @ref main-version (in this case version 1.0 -- Release candidate 4) and some other information from the source code management system. The number after the version tag is the commit count after the given version. In this case the specified version is 41 commits after the last tagged version 'v1.0-rc4'. The next section always starts with a 'g' (for git) and after that contains the first letters of the commit ID. In this case an additional '-dirty' is appended, showing that the software version contains unstaged changes.
In tabular form: *v1.0-rc4-41-gaa41373-dirty*
| Last tagged version | Commits since that version | Start of commit ID | Unstaged changes? |
|---------------------|----------------------------|--------------------|---------------------|
| 1.0-rc4 | 41 | aa41373 | yes |
This git-based version number is automatically put into the application and this documentation during the application's compilation / the documentation's generation. For this *git* is needed. Therefore, it is highly recommended to have 'git' installed for compilation although it is no build dependency. In case of a missing git installation, the string "! version not set !" is compiled into the application.
**/

6
doxygen/widgets.dox Normal file
View File

@@ -0,0 +1,6 @@
/* This file only contains help information for doxygen */
/**
* @defgroup Widgets Custom GTK Widgets
* @ingroup GUI
*/

View File

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

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

@@ -0,0 +1,838 @@
/*
* GDSII-Converter
* Copyright (C) 2018 Mario Hüttel <mario.huettel@gmx.net>
*
* This file is part of GDSII-Converter.
*
* GDSII-Converter is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*
* GDSII-Converter is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with GDSII-Converter. If not, see <http://www.gnu.org/licenses/>.
*/
/**
* @file gds-render-gui.c
* @brief Handling of GUI
* @author Mario Hüttel <mario.huettel@gmx.net>
*/
/** @addtogroup GUI
* @{
*/
#include <stdio.h>
#include <gtk/gtk.h>
#include <glib/gi18n.h>
#include <gds-render/gds-render-gui.h>
#include <gds-render/gds-utils/gds-parser.h>
#include <gds-render/gds-utils/gds-tree-checker.h>
#include <gds-render/layer/layer-selector.h>
#include <gds-render/widgets/activity-bar.h>
#include <gds-render/cell-selector/lib-cell-renderer.h>
#include <gds-render/output-renderers/latex-renderer.h>
#include <gds-render/output-renderers/cairo-renderer.h>
#include <gds-render/widgets/conv-settings-dialog.h>
#include <gds-render/geometric/cell-geometrics.h>
#include <gds-render/version.h>
/** @brief Columns of selection tree view */
enum cell_store_columns {
CELL_SEL_LIBRARY = 0,
CELL_SEL_CELL,
CELL_SEL_CELL_ERROR_STATE, /**< Used for cell color and selectability */
CELL_SEL_COLUMN_COUNT /**< @brief Not a column. Used to determine count of columns */
};
enum gds_render_gui_signal_sig_ids {SIGNAL_WINDOW_CLOSED = 0, SIGNAL_COUNT};
static guint gds_render_gui_signals[SIGNAL_COUNT];
struct gui_button_states {
gboolean rendering_active;
gboolean valid_cell_selected;
};
struct _GdsRenderGui {
/* Parent GObject */
GObject parent;
/* Custom fields */
GtkWindow *main_window;
GtkWidget *convert_button;
GtkWidget *open_button;
GtkWidget *load_layer_button;
GtkWidget *save_layer_button;
GtkWidget *select_all_button;
GtkTreeStore *cell_tree_store;
GtkTreeModelFilter *cell_filter;
GtkWidget *cell_search_entry;
LayerSelector *layer_selector;
GtkTreeView *cell_tree_view;
GList *gds_libraries;
ActivityBar *activity_status_bar;
struct render_settings render_dialog_settings;
ColorPalette *palette;
struct gui_button_states button_state_data;
};
G_DEFINE_TYPE(GdsRenderGui, gds_render_gui, G_TYPE_OBJECT)
/**
* @brief Main window close event
* @param window GtkWindow which is closed
* @param event unused event
* @param user GdsRenderGui instance
* @return Status of the event handling. Always true.
*/
static gboolean on_window_close(gpointer window, GdkEvent *event, gpointer user)
{
GdsRenderGui *self;
(void)event;
self = RENDERER_GUI(user);
/* Don't close window in case of error */
if (!self)
return TRUE;
/* Close Window. Leads to termination of the program/the current instance */
g_clear_object(&self->main_window);
gtk_widget_destroy(GTK_WIDGET(window));
/* Delete loaded library data */
clear_lib_list(&self->gds_libraries);
g_signal_emit(self, gds_render_gui_signals[SIGNAL_WINDOW_CLOSED], 0);
return TRUE;
}
/**
* @brief This function only allows valid cells to be selected
* @param selection
* @param model
* @param path
* @param path_currently_selected
* @param data
* @return TRUE if element is selectable, FALSE if not
*/
static gboolean tree_sel_func(GtkTreeSelection *selection,
GtkTreeModel *model,
GtkTreePath *path,
gboolean path_currently_selected,
gpointer data)
{
GtkTreeIter iter;
struct gds_cell *cell;
unsigned int error_level;
gboolean ret = FALSE;
(void)selection;
(void)path_currently_selected;
(void)data;
gtk_tree_model_get_iter(model, &iter, path);
gtk_tree_model_get(model, &iter, CELL_SEL_CELL, &cell, CELL_SEL_CELL_ERROR_STATE, &error_level, -1);
/* 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 Trigger refiltering of cell filter
* @param entry Unused widget, that emitted the signal
* @param data GdsrenderGui self instance
*/
static void cell_tree_view_change_filter(GtkWidget *entry, gpointer data)
{
GdsRenderGui *self = RENDERER_GUI(data);
(void)entry;
gtk_tree_model_filter_refilter(self->cell_filter);
}
/**
* @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)
{
GdsRenderGui *self;
struct gds_cell *cell;
struct gds_library *lib;
gboolean result = FALSE;
const char *search_string;
self = RENDERER_GUI(data);
g_return_val_if_fail(RENDERER_IS_GUI(self), FALSE);
if (!model || !iter)
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(GTK_ENTRY(self->cell_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(self->cell_tree_view);
exit_filter:
return result;
}
/**
* @brief Setup a GtkTreeView with the necessary columns
* @param self Current GUI object
*/
int gds_render_gui_setup_cell_selector(GdsRenderGui *self)
{
GtkCellRenderer *render_cell;
GtkCellRenderer *render_lib;
GtkTreeViewColumn *column;
self->cell_tree_store = gtk_tree_store_new(CELL_SEL_COLUMN_COUNT, G_TYPE_POINTER,
G_TYPE_POINTER, G_TYPE_UINT);
/* Searching */
self->cell_filter = GTK_TREE_MODEL_FILTER(
gtk_tree_model_filter_new(GTK_TREE_MODEL(self->cell_tree_store), NULL));
gtk_tree_model_filter_set_visible_func(self->cell_filter,
(GtkTreeModelFilterVisibleFunc)cell_store_filter_visible_func,
self, NULL);
g_signal_connect(GTK_SEARCH_ENTRY(self->cell_search_entry), "search-changed",
G_CALLBACK(cell_tree_view_change_filter), self);
gtk_tree_view_set_model(self->cell_tree_view, GTK_TREE_MODEL(self->cell_filter));
render_cell = lib_cell_renderer_new();
render_lib = lib_cell_renderer_new();
column = gtk_tree_view_column_new_with_attributes(_("Library"), render_lib, "gds-lib", CELL_SEL_LIBRARY, NULL);
gtk_tree_view_append_column(self->cell_tree_view, column);
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(self->cell_tree_view, column);
/* Callback for selection
* This prevents selecting a library
*/
gtk_tree_selection_set_select_function(gtk_tree_view_get_selection(self->cell_tree_view),
tree_sel_func, NULL, NULL);
return 0;
}
/**
* @brief Callback function of Load GDS button
* @param button
* @param user GdsRenderGui instance
*/
static void on_load_gds(gpointer button, gpointer user)
{
GList *cell;
GtkTreeIter libiter;
GtkTreeIter celliter;
GList *lib;
struct gds_library *gds_lib;
struct gds_cell *gds_c;
GdsRenderGui *self;
GtkWidget *open_dialog;
GtkFileChooser *file_chooser;
GtkFileFilter *filter;
GtkStyleContext *button_style;
gint dialog_result;
int gds_result;
char *filename;
unsigned int cell_error_level;
self = RENDERER_GUI(user);
if (!self)
return;
open_dialog = gtk_file_chooser_dialog_new(_("Open GDSII File"), self->main_window,
GTK_FILE_CHOOSER_ACTION_OPEN,
_("Cancel"), GTK_RESPONSE_CANCEL,
_("Open GDSII"), GTK_RESPONSE_ACCEPT,
NULL);
file_chooser = GTK_FILE_CHOOSER(open_dialog);
/* Add GDS II Filter */
filter = gtk_file_filter_new();
gtk_file_filter_add_pattern(filter, "*.gds");
gtk_file_filter_set_name(filter, _("GDSII-Files"));
gtk_file_chooser_add_filter(file_chooser, filter);
dialog_result = gtk_dialog_run(GTK_DIALOG(open_dialog));
if (dialog_result != GTK_RESPONSE_ACCEPT)
goto end_destroy;
/* Get File name */
filename = gtk_file_chooser_get_filename(file_chooser);
gtk_tree_store_clear(self->cell_tree_store);
clear_lib_list(&self->gds_libraries);
/* Parse new GDSII file */
gds_result = parse_gds_from_file(filename, &self->gds_libraries);
/* Delete file name afterwards */
g_free(filename);
if (gds_result)
goto end_destroy;
/* remove suggested action from Open button */
button_style = gtk_widget_get_style_context(GTK_WIDGET(button));
gtk_style_context_remove_class(button_style, "suggested-action");
for (lib = self->gds_libraries; lib != NULL; lib = lib->next) {
gds_lib = (struct gds_library *)lib->data;
/* Create top level iter */
gtk_tree_store_append(self->cell_tree_store, &libiter, NULL);
gtk_tree_store_set(self->cell_tree_store, &libiter,
CELL_SEL_LIBRARY, gds_lib,
-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);
for (cell = gds_lib->cells; cell != NULL; cell = cell->next) {
gds_c = (struct gds_cell *)cell->data;
gtk_tree_store_append(self->cell_tree_store, &celliter, &libiter);
/* Get the checking results for this cell */
cell_error_level = 0;
if (gds_c->checks.unresolved_child_count)
cell_error_level |= LIB_CELL_RENDERER_ERROR_WARN;
/* Check if it is completely b0rken */
if (gds_c->checks.affected_by_reference_loop)
cell_error_level |= LIB_CELL_RENDERER_ERROR_ERR;
/* Add cell to tree store model */
gtk_tree_store_set(self->cell_tree_store, &celliter,
CELL_SEL_CELL, gds_c,
CELL_SEL_CELL_ERROR_STATE, cell_error_level,
CELL_SEL_LIBRARY, gds_c->parent_library,
-1);
} /* for cells */
} /* for libraries */
/* Create Layers in Layer Box */
layer_selector_generate_layer_widgets(self->layer_selector, self->gds_libraries);
end_destroy:
/* Destroy dialog and filter */
gtk_widget_destroy(open_dialog);
}
static void process_button_state_changes(GdsRenderGui *self)
{
gboolean convert_button_state = FALSE;
gboolean open_gds_button_state = FALSE;
/* Calculate states */
if (!self->button_state_data.rendering_active) {
open_gds_button_state = TRUE;
if (self->button_state_data.valid_cell_selected)
convert_button_state = TRUE;
}
/* Apply states */
gtk_widget_set_sensitive(self->convert_button, convert_button_state);
gtk_widget_set_sensitive(self->open_button, open_gds_button_state);
}
/**
* @brief Callback for auto coloring button
* @param button
* @param user
*/
static void on_auto_color_clicked(gpointer button, gpointer user)
{
GdsRenderGui *self;
(void)button;
self = RENDERER_GUI(user);
layer_selector_auto_color_layers(self->layer_selector, self->palette, 1.0);
}
static void async_rendering_finished_callback(GdsOutputRenderer *renderer, gpointer gui)
{
GdsRenderGui *self;
self = RENDERER_GUI(gui);
self->button_state_data.rendering_active = FALSE;
process_button_state_changes(self);
activity_bar_set_ready(self->activity_status_bar);
g_object_unref(renderer);
}
static void async_rendering_status_update_callback(GdsOutputRenderer *renderer,
const char *status_message,
gpointer data)
{
GdsRenderGui *gui;
(void)renderer;
gui = RENDERER_GUI(data);
activity_bar_set_busy(gui->activity_status_bar, status_message);
}
/**
* @brief Convert button callback
* @param button
* @param user
*/
static void on_convert_clicked(gpointer button, gpointer user)
{
(void)button;
GdsRenderGui *self;
GtkTreeSelection *selection;
GtkTreeIter iter;
GtkTreeModel *model;
struct gds_cell *cell_to_render;
GtkWidget *dialog;
RendererSettingsDialog *settings;
GtkFileFilter *filter;
gint res;
char *file_name;
union bounding_box cell_box;
unsigned int height, width;
struct render_settings *sett;
LayerSettings *layer_settings;
GdsOutputRenderer *render_engine;
self = RENDERER_GUI(user);
if (!self)
return;
/* Abort if rendering is already active */
if (self->button_state_data.rendering_active == TRUE)
return;
sett = &self->render_dialog_settings;
/* Get selected cell */
selection = gtk_tree_view_get_selection(self->cell_tree_view);
if (gtk_tree_selection_get_selected(selection, &model, &iter) == FALSE)
return;
gtk_tree_model_get(model, &iter, CELL_SEL_CELL, &cell_to_render, -1);
if (!cell_to_render)
return;
/* Get layers that are rendered */
layer_settings = layer_selector_export_rendered_layer_info(self->layer_selector);
/* Calculate cell size in DB units */
bounding_box_prepare_empty(&cell_box);
calculate_cell_bounding_box(&cell_box, cell_to_render);
/* Calculate size in database units
* Note that the results are bound to be positive,
* so casting them to unsigned int is absolutely valid
*/
height = (unsigned int)(cell_box.vectors.upper_right.y - cell_box.vectors.lower_left.y);
width = (unsigned int)(cell_box.vectors.upper_right.x - cell_box.vectors.lower_left.x);
/* Show settings dialog */
settings = renderer_settings_dialog_new(GTK_WINDOW(self->main_window));
renderer_settings_dialog_set_settings(settings, sett);
renderer_settings_dialog_set_database_unit_scale(settings, cell_to_render->parent_library->unit_in_meters);
renderer_settings_dialog_set_cell_height(settings, height);
renderer_settings_dialog_set_cell_width(settings, width);
g_object_set(G_OBJECT(settings), "cell-name", cell_to_render->name, NULL);
res = gtk_dialog_run(GTK_DIALOG(settings));
if (res == GTK_RESPONSE_OK) {
renderer_settings_dialog_get_settings(settings, sett);
gtk_widget_destroy(GTK_WIDGET(settings));
} else {
gtk_widget_destroy(GTK_WIDGET(settings));
goto ret_layer_destroy;
}
/* save file dialog */
dialog = gtk_file_chooser_dialog_new((sett->renderer == RENDERER_LATEX_TIKZ
? "Save LaTeX File" : "Save PDF"),
GTK_WINDOW(self->main_window), GTK_FILE_CHOOSER_ACTION_SAVE,
"Cancel", GTK_RESPONSE_CANCEL, "Save", GTK_RESPONSE_ACCEPT, NULL);
/* Set file filter according to settings */
filter = gtk_file_filter_new();
switch (sett->renderer) {
case RENDERER_LATEX_TIKZ:
gtk_file_filter_add_pattern(filter, "*.tex");
gtk_file_filter_set_name(filter, "LaTeX-Files");
break;
case RENDERER_CAIROGRAPHICS_PDF:
gtk_file_filter_add_pattern(filter, "*.pdf");
gtk_file_filter_set_name(filter, "PDF-Files");
break;
case RENDERER_CAIROGRAPHICS_SVG:
gtk_file_filter_add_pattern(filter, "*.svg");
gtk_file_filter_set_name(filter, "SVG-Files");
break;
}
gtk_file_chooser_add_filter(GTK_FILE_CHOOSER(dialog), filter);
gtk_file_chooser_set_do_overwrite_confirmation(GTK_FILE_CHOOSER(dialog), TRUE);
res = gtk_dialog_run(GTK_DIALOG(dialog));
if (res == GTK_RESPONSE_ACCEPT) {
file_name = gtk_file_chooser_get_filename(GTK_FILE_CHOOSER(dialog));
gtk_widget_destroy(dialog);
switch (sett->renderer) {
case RENDERER_LATEX_TIKZ:
render_engine =
GDS_RENDER_OUTPUT_RENDERER(latex_renderer_new_with_options(sett->tex_pdf_layers,
sett->tex_standalone));
break;
case RENDERER_CAIROGRAPHICS_SVG:
render_engine = GDS_RENDER_OUTPUT_RENDERER(cairo_renderer_new_svg());
break;
case RENDERER_CAIROGRAPHICS_PDF:
render_engine = GDS_RENDER_OUTPUT_RENDERER(cairo_renderer_new_pdf());
break;
default:
/* Abort rendering */
render_engine = NULL;
break;
}
if (render_engine) {
gds_output_renderer_set_output_file(render_engine, file_name);
gds_output_renderer_set_layer_settings(render_engine, layer_settings);
/* Prevent user from overwriting library or triggering additional conversion */
self->button_state_data.rendering_active = TRUE;
process_button_state_changes(self);
g_signal_connect(render_engine, "async-finished", G_CALLBACK(async_rendering_finished_callback),
self);
activity_bar_set_busy(self->activity_status_bar, _("Rendering cell..."));
g_signal_connect(render_engine, "progress-changed",
G_CALLBACK(async_rendering_status_update_callback), self);
gds_output_renderer_render_output_async(render_engine, cell_to_render, sett->scale);
}
g_free(file_name);
} else {
gtk_widget_destroy(dialog);
}
ret_layer_destroy:
g_object_unref(layer_settings);
}
/**
* @brief cell_tree_view_activated Callback for 'double click' on cell selector element
* @param tree_view The tree view the event occured in
* @param path path to the selected row
* @param column The clicked column
* @param user pointer to GdsRenderGui object
*/
static void cell_tree_view_activated(gpointer tree_view, GtkTreePath *path,
GtkTreeViewColumn *column, gpointer user)
{
(void)tree_view;
(void)path;
(void)column;
on_convert_clicked(NULL, user);
}
/**
* @brief Callback for cell-selection change event
*
* This function activates/deactivates the convert button depending on whether
* a cell is selected for conversion or not
* @param sel
* @param self
*/
static void cell_selection_changed(GtkTreeSelection *sel, GdsRenderGui *self)
{
GtkTreeModel *model = NULL;
GtkTreeIter iter;
if (gtk_tree_selection_get_selected(sel, &model, &iter)) {
/* Node selected. Show button */
self->button_state_data.valid_cell_selected = TRUE;
} else {
self->button_state_data.valid_cell_selected = FALSE;
}
process_button_state_changes(self);
}
static void sort_up_callback(GtkWidget *widget, gpointer user)
{
(void)widget;
GdsRenderGui *self;
self = RENDERER_GUI(user);
if (!self)
return;
layer_selector_force_sort(self->layer_selector, LAYER_SELECTOR_SORT_UP);
}
static void sort_down_callback(GtkWidget *widget, gpointer user)
{
(void)widget;
GdsRenderGui *self;
self = RENDERER_GUI(user);
if (!self)
return;
layer_selector_force_sort(self->layer_selector, LAYER_SELECTOR_SORT_DOWN);
}
static void gds_render_gui_dispose(GObject *gobject)
{
GdsRenderGui *self;
self = RENDERER_GUI(gobject);
clear_lib_list(&self->gds_libraries);
g_clear_object(&self->cell_tree_view);
g_clear_object(&self->convert_button);
g_clear_object(&self->layer_selector);
g_clear_object(&self->cell_tree_store);
g_clear_object(&self->cell_filter);
g_clear_object(&self->cell_search_entry);
g_clear_object(&self->activity_status_bar);
g_clear_object(&self->palette);
g_clear_object(&self->load_layer_button);
g_clear_object(&self->save_layer_button);
g_clear_object(&self->open_button);
g_clear_object(&self->select_all_button);
if (self->main_window) {
g_signal_handlers_destroy(self->main_window);
gtk_widget_destroy(GTK_WIDGET(self->main_window));
self->main_window = NULL;
}
/* Chain up */
G_OBJECT_CLASS(gds_render_gui_parent_class)->dispose(gobject);
}
static void gds_render_gui_class_init(GdsRenderGuiClass *klass)
{
GObjectClass *gobject_class = G_OBJECT_CLASS(klass);
gds_render_gui_signals[SIGNAL_WINDOW_CLOSED] =
g_signal_newv("window-closed", RENDERER_TYPE_GUI,
G_SIGNAL_RUN_LAST | G_SIGNAL_NO_RECURSE,
NULL,
NULL,
NULL,
NULL,
G_TYPE_NONE,
0,
NULL);
gobject_class->dispose = gds_render_gui_dispose;
}
/**
* @brief Callback for the 'select all layers'-button
* @param button Button that triggered the event
* @param user_data the GdsrenderGui object containing the main-window the button is placed in
*/
static void on_select_all_layers_clicked(GtkWidget *button, gpointer user_data)
{
GdsRenderGui *gui;
(void)button;
gui = RENDERER_GUI(user_data);
layer_selector_select_all_layers(gui->layer_selector, TRUE);
}
static void auto_naming_clicked(GtkWidget *button, gpointer user_data)
{
GdsRenderGui *gui;
GtkDialog *dialog;
gboolean overwrite;
int dialog_result;
(void)button;
gui = RENDERER_GUI(user_data);
/* Don't do anything if the selector is empty. */
if (!layer_selector_contains_elements(gui->layer_selector))
return;
/* Ask for overwrite */
dialog = GTK_DIALOG(gtk_message_dialog_new(gui->main_window, GTK_DIALOG_USE_HEADER_BAR, GTK_MESSAGE_QUESTION,
GTK_BUTTONS_YES_NO, "Overwrite existing layer names?"));
dialog_result = gtk_dialog_run(dialog);
switch (dialog_result) {
case GTK_RESPONSE_YES:
overwrite = TRUE;
break;
case GTK_RESPONSE_NO: /* Expected fallthrough */
default:
overwrite = FALSE;
break;
}
gtk_widget_destroy(GTK_WIDGET(dialog));
layer_selector_auto_name_layers(gui->layer_selector, overwrite);
}
GtkWindow *gds_render_gui_get_main_window(GdsRenderGui *gui)
{
return gui->main_window;
}
static void gds_render_gui_init(GdsRenderGui *self)
{
GtkBuilder *main_builder;
GtkWidget *listbox;
GtkHeaderBar *header_bar;
GtkWidget *sort_up_button;
GtkWidget *sort_down_button;
GtkWidget *activity_bar_box;
GtkWidget *auto_color_button;
GtkWidget *auto_naming_button;
main_builder = gtk_builder_new_from_resource("/gui/main.glade");
self->cell_tree_view = GTK_TREE_VIEW(gtk_builder_get_object(main_builder, "cell-tree"));
self->cell_search_entry = GTK_WIDGET(gtk_builder_get_object(main_builder, "cell-search"));
gds_render_gui_setup_cell_selector(self);
self->main_window = GTK_WINDOW(gtk_builder_get_object(main_builder, "main-window"));
self->open_button = GTK_WIDGET(gtk_builder_get_object(main_builder, "button-load-gds"));
g_signal_connect(self->open_button,
"clicked", G_CALLBACK(on_load_gds), (gpointer)self);
self->convert_button = GTK_WIDGET(gtk_builder_get_object(main_builder, "convert-button"));
g_signal_connect(self->convert_button, "clicked", G_CALLBACK(on_convert_clicked), (gpointer)self);
listbox = GTK_WIDGET(gtk_builder_get_object(main_builder, "layer-list"));
/* Create layer selector */
self->layer_selector = layer_selector_new(GTK_LIST_BOX(listbox));
activity_bar_box = GTK_WIDGET(gtk_builder_get_object(main_builder, "activity-bar"));
/* Callback for selection change of cell selector */
g_signal_connect(G_OBJECT(gtk_tree_view_get_selection(self->cell_tree_view)), "changed",
G_CALLBACK(cell_selection_changed), self);
g_signal_connect(self->cell_tree_view, "row-activated", G_CALLBACK(cell_tree_view_activated), self);
/* Set version in main window subtitle */
header_bar = GTK_HEADER_BAR(gtk_builder_get_object(main_builder, "header-bar"));
gtk_header_bar_set_subtitle(header_bar, _app_version_string);
/* Get layer sorting buttons and set callbacks */
sort_up_button = GTK_WIDGET(gtk_builder_get_object(main_builder, "button-up-sort"));
sort_down_button = GTK_WIDGET(gtk_builder_get_object(main_builder, "button-down-sort"));
g_signal_connect(sort_up_button, "clicked", G_CALLBACK(sort_up_callback), self);
g_signal_connect(sort_down_button, "clicked", G_CALLBACK(sort_down_callback), self);
/* Set buttons for loading and saving */
self->load_layer_button = GTK_WIDGET(gtk_builder_get_object(main_builder, "button-load-mapping"));
self->save_layer_button = GTK_WIDGET(gtk_builder_get_object(main_builder, "button-save-mapping"));
layer_selector_set_load_mapping_button(self->layer_selector, self->load_layer_button, self->main_window);
layer_selector_set_save_mapping_button(self->layer_selector, self->save_layer_button, self->main_window);
/* Connect delete-event */
g_signal_connect(GTK_WIDGET(self->main_window), "delete-event",
G_CALLBACK(on_window_close), self);
/* Create and apply ActivityBar */
self->activity_status_bar = activity_bar_new();
gtk_container_add(GTK_CONTAINER(activity_bar_box), GTK_WIDGET(self->activity_status_bar));
gtk_widget_show(GTK_WIDGET(self->activity_status_bar));
/* Create color palette */
self->palette = color_palette_new_from_resource("/data/color-palette.txt");
auto_color_button = GTK_WIDGET(gtk_builder_get_object(main_builder, "auto-color-button"));
g_signal_connect(auto_color_button, "clicked", G_CALLBACK(on_auto_color_clicked), self);
/* Set default conversion/rendering settings */
self->render_dialog_settings.scale = 1000;
self->render_dialog_settings.renderer = RENDERER_LATEX_TIKZ;
self->render_dialog_settings.tex_pdf_layers = FALSE;
self->render_dialog_settings.tex_standalone = FALSE;
/* Get select all button and connect callback */
self->select_all_button = GTK_WIDGET(gtk_builder_get_object(main_builder, "button-select-all"));
g_signal_connect(self->select_all_button, "clicked", G_CALLBACK(on_select_all_layers_clicked), self);
/* Setup auto naming button */
auto_naming_button = GTK_WIDGET(gtk_builder_get_object(main_builder, "button-auto-name"));
g_signal_connect(auto_naming_button, "clicked", G_CALLBACK(auto_naming_clicked), self);
g_object_unref(main_builder);
/* Setup default button sensibility data */
self->button_state_data.rendering_active = FALSE;
self->button_state_data.valid_cell_selected = FALSE;
/* Reference all objects referenced by this object */
g_object_ref(self->activity_status_bar);
g_object_ref(self->main_window);
g_object_ref(self->cell_tree_view);
g_object_ref(self->convert_button);
/* g_object_ref(self->layer_selector); <= This is already referenced by the _new() function */
g_object_ref(self->cell_search_entry);
/* g_object_ref(self->palette); */
g_object_ref(self->open_button);
g_object_ref(self->load_layer_button);
g_object_ref(self->save_layer_button);
g_object_ref(self->select_all_button);
}
GdsRenderGui *gds_render_gui_new()
{
return RENDERER_GUI(g_object_new(RENDERER_TYPE_GUI, NULL));
}
/** @} */

View File

@@ -17,27 +17,49 @@
* along with GDSII-Converter. If not, see <http://www.gnu.org/licenses/>.
*/
/*
/**
* @file gds-parser.c
* @brief Implementation of the GDS-Parser
* @author Mario Hüttel <mario.huettel@gmx.net>
*
* What's missing? - A lot:
* Support for Boxes
* Support for 4 Byte real
* Support for pathtypes
* Support for datatypes (only layer so far)
* etc...
*/
/**
* @addtogroup GDS-Utilities
* @{
*/
#include "gds-parser.h"
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <stdbool.h>
#include <math.h>
#include <cairo.h>
#include <glib/gi18n.h>
#define GDS_ERROR(fmt, ...) printf("[PARSE_ERROR] " fmt "\n", ##__VA_ARGS__)
#define GDS_WARN(fmt, ...) printf("[PARSE_WARNING] " fmt "\n", ##__VA_ARGS__)
#include <gds-render/gds-utils/gds-parser.h>
enum record {
/**
* @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
/**< @brief standard printf. But can be disabled in code. */
#define GDS_INF(fmt, ...) printf(fmt, ##__VA_ARGS__)
#else
#define GDS_INF(fmt, ...)
#endif
enum gds_record {
INVALID = 0x0000,
HEADER = 0x0002,
BGNLIB = 0x0102,
@@ -59,9 +81,35 @@ enum record {
BOX = 0x2D00,
LAYER = 0x0D02,
WIDTH = 0x0F03,
PATHTYPE = 0x2102
PATHTYPE = 0x2102,
COLROW = 0x1302,
AREF = 0x0B00
};
/**
* @brief Struct representing an array instantiation.
*
* This struct is defined locally because it is not exposed to the outside of the
* parser. Array references are internally converted to a bunch of standard @ref gds_cell_instance elements.
*/
struct gds_cell_array_instance {
char ref_name[CELL_NAME_MAX]; /**< @brief Name of referenced cell */
struct gds_cell *cell_ref; /**< @brief Referenced gds_cell structure */
struct gds_point control_points[3]; /**< @brief The three control points */
int flipped; /**< @brief Mirror each instance on x-axis before rotation */
double angle; /**< @brief Angle of rotation for each instance (counter clockwise) in degrees */
double magnification; /**< @brief Magnification of each instance */
int columns; /**< @brief Column count */
int rows; /**< @brief Row count */
};
/**
* @brief Name cell reference
* @param cell_inst Cell reference
* @param bytes Length of name
* @param data Name
* @return 0 if successful
*/
static int name_cell_ref(struct gds_cell_instance *cell_inst,
unsigned int bytes, char *data)
{
@@ -72,7 +120,7 @@ static int name_cell_ref(struct gds_cell_instance *cell_inst,
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;
@@ -80,11 +128,46 @@ static int name_cell_ref(struct gds_cell_instance *cell_inst,
/* else: */
strcpy(cell_inst->ref_name, data);
printf("\tCell referenced: %s\n", cell_inst->ref_name);
GDS_INF("\tCell referenced: %s\n", cell_inst->ref_name);
return 0;
}
/**
* @brief Name cell reference
* @param cell_inst Cell reference
* @param bytes Length of name
* @param data Name
* @return 0 if successful
*/
static int name_array_cell_ref(struct gds_cell_array_instance *cell_inst,
unsigned int bytes, char *data)
{
int len;
if (cell_inst == NULL) {
GDS_ERROR("Naming array cell ref with no opened cell ref");
return -1;
}
data[bytes] = 0; // Append '0'
len = (int)strlen(data);
if (len > CELL_NAME_MAX-1) {
GDS_ERROR("Cell name '%s' too long: %d\n", data, len);
return -1;
}
/* else: */
strcpy(cell_inst->ref_name, data);
GDS_INF("\tCell referenced: %s\n", cell_inst->ref_name);
return 0;
}
/**
* @brief Convert GDS 8-byte real to double
* @param data 8 Byte GDS real
* @return result
*/
static double gds_convert_double(const char *data)
{
bool sign_bit;
@@ -101,7 +184,7 @@ static double gds_convert_double(const char *data)
if (data[i] != 0)
break;
if (i == 7) {
/* 7 bytes all 0 */
/* All 8 bytes are 0 */
return 0.0;
}
}
@@ -125,12 +208,17 @@ static double gds_convert_double(const char *data)
return ret_val;
}
/**
* @brief Convert GDS INT32 to int
* @param data Buffer containing the int
* @return result
*/
static signed int gds_convert_signed_int(const char *data)
{
int ret;
if (!data) {
GDS_ERROR("This should not happen");
GDS_ERROR("Conversion from GDS data to signed int failed.");
return 0;
}
@@ -141,6 +229,11 @@ static signed int gds_convert_signed_int(const char *data)
return ret;
}
/**
* @brief Convert GDS INT16 to int16
* @param data Buffer containing the INT16
* @return result
*/
static int16_t gds_convert_signed_int16(const char *data)
{
if (!data) {
@@ -151,7 +244,12 @@ static int16_t gds_convert_signed_int16(const char *data)
(((int16_t)(data[1]) & 0xFF) << 0));
}
static uint16_t gds_convert_unsigend_int16(const char *data)
/**
* @brief Convert GDS UINT16 String to uint16
* @param data Buffer containing the uint16
* @return result
*/
static uint16_t gds_convert_unsigned_int16(const char *data)
{
if (!data) {
GDS_ERROR("This should not happen");
@@ -161,6 +259,12 @@ static uint16_t gds_convert_unsigend_int16(const char *data)
(((uint16_t)(data[1]) & 0xFF) << 0));
}
/**
* @brief Append library to list
* @param curr_list List containing gds_library elements. May be NULL.
* @param library_ptr Return of newly created library.
* @return Newly created list pointer
*/
static GList *append_library(GList *curr_list, struct gds_library **library_ptr)
{
struct gds_library *lib;
@@ -169,7 +273,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;
@@ -179,7 +283,14 @@ static GList *append_library(GList *curr_list, struct gds_library **library_ptr)
return g_list_append(curr_list, lib);
}
static GList *append_graphics(GList *curr_list, enum graphics_type type,
/**
* @brief Prepend graphics to list
* @param curr_list List containing gds_graphics elements. May be NULL
* @param type Type of graphics
* @param graphics_ptr newly created graphic is written here
* @return new list pointer
*/
static __attribute__((warn_unused_result)) GList *prepend_graphics(GList *curr_list, enum graphics_type type,
struct gds_graphics **graphics_ptr)
{
struct gds_graphics *gfx;
@@ -198,9 +309,16 @@ static GList *append_graphics(GList *curr_list, enum graphics_type type,
if (graphics_ptr)
*graphics_ptr = gfx;
return g_list_append(curr_list, gfx);
return g_list_prepend(curr_list, gfx);
}
/**
* @brief Appends vertext List
* @param curr_list List containing gds_point elements. May be NULL.
* @param x x-coordinate of new point
* @param y y-coordinate of new point
* @return new Pointer to List.
*/
static GList *append_vertex(GList *curr_list, int x, int y)
{
struct gds_point *vertex;
@@ -214,6 +332,14 @@ static GList *append_vertex(GList *curr_list, int x, int y)
return g_list_append(curr_list, vertex);
}
/**
* @brief append_cell Append a gds_cell to a list
*
* Usage similar to append_cell_ref().
* @param curr_list List containing gds_cell elements. May be NULL
* @param cell_ptr newly created cell
* @return new pointer to list
*/
static GList *append_cell(GList *curr_list, struct gds_cell **cell_ptr)
{
struct gds_cell *cell;
@@ -223,6 +349,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 */
@@ -232,6 +361,14 @@ static GList *append_cell(GList *curr_list, struct gds_cell **cell_ptr)
return g_list_append(curr_list, cell);
}
/**
* @brief Append a cell reference to the reference GList.
*
* Appends a new gds_cell_instance to \p curr_list and returns the new element via \p instance_ptr
* @param curr_list List of gds_cell_instance elements. May be NULL
* @param instance_ptr newly created element
* @return new GList pointer
*/
static GList *append_cell_ref(GList *curr_list, struct gds_cell_instance **instance_ptr)
{
struct gds_cell_instance *inst;
@@ -241,9 +378,9 @@ static GList *append_cell_ref(GList *curr_list, struct gds_cell_instance **insta
if (inst) {
inst->cell_ref = NULL;
inst->ref_name[0] = 0;
inst->magnification = 1;
inst->magnification = 1.0;
inst->flipped = 0;
inst->angle = 0;
inst->angle = 0.0;
} else
return NULL;
@@ -253,6 +390,13 @@ static GList *append_cell_ref(GList *curr_list, struct gds_cell_instance **insta
return g_list_append(curr_list, inst);
}
/**
* @brief Name a gds_library
* @param current_library Library to name
* @param bytes Lenght of name
* @param data Name
* @return 0 if successful
*/
static int name_library(struct gds_library *current_library,
unsigned int bytes, char *data)
{
@@ -264,18 +408,26 @@ static int name_library(struct gds_library *current_library,
}
data[bytes] = 0; // Append '0'
len = strlen(data);
len = (int)strlen(data);
if (len > CELL_NAME_MAX-1) {
GDS_ERROR("Library name '%s' too long: %d\n", data, len);
return -1;
}
strcpy(current_library->name, data);
printf("Named library: %s\n", current_library->name);
GDS_INF("Named library: %s\n", current_library->name);
return 0;
}
/**
* @brief Names a gds_cell
* @param cell Cell to name
* @param bytes Length of name
* @param data Name
* @param lib Library in which \p cell is located
* @return 0 id successful
*/
static int name_cell(struct gds_cell *cell, unsigned int bytes,
char *data, struct gds_library *lib)
{
@@ -286,14 +438,14 @@ 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;
}
strcpy(cell->name, data);
printf("Named cell: %s\n", cell->name);
GDS_INF("Named cell: %s\n", cell->name);
/* Append cell name to lib's list of names */
lib->cell_names = g_list_append(lib->cell_names, cell->name);
@@ -301,15 +453,21 @@ static int name_cell(struct gds_cell *cell, unsigned int bytes,
return 0;
}
void parse_reference_list(gpointer gcell_ref, gpointer glibrary)
/**
* @brief Search for cell reference \p gcell_ref in \p glibrary
*
* Search cell referenced by \p gcell_ref inside \p glibrary and update gds_cell_instance::cell_ref with found #gds_cell
* @param gcell_ref gpointer cast of struct gds_cell_instance *
* @param glibrary gpointer cast of struct gds_library *
*/
static void parse_reference_list(gpointer gcell_ref, gpointer glibrary)
{
struct gds_cell_instance *inst = (struct gds_cell_instance *)gcell_ref;
struct gds_library *lib = (struct gds_library *)glibrary;
GList *cell_item;
struct gds_cell *cell;
printf("\t\t\tReference: %s: ", inst->ref_name);
GDS_INF("\t\t\tReference: %s: ", inst->ref_name);
/* Find cell */
for (cell_item = lib->cells; cell_item != NULL;
cell_item = cell_item->next) {
@@ -317,37 +475,58 @@ void parse_reference_list(gpointer gcell_ref, gpointer glibrary)
cell = (struct gds_cell *)cell_item->data;
/* Check if cell is found */
if (!strcmp(cell->name, inst->ref_name)) {
printf("found\n");
GDS_INF("found\n");
/* update reference link */
inst->cell_ref = cell;
return;
}
}
printf("MISSING!\n");
GDS_INF("MISSING!\n");
GDS_WARN("referenced cell could not be found in library");
}
void scan_cell_reference_dependencies(gpointer gcell, gpointer library)
/**
* @brief Scans cell references inside cell
This function searches all the references in \p gcell and updates the gds_cell_instance::cell_ref field in each instance
* @param gcell pointer cast of #gds_cell *
* @param library Library where the cell references are searched in
*/
static void scan_cell_reference_dependencies(gpointer gcell, gpointer library)
{
struct gds_cell *cell = (struct gds_cell *)gcell;
printf("\tScanning cell: %s\n", cell->name);
GDS_INF("\tScanning cell: %s\n", cell->name);
/* Scan all library references */
g_list_foreach(cell->child_cells, parse_reference_list, library);
}
void scan_library_references(gpointer library_list_item, gpointer user)
/**
* @brief Scans library's cell references
*
* This function searches all the references between cells and updates the gds_cell_instance::cell_ref field in each instance
* @param library_list_item List containing #gds_library elements
* @param user not used
*/
static void scan_library_references(gpointer library_list_item, gpointer user)
{
struct gds_library *lib = (struct gds_library *)library_list_item;
(void)user;
printf("Scanning Library: %s\n", lib->name);
GDS_INF("Scanning Library: %s\n", lib->name);
g_list_foreach(lib->cells, scan_cell_reference_dependencies, lib);
}
void gds_parse_date(const char *buffer, int length, struct gds_time_field *mod_date, struct gds_time_field *access_date)
/**
* @brief gds_parse_date
* @param buffer Buffer that contains the GDS Date field
* @param length Length of \p buffer
* @param mod_date Modification Date
* @param access_date Last Access Date
*/
static void gds_parse_date(const char *buffer, int length, struct gds_time_field *mod_date, struct gds_time_field *access_date)
{
struct gds_time_field *temp_date;
@@ -363,17 +542,17 @@ void gds_parse_date(const char *buffer, int length, struct gds_time_field *mod_d
}
for (temp_date = mod_date; 1; temp_date = access_date) {
temp_date->year = gds_convert_unsigend_int16(buffer);
temp_date->year = gds_convert_unsigned_int16(buffer);
buffer += 2;
temp_date->month = gds_convert_unsigend_int16(buffer);
temp_date->month = gds_convert_unsigned_int16(buffer);
buffer += 2;
temp_date->day = gds_convert_unsigend_int16(buffer);
temp_date->day = gds_convert_unsigned_int16(buffer);
buffer += 2;
temp_date->hour = gds_convert_unsigend_int16(buffer);
temp_date->hour = gds_convert_unsigned_int16(buffer);
buffer += 2;
temp_date->minute = gds_convert_unsigend_int16(buffer);
temp_date->minute = gds_convert_unsigned_int16(buffer);
buffer += 2;
temp_date->second = gds_convert_unsigend_int16(buffer);
temp_date->second = gds_convert_unsigned_int16(buffer);
buffer += 2;
if (temp_date == access_date)
@@ -381,6 +560,62 @@ void gds_parse_date(const char *buffer, int length, struct gds_time_field *mod_d
}
}
/**
* @brief Convert AREF to a bunch of SREFs and append them to \p container_cell
*
* This function converts a single array reference (\p aref) to gds_cell_array_instance::rows * gds_cell_array_instance::columns
* single references (SREFs). See @ref gds_cell_instance.
*
* Both gds_cell_array_instance::rows and gds_cell_array_instance::columns must be larger than zero.
*
* @param[in] aref Array reference to parse
* @param[in] container_cell cell to add the converted single references to.
*/
static void convert_aref_to_sref(struct gds_cell_array_instance *aref, struct gds_cell *container_cell)
{
struct gds_point origin;
struct gds_point row_shift_vector;
struct gds_point col_shift_vector;
struct gds_cell_instance *sref_inst = NULL;
int col;
int row;
if (!aref || !container_cell)
return;
if (aref->columns == 0 || aref->rows == 0) {
GDS_ERROR("Conversion of array instance aborted. No rows / columns.");
return;
}
origin.x = aref->control_points[0].x;
origin.y = aref->control_points[0].y;
row_shift_vector.x = (aref->control_points[2].x - origin.x) / aref->rows;
row_shift_vector.y = (aref->control_points[2].y - origin.y) / aref->rows;
col_shift_vector.x = (aref->control_points[1].x - origin.x) / aref->columns;
col_shift_vector.y = (aref->control_points[1].y - origin.y) / aref->columns;
/* Iterate over columns and rows */
for (col = 0; col < aref->columns; col++) {
for (row = 0; row < aref->rows; row++) {
/* Create new instance for this row/column and configure data */
container_cell->child_cells = append_cell_ref(container_cell->child_cells, &sref_inst);
if (!sref_inst) {
GDS_ERROR("Appending cell ref failed!");
continue;
}
sref_inst->angle = aref->angle;
sref_inst->magnification = aref->magnification;
sref_inst->flipped = aref->flipped;
strncpy(sref_inst->ref_name, aref->ref_name, CELL_NAME_MAX);
sref_inst->origin.x = origin.x + row_shift_vector.x * row + col_shift_vector.x * col;
sref_inst->origin.y = origin.y + row_shift_vector.y * row + col_shift_vector.y * col;
}
}
GDS_INF("Converted AREF to SREFs\n");
}
int parse_gds_from_file(const char *filename, GList **library_list)
{
char *workbuff;
@@ -389,11 +624,13 @@ int parse_gds_from_file(const char *filename, GList **library_list)
int run = 1;
FILE *gds_file = NULL;
uint16_t rec_data_length;
enum record rec_type;
enum gds_record rec_type;
struct gds_library *current_lib = NULL;
struct gds_cell *current_cell = NULL;
struct gds_graphics *current_graphics = NULL;
struct gds_cell_instance *current_s_reference = NULL;
struct gds_cell_array_instance *current_a_reference = NULL;
struct gds_cell_array_instance temp_a_reference;
int x, y;
////////////
GList *lib_list;
@@ -430,7 +667,7 @@ int parse_gds_from_file(const char *filename, GList **library_list)
break;
}
rec_data_length = gds_convert_unsigend_int16(workbuff);
rec_data_length = gds_convert_unsigned_int16(workbuff);
if (rec_data_length < 4) {
/* Possible Zero-Padding: */
@@ -453,7 +690,8 @@ int parse_gds_from_file(const char *filename, GList **library_list)
GDS_ERROR("Unexpected end of file");
break;
}
rec_type = gds_convert_unsigend_int16(workbuff);
rec_type = gds_convert_unsigned_int16(workbuff);
/* if begin: Allocate structures */
switch (rec_type) {
@@ -465,7 +703,7 @@ int parse_gds_from_file(const char *filename, GList **library_list)
break;
}
printf("Entering Lib\n");
GDS_INF("Entering Lib\n");
break;
case ENDLIB:
if (current_lib == NULL) {
@@ -481,16 +719,24 @@ int parse_gds_from_file(const char *filename, GList **library_list)
break;
}
current_lib = NULL;
printf("Leaving Library\n");
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;
}
printf("Entering Cell\n");
current_cell->parent_library = current_lib;
GDS_INF("Entering cell\n");
break;
case ENDSTR:
if (current_cell == NULL) {
@@ -505,27 +751,30 @@ int parse_gds_from_file(const char *filename, GList **library_list)
break;
}
current_cell = NULL;
printf("Leaving Cell\n");
GDS_INF("Leaving Cell\n");
break;
//case BOX:
case BOX:
case BOUNDARY:
if (current_cell == NULL) {
GDS_ERROR("Boundary outside of cell");
GDS_ERROR("Boundary/Box outside of cell");
run = -3;
break;
}
current_cell->graphic_objs = append_graphics(current_cell->graphic_objs,
GRAPHIC_POLYGON, &current_graphics);
current_cell->graphic_objs = prepend_graphics(current_cell->graphic_objs,
(rec_type == BOUNDARY
? GRAPHIC_POLYGON
: GRAPHIC_BOX),
&current_graphics);
if (current_cell->graphic_objs == NULL) {
GDS_ERROR("Memory allocation failed");
run = -4;
break;
}
printf("\tEntering boundary\n");
GDS_INF("\tEntering boundary/Box\n");
break;
case SREF:
if (current_cell == NULL) {
GDS_ERROR("Path outside of cell");
GDS_ERROR("Cell Reference outside of cell");
run = -3;
break;
}
@@ -537,7 +786,7 @@ int parse_gds_from_file(const char *filename, GList **library_list)
break;
}
printf("\tEntering reference\n");
GDS_INF("\tEntering reference\n");
break;
case PATH:
if (current_cell == NULL) {
@@ -545,25 +794,30 @@ int parse_gds_from_file(const char *filename, GList **library_list)
run = -3;
break;
}
current_cell->graphic_objs = append_graphics(current_cell->graphic_objs,
current_cell->graphic_objs = prepend_graphics(current_cell->graphic_objs,
GRAPHIC_PATH, &current_graphics);
if (current_cell->graphic_objs == NULL) {
GDS_ERROR("Memory allocation failed");
run = -4;
break;
}
printf("\tEntering Path\n");
GDS_INF("\tEntering Path\n");
break;
case ENDEL:
if (current_graphics != NULL) {
printf("\tLeaving %s\n", (current_graphics->gfx_type == GRAPHIC_POLYGON ? "boundary" : "path"));
GDS_INF("\tLeaving %s\n", (current_graphics->gfx_type == GRAPHIC_POLYGON ? "boundary" : "path"));
current_graphics = NULL;
}
if (current_s_reference != NULL) {
printf("\tLeaving Reference\n");
GDS_INF("\tLeaving Reference\n");
current_s_reference = NULL;
}
if (current_a_reference != NULL) {
GDS_INF("\tLeaving Array Reference\n");
convert_aref_to_sref(current_a_reference, current_cell);
current_a_reference = NULL;
}
break;
case XY:
if (current_graphics) {
@@ -572,27 +826,57 @@ int parse_gds_from_file(const char *filename, GList **library_list)
if (rec_data_length != 8) {
GDS_WARN("Instance has weird coordinates. Rendered output might be screwed!");
}
} else if (current_a_reference) {
if (rec_data_length != (3*(4+4)))
GDS_WARN("Array instance has weird coordinates. Rendered output might be screwed!");
}
break;
case AREF:
if (current_cell == NULL) {
GDS_ERROR("Cell array reference outside of cell");
run = -3;
break;
}
if (current_a_reference != NULL) {
GDS_ERROR("Recursive cell array reference");
run = -3;
break;
}
GDS_INF("Entering Array Reference\n");
/* Array references are coverted after fully declared. Therefore,
* only a static buffer is needed
*/
current_a_reference = &temp_a_reference;
current_a_reference->ref_name[0] = '\0';
current_a_reference->angle = 0.0;
current_a_reference->magnification = 1.0;
current_a_reference->flipped = 0;
current_a_reference->rows = 0;
current_a_reference->columns = 0;
break;
case COLROW:
case MAG:
break;
case ANGLE:
break;
case STRANS:
break;
case WIDTH:
break;
case PATHTYPE:
case UNITS:
case LIBNAME:
case SNAME:
case LAYER:
case STRNAME:
break;
default:
//GDS_WARN("Record: %04x, len: %u", (unsigned int)rec_type, (unsigned int)rec_data_length);
GDS_INF("Unhandled Record: %04x, len: %u\n", (unsigned int)rec_type, (unsigned int)rec_data_length);
break;
} /* switch(rec_type) */
/* 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);
@@ -604,9 +888,8 @@ int parse_gds_from_file(const char *filename, GList **library_list)
}
switch (rec_type) {
case AREF:
case HEADER:
case UNITS:
case ENDLIB:
case ENDSTR:
case BOUNDARY:
@@ -617,6 +900,34 @@ int parse_gds_from_file(const char *filename, GList **library_list)
case INVALID:
break;
case COLROW:
if (!current_a_reference) {
GDS_ERROR("COLROW record defined outside of array instance");
break;
}
if (rec_data_length != 4 || read != 4) {
GDS_ERROR("COLUMN/ROW count record contains too few data. Won't set column and row counts (%d, %d)",
rec_data_length, read);
break;
}
current_a_reference->columns = (int)gds_convert_signed_int16(&workbuff[0]);
current_a_reference->rows = (int)gds_convert_signed_int16(&workbuff[2]);
GDS_INF("\tRows: %d\n\tColumns: %d\n", current_a_reference->rows, current_a_reference->columns);
break;
case UNITS:
if (!current_lib) {
GDS_WARN("Units defined outside of library!\n");
break;
}
if (rec_data_length != 16) {
GDS_WARN("Unit define incomplete. Will assume database unit of %E meters\n", current_lib->unit_in_meters);
break;
}
current_lib->unit_in_meters = gds_convert_double(&workbuff[8]);
GDS_INF("Length of database unit: %E meters\n", current_lib->unit_in_meters);
break;
case BGNLIB:
/* Parse date record */
gds_parse_date(workbuff, read, &current_lib->mod_time, &current_lib->access_time);
@@ -625,17 +936,17 @@ int parse_gds_from_file(const char *filename, GList **library_list)
gds_parse_date(workbuff, read, &current_cell->mod_time, &current_cell->access_time);
break;
case LIBNAME:
name_library(current_lib, read, workbuff);
name_library(current_lib, (unsigned int)read, workbuff);
break;
case STRNAME:
name_cell(current_cell, read, workbuff, current_lib);
name_cell(current_cell, (unsigned int)read, workbuff, current_lib);
break;
case XY:
if (current_s_reference) {
/* Get origin of reference */
current_s_reference->origin.x = gds_convert_signed_int(workbuff);
current_s_reference->origin.y = gds_convert_signed_int(&workbuff[4]);
printf("\t\tSet origin to: %d/%d\n", current_s_reference->origin.x,
GDS_INF("\t\tSet origin to: %d/%d\n", current_s_reference->origin.x,
current_s_reference->origin.y);
} else if (current_graphics) {
for (i = 0; i < read/8; i++) {
@@ -643,21 +954,37 @@ int parse_gds_from_file(const char *filename, GList **library_list)
y = gds_convert_signed_int(&workbuff[i*8+4]);
current_graphics->vertices =
append_vertex(current_graphics->vertices, x, y);
printf("\t\tSet coordinate: %d/%d\n", x, y);
GDS_INF("\t\tSet coordinate: %d/%d\n", x, y);
}
} else if (current_a_reference) {
for (i = 0; i < 3; i++) {
x = gds_convert_signed_int(&workbuff[i*8]);
y = gds_convert_signed_int(&workbuff[i*8+4]);
current_a_reference->control_points[i].x = x;
current_a_reference->control_points[i].y = y;
GDS_INF("\tSet control point %d: %d/%d\n", i, x, y);
}
}
break;
case STRANS:
if (!current_s_reference) {
if (current_s_reference) {
current_s_reference->flipped = ((workbuff[0] & 0x80) ? 1 : 0);
} else if (current_a_reference) {
current_a_reference->flipped = ((workbuff[0] & 0x80) ? 1 : 0);
} else {
GDS_ERROR("Transformation defined outside of instance");
break;
}
current_s_reference->flipped = ((workbuff[0] & 0x80) ? 1 : 0);
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 if (current_a_reference) {
name_array_cell_ref(current_a_reference, (unsigned int)read, workbuff);
} else {
GDS_ERROR("Reference name set outside of cell reference");
}
break;
case WIDTH:
if (!current_graphics) {
@@ -674,7 +1001,7 @@ int parse_gds_from_file(const char *filename, GList **library_list)
if (current_graphics->layer < 0) {
GDS_WARN("Layer negative!\n");
}
printf("\t\tAdded layer %d\n", (int)current_graphics->layer);
GDS_INF("\t\tAdded layer %d\n", (int)current_graphics->layer);
break;
case MAG:
if (rec_data_length != 8) {
@@ -687,21 +1014,29 @@ int parse_gds_from_file(const char *filename, GList **library_list)
}
if (current_s_reference != NULL) {
current_s_reference->magnification = gds_convert_double(workbuff);
printf("\t\tMagnification defined: %lf\n", current_s_reference->magnification);
GDS_INF("\t\tMagnification defined: %lf\n", current_s_reference->magnification);
}
if (current_a_reference != NULL) {
current_a_reference->magnification = gds_convert_double(workbuff);
GDS_INF("\t\tMagnification defined: %lf\n", current_a_reference->magnification);
}
break;
case ANGLE:
if (rec_data_length != 8) {
GDS_WARN("Angle is not an 8 byte real. Results may be wrong");
}
if (current_graphics != NULL && current_s_reference != NULL) {
if (current_graphics != NULL && current_s_reference != NULL && current_a_reference != NULL) {
GDS_ERROR("Open Graphics and Cell Reference\n\tMissing ENDEL?");
run = -6;
break;
}
if (current_s_reference != NULL) {
current_s_reference->angle = gds_convert_double(workbuff);
printf("\t\tAngle defined: %lf\n", current_s_reference->angle);
GDS_INF("\t\tAngle defined: %lf\n", current_s_reference->angle);
}
if (current_a_reference != NULL) {
current_a_reference->angle = gds_convert_double(workbuff);
GDS_INF("\t\tAngle defined: %lf\n", current_a_reference->angle);
}
break;
case PATHTYPE:
@@ -710,8 +1045,8 @@ 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);
printf("\t\tPathtype: %d\n", current_graphics->path_render_type);
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");
}
@@ -723,7 +1058,6 @@ 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);
@@ -736,31 +1070,62 @@ int parse_gds_from_file(const char *filename, GList **library_list)
return run;
}
/**
* @brief delete_cell_inst_element
* @param cell_inst
*/
static void delete_cell_inst_element(struct gds_cell_instance *cell_inst)
{
free(cell_inst);
if (cell_inst)
free(cell_inst);
}
/**
* @brief delete_vertex
* @param vertex
*/
static void delete_vertex(struct gds_point *vertex)
{
free(vertex);
if (vertex)
free(vertex);
}
/**
* @brief delete_graphics_obj
* @param gfx
*/
static void delete_graphics_obj(struct gds_graphics *gfx)
{
if (!gfx)
return;
g_list_free_full(gfx->vertices, (GDestroyNotify)delete_vertex);
free(gfx);
}
/**
* @brief delete_cell_element
* @param cell
*/
static void delete_cell_element(struct gds_cell *cell)
{
if (!cell)
return;
g_list_free_full(cell->child_cells, (GDestroyNotify)delete_cell_inst_element);
g_list_free_full(cell->graphic_objs, (GDestroyNotify)delete_graphics_obj);
free(cell);
}
/**
* @brief delete_library_element
* @param lib
*/
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);
@@ -768,9 +1133,15 @@ static void delete_library_element(struct gds_library *lib)
int clear_lib_list(GList **library_list)
{
if (!library_list)
return 0;
if (*library_list == NULL)
return 0;
g_list_free_full(*library_list, (GDestroyNotify)delete_library_element);
*library_list = NULL;
return 0;
}
/** @} */

View File

@@ -0,0 +1,211 @@
/*
* GDSII-Converter
* Copyright (C) 2019 Mario Hüttel <mario.huettel@gmx.net>
*
* This file is part of GDSII-Converter.
*
* GDSII-Converter is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*
* GDSII-Converter is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with GDSII-Converter. If not, see <http://www.gnu.org/licenses/>.
*/
/**
* @file gds-tree-checker.c
* @brief Checking functions of a cell tree
*
* This file contains checking functions for the GDS cell tree.
* These functions include checks if all child references could be resolved,
* and if the cell tree contains loops.
*
* @author Mario Hüttel <mario.huettel@gmx.net>
*/
/**
* @addtogroup GDS-Utilities
* @{
*/
#include <stdio.h>
#include <glib/gi18n.h>
#include <gds-render/gds-utils/gds-tree-checker.h>
int gds_tree_check_cell_references(struct gds_library *lib)
{
GList *cell_iter;
struct gds_cell *cell;
GList *instance_iter;
struct gds_cell_instance *cell_inst;
int total_unresolved_count = 0;
if (!lib)
return -1;
/* Iterate over all cells in library */
for (cell_iter = lib->cells; cell_iter != NULL; cell_iter = g_list_next(cell_iter)) {
cell = (struct gds_cell *)cell_iter->data;
/* Check if this list element is broken. This should never happen */
if (!cell) {
fprintf(stderr, _("Broken cell list item found. Will continue.\n"));
continue;
}
/* Reset the unresolved cell reference counter to 0 */
cell->checks.unresolved_child_count = 0;
/* Iterate through all child cell references and check if the references are set */
for (instance_iter = cell->child_cells; instance_iter != NULL;
instance_iter = g_list_next(instance_iter)) {
cell_inst = (struct gds_cell_instance *)instance_iter->data;
/* Check if broken. This should not happen */
if (!cell_inst) {
fprintf(stderr, _("Broken cell list item found in cell %s. Will continue.\n"),
cell->name);
continue;
}
/* Check if instance is valid; else increment "error" counter of cell */
if (!cell_inst->cell_ref) {
total_unresolved_count++;
cell->checks.unresolved_child_count++;
}
}
}
return total_unresolved_count;
}
/**
* @brief Check if list contains a cell
* @param list GList to check. May be a null pointer
* @param cell Cell to check for
* @return 0 if cell is not in list. 1 if cell is in list
*/
static int gds_tree_check_list_contains_cell(GList *list, struct gds_cell *cell)
{
GList *iter;
for (iter = list; iter != NULL; iter = g_list_next(iter)) {
if ((struct gds_cell *)iter->data == cell)
return 1;
}
return 0;
}
/**
* @brief This function follows down the reference list of a cell and marks each visited subcell and detects loops
* @param cell_to_check The cell to check for reference loops
* @param visited_cells Pointer to list head. May be zero.
* @return 0 if no loops exist; error in processing: <0; loop found: >0
*/
static int gds_tree_check_iterate_ref_and_check(struct gds_cell *cell_to_check, GList **visited_cells)
{
GList *ref_iter;
struct gds_cell_instance *ref;
struct gds_cell *sub_cell;
int res;
if (!cell_to_check)
return -1;
/* Check if this cell is already contained in visited cells. This indicates a loop */
if (gds_tree_check_list_contains_cell(*visited_cells, cell_to_check))
return 1;
/* Add cell to visited cell list */
*visited_cells = g_list_append(*visited_cells, (gpointer)cell_to_check);
/* Mark references and process sub cells */
for (ref_iter = cell_to_check->child_cells; ref_iter != NULL; ref_iter = g_list_next(ref_iter)) {
ref = (struct gds_cell_instance *)ref_iter->data;
if (!ref)
return -1;
sub_cell = ref->cell_ref;
/* If cell is not resolved, ignore. No harm there */
if (!sub_cell)
continue;
res = gds_tree_check_iterate_ref_and_check(sub_cell, visited_cells);
if (res < 0) {
/* Error. return. */
return -3;
} else if (res > 0) {
/* Loop in subcell found. Propagate to top */
return 1;
}
}
/* Remove cell from visted cells */
*visited_cells = g_list_remove(*visited_cells, cell_to_check);
/* No error found in this chain */
return 0;
}
int gds_tree_check_reference_loops(struct gds_library *lib)
{
int res;
int loop_count = 0;
GList *cell_iter;
struct gds_cell *cell_to_check;
GList *visited_cells = NULL;
if (!lib)
return -1;
for (cell_iter = lib->cells; cell_iter != NULL; cell_iter = g_list_next(cell_iter)) {
cell_to_check = (struct gds_cell *)cell_iter->data;
/* A broken cell reference will be counted fatal in this case */
if (!cell_to_check)
return -2;
/* iterate through references and check if loop exists */
res = gds_tree_check_iterate_ref_and_check(cell_to_check, &visited_cells);
if (visited_cells) {
/*
* If cell contains no loop, print error when list not empty.
* In case of a loop, it is completely normal that the list is not empty,
* due to the instant return from gds_tree_check_iterate_ref_and_check()
*/
if (res == 0)
fprintf(stderr,
_("Visited cell list should be empty. This is a bug. Please report this.\n"));
g_list_free(visited_cells);
visited_cells = NULL;
}
if (res < 0) {
/* Error */
return res;
} else if (res > 0) {
/* Loop found: increment loop count and flag cell */
cell_to_check->checks.affected_by_reference_loop = 1;
loop_count++;
} else if (res == 0) {
/* No error found for this cell */
cell_to_check->checks.affected_by_reference_loop = 0;
}
}
return loop_count;
}
/** @} */

231
geometric/bounding-box.c Normal file
View File

@@ -0,0 +1,231 @@
/*
* 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 bounding-box.c
* @brief Calculation of bounding boxes
* @author Mario Hüttel <mario.huettel@gmx.net>
*/
/**
* @addtogroup geometric
* @{
*/
#include <stdio.h>
#include <math.h>
#include <gds-render/geometric/bounding-box.h>
#define MIN(a, b) (((a) < (b)) ? (a) : (b)) /**< @brief Return smaller number */
#define MAX(a, b) (((a) > (b)) ? (a) : (b)) /**< @brief Return bigger number */
#define ABS_DBL(a) ((a) < 0 ? -(a) : (a))
void bounding_box_calculate_polygon(GList *vertices, conv_generic_to_vector_2d_t conv_func, union bounding_box *box)
{
double xmin = DBL_MAX, xmax = -DBL_MAX, ymin = DBL_MAX, ymax = -DBL_MAX;
struct vector_2d temp_vec;
GList *list_item;
/* Check for errors */
if (!conv_func || !box || !vertices)
return;
for (list_item = vertices; list_item != NULL; list_item = g_list_next(list_item)) {
/* Convert generic vertex to vector_2d */
if (conv_func)
conv_func((void *)list_item->data, &temp_vec);
else
vector_2d_copy(&temp_vec, (struct vector_2d *)list_item->data);
/* Update bounding coordinates with vertex */
xmin = MIN(xmin, temp_vec.x);
xmax = MAX(xmax, temp_vec.x);
ymin = MIN(ymin, temp_vec.y);
ymax = MAX(ymax, temp_vec.y);
}
/* Fill bounding box with results */
box->vectors.lower_left.x = xmin;
box->vectors.lower_left.y = ymin;
box->vectors.upper_right.x = xmax;
box->vectors.upper_right.y = ymax;
}
void bounding_box_update_box(union bounding_box *destination, union bounding_box *update)
{
if (!destination || !update)
return;
destination->vectors.lower_left.x = MIN(destination->vectors.lower_left.x,
update->vectors.lower_left.x);
destination->vectors.lower_left.y = MIN(destination->vectors.lower_left.y,
update->vectors.lower_left.y);
destination->vectors.upper_right.x = MAX(destination->vectors.upper_right.x,
update->vectors.upper_right.x);
destination->vectors.upper_right.y = MAX(destination->vectors.upper_right.y,
update->vectors.upper_right.y);
}
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_MAX;
box->vectors.upper_right.y = -DBL_MAX;
}
/**
* @brief Calculate path miter points for a pathwith a \p width and the anchors \p a \p b \p c.
* @param[in] a
* @param[in] b
* @param[in] c
* @param[out] m1
* @param[out] m2
* @param[in] width
* @return Miter points in \p m1 and \p m2
* @note This function is currently unused (and untested). Ignore any compiler warning regarding this function.
*/
static void calculate_path_miter_points(struct vector_2d *a, struct vector_2d *b, struct vector_2d *c,
struct vector_2d *m1, struct vector_2d *m2, double width)
{
double angle, angle_sin, u;
struct vector_2d ba, bc, u_vec, v_vec, ba_norm;
if (!a || !b || !c || !m1 || !m2)
return;
vector_2d_subtract(&ba, a, b);
vector_2d_subtract(&bc, c, b);
angle = vector_2d_calculate_angle_between(&ba, &bc);
if (ABS_DBL(angle) < 0.05 || ABS_DBL(angle - M_PI) < 0.1) {
/* Specail cases Don*/
vector_2d_copy(&ba_norm, &ba);
vector_2d_rotate(&ba_norm, DEG2RAD(90));
vector_2d_normalize(&ba_norm);
vector_2d_scale(&ba_norm, width/2.0);
vector_2d_add(m1, b, &ba_norm);
vector_2d_subtract(m2, b, &ba_norm);
return;
}
angle_sin = sin(angle);
u = width/(2*angle_sin);
vector_2d_copy(&u_vec, &ba);
vector_2d_copy(&v_vec, &bc);
vector_2d_normalize(&u_vec);
vector_2d_normalize(&v_vec);
vector_2d_scale(&u_vec, u);
vector_2d_scale(&v_vec, u);
vector_2d_copy(m1, b);
vector_2d_add(m1, m1, &u_vec);
vector_2d_add(m1, m1, &v_vec);
vector_2d_copy(m2, b);
vector_2d_subtract(m2, m2, &u_vec);
vector_2d_subtract(m2, m2, &v_vec);
}
void bounding_box_update_with_path(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 %s not yet implemented correctly!\n", __func__); */
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);
}
void bounding_box_get_all_points(struct vector_2d *points, union bounding_box *box)
{
if (!points || !box)
return;
points[0].x = box->vectors.lower_left.x;
points[0].y = box->vectors.lower_left.y;
points[1].x = box->vectors.upper_right.x;
points[1].y = box->vectors.lower_left.y;
points[2].x = box->vectors.upper_right.x;
points[2].y = box->vectors.upper_right.y;
points[3].x = box->vectors.lower_left.x;
points[3].y = box->vectors.upper_right.y;
}
void bounding_box_apply_transform(double scale, double rotation_deg, bool flip_at_x, union bounding_box *box)
{
int i;
struct vector_2d input_points[4];
if (!box)
return;
bounding_box_get_all_points(input_points, box);
/* Reset box */
bounding_box_prepare_empty(box);
for (i = 0; i < 4; i++) {
input_points[i].y *= (flip_at_x ? -1 : 1);
vector_2d_rotate(&input_points[i], rotation_deg * M_PI / 180.0);
vector_2d_scale(&input_points[i], scale);
bounding_box_update_point(box, NULL, &input_points[i]);
}
}
/** @} */

120
geometric/cell-geometrics.c Normal file
View File

@@ -0,0 +1,120 @@
/*
* GDSII-Converter
* Copyright (C) 2018 Mario Hüttel <mario.huettel@gmx.net>
*
* This file is part of GDSII-Converter.
*
* GDSII-Converter is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*
* GDSII-Converter is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with GDSII-Converter. If not, see <http://www.gnu.org/licenses/>.
*/
/**
* @file cell-geometrics.c
* @brief Calculation of gds_cell trigonometrics
* @author Mario Hüttel <mario.huettel@gmx.net>
*/
#include <math.h>
#include <gds-render/geometric/cell-geometrics.h>
/**
* @addtogroup geometric
* @{
*/
static void convert_gds_point_to_2d_vector(struct gds_point *pt, struct vector_2d *vector)
{
vector->x = pt->x;
vector->y = pt->y;
}
/**
* @brief Update the given bounding box with the bounding box of a graphics element.
* @param box box to update
* @param gfx Graphics element
*/
static void update_box_with_gfx(union bounding_box *box, struct gds_graphics *gfx)
{
union bounding_box current_box;
bounding_box_prepare_empty(&current_box);
switch (gfx->gfx_type) {
case GRAPHIC_BOX:
/* Expected fallthrough */
case GRAPHIC_POLYGON:
bounding_box_calculate_polygon(gfx->vertices,
(conv_generic_to_vector_2d_t)&convert_gds_point_to_2d_vector,
&current_box);
break;
case GRAPHIC_PATH:
/*
* This is not implemented correctly.
* Please be aware if paths are the outmost elements of your cell.
* You might end up with a completely wrong calculated cell size.
*/
bounding_box_update_with_path(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,150 @@
/*
* 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 vector-operations.c
* @brief 2D Vector operations
* @author Mario Hüttel <mario.huettel@gmx.net>
*/
/**
* @addtogroup geometric
* @{
*/
#include <math.h>
#include <stdlib.h>
#include <gds-render/geometric/vector-operations.h>
#define ABS_DBL(a) ((a) < 0.0 ? -(a) : (a))
double vector_2d_scalar_multipy(struct vector_2d *a, struct vector_2d *b)
{
if (a && b)
return (a->x * b->x) + (a->y * b->y);
else
return 0.0;
}
void vector_2d_normalize(struct vector_2d *vec)
{
double len;
if (!vec)
return;
len = sqrt(pow(vec->x, 2) + pow(vec->y, 2));
vec->x = vec->x/len;
vec->y = vec->y/len;
}
void vector_2d_rotate(struct vector_2d *vec, double angle)
{
double sin_val, cos_val;
struct vector_2d temp;
if (!vec)
return;
sin_val = sin(angle);
cos_val = cos(angle);
vector_2d_copy(&temp, vec);
/* Apply rotation matrix */
vec->x = (cos_val * temp.x) - (sin_val * temp.y);
vec->y = (sin_val * temp.x) + (cos_val * temp.y);
}
struct vector_2d *vector_2d_copy(struct vector_2d *opt_res, struct vector_2d *vec)
{
struct vector_2d *res;
if (!vec)
return NULL;
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)
{
return (struct vector_2d *)malloc(sizeof(struct vector_2d));
}
void vector_2d_free(struct vector_2d *vec)
{
if (vec)
free(vec);
}
void vector_2d_scale(struct vector_2d *vec, double scale)
{
if (!vec)
return;
vec->x *= scale;
vec->y *= scale;
}
double vector_2d_abs(struct vector_2d *vec)
{
double len = 0.0;
if (vec)
len = sqrt(pow(vec->x, 2) + pow(vec->y, 2));
return len;
}
double vector_2d_calculate_angle_between(struct vector_2d *a, struct vector_2d *b)
{
double cos_angle;
if (!a || !b)
return 0.0;
cos_angle = ABS_DBL(vector_2d_scalar_multipy(a, b)) / (vector_2d_abs(a) * vector_2d_abs(b));
return acos(cos_angle);
}
void vector_2d_subtract(struct vector_2d *res, struct vector_2d *a, struct vector_2d *b)
{
if (res && a && b) {
res->x = a->x - b->x;
res->y = a->y - b->y;
}
}
void vector_2d_add(struct vector_2d *res, struct vector_2d *a, struct vector_2d *b)
{
if (res && a && b) {
res->x = a->x + b->x;
res->y = a->y + b->y;
}
}
/** @} */

View File

@@ -1,10 +0,0 @@
add_custom_target(glib-resources DEPENDS ${CMAKE_CURRENT_BINARY_DIR}/resources.c)
add_custom_command(DEPENDS
${CMAKE_CURRENT_SOURCE_DIR}/resources.xml
${CMAKE_CURRENT_SOURCE_DIR}/main.glade
${CMAKE_CURRENT_SOURCE_DIR}/layer-widget.glade
OUTPUT
${CMAKE_CURRENT_BINARY_DIR}/resources.c
COMMAND
glib-compile-resources --target="${CMAKE_CURRENT_BINARY_DIR}/resources.c" --sourcedir="${CMAKE_CURRENT_SOURCE_DIR}" --generate-source "${CMAKE_CURRENT_SOURCE_DIR}/resources.xml"
)

View File

@@ -1,135 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<!-- Generated with glade 3.22.1 -->
<interface>
<requires lib="gtk+" version="3.20"/>
<object class="GtkWindow" id="main-window">
<property name="height_request">250</property>
<property name="visible">True</property>
<property name="can_focus">False</property>
<child type="titlebar">
<object class="GtkHeaderBar">
<property name="name">header</property>
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="title" translatable="yes">GDS Renderer</property>
<property name="subtitle" translatable="yes">GDSII to PDF Converter</property>
<property name="show_close_button">True</property>
<child>
<object class="GtkButton" id="button-load-gds">
<property name="label">gtk-open</property>
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="receives_default">True</property>
<property name="use_stock">True</property>
<property name="always_show_image">True</property>
<style>
<class name="suggested-action"/>
</style>
</object>
</child>
<child>
<object class="GtkButton" id="button-load-mapping">
<property name="label" translatable="yes">Load Mapping</property>
<property name="visible">True</property>
<property name="sensitive">False</property>
<property name="can_focus">True</property>
<property name="receives_default">True</property>
<style>
<class name="destructive-action"/>
</style>
</object>
<packing>
<property name="position">1</property>
</packing>
</child>
<child>
<object class="GtkButton" id="button-save-mapping">
<property name="label" translatable="yes">Save Mapping</property>
<property name="visible">True</property>
<property name="sensitive">False</property>
<property name="can_focus">True</property>
<property name="receives_default">True</property>
<style>
<class name="suggested-action"/>
</style>
</object>
<packing>
<property name="position">2</property>
</packing>
</child>
<child>
<object class="GtkButton" id="convert-button">
<property name="label">gtk-convert</property>
<property name="name">button-convert</property>
<property name="visible">True</property>
<property name="sensitive">False</property>
<property name="can_focus">True</property>
<property name="receives_default">True</property>
<property name="use_stock">True</property>
<property name="always_show_image">True</property>
<style>
<class name="suggested-action"/>
</style>
</object>
<packing>
<property name="position">3</property>
</packing>
</child>
</object>
</child>
<child>
<object class="GtkBox">
<property name="visible">True</property>
<property name="can_focus">False</property>
<child>
<object class="GtkScrolledWindow">
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="hscrollbar_policy">never</property>
<property name="shadow_type">in</property>
<child>
<object class="GtkTreeView" id="cell-tree">
<property name="visible">True</property>
<property name="can_focus">True</property>
<child internal-child="selection">
<object class="GtkTreeSelection"/>
</child>
</object>
</child>
</object>
<packing>
<property name="expand">True</property>
<property name="fill">True</property>
<property name="position">0</property>
</packing>
</child>
<child>
<object class="GtkScrolledWindow">
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="hscrollbar_policy">never</property>
<property name="shadow_type">in</property>
<child>
<object class="GtkViewport">
<property name="visible">True</property>
<property name="can_focus">False</property>
<child>
<object class="GtkListBox" id="layer-list">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="selection_mode">none</property>
</object>
</child>
</object>
</child>
</object>
<packing>
<property name="expand">True</property>
<property name="fill">True</property>
<property name="position">1</property>
</packing>
</child>
</object>
</child>
</object>
</interface>

View File

@@ -1,9 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<gresources>
<gresource prefix="/">
<file compressed="true">main.glade</file>
<file>layer-widget.glade</file>
</gresource>
</gresources>

BIN
icon/128x128/gds-render.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 15 KiB

479
icon/gds-render.svg Normal file
View File

@@ -0,0 +1,479 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!-- Created with Inkscape (http://www.inkscape.org/) -->
<svg
xmlns:osb="http://www.openswatchbook.org/uri/2009/osb"
xmlns:dc="http://purl.org/dc/elements/1.1/"
xmlns:cc="http://creativecommons.org/ns#"
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
xmlns:svg="http://www.w3.org/2000/svg"
xmlns="http://www.w3.org/2000/svg"
xmlns:xlink="http://www.w3.org/1999/xlink"
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
width="30mm"
height="30mm"
viewBox="0 0 30.000001 29.999999"
version="1.1"
id="svg8"
inkscape:version="0.92.2 2405546, 2018-03-11"
sodipodi:docname="gds-render.svg"
inkscape:export-filename="/home/mari/projects/cpp/gds-render/icon/22x22/gds-render.png"
inkscape:export-xdpi="18.62639"
inkscape:export-ydpi="18.62639">
<sodipodi:namedview
id="base"
pagecolor="#ffffff"
bordercolor="#666666"
borderopacity="1.0"
inkscape:pageopacity="0.0"
inkscape:pageshadow="2"
inkscape:zoom="8"
inkscape:cx="123.37499"
inkscape:cy="62.837322"
inkscape:document-units="mm"
inkscape:current-layer="layer2"
showgrid="false"
units="mm"
inkscape:window-width="2880"
inkscape:window-height="1508"
inkscape:window-x="0"
inkscape:window-y="38"
inkscape:window-maximized="1" />
<defs
id="defs2">
<linearGradient
inkscape:collect="always"
id="linearGradient4825-0">
<stop
style="stop-color:#c4a000;stop-opacity:1"
offset="0"
id="stop4821" />
<stop
style="stop-color:#c4a000;stop-opacity:0"
offset="1"
id="stop4823" />
</linearGradient>
<linearGradient
osb:paint="solid"
id="linearGradient4788">
<stop
id="stop4786"
offset="0"
style="stop-color:#c4a000;stop-opacity:1;" />
</linearGradient>
<linearGradient
gradientUnits="userSpaceOnUse"
y2="298.01938"
x2="29.850964"
y1="268.53937"
x1="1.6864967"
id="linearGradient4806"
xlink:href="#linearGradient4825-0"
inkscape:collect="always" />
<linearGradient
gradientUnits="userSpaceOnUse"
y2="261.9151"
x2="7.7163501"
y1="298.01938"
x1="29.850964"
id="linearGradient4833"
xlink:href="#linearGradient4825-0"
inkscape:collect="always" />
<g
id="g4922">
<symbol
id="lx-text4864-glyph0-0"
overflow="visible"
style="overflow:visible">
<path
id="path4892"
d=""
style="stroke:none"
inkscape:connector-curvature="0" />
</symbol>
<symbol
id="lx-text4864-glyph0-1"
overflow="visible"
style="overflow:visible">
<path
id="path4895"
d="m 7.78125,-2.359375 c 0,-0.46875 0.046875,-0.53125 0.8125,-0.53125 v -0.34375 c -0.3125,0.015625 -1.140625,0.015625 -1.5,0.015625 -0.375,0 -1.421875,0 -1.734375,-0.015625 v 0.34375 H 5.71875 c 1.0625,0 1.09375,0.140625 1.09375,0.578125 v 0.765625 c 0,1.359375 -1.5625,1.453125 -1.875,1.453125 -0.9375,0 -3.1875,-0.578125 -3.1875,-4 0,-3.453125 2.265625,-3.96875 3.109375,-3.96875 1.03125,0 2.28125,0.75 2.59375,2.859375 0.015625,0.140625 0.015625,0.171875 0.15625,0.171875 0.171875,0 0.171875,-0.03125 0.171875,-0.28125 v -2.828125 c 0,-0.21875 0,-0.28125 -0.125,-0.28125 -0.0625,0 -0.078125,0.03125 -0.15625,0.15625 l -0.578125,0.9375 C 6.578125,-7.75 5.84375,-8.421875 4.703125,-8.421875 c -2.15625,0 -4.0625,1.890625 -4.0625,4.328125 0,2.484375 1.90625,4.34375 4.078125,4.34375 0.84375,0 1.8125,-0.28125 2.265625,-1.03125 0.21875,0.375 0.609375,0.765625 0.703125,0.765625 0.09375,0 0.09375,-0.0625 0.09375,-0.265625 z m 0,0"
style="stroke:none"
inkscape:connector-curvature="0" />
</symbol>
<symbol
id="lx-text4864-glyph0-2"
overflow="visible"
style="overflow:visible">
<path
id="path4898"
d="m 0.5,-8.15625 v 0.34375 h 0.234375 c 0.875,0 0.90625,0.109375 0.90625,0.5625 v 6.34375 c 0,0.4375 -0.03125,0.5625 -0.90625,0.5625 H 0.5 V 0 h 4.1875 c 2,0 3.59375,-1.796875 3.59375,-4 0,-2.3125 -1.609375,-4.15625 -3.59375,-4.15625 z m 2.625,7.8125 c -0.515625,0 -0.546875,-0.09375 -0.546875,-0.484375 V -7.34375 c 0,-0.390625 0.03125,-0.46875 0.546875,-0.46875 h 1.265625 c 0.984375,0 1.78125,0.46875 2.265625,1.265625 0.546875,0.84375 0.546875,2.046875 0.546875,2.53125 0,0.671875 -0.015625,1.796875 -0.703125,2.671875 -0.390625,0.5 -1.109375,1 -2.109375,1 z m 0,0"
style="stroke:none"
inkscape:connector-curvature="0" />
</symbol>
<symbol
id="lx-text4864-glyph0-3"
overflow="visible"
style="overflow:visible">
<path
id="path4901"
d="M 2.484375,-4.984375 C 1.875,-5.140625 1.34375,-5.734375 1.34375,-6.5 c 0,-0.84375 0.671875,-1.59375 1.59375,-1.59375 1.96875,0 2.21875,1.9375 2.296875,2.453125 0.03125,0.140625 0.03125,0.1875 0.140625,0.1875 0.140625,0 0.140625,-0.0625 0.140625,-0.265625 v -2.421875 c 0,-0.21875 0,-0.28125 -0.125,-0.28125 -0.03125,0 -0.078125,0 -0.171875,0.15625 L 4.828125,-7.53125 C 4.25,-8.265625 3.46875,-8.421875 2.9375,-8.421875 c -1.328125,0 -2.296875,1.078125 -2.296875,2.296875 0,0.5625 0.203125,1.09375 0.65625,1.578125 0.40625,0.453125 0.828125,0.5625 1.671875,0.78125 0.421875,0.09375 1.078125,0.265625 1.25,0.328125 0.5625,0.28125 0.9375,0.921875 0.9375,1.59375 0,0.90625 -0.640625,1.75 -1.625,1.75 -0.546875,0 -1.28125,-0.140625 -1.875,-0.640625 -0.6875,-0.625 -0.734375,-1.484375 -0.75,-1.890625 -0.015625,-0.09375 -0.109375,-0.09375 -0.125,-0.09375 -0.140625,0 -0.140625,0.0625 -0.140625,0.28125 v 2.40625 c 0,0.21875 0,0.28125 0.125,0.28125 C 0.84375,0.25 0.84375,0.234375 0.9375,0.078125 0.984375,-0.015625 1.234375,-0.453125 1.328125,-0.640625 1.75,-0.15625 2.515625,0.25 3.53125,0.25 4.875,0.25 5.84375,-0.890625 5.84375,-2.203125 5.84375,-2.921875 5.5625,-3.46875 5.25,-3.859375 4.8125,-4.40625 4.265625,-4.53125 3.796875,-4.65625 Z m 0,0"
style="stroke:none"
inkscape:connector-curvature="0" />
</symbol>
<symbol
id="lx-text4864-glyph0-4"
overflow="visible"
style="overflow:visible">
<path
id="path4904"
d="M 3.234375,-2.265625 V -2.90625 H 0.125 v 0.640625 z m 0,0"
style="stroke:none"
inkscape:connector-curvature="0" />
</symbol>
<symbol
id="lx-text4864-glyph0-5"
overflow="visible"
style="overflow:visible">
<path
id="path4907"
d="m 5.046875,-4.0625 c 1.1875,-0.28125 2.09375,-1.03125 2.09375,-1.953125 0,-1.15625 -1.34375,-2.140625 -3.0625,-2.140625 H 0.5 v 0.34375 h 0.234375 c 0.875,0 0.90625,0.109375 0.90625,0.5625 v 6.34375 c 0,0.4375 -0.03125,0.5625 -0.90625,0.5625 H 0.5 V 0 c 0.28125,-0.03125 1.25,-0.03125 1.609375,-0.03125 0.34375,0 1.328125,0 1.609375,0.03125 V -0.34375 H 3.484375 c -0.859375,0 -0.90625,-0.125 -0.90625,-0.5625 v -3.0625 H 3.96875 c 0.46875,0 0.90625,0.125 1.234375,0.46875 0.40625,0.453125 0.40625,0.703125 0.40625,1.53125 0,0.9375 0,1.25 0.515625,1.765625 C 6.3125,-0.03125 6.8125,0.25 7.484375,0.25 c 0.9375,0 1.09375,-1.03125 1.09375,-1.296875 0,-0.0625 0,-0.171875 -0.140625,-0.171875 -0.125,0 -0.125,0.078125 -0.125,0.1875 C 8.25,-0.3125 7.90625,0.015625 7.515625,0.015625 6.96875,0.015625 6.84375,-0.546875 6.75,-1.1875 6.734375,-1.265625 6.671875,-1.78125 6.640625,-2.078125 6.546875,-2.671875 6.5,-3.0625 6.140625,-3.4375 c -0.125,-0.125 -0.4375,-0.453125 -1.09375,-0.625 z m -1.125,-0.140625 H 2.578125 V -7.34375 c 0,-0.265625 0,-0.40625 0.25,-0.46875 0.109375,0 0.46875,0 0.703125,0 0.96875,0 2.5,0 2.5,1.796875 0,1.046875 -0.5625,1.8125 -2.109375,1.8125 z m 0,0"
style="stroke:none"
inkscape:connector-curvature="0" />
</symbol>
<symbol
id="lx-text4864-glyph0-6"
overflow="visible"
style="overflow:visible">
<path
id="path4910"
d="m 4.578125,-2.765625 c 0.265625,0 0.28125,0 0.28125,-0.234375 0,-1.203125 -0.640625,-2.328125 -2.09375,-2.328125 -1.359375,0 -2.40625,1.234375 -2.40625,2.703125 0,1.578125 1.21875,2.75 2.546875,2.75 1.421875,0 1.953125,-1.296875 1.953125,-1.546875 0,-0.078125 -0.046875,-0.125 -0.125,-0.125 -0.09375,0 -0.125,0.0625 -0.140625,0.125 -0.3125,1 -1.109375,1.28125 -1.625,1.28125 -0.5,0 -1.703125,-0.34375 -1.703125,-2.40625 v -0.21875 z M 1.28125,-3 c 0.09375,-1.875 1.140625,-2.09375 1.484375,-2.09375 1.28125,0 1.34375,1.6875 1.359375,2.09375 z m 0,0"
style="stroke:none"
inkscape:connector-curvature="0" />
</symbol>
<symbol
id="lx-text4864-glyph0-7"
overflow="visible"
style="overflow:visible">
<path
id="path4913"
d="m 5.3125,-2.90625 c 0,-1.109375 0,-1.4375 -0.265625,-1.828125 -0.34375,-0.46875 -0.90625,-0.53125 -1.3125,-0.53125 -1.171875,0 -1.625,0.984375 -1.71875,1.21875 v -1.21875 l -1.640625,0.125 v 0.34375 c 0.8125,0 0.921875,0.09375 0.921875,0.671875 v 3.234375 c 0,0.546875 -0.140625,0.546875 -0.921875,0.546875 V 0 c 0.3125,-0.03125 0.96875,-0.03125 1.296875,-0.03125 0.34375,0 1,0 1.296875,0.03125 v -0.34375 c -0.75,0 -0.90625,0 -0.90625,-0.546875 v -2.21875 c 0,-1.25 0.828125,-1.921875 1.578125,-1.921875 0.734375,0 0.90625,0.609375 0.90625,1.34375 v 2.796875 c 0,0.546875 -0.140625,0.546875 -0.90625,0.546875 V 0 c 0.296875,-0.03125 0.953125,-0.03125 1.28125,-0.03125 0.34375,0 1,0 1.3125,0.03125 v -0.34375 c -0.609375,0 -0.90625,0 -0.921875,-0.359375 z m 0,0"
style="stroke:none"
inkscape:connector-curvature="0" />
</symbol>
<symbol
id="lx-text4864-glyph0-8"
overflow="visible"
style="overflow:visible">
<path
id="path4916"
d="M 3.578125,-8.15625 V -7.8125 C 4.40625,-7.8125 4.5,-7.734375 4.5,-7.140625 V -4.5 C 4.25,-4.859375 3.734375,-5.265625 3,-5.265625 c -1.390625,0 -2.578125,1.171875 -2.578125,2.703125 0,1.515625 1.125,2.6875 2.453125,2.6875 0.90625,0 1.421875,-0.609375 1.59375,-0.828125 V 0.125 L 6.15625,0 V -0.34375 C 5.34375,-0.34375 5.25,-0.4375 5.25,-1.015625 v -7.28125 z m 0.890625,6.75 c 0,0.21875 0,0.265625 -0.171875,0.515625 -0.28125,0.421875 -0.765625,0.765625 -1.375,0.765625 -0.296875,0 -1.59375,-0.109375 -1.59375,-2.4375 0,-0.859375 0.140625,-1.328125 0.40625,-1.734375 0.234375,-0.359375 0.71875,-0.734375 1.3125,-0.734375 0.75,0 1.15625,0.53125 1.28125,0.734375 0.140625,0.203125 0.140625,0.21875 0.140625,0.4375 z m 0,0"
style="stroke:none"
inkscape:connector-curvature="0" />
</symbol>
<symbol
id="lx-text4864-glyph0-9"
overflow="visible"
style="overflow:visible">
<path
id="path4919"
d="m 2,-2.78125 c 0,-1.15625 0.46875,-2.25 1.390625,-2.25 0.09375,0 0.125,0 0.171875,0.015625 -0.09375,0.046875 -0.28125,0.109375 -0.28125,0.4375 0,0.34375 0.265625,0.484375 0.453125,0.484375 0.25,0 0.484375,-0.15625 0.484375,-0.484375 0,-0.359375 -0.328125,-0.6875 -0.84375,-0.6875 -1.015625,0 -1.359375,1.09375 -1.421875,1.328125 H 1.9375 v -1.328125 l -1.609375,0.125 v 0.34375 c 0.8125,0 0.921875,0.09375 0.921875,0.671875 v 3.234375 c 0,0.546875 -0.140625,0.546875 -0.921875,0.546875 V 0 c 0.34375,-0.03125 1,-0.03125 1.359375,-0.03125 0.328125,0 1.171875,0 1.4375,0.03125 V -0.34375 H 2.890625 C 2.015625,-0.34375 2,-0.484375 2,-0.90625 Z m 0,0"
style="stroke:none"
inkscape:connector-curvature="0" />
</symbol>
</g>
</defs>
<metadata
id="metadata5">
<rdf:RDF>
<cc:Work
rdf:about="">
<dc:format>image/svg+xml</dc:format>
<dc:type
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
<dc:title></dc:title>
</cc:Work>
</rdf:RDF>
</metadata>
<g
sodipodi:insensitive="true"
style="display:inline"
transform="translate(0,-267.00004)"
id="layer1"
inkscape:groupmode="layer"
inkscape:label="Layer 1">
<rect
ry="4.8109269"
y="267.27731"
x="0.27727795"
height="29.445444"
width="29.445444"
id="rect863"
style="fill:url(#linearGradient4833);fill-opacity:1;fill-rule:nonzero;stroke:url(#linearGradient4806);stroke-width:0.55500001;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" />
</g>
<g
style="display:inline"
inkscape:label="GDS"
id="layer2"
inkscape:groupmode="layer"
sodipodi:insensitive="true">
<g
transform="matrix(1.1803494,0,0,1.1803494,-3.0934521,2.5343859)"
id="g4860">
<rect
style="fill:#5c3566;fill-opacity:1;fill-rule:nonzero;stroke:#5c3566;stroke-width:0.03089017;stroke-linecap:square;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
id="rect4722-9"
width="7.315506"
height="2.6185424"
x="17.855755"
y="2.8206506" />
<rect
style="fill:#5c3566;fill-opacity:1;fill-rule:nonzero;stroke:#5c3566;stroke-width:0.03089017;stroke-linecap:square;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
id="rect4722"
width="7.315506"
height="2.6185424"
x="5.0017018"
y="2.8206506" />
<rect
style="fill:#729fcf;fill-opacity:1;fill-rule:nonzero;stroke:#3465a4;stroke-width:0.18781857;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
id="rect4647"
width="21.451309"
height="5.3823962"
x="4.4756289"
y="5.5161438"
ry="0.57490903" />
<path
style="fill:#5c3566;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:0.4249042;stroke-linecap:square;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
d="m 10.647111,2.1885173 c 1.371044,1.5346563 7.602828,2.1172607 8.900202,0 V 5.445367 h -8.900202 z"
id="rect4673"
inkscape:connector-curvature="0"
sodipodi:nodetypes="ccccc" />
<path
style="fill:#f57900;fill-opacity:1;stroke:#ce5c00;stroke-width:0.09766429;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
d="m 10.743177,2.1889465 v 1.1220392 l 1.692999,1.126e-4 0.846062,1.2390311 h 1.693 2.051725 l 0.826813,-1.2343732 h 1.693537 V 2.1885173 H 17.515176 L 16.669114,3.4240551 H 14.975238 13.620839 L 12.7949,2.1885173 Z"
id="path4655"
inkscape:connector-curvature="0"
sodipodi:nodetypes="ccccccccccccccc" />
<path
style="fill:#f57900;fill-opacity:1;stroke:#ce5c00;stroke-width:0.12909999;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
d="M 10.444636,4.7267469 9.7322177,4.2143924 8.4348855,4.2137428 7.1896962,2.1729032 H 4.4609914 v 1.1220392 h 1.6548333 l 0.8269886,2.1548987 h 1.6548343 l 1.8914814,0.011475 z"
id="path4655-6"
inkscape:connector-curvature="0"
sodipodi:nodetypes="ccccccccccc" />
<rect
style="fill:#cc0000;fill-opacity:1;fill-rule:nonzero;stroke:#cc0000;stroke-width:0.03570647;stroke-linecap:square;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
id="rect4703"
width="2.6473525"
height="0.67746186"
x="13.879735"
y="4.5986104"
ry="0" />
<path
style="fill:#f57900;fill-opacity:1;stroke:#ce5c00;stroke-width:0.13003762;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
d="m 19.828607,4.7038749 0.722805,-0.5123545 1.316244,-6.495e-4 1.263343,-2.0408398 h 2.768485 v 1.1220392 h -1.678958 l -0.839046,2.154899 h -1.678958 l -1.919057,0.011474 z"
id="path4655-6-2"
inkscape:connector-curvature="0"
sodipodi:nodetypes="ccccccccccc" />
<path
style="fill:#4e9a06;fill-opacity:1;fill-rule:nonzero;stroke:#73d216;stroke-width:0.06713366;stroke-linecap:square;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
d="m 6.5082658,5.4557442 v 1.4172746 1.225227 l 0.038859,0.1943268 v 0 c 0.128985,0.3512949 0.5947729,0.6114739 1.1565142,0.6114739 h 5.351728 c 0.561743,0 1.063373,-0.2021525 1.192356,-0.5534475 l 0.0031,-0.058026 V 8.0982458 6.8730188 5.4557442 Z"
id="rect4739"
inkscape:connector-curvature="0"
sodipodi:nodetypes="cccccsscccccc" />
<path
style="fill:#4e9a06;fill-opacity:1;fill-rule:nonzero;stroke:#73d216;stroke-width:0.0674862;stroke-linecap:square;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
d="m 16.02714,5.4330487 v 1.4171297 1.2251018 l 0.03927,0.1943069 v 0 c 0.13036,0.3512589 0.601098,0.6114113 1.168812,0.6114113 h 5.408637 c 0.567714,0 1.074679,-0.2021319 1.205035,-0.5533908 l 0.0031,-0.05802 V 8.0752802 6.8501784 5.4330487 Z"
id="rect4739-2"
inkscape:connector-curvature="0"
sodipodi:nodetypes="cccccsscccccc" />
</g>
<g
id="lx-text4864"
transform="matrix(0.38106292,0,0,0.38106292,2.3851025,22.428875)">
<defs
id="defs4924">
<g
id="g5236">
<symbol
id="symbol5198"
overflow="visible"
style="overflow:visible">
<path
id="path5196"
d=""
style="stroke:none"
inkscape:connector-curvature="0" />
</symbol>
<symbol
id="symbol5202"
overflow="visible"
style="overflow:visible">
<path
id="path5200"
d="m 7.78125,-2.359375 c 0,-0.46875 0.046875,-0.53125 0.8125,-0.53125 v -0.34375 c -0.3125,0.015625 -1.140625,0.015625 -1.5,0.015625 -0.375,0 -1.421875,0 -1.734375,-0.015625 v 0.34375 H 5.71875 c 1.0625,0 1.09375,0.140625 1.09375,0.578125 v 0.765625 c 0,1.359375 -1.5625,1.453125 -1.875,1.453125 -0.9375,0 -3.1875,-0.578125 -3.1875,-4 0,-3.453125 2.265625,-3.96875 3.109375,-3.96875 1.03125,0 2.28125,0.75 2.59375,2.859375 0.015625,0.140625 0.015625,0.171875 0.15625,0.171875 0.171875,0 0.171875,-0.03125 0.171875,-0.28125 v -2.828125 c 0,-0.21875 0,-0.28125 -0.125,-0.28125 -0.0625,0 -0.078125,0.03125 -0.15625,0.15625 l -0.578125,0.9375 C 6.578125,-7.75 5.84375,-8.421875 4.703125,-8.421875 c -2.15625,0 -4.0625,1.890625 -4.0625,4.328125 0,2.484375 1.90625,4.34375 4.078125,4.34375 0.84375,0 1.8125,-0.28125 2.265625,-1.03125 0.21875,0.375 0.609375,0.765625 0.703125,0.765625 0.09375,0 0.09375,-0.0625 0.09375,-0.265625 z m 0,0"
style="stroke:none"
inkscape:connector-curvature="0" />
</symbol>
<symbol
id="symbol5206"
overflow="visible"
style="overflow:visible">
<path
id="path5204"
d="m 0.5,-8.15625 v 0.34375 h 0.234375 c 0.875,0 0.90625,0.109375 0.90625,0.5625 v 6.34375 c 0,0.4375 -0.03125,0.5625 -0.90625,0.5625 H 0.5 V 0 h 4.1875 c 2,0 3.59375,-1.796875 3.59375,-4 0,-2.3125 -1.609375,-4.15625 -3.59375,-4.15625 z m 2.625,7.8125 c -0.515625,0 -0.546875,-0.09375 -0.546875,-0.484375 V -7.34375 c 0,-0.390625 0.03125,-0.46875 0.546875,-0.46875 h 1.265625 c 0.984375,0 1.78125,0.46875 2.265625,1.265625 0.546875,0.84375 0.546875,2.046875 0.546875,2.53125 0,0.671875 -0.015625,1.796875 -0.703125,2.671875 -0.390625,0.5 -1.109375,1 -2.109375,1 z m 0,0"
style="stroke:none"
inkscape:connector-curvature="0" />
</symbol>
<symbol
id="symbol5210"
overflow="visible"
style="overflow:visible">
<path
id="path5208"
d="M 2.484375,-4.984375 C 1.875,-5.140625 1.34375,-5.734375 1.34375,-6.5 c 0,-0.84375 0.671875,-1.59375 1.59375,-1.59375 1.96875,0 2.21875,1.9375 2.296875,2.453125 0.03125,0.140625 0.03125,0.1875 0.140625,0.1875 0.140625,0 0.140625,-0.0625 0.140625,-0.265625 v -2.421875 c 0,-0.21875 0,-0.28125 -0.125,-0.28125 -0.03125,0 -0.078125,0 -0.171875,0.15625 L 4.828125,-7.53125 C 4.25,-8.265625 3.46875,-8.421875 2.9375,-8.421875 c -1.328125,0 -2.296875,1.078125 -2.296875,2.296875 0,0.5625 0.203125,1.09375 0.65625,1.578125 0.40625,0.453125 0.828125,0.5625 1.671875,0.78125 0.421875,0.09375 1.078125,0.265625 1.25,0.328125 0.5625,0.28125 0.9375,0.921875 0.9375,1.59375 0,0.90625 -0.640625,1.75 -1.625,1.75 -0.546875,0 -1.28125,-0.140625 -1.875,-0.640625 -0.6875,-0.625 -0.734375,-1.484375 -0.75,-1.890625 -0.015625,-0.09375 -0.109375,-0.09375 -0.125,-0.09375 -0.140625,0 -0.140625,0.0625 -0.140625,0.28125 v 2.40625 c 0,0.21875 0,0.28125 0.125,0.28125 C 0.84375,0.25 0.84375,0.234375 0.9375,0.078125 0.984375,-0.015625 1.234375,-0.453125 1.328125,-0.640625 1.75,-0.15625 2.515625,0.25 3.53125,0.25 4.875,0.25 5.84375,-0.890625 5.84375,-2.203125 5.84375,-2.921875 5.5625,-3.46875 5.25,-3.859375 4.8125,-4.40625 4.265625,-4.53125 3.796875,-4.65625 Z m 0,0"
style="stroke:none"
inkscape:connector-curvature="0" />
</symbol>
<symbol
id="symbol5214"
overflow="visible"
style="overflow:visible">
<path
id="path5212"
d="M 3.234375,-2.265625 V -2.90625 H 0.125 v 0.640625 z m 0,0"
style="stroke:none"
inkscape:connector-curvature="0" />
</symbol>
<symbol
id="symbol5218"
overflow="visible"
style="overflow:visible">
<path
id="path5216"
d="m 5.046875,-4.0625 c 1.1875,-0.28125 2.09375,-1.03125 2.09375,-1.953125 0,-1.15625 -1.34375,-2.140625 -3.0625,-2.140625 H 0.5 v 0.34375 h 0.234375 c 0.875,0 0.90625,0.109375 0.90625,0.5625 v 6.34375 c 0,0.4375 -0.03125,0.5625 -0.90625,0.5625 H 0.5 V 0 c 0.28125,-0.03125 1.25,-0.03125 1.609375,-0.03125 0.34375,0 1.328125,0 1.609375,0.03125 V -0.34375 H 3.484375 c -0.859375,0 -0.90625,-0.125 -0.90625,-0.5625 v -3.0625 H 3.96875 c 0.46875,0 0.90625,0.125 1.234375,0.46875 0.40625,0.453125 0.40625,0.703125 0.40625,1.53125 0,0.9375 0,1.25 0.515625,1.765625 C 6.3125,-0.03125 6.8125,0.25 7.484375,0.25 c 0.9375,0 1.09375,-1.03125 1.09375,-1.296875 0,-0.0625 0,-0.171875 -0.140625,-0.171875 -0.125,0 -0.125,0.078125 -0.125,0.1875 C 8.25,-0.3125 7.90625,0.015625 7.515625,0.015625 6.96875,0.015625 6.84375,-0.546875 6.75,-1.1875 6.734375,-1.265625 6.671875,-1.78125 6.640625,-2.078125 6.546875,-2.671875 6.5,-3.0625 6.140625,-3.4375 c -0.125,-0.125 -0.4375,-0.453125 -1.09375,-0.625 z m -1.125,-0.140625 H 2.578125 V -7.34375 c 0,-0.265625 0,-0.40625 0.25,-0.46875 0.109375,0 0.46875,0 0.703125,0 0.96875,0 2.5,0 2.5,1.796875 0,1.046875 -0.5625,1.8125 -2.109375,1.8125 z m 0,0"
style="stroke:none"
inkscape:connector-curvature="0" />
</symbol>
<symbol
id="symbol5222"
overflow="visible"
style="overflow:visible">
<path
id="path5220"
d="m 4.578125,-2.765625 c 0.265625,0 0.28125,0 0.28125,-0.234375 0,-1.203125 -0.640625,-2.328125 -2.09375,-2.328125 -1.359375,0 -2.40625,1.234375 -2.40625,2.703125 0,1.578125 1.21875,2.75 2.546875,2.75 1.421875,0 1.953125,-1.296875 1.953125,-1.546875 0,-0.078125 -0.046875,-0.125 -0.125,-0.125 -0.09375,0 -0.125,0.0625 -0.140625,0.125 -0.3125,1 -1.109375,1.28125 -1.625,1.28125 -0.5,0 -1.703125,-0.34375 -1.703125,-2.40625 v -0.21875 z M 1.28125,-3 c 0.09375,-1.875 1.140625,-2.09375 1.484375,-2.09375 1.28125,0 1.34375,1.6875 1.359375,2.09375 z m 0,0"
style="stroke:none"
inkscape:connector-curvature="0" />
</symbol>
<symbol
id="symbol5226"
overflow="visible"
style="overflow:visible">
<path
id="path5224"
d="m 5.3125,-2.90625 c 0,-1.109375 0,-1.4375 -0.265625,-1.828125 -0.34375,-0.46875 -0.90625,-0.53125 -1.3125,-0.53125 -1.171875,0 -1.625,0.984375 -1.71875,1.21875 v -1.21875 l -1.640625,0.125 v 0.34375 c 0.8125,0 0.921875,0.09375 0.921875,0.671875 v 3.234375 c 0,0.546875 -0.140625,0.546875 -0.921875,0.546875 V 0 c 0.3125,-0.03125 0.96875,-0.03125 1.296875,-0.03125 0.34375,0 1,0 1.296875,0.03125 v -0.34375 c -0.75,0 -0.90625,0 -0.90625,-0.546875 v -2.21875 c 0,-1.25 0.828125,-1.921875 1.578125,-1.921875 0.734375,0 0.90625,0.609375 0.90625,1.34375 v 2.796875 c 0,0.546875 -0.140625,0.546875 -0.90625,0.546875 V 0 c 0.296875,-0.03125 0.953125,-0.03125 1.28125,-0.03125 0.34375,0 1,0 1.3125,0.03125 v -0.34375 c -0.609375,0 -0.90625,0 -0.921875,-0.359375 z m 0,0"
style="stroke:none"
inkscape:connector-curvature="0" />
</symbol>
<symbol
id="symbol5230"
overflow="visible"
style="overflow:visible">
<path
id="path5228"
d="M 3.578125,-8.15625 V -7.8125 C 4.40625,-7.8125 4.5,-7.734375 4.5,-7.140625 V -4.5 C 4.25,-4.859375 3.734375,-5.265625 3,-5.265625 c -1.390625,0 -2.578125,1.171875 -2.578125,2.703125 0,1.515625 1.125,2.6875 2.453125,2.6875 0.90625,0 1.421875,-0.609375 1.59375,-0.828125 V 0.125 L 6.15625,0 V -0.34375 C 5.34375,-0.34375 5.25,-0.4375 5.25,-1.015625 v -7.28125 z m 0.890625,6.75 c 0,0.21875 0,0.265625 -0.171875,0.515625 -0.28125,0.421875 -0.765625,0.765625 -1.375,0.765625 -0.296875,0 -1.59375,-0.109375 -1.59375,-2.4375 0,-0.859375 0.140625,-1.328125 0.40625,-1.734375 0.234375,-0.359375 0.71875,-0.734375 1.3125,-0.734375 0.75,0 1.15625,0.53125 1.28125,0.734375 0.140625,0.203125 0.140625,0.21875 0.140625,0.4375 z m 0,0"
style="stroke:none"
inkscape:connector-curvature="0" />
</symbol>
<symbol
id="symbol5234"
overflow="visible"
style="overflow:visible">
<path
id="path5232"
d="m 2,-2.78125 c 0,-1.15625 0.46875,-2.25 1.390625,-2.25 0.09375,0 0.125,0 0.171875,0.015625 -0.09375,0.046875 -0.28125,0.109375 -0.28125,0.4375 0,0.34375 0.265625,0.484375 0.453125,0.484375 0.25,0 0.484375,-0.15625 0.484375,-0.484375 0,-0.359375 -0.328125,-0.6875 -0.84375,-0.6875 -1.015625,0 -1.359375,1.09375 -1.421875,1.328125 H 1.9375 v -1.328125 l -1.609375,0.125 v 0.34375 c 0.8125,0 0.921875,0.09375 0.921875,0.671875 v 3.234375 c 0,0.546875 -0.140625,0.546875 -0.921875,0.546875 V 0 c 0.34375,-0.03125 1,-0.03125 1.359375,-0.03125 0.328125,0 1.171875,0 1.4375,0.03125 V -0.34375 H 2.890625 C 2.015625,-0.34375 2,-0.484375 2,-0.90625 Z m 0,0"
style="stroke:none"
inkscape:connector-curvature="0" />
</symbol>
</g>
</defs>
<g
id="lx-text4864-surface1">
<g
id="g4946"
style="fill:#000000;fill-opacity:1">
<use
id="use4926"
y="0"
x="0"
xlink:href="#lx-text4864-glyph0-1"
width="100%"
height="100%" />
<use
id="use4928"
y="0"
x="9.1851797"
xlink:href="#lx-text4864-glyph0-2"
width="100%"
height="100%" />
<use
id="use4930"
y="0"
x="18.125278"
xlink:href="#lx-text4864-glyph0-3"
width="100%"
height="100%" />
<use
id="use4932"
y="0"
x="24.628908"
xlink:href="#lx-text4864-glyph0-4"
width="100%"
height="100%" />
<use
id="use4934"
y="0"
x="28.531084"
xlink:href="#lx-text4864-glyph0-5"
width="100%"
height="100%" />
<use
id="use4936"
y="0"
x="37.146004"
xlink:href="#lx-text4864-glyph0-6"
width="100%"
height="100%" />
<use
id="use4938"
y="0"
x="42.348904"
xlink:href="#lx-text4864-glyph0-7"
width="100%"
height="100%" />
<use
id="use4940"
y="0"
x="48.852535"
xlink:href="#lx-text4864-glyph0-8"
width="100%"
height="100%" />
<use
id="use4942"
y="0"
x="55.356163"
xlink:href="#lx-text4864-glyph0-6"
width="100%"
height="100%" />
<use
id="use4944"
y="0"
x="60.559067"
xlink:href="#lx-text4864-glyph0-9"
width="100%"
height="100%" />
</g>
</g>
</g>
</g>
</svg>

After

Width:  |  Height:  |  Size: 29 KiB

View File

@@ -17,6 +17,17 @@
* along with GDSII-Converter. If not, see <http://www.gnu.org/licenses/>.
*/
/**
* @file lib-cell-renderer.h
* @brief Header file for the LibCellRenderer GObject Class
* @author Mario Hüttel <mario.huettel@gmx.net>
*/
/**
* @addtogroup LibCellRenderer
* @{
*/
#ifndef __LIB_CELL_RENDERER_H__
#define __LIB_CELL_RENDERER_H__
@@ -27,15 +38,33 @@ G_BEGIN_DECLS
G_DECLARE_FINAL_TYPE(LibCellRenderer, lib_cell_renderer, LIB_CELL, RENDERER, GtkCellRendererText)
#define TYPE_LIB_CELL_RENDERER (lib_cell_renderer_get_type())
/** @{
* Error levels
*/
#define LIB_CELL_RENDERER_ERROR_WARN (1U<<0)
#define LIB_CELL_RENDERER_ERROR_ERR (1U<<1)
/** @} */
typedef struct _LibCellRenderer {
/* Inheritance */
GtkCellRendererText super;
/* Custom Elements */
} LibCellRenderer;
/**
* @brief lib_cell_renderer_get_type
* @return GObject Type
*/
GType lib_cell_renderer_get_type(void);
/**
* @brief Create a new renderer for renderering @ref gds_cell and @ref gds_library elements.
* @return New renderer object
*/
GtkCellRenderer *lib_cell_renderer_new(void);
G_END_DECLS
#endif /* __LIB_CELL_RENDERER_H__ */
/** @} */

View File

@@ -0,0 +1,76 @@
/*
* 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 command-line.h
* @brief Render according to command line parameters
* @author Mario Hüttel <mario.huettel@gmx.net>
*/
/**
* @addtogroup cmdline
* @{
*/
#ifndef _COMMAND_LINE_H_
#define _COMMAND_LINE_H_
#include <glib.h>
/**
* @brief External renderer paramameters to command line renderer
*/
struct external_renderer_params {
/**
* @brief Path to shared object
*/
char *so_path;
/**
* @brief Command line parameters given
*/
char *cli_params;
};
/**
* @brief Convert GDS according to command line parameters
* @param gds_name Path to GDS File
* @param cell_name Cell name
* @param renderers Renderer ids
* @param output_file_names Output file names
* @param layer_file Layer mapping file
* @param ext_param Settings for external library renderer
* @param tex_standalone Standalone TeX
* @param tex_layers TeX OCR layers
* @param scale Scale value
* @return Error code, 0 if successful
*/
int command_line_convert_gds(const char *gds_name,
const char *cell_name,
char **renderers,
char **output_file_names,
const char *layer_file,
struct external_renderer_params *ext_param,
gboolean tex_standalone,
gboolean tex_layers,
double scale);
#endif /* _COMMAND_LINE_H_ */
/** @} */

View File

@@ -0,0 +1,61 @@
/*
* GDSII-Converter
* Copyright (C) 2018 Mario Hüttel <mario.huettel@gmx.net>
*
* This file is part of GDSII-Converter.
*
* GDSII-Converter is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*
* GDSII-Converter is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with GDSII-Converter. If not, see <http://www.gnu.org/licenses/>.
*/
/**
* @file gds-render-gui.h
* @brief Header for GdsRenderGui Object
* @author Mario Hüttel <mario.huettel@gmx.net>
*/
#ifndef _GDS_RENDER_GUI_
#define _GDS_RENDER_GUI_
/**
* @addtogroup GUI
* @{
*/
#include <gtk/gtk.h>
G_BEGIN_DECLS
G_DECLARE_FINAL_TYPE(GdsRenderGui, gds_render_gui, RENDERER, GUI, GObject);
#define RENDERER_TYPE_GUI (gds_render_gui_get_type())
/**
* @brief Create new GdsRenderGui Object
* @return New object
*/
GdsRenderGui *gds_render_gui_new();
/**
* @brief Get main window
*
* This function returns the main window of the GUI, which can later be displayed.
* All handling of hte GUI is taken care of inside the GdsRenderGui Object
* @return The generated main window
*/
GtkWindow *gds_render_gui_get_main_window(GdsRenderGui *gui);
G_END_DECLS
/** @} */
#endif /* _GDS_RENDER_GUI_ */

View File

@@ -0,0 +1,64 @@
/*
* GDSII-Converter
* Copyright (C) 2018 Mario Hüttel <mario.huettel@gmx.net>
*
* This file is part of GDSII-Converter.
*
* GDSII-Converter is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*
* GDSII-Converter is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with GDSII-Converter. If not, see <http://www.gnu.org/licenses/>.
*/
/**
* @file gds-parser.h
* @brief Header file for the GDS-Parser
* @author Mario Hüttel <mario.huettel@gmx.net>
*/
#ifndef _GDSPARSER_H_
#define _GDSPARSER_H_
/**
* @addtogroup GDS-Utilities
* @{
*/
#include <glib.h>
#include <gds-render/gds-utils/gds-types.h>
#define GDS_PRINT_DEBUG_INFOS (0) /**< @brief 1: Print infos, 0: Don't print */
/**
* @brief Parse a GDS file
*
* This function parses a GDS File and creates a list of libraries,
* which then contain the different cells.
*
* The function appends The detected libraries to the \p library_array list.
* The library array may be empty, meaning *library_list may be NULL.
*
* @param[in] filename Path to the GDS file
* @param[in,out] library_array GList Pointer.
* @return 0 if successful
*/
int parse_gds_from_file(const char *filename, GList **library_array);
/**
* @brief Deletes all libraries including cells, references etc.
* @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);
/** @} */
#endif /* _GDSPARSER_H_ */

View File

@@ -0,0 +1,61 @@
/*
* GDSII-Converter
* Copyright (C) 2019 Mario Hüttel <mario.huettel@gmx.net>
*
* This file is part of GDSII-Converter.
*
* GDSII-Converter is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*
* GDSII-Converter is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with GDSII-Converter. If not, see <http://www.gnu.org/licenses/>.
*/
/**
* @file gds-tree-checker.h
* @brief Checking functions of a cell tree (Header)
* @author Mario Hüttel <mario.huettel@gmx.net>
*/
/**
* @addtogroup GDS-Utilities
* @{
*/
#ifndef _GDS_TREE_CHECKER_H_
#define _GDS_TREE_CHECKER_H_
#include <gds-render/gds-utils/gds-types.h>
/**
* @brief gds_tree_check_cell_references checks if all child cell references can be resolved in the given library
*
* This function will only mark cells that
* directly contain unresolved references.
*
* If a cell contains a reference to a cell with unresolved references, it is not flagged.
*
* @param lib The GDS library to check
* @return less than 0 if an error occured during processing; 0 if all child cells could be resolved;
* greater than zero if the processing was successful but not all cell references could be resolved.
* In this case the number of unresolved references is returned
*/
int gds_tree_check_cell_references(struct gds_library *lib);
/**
* @brief gds_tree_check_reference_loops checks if the given library contains reference loops
* @param lib GDS library
* @return negative if an error occured, zero if there are no reference loops, else a positive number representing the number
* of affected cells
*/
int gds_tree_check_reference_loops(struct gds_library *lib);
#endif /* _GDS_TREE_CHECKER_H_ */
/** @} */

View File

@@ -0,0 +1,146 @@
/*
* GDSII-Converter
* Copyright (C) 2018 Mario Hüttel <mario.huettel@gmx.net>
*
* This file is part of GDSII-Converter.
*
* GDSII-Converter is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*
* GDSII-Converter is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with GDSII-Converter. If not, see <http://www.gnu.org/licenses/>.
*/
/**
* @file gds-types.h
* @brief Defines types and macros used by the GDS-Parser
* @author Mario Hüttel <mario.huettel@gmx.net>
*/
/**
* @addtogroup GDS-Utilities
* @{
*/
#ifndef __GDS_TYPES_H__
#define __GDS_TYPES_H__
#include <stdint.h>
#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
{
GRAPHIC_PATH = 0, /**< @brief Path. Esentially a line */
GRAPHIC_POLYGON = 1, /**< @brief An arbitrary polygon */
GRAPHIC_BOX = 2 /**< @brief A rectangle. @warning Implementation in renderers might be buggy!*/
};
/**
* @brief Defines the line caps of a path
*/
enum path_type {PATH_FLUSH = 0, PATH_ROUNDED = 1, PATH_SQUARED = 2}; /**< Path line caps */
/**
* @brief A point in the 2D plane. Sometimes referred to as vertex
*/
struct gds_point {
int x;
int y;
};
/**
* @brief Stores the result of the cell checks.
*/
struct gds_cell_checks {
int unresolved_child_count; /**< @brief Number of unresolved cell instances inside this cell. Default: @ref GDS_CELL_CHECK_NOT_RUN */
int affected_by_reference_loop; /**< @brief 1 if the cell is affected by a reference loop and therefore not renderable. Default: @ref GDS_CELL_CHECK_NOT_RUN*/
/**
* @brief For the internal use of the checker.
* @warning Do not use this structure and its contents!
*/
struct _check_internals {
int marker;
} _internal;
};
/**
* @brief Date information for cells and libraries
*/
struct gds_time_field {
uint16_t year;
uint16_t month;
uint16_t day;
uint16_t hour;
uint16_t minute;
uint16_t second;
};
/**
* @brief A GDS graphics object
*/
struct gds_graphics {
enum graphics_type gfx_type; /**< \brief Type of graphic */
GList *vertices; /**< @brief List of #gds_point */
enum path_type path_render_type; /**< @brief Line cap */
int width_absolute; /**< @brief Width. Not used for objects other than paths */
int16_t layer; /**< @brief Layer the graphic object is on */
uint16_t datatype;
};
/**
* @brief This represents an instanc of a cell inside another cell
*/
struct gds_cell_instance {
char ref_name[CELL_NAME_MAX]; /**< @brief Name of referenced cell */
struct gds_cell *cell_ref; /**< @brief Referenced gds_cell structure */
struct gds_point origin; /**< @brief Origin */
int flipped; /**< @brief Mirrored on x-axis before rotation */
double angle; /**< @brief Angle of rotation (counter clockwise) in degrees */
double magnification; /**< @brief magnification */
};
/**
* @brief A Cell inside a gds_library
*/
struct gds_cell {
char name[CELL_NAME_MAX];
struct gds_time_field mod_time;
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 */
};
/**
* @brief GDS Toplevel library
*/
struct gds_library {
char name[CELL_NAME_MAX];
struct gds_time_field mod_time;
struct gds_time_field access_time;
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 */;
};
/** @} */
#endif /* __GDS_TYPES_H__ */

View File

@@ -0,0 +1,121 @@
/*
* 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 bounding-box.h
* @brief Header for calculation of bounding boxes
* @author Mario Hüttel <mario.huettel@gmx.net>
*/
/**
* @addtogroup geometric
* @{
*/
#ifndef _BOUNDING_BOX_H_
#define _BOUNDING_BOX_H_
#include <glib.h>
#include <gds-render/geometric/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;
} vectors;
struct vector_2d vector_array[2];
};
typedef void (*conv_generic_to_vector_2d_t)(void *, struct vector_2d *);
/**
* @brief Calculate bounding box of polygon
* @param vertices List of vertices that describe the polygon
* @param conv_func Conversion function to convert vertices to vector_2d structs.
* @param box Box to write to. This box is not updated! All previous data is discarded
*/
void bounding_box_calculate_polygon(GList *vertices, conv_generic_to_vector_2d_t conv_func, union bounding_box *box);
/**
* @brief Update an exisitng bounding box with another one.
* @param destination Target box to update
* @param update Box to update the target with
*/
void bounding_box_update_box(union bounding_box *destination, union bounding_box *update);
/**
* @brief Prepare an empty bounding box.
*
* Updating this specially prepared box, results in a bounding box that is the same size as the update
*
* @param box Box to preapre
*/
void bounding_box_prepare_empty(union bounding_box *box);
/**
* @brief Update bounding box with a point
* @param destination Bounding box to update
* @param conv_func Conversion function to convert \p pt to a vector_2d. May be NULL
* @param pt Point to update bounding box with
*/
void bounding_box_update_point(union bounding_box *destination, conv_generic_to_vector_2d_t conv_func, void *pt);
/**
* @brief Return all four corner points of a bounding box
* @param[out] points Array of 4 vector_2d structs that has to be allocated by the caller
* @param box Bounding box
*/
void bounding_box_get_all_points(struct vector_2d *points, union bounding_box *box);
/**
* @brief Apply transformations onto bounding box.
*
* All corner points \f$ \vec{P_i} \f$ of the bounding box are transformed to output points \f$ \vec{P_o} \f$ by:
*
* \f$ \vec{P_o} = s \cdot \begin{pmatrix}\cos\left(\phi\right) & -\sin\left(\phi\right)\\ \sin\left(\phi\right) & \cos\left(\phi\right)\end{pmatrix} \cdot \begin{pmatrix} 1 & 0 \\ 0 & -1^{m} \end{pmatrix} \cdot \vec{P_i} \f$, with:
*
* * \f$s\f$: Scale
* * \f$m\f$: 1, if flipped_at_x is True, else 0
* * \f$\phi\f$: Rotation angle in radians. The conversion degrees => radians is done internally
*
* The result is the bounding box generated around all output points
*
* @param scale Scaling factor
* @param rotation_deg Rotation 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.
* @note Keep in mind, that this bounding boxy is actually the bounding box of the rotated boundig box and not the object itself.
* It might be too big.
*/
void bounding_box_apply_transform(double scale, double rotation_deg, bool flip_at_x, union bounding_box *box);
/**
* @brief Calculate the bounding box of a path and update the given bounding box
* @param vertices Vertices the path is made up of
* @param thickness Thisckness of the path
* @param conv_func Conversion function for vertices to vector_2d structs
* @param box Bounding box to write results in.
*/
void bounding_box_update_with_path(GList *vertices, double thickness, conv_generic_to_vector_2d_t conv_func, union bounding_box *box);
#endif /* _BOUNDING_BOX_H_ */
/** @} */

View File

@@ -17,24 +17,31 @@
* along with GDSII-Converter. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef __LAYER_SELECTOR_H__
#define __LAYER_SELECTOR_H__
/**
* @file cell-geometrics.h
* @brief Calculation of gds_cell geometrics
* @author Mario Hüttel <mario.huettel@gmx.net>
*/
#include <gtk/gtk.h>
#include <glib.h>
/**
* @addtogroup geometric
* @{
*/
struct layer_info
{
int layer;
char *name;
int stacked_position; ///< Lower is bottom, higher is top
GdkRGBA color;
};
#ifndef _CELL_GEOMETRICS_H_
#define _CELL_GEOMETRICS_H_
void generate_layer_widgets(GtkListBox *listbox, GList *libs);
void setup_load_mapping_callback(GtkWidget *button, GtkWindow *main_window);
void setup_save_mapping_callback(GtkWidget *button, GtkWindow *main_window);
GList *export_rendered_layer_info();
void delete_layer_info_struct(struct layer_info *info);
#include <gds-render/geometric/bounding-box.h>
#include <gds-render/gds-utils/gds-types.h>
#endif /* __LAYER_SELECTOR_H__ */
/**
* @brief calculate_cell_bounding_box Calculate bounding box of gds cell
* @param box Resulting boundig box. Will be uüdated and not overwritten
* @param cell Toplevel cell
* @warning Path handling not yet implemented correctly.
*/
void calculate_cell_bounding_box(union bounding_box *box, struct gds_cell *cell);
#endif /* _CELL_GEOMETRICS_H_ */
/** @} */

View File

@@ -0,0 +1,58 @@
/*
* 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 vector-operations.h
* @brief Header for 2D Vector operations
* @author Mario Hüttel <mario.huettel@gmx.net>
*/
/**
* @addtogroup geometric
* @{
*/
#ifndef _VECTOR_OPERATIONS_H_
#define _VECTOR_OPERATIONS_H_
#include <math.h>
struct vector_2d {
double x;
double y;
};
#define DEG2RAD(a) ((a)*M_PI/180.0)
double vector_2d_scalar_multipy(struct vector_2d *a, struct vector_2d *b);
void vector_2d_normalize(struct vector_2d *vec);
void vector_2d_rotate(struct vector_2d *vec, double angle);
struct vector_2d *vector_2d_copy(struct vector_2d *opt_res, struct vector_2d *vec);
struct vector_2d *vector_2d_alloc(void);
void vector_2d_free(struct vector_2d *vec);
void vector_2d_scale(struct vector_2d *vec, double scale);
double vector_2d_abs(struct vector_2d *vec);
double vector_2d_calculate_angle_between(struct vector_2d *a, struct vector_2d *b);
void vector_2d_subtract(struct vector_2d *res, struct vector_2d *a, struct vector_2d *b);
void vector_2d_add(struct vector_2d *res, struct vector_2d *a, struct vector_2d *b);
#endif /* _VECTOR_OPERATIONS_H_ */
/** @} */

View File

@@ -0,0 +1,70 @@
/*
* GDSII-Converter
* Copyright (C) 2019 Mario Hüttel <mario.huettel@gmx.net>
*
* This file is part of GDSII-Converter.
*
* GDSII-Converter is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*
* GDSII-Converter is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with GDSII-Converter. If not, see <http://www.gnu.org/licenses/>.
*/
/**
* @file color-palette.h
* @brief Class representing a color palette
* @author Mario Hüttel <mario.huettel@gmx.net>
*/
#ifndef _COLOR_PALETTE_H_
#define _COLOR_PALETTE_H_
#include <glib.h>
#include <gtk/gtk.h>
G_BEGIN_DECLS
G_DECLARE_FINAL_TYPE(ColorPalette, color_palette, GDS_RENDER, COLOR_PALETTE, GObject);
#define TYPE_GDS_RENDER_COLOR_PALETTE (color_palette_get_type())
/**
* @brief Create a new object with from a resource containing the html hex color scheme
* @param resource_name Name of the resource
* @return New object
*/
ColorPalette *color_palette_new_from_resource(char *resource_name);
/**
* @brief Get the n-th color in the palette identified by the index.
*
* This function fills the nth color into the supplied \p color.
* \p color is returned.
*
* If \p color is NULL, a new GdkRGBA is created and returned.
* This element must be freed afterwards.
*
* @param palette Color palette
* @param color GdkRGBA struct to fill data in. May be NULL.
* @param index Index of color. Starts at 0
* @return GdkRGBA color. If \p color is NULL, the returned color must be freed afterwards
*/
GdkRGBA *color_palette_get_color(ColorPalette *palette, GdkRGBA *color, unsigned int index);
/**
* @brief Return amount of stored colors in \p palette
* @param palette Color palette
* @return Count of colors
*/
unsigned int color_palette_get_color_count(ColorPalette *palette);
G_END_DECLS
#endif /* _COLOR_PALETTE_H_ */

View File

@@ -0,0 +1,137 @@
/*
* GDSII-Converter
* Copyright (C) 2018 Mario Hüttel <mario.huettel@gmx.net>
*
* This file is part of GDSII-Converter.
*
* GDSII-Converter is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*
* GDSII-Converter is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with GDSII-Converter. If not, see <http://www.gnu.org/licenses/>.
*/
/**
* @file layer-selector.h
* @brief Implementation of the Layer selection list
* @author Mario Hüttel <mario.huettel@gmx.net>
*/
/**
* @addtogroup layer-selector
* @{
*/
#ifndef __LAYER_SELECTOR_H__
#define __LAYER_SELECTOR_H__
#include <gtk/gtk.h>
#include <glib.h>
#include <gds-render/layer/color-palette.h>
#include <gds-render/layer/layer-settings.h>
G_BEGIN_DECLS
G_DECLARE_FINAL_TYPE(LayerSelector, layer_selector, LAYER, SELECTOR, GObject);
#define TYPE_LAYER_SELECTOR (layer_selector_get_type())
/**
* @brief Defines how to sort the layer selector list box.
*/
enum layer_selector_sort_algo {LAYER_SELECTOR_SORT_DOWN = 0, LAYER_SELECTOR_SORT_UP};
/**
* @brief layer_selector_new
* @param list_box The associated list box, the content is displayed in
* @return Newly created layer selector
*/
LayerSelector *layer_selector_new(GtkListBox *list_box);
/**
* @brief Generate layer widgets in in the LayerSelector instance
* @note This clears all previously inserted elements
* @param selector LayerSelector instance
* @param libs The libraries to add
*/
void layer_selector_generate_layer_widgets(LayerSelector *selector, GList *libs);
/**
* @brief Supply button for loading the layer mapping
* @param selector LayerSelector instance
* @param button Load button. Will be referenced
* @param main_window Parent window for dialogs. Will be referenced
*/
void layer_selector_set_load_mapping_button(LayerSelector *selector, GtkWidget *button, GtkWindow *main_window);
/**
* @brief Supply button for saving the layer mapping
* @param selector LayerSelector instance
* @param button Save button. Will be refeneced
* @param main_window Parent window for dialogs. Will be referenced
*/
void layer_selector_set_save_mapping_button(LayerSelector *selector, GtkWidget *button, GtkWindow *main_window);
/**
* @brief Get a list of all layers that shall be exported when rendering the cells
* @param selector Layer selector instance
* @return LayerSettings containing the layer information
*/
LayerSettings *layer_selector_export_rendered_layer_info(LayerSelector *selector);
/**
* @brief Force the layer selector list to be sorted according to \p sort_function
* @param selector LayerSelector instance
* @param sort_function The sorting method (up or down sorting)
*/
void layer_selector_force_sort(LayerSelector *selector, enum layer_selector_sort_algo sort_function);
/**
* @brief Set 'export' value of all layers in the LayerSelector to the supplied select value
* @param layer_selector LayerSelector object
* @param select
*/
void layer_selector_select_all_layers(LayerSelector *layer_selector, gboolean select);
/**
* @brief Apply colors from palette to all layers. Aditionally set alpha
* @param layer_selector LayerSelector object
* @param palette Color palette to use
* @param global_alpha Additional alpha value that is applied to all layers. Must be > 0
*/
void layer_selector_auto_color_layers(LayerSelector *layer_selector, ColorPalette *palette, double global_alpha);
/**
* @brief Auto name all layers in the layer selector.
*
* This functions sets the name of the layer equal to its number.
* The \p overwrite parameter specifies if already set layer names are overwritten.
*
* @param layer_selector LayerSelector
* @param overwrite Overwrite existing layer names
*/
void layer_selector_auto_name_layers(LayerSelector *layer_selector, gboolean overwrite);
/**
* @brief Check if the given layer selector contains layer elements.
*
* This function checks whether there are elements present.
* If an invalid object pointer \p layer_selector is passed,
* the function returns FALSE
*
* @param[in] layer_selector Selector to check
* @return True, if there is at least one layer present inside the selector
*/
gboolean layer_selector_contains_elements(LayerSelector *layer_selector);
G_END_DECLS
#endif /* __LAYER_SELECTOR_H__ */
/** @} */

View File

@@ -0,0 +1,123 @@
/*
* 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-settings.h
* @brief LayerSettings class header file
* @author Mario Hüttel <mario.huettel@gmx.net>
*/
#ifndef _LAYER_INFO_H_
#define _LAYER_INFO_H_
#include <gtk/gtk.h>
G_BEGIN_DECLS
/**
* @brief Layer information.
*
* This structs contains information on how to render a layer
* @note You probably don't want to use this struct standalone but in combination
* with a LayerSettings object.
*/
struct layer_info
{
int layer; /**< @brief Layer number */
char *name; /**< @brief Layer name. */
int stacked_position; ///< @brief Position of layer in output @warning This parameter is not used by any renderer so far @note Lower is bottom, higher is top
GdkRGBA color; /**< @brief RGBA color used to render this layer */
int render; /**< @brief true: Render to output */
};
G_DECLARE_FINAL_TYPE(LayerSettings, layer_settings, GDS_RENDER, LAYER_SETTINGS, GObject)
#define GDS_RENDER_TYPE_LAYER_SETTINGS (layer_settings_get_type())
/**
* @brief Maximum length of a layer mapping CSV line
*/
#define CSV_LINE_MAX_LEN (1024)
/**
* @brief New LayerSettings object
* @return New object
*/
LayerSettings *layer_settings_new();
/**
* @brief layer_settings_append_layer_info
* @param settings LayerSettings object.
* @param info Info to append
* @return Error code. 0 if successful
* @note \p info is copied internally. You can free this struct afterwards.
*/
int layer_settings_append_layer_info(LayerSettings *settings, struct layer_info *info);
/**
* @brief Clear all layers in this settings object
* @param settings LayerSettings object
*/
void layer_settings_clear(LayerSettings *settings);
/**
* @brief Remove a specific layer number from the layer settings.
* @param settings LayerSettings object
* @param layer Layer number
* @return Error code. 0 if successful
*/
int layer_settings_remove_layer(LayerSettings *settings, int layer);
/**
* @brief Get a GList with layer_info structs
*
* This function returns a GList with all layer_info structs in rendering order
* (bottom to top) that shall be rendered.
*
* @param settings LayerSettings object
* @return GList with struct layer_info elements.
*/
GList *layer_settings_get_layer_info_list(LayerSettings *settings);
/**
* @brief Write layer settings to a CSV file.
*
* This function writes the layer settings to a CSV file according to the
* layer mapping specification (@ref lmf-spec)
* @param settings LayerSettings object
* @param path Output path for CSV file.
* @return 0 if successful
*/
int layer_settings_to_csv(LayerSettings *settings, const char *path);
/**
* @brief Load new layer Settings from CSV
*
* This function loads the layer information from a CSV file.
* All data inside the \p settings is cleared beforehand.
*
* @param settings Settings to write to.
* @param path CSV file path
* @return 0 if successful
*/
int layer_settings_load_from_csv(LayerSettings *settings, const char *path);
G_END_DECLS
#endif // _LAYER_INFO_H_

View File

@@ -0,0 +1,60 @@
/*
* 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 cairo-renderer.h
* @brief Header File for Cairo output renderer
* @author Mario Hüttel <mario.huettel@gmx.net>
*/
#ifndef _CAIRO_OUTPUT_H_
#define _CAIRO_OUTPUT_H_
#include <gds-render/gds-utils/gds-types.h>
#include <gds-render/output-renderers/gds-output-renderer.h>
#include <glib-object.h>
G_BEGIN_DECLS
/** @addtogroup Cairo-Renderer
* @{
*/
G_DECLARE_FINAL_TYPE(CairoRenderer, cairo_renderer, GDS_RENDER, CAIRO_RENDERER, GdsOutputRenderer)
#define GDS_RENDER_TYPE_CAIRO_RENDERER (cairo_renderer_get_type())
#define MAX_LAYERS (300) /**< \brief Maximum layer count the output renderer can process. Typically GDS only specifies up to 255 layers.*/
/**
* @brief Create new CairoRenderer for SVG output
* @return New object
*/
CairoRenderer *cairo_renderer_new_svg();
/**
* @brief Create new CairoRenderer for PDF output
* @return New object
*/
CairoRenderer *cairo_renderer_new_pdf();
/** @} */
G_END_DECLS
#endif /* _CAIRO_OUTPUT_H_ */

View File

@@ -0,0 +1,57 @@
#ifndef __EXTERNAL_RENDERER_INTERFACES_H__
#define __EXTERNAL_RENDERER_INTERFACES_H__
#ifndef xstr
#define xstr(a) str(a)
#define str(a) #a
#endif /* xstr */
/**
* @addtogroup ExternalRenderer
* @{
*/
/**
* @brief This define is used to export a function from a shared object
*/
#define EXPORT_FUNC __attribute__((visibility("default")))
/**
* @brief Function name expected to be found in external library for rendering.
*
* The function has to be defined as follows:
* @code
* int EXTERNAL_LIBRARY_RENDER_FUNCTION(struct gds_cell *toplevel, GList *layer_info_list, const char *output_file_name, double scale);
* @endcode
*/
#define EXTERNAL_LIBRARY_RENDER_FUNCTION exported_render_cell_to_file
/**
* @brief Function name expected to be found in external library for initialization.
*
* @code
* int EXTERNAL_LIBRARY_INIT_FUNCTION(const char *option_string, const char *version_string);
* @endcode
*/
#define EXTERNAL_LIBRARY_INIT_FUNCTION exported_init
/**
* @brief Global integer specified by an external renderer to signal, that the init and render functions shall be executed in a subprocess
*
* The pure presence of this symbol name causes forking. The content of this variable is don't care.
* @note Use this if you mess with the internal structures of gds-render
*/
#define EXTERNAL_LIBRARY_FORK_REQUEST exported_fork_request
/**
* @brief Define for declaring the exported functions.
*
* This not only helps with the declaration but also makes the symbols visible, so they can be called form outside the library
*/
#define EXPORTED_FUNC_DECL(FUNC) EXPORT_FUNC FUNC
/** @} */
#endif /* __EXTERNAL_RENDERER_INTERFACES_H__ */

View File

@@ -0,0 +1,62 @@
/*
* 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 ExternalRenderer
* @{
*/
#ifndef _EXTERNAL_RENDERER_H_
#define _EXTERNAL_RENDERER_H_
#include <gds-render/output-renderers/gds-output-renderer.h>
#include <gds-render/gds-utils/gds-types.h>
#include <gds-render/output-renderers/external-renderer-interfaces.h>
G_BEGIN_DECLS
#define GDS_RENDER_TYPE_EXTERNAL_RENDERER (external_renderer_get_type())
G_DECLARE_FINAL_TYPE(ExternalRenderer, external_renderer, GDS_RENDER, EXTERNAL_RENDERER, GdsOutputRenderer)
/**
* @brief Create new ExternalRenderer object
* @return New object
*/
ExternalRenderer *external_renderer_new();
/**
* @brief Create new ExternalRenderer object with specified shared object path
* @param so_path Path to shared object, the rendering function is searched in
* @param param_string Command line parameter string passed to external renderer
* @return New object.
*/
ExternalRenderer *external_renderer_new_with_so_and_param(const char *so_path, const char *param_string);
G_END_DECLS
#endif /* _EXTERNAL_RENDERER_H_ */
/** @} */

View File

@@ -0,0 +1,161 @@
/*
* GDSII-Converter
* Copyright (C) 2018 Mario Hüttel <mario.huettel@gmx.net>
*
* This file is part of GDSII-Converter.
*
* GDSII-Converter is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*
* GDSII-Converter is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with GDSII-Converter. If not, see <http://www.gnu.org/licenses/>.
*/
/**
* @file gds-output-renderer.h
* @brief Header for output renderer base class
* @author Mario Hüttel <mario.huettel@gmx.net>
*/
/**
* @addtogroup GdsOutputRenderer
* @{
*/
#ifndef _GDS_OUTPUT_RENDERER_H_
#define _GDS_OUTPUT_RENDERER_H_
#include <gds-render/gds-utils/gds-types.h>
#include <glib-object.h>
#include <glib.h>
#include <gds-render/layer/layer-settings.h>
G_BEGIN_DECLS
#define GDS_RENDER_TYPE_OUTPUT_RENDERER (gds_output_renderer_get_type())
G_DECLARE_DERIVABLE_TYPE(GdsOutputRenderer, gds_output_renderer, GDS_RENDER, OUTPUT_RENDERER, GObject);
/**
* @brief Base output renderer class structure.
* @note This structure is only used for internal inheritance of GObjects. Do not use in code outside of these classes.
*/
struct _GdsOutputRendererClass {
GObjectClass parent_class;
/**
* @brief Virtual render output function. Overwritten by final class implementation
*/
int (*render_output)(GdsOutputRenderer *renderer,
struct gds_cell *cell,
double scale);
gpointer padding[4];
};
enum {
GDS_OUTPUT_RENDERER_GEN_ERR = -100, /**< @brief Error set by the _GdsOutputRendererClass::render_output virtual function, if renderer is invalid. */
GDS_OUTPUT_RENDERER_PARAM_ERR = -200 /**< @brief Error set by the _GdsOutputRendererClass::render_output virtual function, if parameters are faulty. */
};
/**
* @brief Create a new GdsOutputRenderer GObject.
* @return New object
*/
GdsOutputRenderer *gds_output_renderer_new();
/**
* @brief Create a new GdsOutputRenderer GObject with its properties
* @param output_file Output file of the renderer
* @param layer_settings Layer settings object
* @return New object
*/
GdsOutputRenderer *gds_output_renderer_new_with_props(const char *output_file, LayerSettings *layer_settings);
/**
* @brief gds_output_renderer_render_output
* @param renderer Renderer object
* @param cell Cell to render
* @param scale scale value. The output is scaled *down* by this value
* @return 0 if successful
*/
int gds_output_renderer_render_output(GdsOutputRenderer *renderer,
struct gds_cell *cell,
double scale);
/**
* @brief Convenience function for setting the "output-file" property
* @param renderer Renderer object
* @param file_name Output file path
*/
void gds_output_renderer_set_output_file(GdsOutputRenderer *renderer, const gchar *file_name);
/**
* @brief Convenience function for getting the "output-file" property
* @param renderer
* @return Output file path. This must not be freed
*/
const char *gds_output_renderer_get_output_file(GdsOutputRenderer *renderer);
/**
* @brief Get layer settings
*
* This is a convenience function for getting the
* "layer-settings" property. This also references it.
* This is to prevent race conditions with another thread that might
* alter the layer settings before they are read out.
*
* @param renderer Renderer
* @return Layer settings object
*/
LayerSettings *gds_output_renderer_get_and_ref_layer_settings(GdsOutputRenderer *renderer);
/**
* @brief Set layer settings
*
* This is a convenience function for setting the
* "layer-settings" property.
*
* If another Layer settings has previously been supplied,
* it is unref'd.
*
* @param renderer Renderer
* @param settings LayerSettings object
*/
void gds_output_renderer_set_layer_settings(GdsOutputRenderer *renderer, LayerSettings *settings);
/**
* @brief Render output asynchronously
*
* This function will render in a separate thread.
* To wait for the completion of the rendering process.
*
* @note A second async thread cannot be spawned.
*
* @param renderer Output renderer
* @param cell Cell to render
* @param scale Scale
* @return 0 if successful. In case no thread can be spawned < 0
*/
int gds_output_renderer_render_output_async(GdsOutputRenderer *renderer, struct gds_cell *cell, double scale);
/**
* @brief This function emits the 'progress-changed' in the thread/context that triggered an asynchronous rendering
*
* If the rendering is not asynchronous, this function has no effect.
*
* @param renderer GdsOutputrenderer object
* @param status Status to supply to signal emission
*/
void gds_output_renderer_update_async_progress(GdsOutputRenderer *renderer, const char *status);
G_END_DECLS
#endif /* _GDS_OUTPUT_RENDERER_H_ */
/** @} */

View File

@@ -0,0 +1,74 @@
/*
* GDSII-Converter
* Copyright (C) 2018 Mario Hüttel <mario.huettel@gmx.net>
*
* This file is part of GDSII-Converter.
*
* GDSII-Converter is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*
* GDSII-Converter is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with GDSII-Converter. If not, see <http://www.gnu.org/licenses/>.
*/
/**
* @file latex-renderer.h
* @brief LaTeX output renderer
* @author Mario Hüttel <mario.huettel@gmx.net>
*/
/**
* @addtogroup LaTeX-Renderer
* @{
*/
#ifndef _LATEX_OUTPUT_H_
#define _LATEX_OUTPUT_H_
#include <gds-render/output-renderers/gds-output-renderer.h>
#include <gds-render/gds-utils/gds-types.h>
G_BEGIN_DECLS
G_DECLARE_FINAL_TYPE(LatexRenderer, latex_renderer, GDS_RENDER, LATEX_RENDERER, GdsOutputRenderer)
#define GDS_RENDER_TYPE_LATEX_RENDERER (latex_renderer_get_type())
/**
* @brief Buffer for LaTeX Code line in KiB
*/
#define LATEX_LINE_BUFFER_KB (10)
/**
* @brief Create new LatexRenderer object
* @return New object
*/
LatexRenderer *latex_renderer_new();
/**
* @brief Create new LatexRenderer object
*
* This function sets the 'pdf-layers' and 'standalone'
* properties for the newly created object.
*
* They can later be changes by modifying the properties again.
* On top of that, The options can be changed in the resulting
* LaTeX output file if needed.
*
* @param pdf_layers If PDF OCR layers should be enabled
* @param standalone If output TeX file should be standalone compilable
* @return New object
*/
LatexRenderer *latex_renderer_new_with_options(gboolean pdf_layers, gboolean standalone);
G_END_DECLS
#endif /* _LATEX_OUTPUT_H_ */
/** @} */

View File

@@ -17,13 +17,14 @@
* along with GDSII-Converter. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef __GDSPARSE_H__
#define __GDSPARSE_H__
/**
* @addtogroup version
* @{
*/
#include <glib.h>
#include "gds-types.h"
/** @brief This string holds the @ref git-version-num of the app */
extern const char *_app_version_string;
int parse_gds_from_file(const char *filename, GList **library_array);
int clear_lib_list(GList **library_list);
#endif /* __GDSPARSE_H__ */
/** @brief This string holds the git commit hash of the current HEAD revision */
extern const char *_app_git_commit;
/** @} */

View File

@@ -0,0 +1,68 @@
/*
* GDSII-Converter
* Copyright (C) 2019 Mario Hüttel <mario.huettel@gmx.net>
*
* This file is part of GDSII-Converter.
*
* GDSII-Converter is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*
* GDSII-Converter is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with GDSII-Converter. If not, see <http://www.gnu.org/licenses/>.
*/
/**
* @file activity-bar.h
* @brief Header file for activity bar widget
* @author Mario Hüttel <mario.huettel@gmx.net>
*/
/**
* @addtogroup ActivityBar
* @ingroup Widgets
* @{
*/
#ifndef __LAYER_ELEMENT_H__
#define __LAYER_ELEMENT_H__
#include <gtk/gtk.h>
G_BEGIN_DECLS
/* Creates Class structure etc */
G_DECLARE_FINAL_TYPE(ActivityBar, activity_bar, ACTIVITY, BAR, GtkBox)
#define TYPE_ACTIVITY_BAR (activity_bar_get_type())
/**
* @brief Create new Object ActivityBar
* @return New object. In case of error: NULL.
*/
ActivityBar *activity_bar_new();
/**
* @brief Deletes all applied tasks and sets bar to "Ready".
* @param[in] bar AcitivityBar object.
*/
void activity_bar_set_ready(ActivityBar *bar);
/**
* @brief Enable spinner and set \p text. If text is NULL, 'Working...' is displayed
* @param bar Activity bar object
* @param text Text to display, may be NULL
*/
void activity_bar_set_busy(ActivityBar *bar, const char *text);
G_END_DECLS
#endif /* __LAYER_ELEMENT_H__ */
/** @} */

View File

@@ -0,0 +1,102 @@
/*
* 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 conv-settings-dialog.h
* @brief Header file for the Conversion Settings Dialog
* @author Mario.Huettel@gmx.net <mario.huettel@gmx.net>
*/
/**
* @addtogroup RendererSettingsDialog
* @ingroup Widgets
* @{
*/
#ifndef __CONV_SETTINGS_DIALOG_H__
#define __CONV_SETTINGS_DIALOG_H__
#include <gtk/gtk.h>
G_BEGIN_DECLS
/** @brief return type of the RedererSettingsDialog */
enum output_renderer {RENDERER_LATEX_TIKZ, RENDERER_CAIROGRAPHICS_PDF, RENDERER_CAIROGRAPHICS_SVG};
G_DECLARE_FINAL_TYPE(RendererSettingsDialog, renderer_settings_dialog, RENDERER, SETTINGS_DIALOG, GtkDialog)
/**
* @brief Create a new RedererSettingsDialog GObject
* @param parent Parent window
* @return Created dialog object
*/
RendererSettingsDialog *renderer_settings_dialog_new(GtkWindow *parent);
#define RENDERER_TYPE_SETTINGS_DIALOG (renderer_settings_dialog_get_type())
/**
* @brief This struct holds the renderer configuration
*/
struct render_settings {
double scale; /**< @brief Scale image down by this factor. @note Used to keep image in bound of maximum coordinate limit */
enum output_renderer renderer; /**< The renderer to use */
gboolean tex_pdf_layers; /**< Create OCG layers when rendering with TikZ */
gboolean tex_standalone; /**< Create a standalone compile TeX file */
};
G_END_DECLS
/**
* @brief Apply settings to dialog
* @param dialog
* @param settings
*/
void renderer_settings_dialog_set_settings(RendererSettingsDialog *dialog, struct render_settings *settings);
/**
* @brief Get the settings configured in the dialog
* @param dialog
* @param settings
*/
void renderer_settings_dialog_get_settings(RendererSettingsDialog *dialog, struct render_settings *settings);
/**
* @brief renderer_settings_dialog_set_cell_width Set width for rendered cell
* @param dialog
* @param width Width in database units
*/
void renderer_settings_dialog_set_cell_width(RendererSettingsDialog *dialog, unsigned int width);
/**
* @brief renderer_settings_dialog_set_cell_height Set height for rendered cell
* @param dialog
* @param height Height in database units
*/
void renderer_settings_dialog_set_cell_height(RendererSettingsDialog *dialog, unsigned int height);
/**
* @brief renderer_settings_dialog_set_database_unit_scale Set database scale
* @param dialog dialog element
* @param unit_in_meters Database unit in meters
*/
void renderer_settings_dialog_set_database_unit_scale(RendererSettingsDialog *dialog, double unit_in_meters);
#endif /* __CONV_SETTINGS_DIALOG_H__ */
/** @} */

View File

@@ -0,0 +1,149 @@
/*
* GDSII-Converter
* Copyright (C) 2018 Mario Hüttel <mario.huettel@gmx.net>
*
* This file is part of GDSII-Converter.
*
* GDSII-Converter is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*
* GDSII-Converter is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with GDSII-Converter. If not, see <http://www.gnu.org/licenses/>.
*/
/**
* @file layer-element.h
* @brief Implementation of the layer element used for configuring layer colors etc.
* @author Mario Hüttel <mario.huettel@gmx.net>
*/
/**
* @addtogroup LayerElement
* @ingroup Widgets
* @{
*/
#ifndef __LAYER_ELEMENT_H__
#define __LAYER_ELEMENT_H__
#include <gtk/gtk.h>
G_BEGIN_DECLS
/* Creates Class structure etc */
G_DECLARE_FINAL_TYPE(LayerElement, layer_element, LAYER, ELEMENT, GtkListBoxRow)
#define TYPE_LAYER_ELEMENT (layer_element_get_type())
typedef struct _LayerElementPriv {
GtkEntry *name;
GtkLabel *layer;
int layer_num;
GtkEventBox *event_handle;
GtkColorButton *color;
GtkCheckButton *export;
} LayerElementPriv;
struct _LayerElement {
/* Inheritance */
GtkListBoxRow parent;
/* Custom Elements */
LayerElementPriv priv;
};
/**
* @brief This structure holds the necessary data to set up a LayerElement for Drag'n'Drop
*/
struct layer_element_dnd_data {
/** @brief Array of target entries for the DnD operation */
GtkTargetEntry *entries;
/** @brief Count of elements in layer_element_dnd_data::entries array */
int entry_count;
/** @brief Callback function for drag_begin event */
void (*drag_begin)(GtkWidget *, GdkDragContext *, gpointer);
/** @brief Callback fucktion for data_get event */
void (*drag_data_get)(GtkWidget *, GdkDragContext *, GtkSelectionData *, guint, guint, gpointer);
/** @brief Callback function for drag_end event */
void (*drag_end)(GtkWidget *, GdkDragContext *, gpointer);
};
/**
* @brief Create new layer element object
* @return new object
*/
GtkWidget *layer_element_new(void);
/**
* @brief get name of the layer
* @param elem Layer element
* @return Name. Must not be changed, freed or anything else.
*/
const char *layer_element_get_name(LayerElement *elem);
/**
* @brief layer_element_set_name
* @param elem set the name of the layer
* @param name Name. Can be freed after call to this function
*/
void layer_element_set_name(LayerElement *elem, const char* name);
/**
* @brief Set layer number for this layer
* @param elem Layer element
* @param layer Layer number
*/
void layer_element_set_layer(LayerElement *elem, int layer);
/**
* @brief Get layer number
* @param elem Layer Element
* @return Number of this layer
*/
int layer_element_get_layer(LayerElement *elem);
/**
* @brief Set export flag for this layer
* @param elem Layer Element
* @param export flag
*/
void layer_element_set_export(LayerElement *elem, gboolean export);
/**
* @brief Get export flag of layer
* @param elem Layer Element
* @return
*/
gboolean layer_element_get_export(LayerElement *elem);
/**
* @brief Get color of layer
* @param elem Layer Element
* @param rgba RGBA color
*/
void layer_element_get_color(LayerElement *elem, GdkRGBA *rgba);
/**
* @brief Set color of layer
* @param elem Layer Element
* @param rgba RGBA color
*/
void layer_element_set_color(LayerElement *elem, GdkRGBA *rgba);
/**
* @brief Setup drag and drop of \p elem for use in the LayerSelector
* @param elem Layer element to set up
* @param data Data array containing the necessary callbacks etc. for drag and drop.
*/
void layer_element_set_dnd_callbacks(LayerElement *elem, struct layer_element_dnd_data *data);
G_END_DECLS
#endif /* __LAYER_ELEMENT_H__ */
/** @} */

View File

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

View File

@@ -1,436 +0,0 @@
/*
* GDSII-Converter
* Copyright (C) 2018 Mario Hüttel <mario.huettel@gmx.net>
*
* This file is part of GDSII-Converter.
*
* GDSII-Converter is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*
* GDSII-Converter is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with GDSII-Converter. If not, see <http://www.gnu.org/licenses/>.
*/
#include "layer-selector.h"
#include "gds-parser/gds-parser.h"
#include "layer-widget/layer-element.h"
#include <glib.h>
#include <string.h>
#include <stdio.h>
#include <stdlib.h>
static GtkWidget *global_load_button;
static GtkWidget *global_save_button;
static GtkListBox *global_list_box;
void delete_layer_info_struct(struct layer_info *info)
{
if (info)
free(info);
}
/**
* @brief export_rendered_layer_info
* @return new list with all info elements needed to render cells
*/
GList *export_rendered_layer_info()
{
GList *info_list = NULL;
LayerElement *le;
struct layer_info *linfo;
GList *row_list;
GList *temp;
int i;
row_list = gtk_container_get_children(GTK_CONTAINER(global_list_box));
/* Iterate through widgets and add layers that shall be exported */
for (i = 0, temp = row_list; temp != NULL; temp = temp->next, i++) {
le = LAYER_ELEMENT(temp->data);
if (layer_element_get_export(le) == TRUE) {
/* Allocate new info and fill with info */
linfo = (struct layer_info *)malloc(sizeof(struct layer_info));
layer_element_get_color(le, &linfo->color);
linfo->layer = layer_element_get_layer(le);
linfo->stacked_position = i;
linfo->name = (char *)layer_element_get_name(le);
/* Append to list */
info_list = g_list_append(info_list, (gpointer)linfo);
}
}
return info_list;
}
void clear_list_box_widgets(GtkListBox *box)
{
GList *list;
GList *temp;
list = gtk_container_get_children(GTK_CONTAINER(box));
for (temp = list; temp != NULL; temp = temp->next) {
gtk_container_remove(GTK_CONTAINER(box), GTK_WIDGET(temp->data));
}
/* Widgets are already destroyed when removed from box because they are only referenced inside the container */
g_list_free(list);
/* Deactivate buttons */
gtk_widget_set_sensitive(global_load_button, FALSE);
gtk_widget_set_sensitive(global_save_button, FALSE);
}
static gboolean check_if_layer_widget_exists(int layer) {
GList *list;
GList *temp;
LayerElement *widget;
gboolean ret = FALSE;
list = gtk_container_get_children(GTK_CONTAINER(global_list_box));
for (temp = list; temp != NULL; temp = temp->next) {
widget = LAYER_ELEMENT(temp->data);
if (layer_element_get_layer(widget) == layer) {
ret = TRUE;
break;
}
}
g_list_free(list);
return ret;
}
static void analyze_cell_layers(GtkListBox *listbox, struct gds_cell *cell)
{
GList *graphics;
struct gds_graphics *gfx;
int layer;
GtkWidget *le;
for (graphics = cell->graphic_objs; graphics != NULL; graphics = graphics->next) {
gfx = (struct gds_graphics *)graphics->data;
layer = (int)gfx->layer;
if (check_if_layer_widget_exists(layer) == FALSE) {
le = layer_element_new();
layer_element_set_layer(LAYER_ELEMENT(le), layer);
gtk_list_box_insert(listbox, le, -1);
gtk_widget_show(le);
}
}
}
gint sort_func(GtkListBoxRow *row1, GtkListBoxRow *row2, gpointer unused)
{
LayerElement *le1, *le2;
gint ret;
le1 = LAYER_ELEMENT(row1);
le2 = LAYER_ELEMENT(row2);
ret = layer_element_get_layer(le1) - layer_element_get_layer(le2);
return ret;
}
void generate_layer_widgets(GtkListBox *listbox, GList *libs)
{
GList *cell_list = NULL;
struct gds_library *lib;
global_list_box = listbox;
clear_list_box_widgets(listbox);
gtk_list_box_set_sort_func(listbox, sort_func, NULL, NULL);
for (; libs != NULL; libs = libs->next) {
lib = (struct gds_library *)libs->data;
for (cell_list = lib->cells; cell_list != NULL; cell_list = cell_list->next) {
analyze_cell_layers(listbox, (struct gds_cell *)cell_list->data);
} /* For Cell List */
} /* For libs */
/* Force sort */
gtk_list_box_invalidate_sort(listbox);
/* Disable sort, so user can sort layers */
gtk_list_box_set_sort_func(listbox, NULL, NULL, NULL);
/* Activate Buttons */
gtk_widget_set_sensitive(global_load_button, TRUE);
gtk_widget_set_sensitive(global_save_button, TRUE);
}
/**
* @brief load_csv_line
* @param file
* @param export
* @param name
* @param layer
* @param color
* @param opacity
* @return 0 if succesfull, 1 if line was malformatted or parameters are broken, -1 if file end
*/
static int load_csv_line(GDataInputStream *stream, gboolean *export, char **name, int *layer, GdkRGBA *color)
{
int ret;
gsize len;
gchar *line;
GRegex *regex;
GMatchInfo *mi;
char *match;
if ((!export) || (!name) || (!layer) || (!color)) {
ret = 1;
goto ret_direct;
}
regex = g_regex_new("^(?<layer>[0-9]+),(?<r>[0-9\\.]+),(?<g>[0-9\\.]+),(?<b>[0-9\\.]+),(?<a>[0-9\\.]+),(?<export>[01]),(?<name>.*)$", 0, 0, NULL);
line = g_data_input_stream_read_line(stream, &len, NULL, NULL);
if (!line) {
ret = -1;
goto destroy_regex;
}
/* Match line in CSV */
g_regex_match(regex, line, 0, &mi);
if (g_match_info_matches(mi)) {
/* Line is valid */
match = g_match_info_fetch_named(mi, "layer");
*layer = (int)g_ascii_strtoll(match, NULL, 10);
g_free(match);
match = g_match_info_fetch_named(mi, "r");
color->red = g_ascii_strtod(match, NULL);
g_free(match);
match = g_match_info_fetch_named(mi, "g");
color->green = g_ascii_strtod(match, NULL);
g_free(match);
match = g_match_info_fetch_named(mi, "b");
color->blue = g_ascii_strtod(match, NULL);
g_free(match);
match = g_match_info_fetch_named(mi, "a");
color->alpha = g_ascii_strtod(match, NULL);
g_free(match);
match = g_match_info_fetch_named(mi, "export");
*export = ((!strcmp(match, "1")) ? TRUE : FALSE);
g_free(match);
match = g_match_info_fetch_named(mi, "name");
*name = match;
ret = 0;
} else {
/* Line is malformatted */
printf("Could not recognize line in CSV as valid entry: %s\n", line);
ret = 1;
}
g_match_info_free(mi);
g_free(line);
destroy_regex:
g_regex_unref(regex);
ret_direct:
return ret;
}
static LayerElement *find_layer_element_in_list(GList *el_list, int layer)
{
LayerElement *ret = NULL;
for (; el_list != NULL; el_list = el_list->next) {
if (layer_element_get_layer(LAYER_ELEMENT(el_list->data)) == layer) {
ret = LAYER_ELEMENT(el_list->data);
break;
}
}
return ret;
}
static void load_layer_mapping_from_file(gchar *file_name)
{
GFile *file;
GFileInputStream *stream;
GDataInputStream *dstream;
LayerElement *le;
char *name;
gboolean export;
int layer;
GdkRGBA color;
int result;
GList *rows;
GList *temp;
file = g_file_new_for_path(file_name);
stream = g_file_read(file, NULL, NULL);
if (!stream)
goto destroy_file;
dstream = g_data_input_stream_new(G_INPUT_STREAM(stream));
rows = gtk_container_get_children(GTK_CONTAINER(global_list_box));
/* Reference and remove all rows from box */
for (temp = rows; temp != NULL; temp = temp->next) {
le = LAYER_ELEMENT(temp->data);
/* Referencing protets the widget from being deleted when removed */
g_object_ref(G_OBJECT(le));
gtk_container_remove(GTK_CONTAINER(global_list_box), GTK_WIDGET(le));
}
while((result = load_csv_line(dstream, &export, &name, &layer, &color)) >= 0) {
/* skip broken line */
if (result == 1)
continue;
/* Add rows in the same order as in file */
if ((le = find_layer_element_in_list(rows, layer))) {
gtk_list_box_insert(global_list_box, GTK_WIDGET(le), -1);
layer_element_set_color(le, &color);
layer_element_set_export(le, export);
layer_element_set_name(le, name);
g_free(name);
/* Dereference and remove from list */
g_object_unref(G_OBJECT(le));
rows = g_list_remove(rows, le);
}
}
/* Add remaining elements */
for (temp = rows; temp != NULL; temp = temp->next) {
le = LAYER_ELEMENT(temp->data);
/* Referencing protets the widget from being deleted when removed */
gtk_list_box_insert(global_list_box, GTK_WIDGET(le), -1);
g_object_unref(G_OBJECT(le));
}
/* Delete list */
g_list_free(rows);
/* read line */
g_object_unref(dstream);
g_object_unref(stream);
destroy_file:
g_object_unref(file);
}
static void load_mapping_clicked(GtkWidget *button, gpointer user_data)
{
GtkWidget *dialog;
gint res;
gchar *file_name;
dialog = gtk_file_chooser_dialog_new("Load Mapping File", GTK_WINDOW(user_data), GTK_FILE_CHOOSER_ACTION_OPEN,
"Cancel", GTK_RESPONSE_CANCEL, "Load Mapping", GTK_RESPONSE_ACCEPT, NULL);
res = gtk_dialog_run(GTK_DIALOG(dialog));
if (res == GTK_RESPONSE_ACCEPT) {
file_name = gtk_file_chooser_get_filename(GTK_FILE_CHOOSER(dialog));
load_layer_mapping_from_file(file_name);
g_free(file_name);
}
gtk_widget_destroy(dialog);
}
static void create_csv_line(LayerElement *layer_element, char *line_buffer, size_t max_len)
{
GString *string;
gboolean export;
const gchar *name;
int layer;
GdkRGBA color;
string = g_string_new_len(NULL, max_len-1);
/* Extract values */
export = layer_element_get_export(layer_element);
name = (const gchar*)layer_element_get_name(layer_element);
layer = layer_element_get_layer(layer_element);
layer_element_get_color(layer_element, &color);
/* print values to line */
g_string_printf(string, "%d,%lf,%lf,%lf,%lf,%d,%s\n",
layer, color.red, color.green,
color.blue, color.alpha, (export == TRUE ? 1 : 0), name);
if (string->len > (max_len-1)) {
printf("Layer Definition too long. Please shorten Layer Name!!\n");
line_buffer[0] = 0x0;
return;
}
/* copy max_len bytes of string */
strncpy(line_buffer, (char *)string->str, max_len-1);
line_buffer[max_len-1] = 0;
/* Completely remove string */
g_string_free(string, TRUE);
}
static void save_layer_mapping_data(const gchar *file_name, GtkListBox *list_box)
{
FILE *file;
char workbuff[512];
GList *le_list;
GList *temp;
/* Overwrite existing file */
file = fopen((const char *)file_name, "w");
le_list = gtk_container_get_children(GTK_CONTAINER(list_box));
/* File format is CSV: <Layer>,<target_pos>,<R>,<G>,<B>,<Alpha>,<Export?>,<Name> */
for (temp = le_list; temp != NULL; temp = temp->next) {
/* To be sure it is a valid string */
workbuff[0] = 0;
create_csv_line(LAYER_ELEMENT(temp->data), workbuff, sizeof(workbuff));
fwrite(workbuff, sizeof(char), strlen(workbuff), file);
}
g_list_free(le_list);
/* Save File */
fflush(file);
fclose(file);
}
static void save_mapping_clicked(GtkWidget *button, gpointer user_data)
{
GtkWidget *dialog;
gint res;
gchar *file_name;
dialog = gtk_file_chooser_dialog_new("Save Mapping File", GTK_WINDOW(user_data), GTK_FILE_CHOOSER_ACTION_SAVE,
"Cancel", GTK_RESPONSE_CANCEL, "Save Mapping", GTK_RESPONSE_ACCEPT, NULL);
res = gtk_dialog_run(GTK_DIALOG(dialog));
if (res == GTK_RESPONSE_ACCEPT) {
file_name = gtk_file_chooser_get_filename(GTK_FILE_CHOOSER(dialog));
save_layer_mapping_data(file_name, global_list_box);
g_free(file_name);
}
gtk_widget_destroy(dialog);
}
void setup_load_mapping_callback(GtkWidget *button, GtkWindow *main_window)
{
g_object_ref(G_OBJECT(button));
global_load_button = button;
g_signal_connect(button, "clicked", G_CALLBACK(load_mapping_clicked), main_window);
}
void setup_save_mapping_callback(GtkWidget *button, GtkWindow *main_window)
{
g_object_ref(G_OBJECT(button));
global_save_button = button;
g_signal_connect(button, "clicked", G_CALLBACK(save_mapping_clicked), main_window);
}

View File

@@ -1,61 +0,0 @@
/*
* GDSII-Converter
* Copyright (C) 2018 Mario Hüttel <mario.huettel@gmx.net>
*
* This file is part of GDSII-Converter.
*
* GDSII-Converter is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*
* GDSII-Converter is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with GDSII-Converter. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef __LAYER_ELEMENT_H__
#define __LAYER_ELEMENT_H__
#include <gtk/gtk.h>
G_BEGIN_DECLS
/* Creates Class structure etc */
G_DECLARE_FINAL_TYPE(LayerElement, layer_element, LAYER, ELEMENT, GtkListBoxRow)
#define TYPE_LAYER_ELEMENT (layer_element_get_type())
typedef struct _LayerElementPriv {
GtkEntry *name;
GtkLabel *layer;
int layer_num;
GtkEventBox *event_handle;
GtkColorButton *color;
GtkCheckButton *export;
} LayerElementPriv;
typedef struct _LayerElement {
/* Inheritance */
GtkListBoxRow parent;
/* Custom Elements */
LayerElementPriv priv;
} LayerElement;
GtkWidget *layer_element_new(void);
const char *layer_element_get_name(LayerElement *elem);
void layer_element_set_name(LayerElement *elem, const char* name);
void layer_element_set_layer(LayerElement *elem, int layer);
int layer_element_get_layer(LayerElement *elem);
void layer_element_set_export(LayerElement *elem, gboolean export);
gboolean layer_element_get_export(LayerElement *elem);
void layer_element_get_color(LayerElement *elem, GdkRGBA *rgba);
void layer_element_set_color(LayerElement *elem, GdkRGBA *rgba);
G_END_DECLS
#endif /* __LAYER_ELEMENT_H__ */

259
layer/color-palette.c Normal file
View File

@@ -0,0 +1,259 @@
/*
* GDSII-Converter
* Copyright (C) 2019 Mario Hüttel <mario.huettel@gmx.net>
*
* This file is part of GDSII-Converter.
*
* GDSII-Converter is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*
* GDSII-Converter is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with GDSII-Converter. If not, see <http://www.gnu.org/licenses/>.
*/
/**
* @file color-palette.c
* @brief Class representing a color palette
* @author Mario Hüttel <mario.huettel@gmx.net>
*/
#include <gds-render/layer/color-palette.h>
struct _ColorPalette {
/* Inheritance */
GObject parent;
/* Custom fields */
/** @brief The internal array to store the colors */
GdkRGBA *color_array;
/** @brief The length of the _ColorPalette::color_array array */
unsigned int color_array_length;
/* Dummy bytes to ensure ABI compatibility in future versions */
gpointer dummy[4];
};
G_DEFINE_TYPE(ColorPalette, color_palette, G_TYPE_OBJECT)
/**
* @brief Return the number of non empty lines in array
*
* This function returns the number of non empty lines in an
* array. The scanning is either terminated by the given length
* or if a \0 terminator is found.
*
* @param[in] data Array to count lines in
* @param[in] length Length of \p data
* @return < 0: Error, >=0: Lines
*/
static int count_non_empty_lines_in_array(const char *data, size_t length)
{
unsigned int idx;
int non_empty_lines = 0;
char last_char = '\n';
if (!data)
return -1;
/* Count each '\n' as a new line if it is not directly preceded by another '\n' */
for (idx = 0; idx < length && data[idx]; idx++) {
if (data[idx] == '\n' && last_char != '\n')
non_empty_lines++;
last_char = data[idx];
}
/* Count the last line in case the data does not end with a '\n' */
if (data[idx-1] != '\n')
non_empty_lines++;
return non_empty_lines;
}
/**
* @brief color_palette_fill_with_resource
* @param palette
* @param resource_name
* @return 0 if successful
*/
static int color_palette_fill_with_resource(ColorPalette *palette, char *resource_name)
{
GBytes *data;
char line[10];
int line_idx;
unsigned int color_idx;
int idx;
const char *char_array;
gsize byte_count;
int lines;
GRegex *regex;
GMatchInfo *mi;
char *match;
if (!palette || !resource_name)
return -1;
data = g_resources_lookup_data(resource_name, 0, NULL);
if (!data)
return -2;
char_array = (const char *)g_bytes_get_data(data, &byte_count);
if (!char_array || !byte_count)
goto ret_unref_data;
/* Get maximum lenght of color palette, assuming all entries are valid */
lines = count_non_empty_lines_in_array(char_array, byte_count);
if (lines <= 0)
goto ret_unref_data;
palette->color_array = (GdkRGBA *)malloc(sizeof(GdkRGBA) * (unsigned int)lines);
/* Setup regex for hexadecimal RGB colors like 'A0CB3F' */
regex = g_regex_new("^(?<red>[0-9A-Fa-f][0-9A-Fa-f])(?<green>[0-9A-Fa-f][0-9A-Fa-f])(?<blue>[0-9A-Fa-f][0-9A-Fa-f])$",
0, 0, NULL);
/* Reset line */
line_idx = 0;
line[0] = '\0';
/* Set color index */
color_idx = 0;
/* interate over lines and match */
for (idx = 0 ; (unsigned int)idx < byte_count; idx++) {
/* Fillup line. */
line[line_idx] = char_array[idx];
/* If end of line/string is reached, process */
if (line[line_idx] == '\n' || line[line_idx] == '\0') {
line[line_idx] = '\0';
/* Match the line */
g_regex_match(regex, line, 0, &mi);
if (g_match_info_matches(mi) && color_idx < (unsigned int)lines) {
match = g_match_info_fetch_named(mi, "red");
palette->color_array[color_idx].red =
(double)g_ascii_strtoll(match, NULL, 16) / 255.0;
g_free(match);
match = g_match_info_fetch_named(mi, "green");
palette->color_array[color_idx].green =
(double)g_ascii_strtoll(match, NULL, 16) / 255.0;
g_free(match);
match = g_match_info_fetch_named(mi, "blue");
palette->color_array[color_idx].blue =
(double)g_ascii_strtoll(match, NULL, 16) / 255.0;
g_free(match);
/* Only RGB supported so far. Fix alpha channel to 1.0 */
palette->color_array[color_idx].alpha = 1.0;
color_idx++;
}
g_match_info_free(mi);
/* End of string */
if (char_array[idx] == '\0')
break;
line_idx = 0;
continue;
}
/* increment line index. If end is reached write all bytes to the line end.
* Line is longer than required for parsing. This ensures, that everything works as expected
*/
line_idx += ((unsigned int)line_idx < sizeof(line)-1 ? 1 : 0);
}
/* Data read; Shrink array in case of invalid lines */
palette->color_array = realloc(palette->color_array, (size_t)color_idx * sizeof(GdkRGBA));
palette->color_array_length = color_idx;
g_regex_unref(regex);
ret_unref_data:
g_bytes_unref(data);
return 0;
}
ColorPalette *color_palette_new_from_resource(char *resource_name)
{
ColorPalette *palette;
palette = GDS_RENDER_COLOR_PALETTE(g_object_new(TYPE_GDS_RENDER_COLOR_PALETTE, NULL));
if (palette)
(void)color_palette_fill_with_resource(palette, resource_name);
return palette;
}
GdkRGBA *color_palette_get_color(ColorPalette *palette, GdkRGBA *color, unsigned int index)
{
GdkRGBA *c = NULL;
if (!palette)
goto ret_c;
if (index >= palette->color_array_length)
goto ret_c;
if (color)
c = color;
else
c = (GdkRGBA *)malloc(sizeof(GdkRGBA));
/* Copy color */
c->red = palette->color_array[index].red;
c->green = palette->color_array[index].green;
c->blue = palette->color_array[index].blue;
c->alpha = palette->color_array[index].alpha;
ret_c:
return c;
}
unsigned int color_palette_get_color_count(ColorPalette *palette)
{
unsigned int return_val = 0;
if (palette)
return_val = palette->color_array_length;
return return_val;
}
static void color_palette_dispose(GObject *gobj)
{
ColorPalette *palette;
palette = GDS_RENDER_COLOR_PALETTE(gobj);
if (palette->color_array) {
palette->color_array_length = 0;
free(palette->color_array);
}
/* Chain up to parent class */
G_OBJECT_CLASS(color_palette_parent_class)->dispose(gobj);
}
static void color_palette_class_init(ColorPaletteClass *klass)
{
GObjectClass *gclass;
gclass = G_OBJECT_CLASS(klass);
gclass->dispose = color_palette_dispose;
}
static void color_palette_init(ColorPalette *self)
{
self->color_array = NULL;
self->color_array_length = 0;
}

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

@@ -0,0 +1,901 @@
/*
* GDSII-Converter
* Copyright (C) 2018 Mario Hüttel <mario.huettel@gmx.net>
*
* This file is part of GDSII-Converter.
*
* GDSII-Converter is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*
* GDSII-Converter is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with GDSII-Converter. If not, see <http://www.gnu.org/licenses/>.
*/
/**
* @file layer-selector.c
* @brief Implementation of the layer selector
* @author Mario Hüttel <mario.huettel@gmx.net>
*/
/**
* @addtogroup layer-selector
* @{
*/
#include <glib.h>
#include <string.h>
#include <stdio.h>
#include <stdlib.h>
#include <gds-render/layer/layer-selector.h>
#include <gds-render/gds-utils/gds-parser.h>
#include <gds-render/widgets/layer-element.h>
struct _LayerSelector {
/* Parent */
GObject parent;
/* Own fields */
GtkWidget *associated_load_button;
GtkWidget *associated_save_button;
GtkWindow *load_parent_window;
GtkWindow *save_parent_window;
GtkListBox *list_box;
GtkTargetEntry dnd_target;
gpointer dummy[4];
};
G_DEFINE_TYPE(LayerSelector, layer_selector, G_TYPE_OBJECT)
/*
* Drag and drop code
* Original code from https://blog.gtk.org/2017/06/01/drag-and-drop-in-lists-revisited/
*/
static void sel_layer_element_drag_begin(GtkWidget *widget, GdkDragContext *context, gpointer data)
{
GtkWidget *row;
GtkAllocation alloc;
cairo_surface_t *surface;
cairo_t *cr;
int x, y;
(void)data;
row = gtk_widget_get_ancestor(widget, GTK_TYPE_LIST_BOX_ROW);
gtk_widget_get_allocation(row, &alloc);
surface = cairo_image_surface_create(CAIRO_FORMAT_ARGB32, alloc.width, alloc.height);
cr = cairo_create(surface);
gtk_style_context_add_class(gtk_widget_get_style_context(row), "drag-icon");
gtk_widget_draw(row, cr);
gtk_style_context_remove_class(gtk_widget_get_style_context(row), "drag-icon");
gtk_widget_translate_coordinates(widget, row, 0, 0, &x, &y);
cairo_surface_set_device_offset(surface, -x, -y);
gtk_drag_set_icon_surface(context, surface);
cairo_destroy(cr);
cairo_surface_destroy(surface);
g_object_set_data(G_OBJECT(gtk_widget_get_parent(row)), "drag-row", row);
gtk_style_context_add_class(gtk_widget_get_style_context(row), "drag-row");
}
static void sel_layer_element_drag_end(GtkWidget *widget, GdkDragContext *context, gpointer data)
{
GtkWidget *row;
(void)context;
(void)data;
row = gtk_widget_get_ancestor(widget, GTK_TYPE_LIST_BOX_ROW);
g_object_set_data(G_OBJECT(gtk_widget_get_parent(row)), "drag-row", NULL);
gtk_style_context_remove_class(gtk_widget_get_style_context(row), "drag-row");
gtk_style_context_remove_class(gtk_widget_get_style_context(row), "drag-hover");
}
static void sel_layer_element_drag_data_get(GtkWidget *widget, GdkDragContext *context,
GtkSelectionData *selection_data,
guint info, guint time, gpointer data)
{
(void)context;
(void)info;
(void)time;
(void)data;
GdkAtom atom;
atom = gdk_atom_intern_static_string("GTK_LIST_BOX_ROW");
gtk_selection_data_set(selection_data, atom,
32, (const guchar *)&widget, sizeof(gpointer));
}
static GtkListBoxRow *layer_selector_get_last_row(GtkListBox *list)
{
int i;
GtkListBoxRow *row;
GtkListBoxRow *tmp;
row = NULL;
for (i = 0; ; i++) {
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;
/* Handle unused parameters */
(void)context;
(void)x;
(void)y;
(void)info;
(void)time;
(void)data;
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;
(void)context;
(void)x;
(void)y;
(void)time;
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;
(void)context;
(void)time;
drag_row = GTK_WIDGET(g_object_get_data(G_OBJECT(widget), "drag-row"));
row_before = GTK_WIDGET(g_object_get_data(G_OBJECT(widget), "row-before"));
row_after = GTK_WIDGET(g_object_get_data(G_OBJECT(widget), "row-after"));
gtk_style_context_remove_class(gtk_widget_get_style_context(drag_row), "drag-hover");
if (row_before)
gtk_style_context_remove_class(gtk_widget_get_style_context(row_before), "drag-hover-bottom");
if (row_after)
gtk_style_context_remove_class(gtk_widget_get_style_context(row_after), "drag-hover-top");
}
static const char *dnd_additional_css =
".row:not(:first-child) { "
" border-top: 1px solid alpha(gray,0.5); "
" border-bottom: 1px solid transparent; "
"}"
".row:first-child { "
" border-top: 1px solid transparent; "
" border-bottom: 1px solid transparent; "
"}"
".row:last-child { "
" border-top: 1px solid alpha(gray,0.5); "
" border-bottom: 1px solid alpha(gray,0.5); "
"}"
".row.drag-icon { "
" background: #282828; "
" border: 1px solid blue; "
"}"
".row.drag-row { "
" color: gray; "
" background: alpha(gray,0.2); "
"}"
".row.drag-row.drag-hover { "
" border-top: 1px solid #4e9a06; "
" border-bottom: 1px solid #4e9a06; "
"}"
".row.drag-hover image, "
".row.drag-hover label { "
" color: #4e9a06; "
"}"
".row.drag-hover-top {"
" border-top: 1px solid #4e9a06; "
"}"
".row.drag-hover-bottom {"
" border-bottom: 1px solid #4e9a06; "
"}";
static void layer_selector_dispose(GObject *self)
{
LayerSelector *sel = LAYER_SELECTOR(self);
g_clear_object(&sel->list_box);
g_clear_object(&sel->load_parent_window);
g_clear_object(&sel->save_parent_window);
g_clear_object(&sel->associated_load_button);
g_clear_object(&sel->associated_save_button);
if (sel->dnd_target.target) {
g_free(sel->dnd_target.target);
sel->dnd_target.target = NULL;
}
/* Chain up to parent's dispose function */
G_OBJECT_CLASS(layer_selector_parent_class)->dispose(self);
}
static void layer_selector_class_init(LayerSelectorClass *klass)
{
GObjectClass *object_class = G_OBJECT_CLASS(klass);
GtkCssProvider *provider;
/* Implement handles to virtual functions */
object_class->dispose = layer_selector_dispose;
/* Setup the CSS provider for the drag and drop animations once */
provider = gtk_css_provider_new();
gtk_css_provider_load_from_data(provider, dnd_additional_css, -1, NULL);
gtk_style_context_add_provider_for_screen(gdk_screen_get_default(), GTK_STYLE_PROVIDER(provider), 800);
g_object_unref(provider);
}
static void layer_selector_setup_dnd(LayerSelector *self)
{
gtk_drag_dest_set(GTK_WIDGET(self->list_box), GTK_DEST_DEFAULT_MOTION | GTK_DEST_DEFAULT_DROP,
&self->dnd_target, 1, GDK_ACTION_MOVE);
g_signal_connect(self->list_box, "drag-data-received", G_CALLBACK(layer_selector_drag_data_received), NULL);
g_signal_connect(self->list_box, "drag-motion", G_CALLBACK(layer_selector_drag_motion), NULL);
g_signal_connect(self->list_box, "drag-leave", G_CALLBACK(layer_selector_drag_leave), NULL);
}
/* Drag and drop end */
static void layer_selector_init(LayerSelector *self)
{
self->load_parent_window = NULL;
self->save_parent_window = NULL;
self->associated_load_button = NULL;
self->associated_save_button = NULL;
self->dnd_target.target = g_strdup_printf("LAYER_SELECTOR_DND_%p", self);
self->dnd_target.info = 0;
self->dnd_target.flags = GTK_TARGET_SAME_APP;
}
LayerSelector *layer_selector_new(GtkListBox *list_box)
{
LayerSelector *selector;
if (GTK_IS_LIST_BOX(list_box) == FALSE)
return NULL;
selector = LAYER_SELECTOR(g_object_new(TYPE_LAYER_SELECTOR, NULL));
selector->list_box = list_box;
layer_selector_setup_dnd(selector);
g_object_ref(G_OBJECT(list_box));
return selector;
}
LayerSettings *layer_selector_export_rendered_layer_info(LayerSelector *selector)
{
LayerSettings *layer_settings;
struct layer_info linfo;
GList *row_list;
GList *iterator;
LayerElement *le;
int i;
layer_settings = layer_settings_new();
if (!layer_settings)
return NULL;
row_list = gtk_container_get_children(GTK_CONTAINER(selector->list_box));
for (i = 0, iterator = row_list; iterator != NULL; iterator = g_list_next(iterator), i++) {
le = LAYER_ELEMENT(iterator->data);
/* Get name from layer element. This must not be freed */
linfo.name = (char *)layer_element_get_name(le);
layer_element_get_color(le, &linfo.color);
linfo.render = (layer_element_get_export(le) ? 1 : 0);
linfo.stacked_position = i;
linfo.layer = layer_element_get_layer(le);
/* This function copies the entire layer info struct including the name string.
* Therefore, using the same layer_info struct over and over is safe.
*/
layer_settings_append_layer_info(layer_settings, &linfo);
}
return layer_settings;
}
static void layer_selector_clear_widgets(LayerSelector *self)
{
GList *list;
GList *temp;
list = gtk_container_get_children(GTK_CONTAINER(self->list_box));
for (temp = list; temp != NULL; temp = temp->next)
gtk_container_remove(GTK_CONTAINER(self->list_box), GTK_WIDGET(temp->data));
/* Widgets are already destroyed when removed from box because they are only referenced inside the container */
g_list_free(list);
/* Deactivate buttons */
if (self->associated_load_button)
gtk_widget_set_sensitive(self->associated_load_button, FALSE);
if (self->associated_save_button)
gtk_widget_set_sensitive(self->associated_save_button, FALSE);
}
/**
* @brief Check if a specific layer element with the given layer number is present in the layer selector
* @param self LayerSelector instance
* @param layer Layer number to check for
* @return TRUE if layer is present, else FALSE
*/
static gboolean layer_selector_check_if_layer_widget_exists(LayerSelector *self, int layer)
{
GList *list;
GList *temp;
LayerElement *widget;
gboolean ret = FALSE;
list = gtk_container_get_children(GTK_CONTAINER(self->list_box));
for (temp = list; temp != NULL; temp = temp->next) {
widget = LAYER_ELEMENT(temp->data);
if (layer_element_get_layer(widget) == layer) {
ret = TRUE;
break;
}
}
g_list_free(list);
return ret;
}
/**
* @brief Setup the necessary drag and drop callbacks of layer elements.
* @param self LayerSelector instance. Used to get the DnD target entry.
* @param element LayerElement instance to set the callbacks
*/
static void sel_layer_element_setup_dnd_callbacks(LayerSelector *self, LayerElement *element)
{
struct layer_element_dnd_data dnd_data;
if (!self || !element)
return;
dnd_data.entries = &self->dnd_target;
dnd_data.entry_count = 1;
dnd_data.drag_end = sel_layer_element_drag_end;
dnd_data.drag_begin = sel_layer_element_drag_begin;
dnd_data.drag_data_get = sel_layer_element_drag_data_get;
layer_element_set_dnd_callbacks(element, &dnd_data);
}
/**
* @brief Analyze \p cell layers and append detected layers to layer selector \p self
* @param self LayerSelector instance
* @param cell Cell to analyze
*/
static void layer_selector_analyze_cell_layers(LayerSelector *self, struct gds_cell *cell)
{
GList *graphics;
struct gds_graphics *gfx;
int layer;
GtkWidget *le;
for (graphics = cell->graphic_objs; graphics != NULL; graphics = graphics->next) {
gfx = (struct gds_graphics *)graphics->data;
layer = (int)gfx->layer;
if (layer_selector_check_if_layer_widget_exists(self, layer) == FALSE) {
le = layer_element_new();
sel_layer_element_setup_dnd_callbacks(self, LAYER_ELEMENT(le));
layer_element_set_layer(LAYER_ELEMENT(le), layer);
gtk_list_box_insert(self->list_box, le, -1);
gtk_widget_show(le);
}
}
}
/**
* @brief sort_func Sort callback for list box
* @param row1
* @param row2
* @param unused
* @note Do not use this function. This is an internal callback
* @return See sort function documentation of GTK+
*/
static gint layer_selector_sort_func(GtkListBoxRow *row1, GtkListBoxRow *row2, gpointer unused)
{
LayerElement *le1, *le2;
gint ret;
static const enum layer_selector_sort_algo default_sort = LAYER_SELECTOR_SORT_DOWN;
const enum layer_selector_sort_algo *algo = (const enum layer_selector_sort_algo *)unused;
/* Assume downward sorting */
/* TODO: This is nasty. Find a better way */
if (!algo)
algo = &default_sort;
le1 = LAYER_ELEMENT(row1);
le2 = LAYER_ELEMENT(row2);
/* Determine sort fow downward sort */
ret = layer_element_get_layer(le1) - layer_element_get_layer(le2);
/* Change order if upward sort is requested */
ret *= (*algo == LAYER_SELECTOR_SORT_DOWN ? 1 : -1);
return ret;
}
void layer_selector_generate_layer_widgets(LayerSelector *selector, GList *libs)
{
GList *cell_list = NULL;
struct gds_library *lib;
layer_selector_clear_widgets(selector);
for (; libs != NULL; libs = libs->next) {
lib = (struct gds_library *)libs->data;
for (cell_list = lib->cells; cell_list != NULL; cell_list = cell_list->next)
layer_selector_analyze_cell_layers(selector, (struct gds_cell *)cell_list->data);
} /* For libs */
/* Sort the layers */
layer_selector_force_sort(selector, LAYER_SELECTOR_SORT_DOWN);
/* Activate Buttons */
if (selector->associated_load_button)
gtk_widget_set_sensitive(selector->associated_load_button, TRUE);
if (selector->associated_save_button)
gtk_widget_set_sensitive(selector->associated_save_button, TRUE);
}
/**
* @brief Find LayerElement in list with specified layer number
* @param el_list List with elements of type LayerElement
* @param layer Layer number
* @return Found LayerElement. If nothing is found, NULL.
*/
static LayerElement *layer_selector_find_layer_element_in_list(GList *el_list, int layer)
{
LayerElement *ret = NULL;
for (; el_list != NULL; el_list = el_list->next) {
if (layer_element_get_layer(LAYER_ELEMENT(el_list->data)) == layer) {
ret = LAYER_ELEMENT(el_list->data);
break;
}
}
return ret;
}
/**
* @brief Load the layer mapping from a CSV formatted file
*
* This function imports the layer specification from a file (see @ref lmf-spec).
* The layer ordering defined in the file is kept. All layers present in the
* current loaded library, which are not present in the layer mapping file
* are appended at the end of the layer selector list.
*
* @param self LayerSelector instance
* @param file_name File name to load from
*/
static void layer_selector_load_layer_mapping_from_file(LayerSelector *self, const gchar *file_name)
{
GFile *file;
GFileInputStream *stream;
GDataInputStream *dstream;
LayerElement *le;
GList *rows;
GList *temp;
GList *layer_infos;
int status;
LayerSettings *layer_settings;
struct layer_info *linfo;
file = g_file_new_for_path(file_name);
stream = g_file_read(file, NULL, NULL);
if (!stream)
goto destroy_file;
dstream = g_data_input_stream_new(G_INPUT_STREAM(stream));
rows = gtk_container_get_children(GTK_CONTAINER(self->list_box));
/* Reference and remove all rows from box */
for (temp = rows; temp != NULL; temp = temp->next) {
le = LAYER_ELEMENT(temp->data);
/* Referencing protects the widget from being deleted when removed */
g_object_ref(G_OBJECT(le));
gtk_container_remove(GTK_CONTAINER(self->list_box), GTK_WIDGET(le));
}
/* Load Layer settings. No need to check pointer, will be checked by load csv func. */
layer_settings = layer_settings_new();
status = layer_settings_load_from_csv(layer_settings, file_name);
if (status)
goto abort_layer_settings;
layer_infos = layer_settings_get_layer_info_list(layer_settings);
if (!layer_infos)
goto abort_layer_settings;
/* Loop over all layer infos read from the CSV file */
for (; layer_infos; layer_infos = g_list_next(layer_infos)) {
linfo = (struct layer_info *)layer_infos->data;
le = layer_selector_find_layer_element_in_list(rows, linfo->layer);
if (!le)
continue;
layer_element_set_name(le, linfo->name);
layer_element_set_export(le, (linfo->render ? TRUE : FALSE));
layer_element_set_color(le, &linfo->color);
gtk_container_add(GTK_CONTAINER(self->list_box), GTK_WIDGET(le));
rows = g_list_remove(rows, le);
}
abort_layer_settings:
/* Destroy layer settings. Not needed for adding remaining elements */
g_object_unref(layer_settings);
/* Add remaining elements */
for (temp = rows; temp != NULL; temp = temp->next) {
le = LAYER_ELEMENT(temp->data);
/* Referencing protets the widget from being deleted when removed */
gtk_list_box_insert(self->list_box, GTK_WIDGET(le), -1);
g_object_unref(G_OBJECT(le));
}
/* Delete list */
g_list_free(rows);
/* read line */
g_object_unref(dstream);
g_object_unref(stream);
destroy_file:
g_object_unref(file);
}
/**
* @brief Callback for Load Mapping Button
* @param button
* @param user_data
*/
static void layer_selector_load_mapping_clicked(GtkWidget *button, gpointer user_data)
{
LayerSelector *sel;
GtkWidget *dialog;
gint res;
gchar *file_name;
(void)button;
sel = LAYER_SELECTOR(user_data);
dialog = gtk_file_chooser_dialog_new("Load Mapping File", GTK_WINDOW(sel->load_parent_window),
GTK_FILE_CHOOSER_ACTION_OPEN,
"Cancel", GTK_RESPONSE_CANCEL, "Load Mapping", GTK_RESPONSE_ACCEPT, NULL);
res = gtk_dialog_run(GTK_DIALOG(dialog));
if (res == GTK_RESPONSE_ACCEPT) {
file_name = gtk_file_chooser_get_filename(GTK_FILE_CHOOSER(dialog));
layer_selector_load_layer_mapping_from_file(sel, file_name);
g_free(file_name);
}
gtk_widget_destroy(dialog);
}
/**
* @brief Save layer mapping of selector \p self to a file
* @param self LayerSelector instance
* @param file_name File name to save to
*/
static void layer_selector_save_layer_mapping_data(LayerSelector *self, const gchar *file_name)
{
LayerSettings *layer_settings;
g_return_if_fail(LAYER_IS_SELECTOR(self));
g_return_if_fail(file_name);
/* Get layer settings. No need to check return value. to_csv func is safe */
layer_settings = layer_selector_export_rendered_layer_info(self);
(void)layer_settings_to_csv(layer_settings, file_name);
}
/**
* @brief Callback for Save Layer Mapping Button
* @param button
* @param user_data
*/
static void layer_selector_save_mapping_clicked(GtkWidget *button, gpointer user_data)
{
GtkWidget *dialog;
gint res;
gchar *file_name;
LayerSelector *sel;
(void)button;
sel = LAYER_SELECTOR(user_data);
dialog = gtk_file_chooser_dialog_new("Save Mapping File", GTK_WINDOW(sel->save_parent_window),
GTK_FILE_CHOOSER_ACTION_SAVE,
"Cancel", GTK_RESPONSE_CANCEL, "Save Mapping", GTK_RESPONSE_ACCEPT, NULL);
gtk_file_chooser_set_do_overwrite_confirmation(GTK_FILE_CHOOSER(dialog), TRUE);
res = gtk_dialog_run(GTK_DIALOG(dialog));
if (res == GTK_RESPONSE_ACCEPT) {
file_name = gtk_file_chooser_get_filename(GTK_FILE_CHOOSER(dialog));
layer_selector_save_layer_mapping_data(sel, file_name);
g_free(file_name);
}
gtk_widget_destroy(dialog);
}
void layer_selector_set_load_mapping_button(LayerSelector *selector, GtkWidget *button, GtkWindow *main_window)
{
g_clear_object(&selector->load_parent_window);
g_clear_object(&selector->associated_load_button);
g_object_ref(G_OBJECT(button));
g_object_ref(G_OBJECT(main_window));
selector->associated_load_button = button;
selector->load_parent_window = main_window;
g_signal_connect(button, "clicked", G_CALLBACK(layer_selector_load_mapping_clicked), selector);
}
void layer_selector_set_save_mapping_button(LayerSelector *selector, GtkWidget *button, GtkWindow *main_window)
{
g_clear_object(&selector->save_parent_window);
g_clear_object(&selector->associated_save_button);
g_object_ref(G_OBJECT(button));
g_object_ref(G_OBJECT(main_window));
selector->associated_save_button = button;
selector->save_parent_window = main_window;
g_signal_connect(button, "clicked", G_CALLBACK(layer_selector_save_mapping_clicked), selector);
}
void layer_selector_force_sort(LayerSelector *selector, enum layer_selector_sort_algo sort_function)
{
GtkListBox *box;
if (!selector)
return;
box = selector->list_box;
if (!box)
return;
/* Set sorting function, sort, and disable sorting function */
gtk_list_box_set_sort_func(box, layer_selector_sort_func, (gpointer)&sort_function, NULL);
gtk_list_box_invalidate_sort(box);
gtk_list_box_set_sort_func(box, NULL, NULL, NULL);
}
void layer_selector_select_all_layers(LayerSelector *layer_selector, gboolean select)
{
GList *le_list;
GList *iter;
LayerElement *le;
g_return_if_fail(LAYER_IS_SELECTOR(layer_selector));
g_return_if_fail(GTK_IS_LIST_BOX(layer_selector->list_box));
le_list = gtk_container_get_children(GTK_CONTAINER(layer_selector->list_box));
for (iter = le_list; iter != NULL; iter = g_list_next(iter)) {
le = LAYER_ELEMENT(iter->data);
if (LAYER_IS_ELEMENT(le))
layer_element_set_export(le, select);
}
g_list_free(le_list);
}
void layer_selector_auto_color_layers(LayerSelector *layer_selector, ColorPalette *palette, double global_alpha)
{
GList *le_list;
GList *le_list_ptr;
LayerElement *le;
unsigned int color_index = 0;
unsigned int color_count;
GdkRGBA color;
if (GDS_RENDER_IS_COLOR_PALETTE(palette) == FALSE || LAYER_IS_SELECTOR(layer_selector) == FALSE)
return;
if (global_alpha <= 0)
return;
if (GTK_IS_LIST_BOX(layer_selector->list_box) == FALSE)
return;
le_list = gtk_container_get_children(GTK_CONTAINER(layer_selector->list_box));
/* iterate over layer elements and fill colors */
color_index = 0;
color_count = color_palette_get_color_count(palette);
if (color_count == 0)
goto ret_free_le_list;
for (le_list_ptr = le_list; le_list_ptr != NULL; le_list_ptr = le_list_ptr->next) {
le = LAYER_ELEMENT(le_list_ptr->data);
if (le) {
color_palette_get_color(palette, &color, color_index++);
color.alpha *= global_alpha;
layer_element_set_color(le, &color);
if (color_index >= color_count)
color_index = 0;
}
}
ret_free_le_list:
g_list_free(le_list);
}
void layer_selector_auto_name_layers(LayerSelector *layer_selector, gboolean overwrite)
{
GList *le_list;
GList *le_list_ptr;
LayerElement *le;
const char *old_layer_name;
GString *new_layer_name;
g_return_if_fail(LAYER_IS_SELECTOR(layer_selector));
new_layer_name = g_string_new_len(NULL, 10);
le_list = gtk_container_get_children(GTK_CONTAINER(layer_selector->list_box));
for (le_list_ptr = le_list; le_list_ptr != NULL; le_list_ptr = g_list_next(le_list_ptr)) {
le = LAYER_ELEMENT(le_list_ptr->data);
if (!le)
continue;
old_layer_name = layer_element_get_name(le);
/* Check if layer name is empty or may be overwritten */
if (!old_layer_name || *old_layer_name == '\0' || overwrite) {
g_string_printf(new_layer_name, "Layer %d", layer_element_get_layer(le));
layer_element_set_name(le, new_layer_name->str);
}
}
g_string_free(new_layer_name, TRUE);
g_list_free(le_list);
}
gboolean layer_selector_contains_elements(LayerSelector *layer_selector)
{
GList *layer_element_list;
/* Check objects */
g_return_val_if_fail(LAYER_IS_SELECTOR(layer_selector), FALSE);
g_return_val_if_fail(GTK_IS_LIST_BOX(layer_selector->list_box), FALSE);
/* Get a list of the child elements inside the list boy associated with this selector */
layer_element_list = gtk_container_get_children(GTK_CONTAINER(layer_selector->list_box));
/* Return TRUE if there is an element in the list, else return FALSE */
return (layer_element_list ? TRUE : FALSE);
}
/** @} */

354
layer/layer-settings.c Normal file
View File

@@ -0,0 +1,354 @@
/*
* 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-settings.c
* @brief Implementation of the LayerSettings class
* @author Mario Hüttel <mario.huettel@gmx.net>
*/
#include <gds-render/layer/layer-settings.h>
#include <stdlib.h>
struct _LayerSettings {
GObject parent;
GList *layer_infos;
gpointer padding[12];
};
G_DEFINE_TYPE(LayerSettings, layer_settings, G_TYPE_OBJECT)
static void layer_settings_init(LayerSettings *self)
{
self->layer_infos = NULL;
}
static void layer_info_delete_with_name(struct layer_info *const info)
{
if (!info)
return;
if (info->name)
free(info->name);
free(info);
}
static void layer_settings_dispose(GObject *obj)
{
LayerSettings *self;
self = GDS_RENDER_LAYER_SETTINGS(obj);
if (self->layer_infos) {
g_list_free_full(self->layer_infos, (GDestroyNotify)layer_info_delete_with_name);
self->layer_infos = NULL;
}
G_OBJECT_CLASS(layer_settings_parent_class)->dispose(obj);
}
static void layer_settings_class_init(LayerSettingsClass *klass)
{
GObjectClass *oclass;
oclass = G_OBJECT_CLASS(klass);
oclass->dispose = layer_settings_dispose;
return;
}
/**
* @brief Copy layer_info struct
*
* This function copies a layer info struct.
*
* @note Be aware, that it does not only copy the pointer to the
* layer name, but instead duplicates the string.
* @param info Info to copy
* @return new layer_info struct
*/
static struct layer_info *layer_info_copy(const struct layer_info * const info)
{
struct layer_info *copy;
if (!info)
return 0;
copy = (struct layer_info *)malloc(sizeof(struct layer_info));
if (!copy)
return 0;
/* Copy data */
memcpy(copy, info, sizeof(struct layer_info));
/* Duplicate string */
if (info->name)
copy->name = strdup(info->name);
return copy;
}
LayerSettings *layer_settings_new()
{
return g_object_new(GDS_RENDER_TYPE_LAYER_SETTINGS, NULL);
}
int layer_settings_append_layer_info(LayerSettings *settings, struct layer_info *info)
{
struct layer_info *info_copy;
g_return_val_if_fail(GDS_RENDER_IS_LAYER_SETTINGS(settings), -1);
if (!info)
return -2;
/* Copy layer info */
info_copy = layer_info_copy(info);
/* Append to list */
settings->layer_infos = g_list_append(settings->layer_infos, info_copy);
return (settings->layer_infos ? 0 : -3);
}
void layer_settings_clear(LayerSettings *settings)
{
g_return_if_fail(GDS_RENDER_IS_LAYER_SETTINGS(settings));
/* Clear list and delete layer_info structs including the name field */
g_list_free_full(settings->layer_infos, (GDestroyNotify)layer_info_delete_with_name);
settings->layer_infos = NULL;
}
int layer_settings_remove_layer(LayerSettings *settings, int layer)
{
GList *list_iter;
GList *found = NULL;
struct layer_info *inf;
g_return_val_if_fail(GDS_RENDER_IS_LAYER_SETTINGS(settings), -1);
/* Find in list */
for (list_iter = settings->layer_infos; list_iter; list_iter = list_iter->next) {
inf = (struct layer_info *)list_iter->data;
if (!inf)
continue;
if (inf->layer == layer)
found = list_iter;
}
if (found) {
/* Free the layer_info struct */
layer_info_delete_with_name((struct layer_info *)found->data);
/* Delete the list element */
settings->layer_infos = g_list_delete_link(settings->layer_infos, found);
return 0;
}
return -2;
}
GList *layer_settings_get_layer_info_list(LayerSettings *settings)
{
g_return_val_if_fail(GDS_RENDER_IS_LAYER_SETTINGS(settings), NULL);
return settings->layer_infos;
}
/**
* @brief Generate a layer mapping CSV line for a given layer_info struct
* @param string Buffer to write to
* @param linfo Layer information
*/
static void layer_settings_gen_csv_line(GString *string, struct layer_info *linfo)
{
int i;
g_string_printf(string, "%d:%lf:%lf:%lf:%lf:%d:%s\n",
linfo->layer, linfo->color.red, linfo->color.green,
linfo->color.blue, linfo->color.alpha, (linfo->render ? 1 : 0), linfo->name);
/* Fix broken locale settings */
for (i = 0; string->str[i]; i++) {
if (string->str[i] == ',')
string->str[i] = '.';
}
for (i = 0; string->str[i]; i++) {
if (string->str[i] == ':')
string->str[i] = ',';
}
}
int layer_settings_to_csv(LayerSettings *settings, const char *path)
{
GFile *file;
GOutputStream *w_fstream;
GString *string;
GList *info_iter;
struct layer_info *linfo;
int ret = 0;
file = g_file_new_for_path(path);
w_fstream = G_OUTPUT_STREAM(g_file_replace(file, NULL, FALSE, G_FILE_CREATE_NONE, NULL, NULL));
if (!w_fstream) {
ret = -1;
goto ret_unref_file;
}
/* Allocate new working buffer string. A size bigger than 200 is unexpected, but possible
* 200 is a tradeoff between memory usage and preventing the necessity of realloc'ing the string
*/
string = g_string_new_len(NULL, 200);
if (!string) {
ret = -2;
goto ret_close_file;
}
/* Loop over layers and write CSV lines */
for (info_iter = settings->layer_infos; info_iter; info_iter = info_iter->next) {
linfo = (struct layer_info *)info_iter->data;
layer_settings_gen_csv_line(string, linfo);
g_output_stream_write(w_fstream, string->str, string->len * sizeof(gchar), NULL, NULL);
}
/* Delete string */
g_string_free(string, TRUE);
ret_close_file:
g_output_stream_flush(w_fstream, NULL, NULL);
g_output_stream_close(w_fstream, NULL, NULL);
g_object_unref(w_fstream);
ret_unref_file:
g_object_unref(file);
return ret;
}
/**
* @brief Load a line from \p stream and parse try to parse it as layer information
* @param stream Input data stream
* @param linfo Layer info struct to fill
* @return 1 if malformatted line, 0 if parsing was successful and parameters are valid, -1 if file end
*/
static int layer_settings_load_csv_line_from_stream(GDataInputStream *stream, struct layer_info *linfo)
{
int ret;
gsize len;
gchar *line;
GRegex *regex;
GMatchInfo *mi;
char *match;
if (!linfo) {
ret = 1;
goto ret_direct;
}
regex = g_regex_new("^(?<layer>[0-9]+),(?<r>[0-9\\.]+),(?<g>[0-9\\.]+),(?<b>[0-9\\.]+),(?<a>[0-9\\.]+),(?<export>[01]),(?<name>.*)$", 0, 0, NULL);
line = g_data_input_stream_read_line(stream, &len, NULL, NULL);
if (!line) {
ret = -1;
goto destroy_regex;
}
/* Match line in CSV */
g_regex_match(regex, line, 0, &mi);
if (g_match_info_matches(mi)) {
/* Line is valid */
match = g_match_info_fetch_named(mi, "layer");
linfo->layer = (int)g_ascii_strtoll(match, NULL, 10);
g_free(match);
match = g_match_info_fetch_named(mi, "r");
linfo->color.red = g_ascii_strtod(match, NULL);
g_free(match);
match = g_match_info_fetch_named(mi, "g");
linfo->color.green = g_ascii_strtod(match, NULL);
g_free(match);
match = g_match_info_fetch_named(mi, "b");
linfo->color.blue = g_ascii_strtod(match, NULL);
g_free(match);
match = g_match_info_fetch_named(mi, "a");
linfo->color.alpha = g_ascii_strtod(match, NULL);
g_free(match);
match = g_match_info_fetch_named(mi, "export");
linfo->render = ((!strcmp(match, "1")) ? 1 : 0);
g_free(match);
match = g_match_info_fetch_named(mi, "name");
linfo->name = match;
ret = 0;
} else {
/* Line is malformatted */
printf("Could not recognize line in CSV as valid entry: %s\n", line);
ret = 1;
}
g_match_info_free(mi);
g_free(line);
destroy_regex:
g_regex_unref(regex);
ret_direct:
return ret;
}
int layer_settings_load_from_csv(LayerSettings *settings, const char *path)
{
GFile *file;
int ret = 0;
GInputStream *in_stream;
GDataInputStream *data_stream;
int parser_ret;
int stacked_pos;
struct layer_info linfo;
file = g_file_new_for_path(path);
in_stream = G_INPUT_STREAM(g_file_read(file, NULL, NULL));
g_return_val_if_fail(GDS_RENDER_IS_LAYER_SETTINGS(settings), -2);
if (!in_stream) {
ret = -1;
goto ret_destroy_file;
}
/* Delete old settings */
layer_settings_clear(settings);
data_stream = g_data_input_stream_new(in_stream);
stacked_pos = 0;
while ((parser_ret = layer_settings_load_csv_line_from_stream(data_stream, &linfo)) >= 0) {
/* Line broken */
if (parser_ret == 1)
continue;
linfo.stacked_position = stacked_pos++;
layer_settings_append_layer_info(settings, &linfo);
/* Clear name to prevent memory leak */
if (linfo.name)
g_free(linfo.name);
}
g_object_unref(data_stream);
g_object_unref(in_stream);
ret_destroy_file:
g_object_unref(file);
return ret;
}

503
main.c
View File

@@ -17,261 +17,334 @@
* along with GDSII-Converter. If not, see <http://www.gnu.org/licenses/>.
*/
/**
* @file main.c
* @brief main.c
* @author Mario Hüttel <mario.huettel@gmx.net>
*/
#include <stdio.h>
#include "gds-parser/gds-parser.h"
#include <gtk/gtk.h>
#include "layer-widget/layer-element.h"
#include "layer-selector.h"
#include "tree-renderer/tree-store.h"
#include "latex-output/latex-output.h"
#include <glib.h>
#include <glib/gi18n.h>
#include <locale.h>
struct open_button_data {
GtkWindow *main_window;
GList **list_ptr;
GtkTreeStore *cell_store;
GtkListBox *layer_box;
#include <gds-render/gds-render-gui.h>
#include <gds-render/command-line.h>
#include <gds-render/output-renderers/external-renderer.h>
#include <gds-render/version.h>
/**
* @brief Structure containing The GtkApplication and a list containing the GdsRenderGui objects.
*/
struct application_data {
GtkApplication *app;
GList *gui_list;
};
struct convert_button_data {
GtkTreeView *tree_view;
GtkWindow *main_window;
/**
* @brief Callback for the menu entry 'Quit'
*
* Destroys all GUIs contained in the application_data structure
* provided by \p user_data.
*
* The complete suspension of all main windows leads to the termination of the
* GApplication.
*
* @param action unused
* @param parameter unused
* @param user_data application_data structure
*/
static void app_quit(GSimpleAction *action, GVariant *parameter, gpointer user_data)
{
struct application_data * const appdata = (struct application_data *)user_data;
(void)action;
(void)parameter;
GList *list_iter;
GdsRenderGui *gui;
/* Dispose all GUIs */
for (list_iter = appdata->gui_list; list_iter != NULL; list_iter = g_list_next(list_iter)) {
gui = RENDERER_GUI(list_iter->data);
g_object_unref(gui);
}
g_list_free(appdata->gui_list);
appdata->gui_list = NULL;
}
/**
* @brief Callback for the 'About' menu entry
*
* This function shows the about dialog.
*
* @param action GSimpleAction, unused
* @param parameter Unused.
* @param user_data Unused
*/
static void app_about(GSimpleAction *action, GVariant *parameter, gpointer user_data)
{
GtkBuilder *builder;
GtkDialog *dialog;
GdkPixbuf *logo_buf;
GError *error = NULL;
(void)user_data;
(void)action;
(void)parameter;
GString *comment_text;
comment_text = g_string_new(_("gds-render is a free tool for rendering GDS2 layout files into vector graphics."));
g_string_append_printf(comment_text, _("\n\nFull git commit: %s"), _app_git_commit);
builder = gtk_builder_new_from_resource("/gui/about.glade");
dialog = GTK_DIALOG(gtk_builder_get_object(builder, "about-dialog"));
gtk_window_set_transient_for(GTK_WINDOW(dialog), NULL);
gtk_about_dialog_set_version(GTK_ABOUT_DIALOG(dialog), _app_version_string);
gtk_about_dialog_set_comments(GTK_ABOUT_DIALOG(dialog), comment_text->str);
g_string_free(comment_text, TRUE);
/* Load icon from resource */
logo_buf = gdk_pixbuf_new_from_resource_at_scale("/images/logo.svg", 100, 100, TRUE, &error);
if (logo_buf) {
/* Set logo */
gtk_about_dialog_set_logo(GTK_ABOUT_DIALOG(dialog), logo_buf);
/* Pixbuf is now owned by about dialog. Unref */
g_object_unref(logo_buf);
} else if (error) {
fprintf(stderr, _("Logo could not be displayed: %s\n"), error->message);
g_error_free(error);
}
gtk_dialog_run(dialog);
gtk_widget_destroy(GTK_WIDGET(dialog));
g_object_unref(builder);
}
/**
* @brief Contains the application menu entries
*/
static const GActionEntry app_actions[] = {
{ "quit", app_quit, NULL, NULL, NULL, {0} },
{ "about", app_about, NULL, NULL, NULL, {0} },
};
gboolean on_window_close(gpointer window, gpointer user)
/**
* @brief Called when a GUI main window is closed
*
* The GdsRenderGui object associated with the closed main window
* is removed from the list of open GUIs (\p user_data) and dereferenced.
*
* @param gui The GUI instance the closed main window belongs to
* @param user_data List of GUIs
*/
static void gui_window_closed_callback(GdsRenderGui *gui, gpointer user_data)
{
gtk_widget_destroy(GTK_WIDGET(window));
gtk_main_quit();
return TRUE;
GList **gui_list = (GList **)user_data;
/* Dispose of Gui element */
*gui_list = g_list_remove(*gui_list, gui);
g_object_unref(gui);
}
static GString *generate_string_from_date(struct gds_time_field *date)
/**
* @brief Activation of the GUI
* @param app The GApplication reference
* @param user_data Used to store the individual GUI instances.
*/
static void gapp_activate(GApplication *app, gpointer user_data)
{
GString *str;
GtkWindow *main_window;
GdsRenderGui *gui;
struct application_data * const appdata = (struct application_data *)user_data;
str = g_string_new_len(NULL, 50);
g_string_printf(str, "%02u.%02u.%u - %02u:%02u",
(unsigned int)date->day,
(unsigned int)date->month,
(unsigned int)date->year,
(unsigned int)date->hour,
(unsigned int)date->minute);
return str;
gui = gds_render_gui_new();
appdata->gui_list = g_list_append(appdata->gui_list, gui);
g_signal_connect(gui, "window-closed", G_CALLBACK(gui_window_closed_callback), &appdata->gui_list);
main_window = gds_render_gui_get_main_window(gui);
gtk_application_add_window(GTK_APPLICATION(app), main_window);
gtk_widget_show(GTK_WIDGET(main_window));
}
void on_load_gds(gpointer button, gpointer user)
/**
* @brief Start the graphical interface.
*
* This function starts the GUI. If there's already a
* running instance of this program, a second window will be
* created in that instance and the second one is terminated.
*
* @param argc
* @param argv
* @return
*/
static int start_gui(int argc, char **argv)
{
GList *cell;
GtkTreeIter libiter;
GtkTreeIter celliter;
GList *lib;
struct gds_library *gds_lib;
struct gds_cell *gds_c;
struct open_button_data *ptr = (struct open_button_data *)user;
GtkTreeStore *store = ptr->cell_store;
GtkWidget *open_dialog;
GtkFileChooser *file_chooser;
GtkFileFilter *filter;
GtkStyleContext *button_style;
gint dialog_result;
int gds_result;
char *filename;
GString *mod_date;
GString *acc_date;
GtkApplication *gapp;
GString *application_domain;
int app_status;
static struct application_data appdata = {
.gui_list = NULL
};
GMenu *menu;
GMenu *m_quit;
GMenu *m_about;
open_dialog = gtk_file_chooser_dialog_new("Open GDSII File", ptr->main_window, GTK_FILE_CHOOSER_ACTION_OPEN,
"Cancel", GTK_RESPONSE_CANCEL, "Open GDSII", GTK_RESPONSE_ACCEPT, NULL);
file_chooser = GTK_FILE_CHOOSER(open_dialog);
/* Add GDS II Filter */
filter = gtk_file_filter_new();
gtk_file_filter_add_pattern(filter, "*.gds");
gtk_file_filter_set_name(filter, "GDSII-Files");
gtk_file_chooser_add_filter(file_chooser, filter);
/*
* Generate version dependent application id
* This allows running the application in different versions at the same time.
*/
application_domain = g_string_new(NULL);
g_string_printf(application_domain, "de.shimatta.gds_render_%s", _app_git_commit);
dialog_result = gtk_dialog_run(GTK_DIALOG(open_dialog));
gapp = gtk_application_new(application_domain->str, G_APPLICATION_FLAGS_NONE);
g_string_free(application_domain, TRUE);
if (dialog_result == GTK_RESPONSE_ACCEPT) {
g_application_register(G_APPLICATION(gapp), NULL, NULL);
g_signal_connect(gapp, "activate", G_CALLBACK(gapp_activate), &appdata);
/* Get File name */
filename = gtk_file_chooser_get_filename(file_chooser);
gtk_tree_store_clear(store);
clear_lib_list(ptr->list_ptr);
/* Parse new GDSII file */
gds_result = parse_gds_from_file(filename, ptr->list_ptr);
/* Delete file name afterwards */
g_free(filename);
if (gds_result)
goto end_destroy;
/* remove suggested action from Open button */
button_style = gtk_widget_get_style_context(GTK_WIDGET(button));
gtk_style_context_remove_class(button_style, "suggested-action");
for (lib = *(ptr->list_ptr); lib != NULL; lib = lib->next) {
gds_lib = (struct gds_library *)lib->data;
/* Create top level iter */
gtk_tree_store_append (store, &libiter, NULL);
/* Convert dates to String */
mod_date = generate_string_from_date(&gds_lib->mod_time);
acc_date = generate_string_from_date(&gds_lib->access_time);
gtk_tree_store_set (store, &libiter,
CELL_SEL_LIBRARY, gds_lib,
CELL_SEL_MODDATE, mod_date->str,
CELL_SEL_ACCESSDATE, acc_date->str,
-1);
/* Delete GStrings including string data. */
/* Cell store copies String type data items */
g_string_free(mod_date, TRUE);
g_string_free(acc_date, TRUE);
for (cell = gds_lib->cells; cell != NULL; cell = cell->next) {
gds_c = (struct gds_cell *)cell->data;
gtk_tree_store_append (store, &celliter, &libiter);
/* Convert dates to String */
mod_date = generate_string_from_date(&gds_c->mod_time);
acc_date = generate_string_from_date(&gds_c->access_time);
gtk_tree_store_set (store, &celliter,
CELL_SEL_CELL, gds_c,
CELL_SEL_MODDATE, mod_date->str,
CELL_SEL_ACCESSDATE, acc_date->str,
-1);
/* Delete GStrings including string data. */
/* Cell store copies String type data items */
g_string_free(mod_date, TRUE);
g_string_free(acc_date, TRUE);
}
}
/* Create Layers in Layer Box */
generate_layer_widgets(ptr->layer_box, *(ptr->list_ptr));
if (g_application_get_is_remote(G_APPLICATION(gapp)) == TRUE) {
g_application_activate(G_APPLICATION(gapp));
printf(_("There is already an open instance. Will open second window in that instance.\n"));
return 0;
}
end_destroy:
/* Destroy dialog and filter */
gtk_widget_destroy(open_dialog);
menu = g_menu_new();
m_quit = g_menu_new();
m_about = g_menu_new();
g_menu_append(m_quit, _("Quit"), "app.quit");
g_menu_append(m_about, _("About"), "app.about");
g_menu_append_section(menu, NULL, G_MENU_MODEL(m_about));
g_menu_append_section(menu, NULL, G_MENU_MODEL(m_quit));
g_action_map_add_action_entries(G_ACTION_MAP(gapp), app_actions,
G_N_ELEMENTS(app_actions), &appdata);
gtk_application_set_app_menu(GTK_APPLICATION(gapp), G_MENU_MODEL(menu));
g_object_unref(m_quit);
g_object_unref(m_about);
g_object_unref(menu);
app_status = g_application_run(G_APPLICATION(gapp), argc, argv);
g_object_unref(gapp);
g_list_free(appdata.gui_list);
return app_status;
}
static void on_convert_clicked(gpointer button, gpointer user)
/**
* @brief Print the application version string to stdout
*/
static void print_version(void)
{
struct convert_button_data *data = (struct convert_button_data *)user;
GtkTreeSelection *selection;
GtkTreeIter iter;
GtkTreeModel *model;
GList *layer_list;
struct gds_cell *cell_to_render;
FILE *tex_file;
GtkWidget *dialog;
gint res;
char *file_name;
/* Get selected cell */
selection = gtk_tree_view_get_selection(data->tree_view);
if (gtk_tree_selection_get_selected(selection, &model, &iter) == FALSE)
return;
gtk_tree_model_get(model, &iter, CELL_SEL_CELL, &cell_to_render, -1);
if (!cell_to_render)
return;
/* Get layers that are rendered */
layer_list = export_rendered_layer_info();
/* save file dialog */
dialog = gtk_file_chooser_dialog_new("Save TeX File", GTK_WINDOW(data->main_window), GTK_FILE_CHOOSER_ACTION_SAVE,
"Cancel", GTK_RESPONSE_CANCEL, "Save", GTK_RESPONSE_ACCEPT, NULL);
res = gtk_dialog_run(GTK_DIALOG(dialog));
if (res == GTK_RESPONSE_ACCEPT) {
file_name = gtk_file_chooser_get_filename(GTK_FILE_CHOOSER(dialog));
tex_file = fopen(file_name, "w");
g_free(file_name);
gtk_widget_destroy(dialog);
render_cell_to_code(cell_to_render, layer_list, tex_file);
fclose(tex_file);
} else {
gtk_widget_destroy(dialog);
}
g_list_free_full(layer_list, (GDestroyNotify)delete_layer_info_struct);
}
/* This function activates/deactivates the convert button depending on whether
* a cell is selected for conversion or not */
static void cell_selection_changed(GtkTreeSelection *sel, GtkWidget *convert_button)
{
GtkTreeModel *model = NULL;
GtkTreeIter iter;
if (gtk_tree_selection_get_selected(sel, &model, &iter)) {
/* Node selected. Show button */
gtk_widget_set_sensitive(convert_button, TRUE);
} else {
gtk_widget_set_sensitive(convert_button, FALSE);
}
printf(_("This is gds-render, version: %s\n\nFor a list of supported commands execute with --help option.\n"),
_app_version_string);
}
/**
* @brief The "entry point" of the application
* @param argc Number of command line parameters
* @param argv Command line parameters
* @return Execution status of the application
*/
int main(int argc, char **argv)
{
GtkBuilder *main_builder;
GList *gds_libs = NULL;
GtkTreeView *cell_tree;
GtkTreeStore *cell_store;
GtkWidget *conv_button;
GtkWidget *listbox;
int i;
GError *error = NULL;
GOptionContext *context;
gchar *gds_name;
gchar **output_paths = NULL;
gchar *mappingname = NULL;
gchar *cellname = NULL;
gchar **renderer_args = NULL;
gboolean version = FALSE, pdf_standalone = FALSE, pdf_layers = FALSE;
int scale = 1000;
int app_status = 0;
struct external_renderer_params so_render_params;
struct open_button_data open_data;
struct convert_button_data conv_data;
so_render_params.so_path = NULL;
so_render_params.cli_params = NULL;
gtk_init(&argc, &argv);
bindtextdomain(GETTEXT_PACKAGE, LOCALEDATADIR "/locale");
bind_textdomain_codeset(GETTEXT_PACKAGE, "UTF-8");
textdomain(GETTEXT_PACKAGE);
main_builder = gtk_builder_new_from_resource("/main.glade");
gtk_builder_connect_signals(main_builder, NULL);
GOptionEntry entries[] = {
{"version", 'v', 0, G_OPTION_ARG_NONE, &version, _("Print version"), NULL},
{"renderer", 'r', 0, G_OPTION_ARG_STRING_ARRAY, &renderer_args,
_("Renderer to use. Can be used multiple times."), "pdf|svg|tikz|ext"},
{"scale", 's', 0, G_OPTION_ARG_INT, &scale, _("Divide output coordinates by <SCALE>"), "<SCALE>" },
{"output-file", 'o', 0, G_OPTION_ARG_FILENAME_ARRAY, &output_paths,
_("Output file path. Can be used multiple times."), "PATH" },
{"mapping", 'm', 0, G_OPTION_ARG_FILENAME, &mappingname, _("Path for Layer Mapping File"), "PATH" },
{"cell", 'c', 0, G_OPTION_ARG_STRING, &cellname, _("Cell to render"), "NAME" },
{"tex-standalone", 'a', 0, G_OPTION_ARG_NONE, &pdf_standalone, _("Create standalone TeX"), 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, &so_render_params.so_path,
_("Path to a custom shared object, that implements the necessary rendering functions"), "PATH"},
{"render-lib-params", 'W', 0, G_OPTION_ARG_STRING, &so_render_params.cli_params,
_("Argument string passed to render lib"), NULL},
{NULL, 0, 0, 0, NULL, NULL, 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)) {
g_print(_("Option parsing failed: %s\n"), error->message);
exit(1);
}
cell_tree = (GtkTreeView *)gtk_builder_get_object(main_builder, "cell-tree");
cell_store = setup_cell_selector(cell_tree);
g_option_context_free(context);
if (version) {
print_version();
goto ret_status;
}
open_data.cell_store = cell_store;
open_data.list_ptr = &gds_libs;
open_data.main_window = GTK_WINDOW(gtk_builder_get_object(main_builder, "main-window"));
g_signal_connect(GTK_WIDGET(gtk_builder_get_object(main_builder, "button-load-gds")),
"clicked", G_CALLBACK(on_load_gds), (gpointer)&open_data);
if (argc >= 2) {
if (scale < 1) {
printf(_("Scale < 1 not allowed. Setting to 1\n"));
scale = 1;
}
/* Connect delete-event */
g_signal_connect(GTK_WIDGET(open_data.main_window), "delete-event", G_CALLBACK(on_window_close), NULL);
/* Get gds name */
gds_name = argv[1];
/* Connect Convert button */
conv_data.tree_view = cell_tree;
conv_data.main_window = open_data.main_window;
/* Print out additional arguments as ignored */
for (i = 2; i < argc; i++)
printf(_("Ignored argument: %s"), argv[i]);
conv_button = GTK_WIDGET(gtk_builder_get_object(main_builder, "convert-button"));
g_signal_connect(conv_button, "clicked", G_CALLBACK(on_convert_clicked), &conv_data);
app_status =
command_line_convert_gds(gds_name, cellname, renderer_args, output_paths, mappingname,
&so_render_params, pdf_standalone, pdf_layers, scale);
listbox = GTK_WIDGET(gtk_builder_get_object(main_builder, "layer-list"));
open_data.layer_box = GTK_LIST_BOX(listbox);
} else {
app_status = start_gui(argc, argv);
}
/* Set buttons fpr layer mapping GUI */
setup_load_mapping_callback(GTK_WIDGET(gtk_builder_get_object(main_builder, "button-load-mapping")),
open_data.main_window);
setup_save_mapping_callback(GTK_WIDGET(gtk_builder_get_object(main_builder, "button-save-mapping")),
open_data.main_window);
ret_status:
/* If necessary, free command line parameters.
* This is only really necessary for automated mem-leak testing.
* Omitting these frees would be perfectly fine.
*/
if (output_paths)
g_strfreev(output_paths);
if (renderer_args)
g_strfreev(renderer_args);
if (mappingname)
g_free(mappingname);
if (cellname)
free(cellname);
if (so_render_params.so_path)
free(so_render_params.so_path);
if (so_render_params.cli_params)
g_free(so_render_params.cli_params);
/* Callback for selection change of cell selector */
g_signal_connect(G_OBJECT(gtk_tree_view_get_selection(cell_tree)), "changed",
G_CALLBACK(cell_selection_changed), conv_button);
gtk_main();
return 0;
return app_status;
}

View File

@@ -0,0 +1,503 @@
/*
* 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 cairo-renderer.c
* @brief Output renderer for Cairo PDF export
* @author Mario Hüttel <mario.huettel@gmx.net>
*/
/** @addtogroup Cairo-Renderer
* @{
*/
#include <math.h>
#include <stdlib.h>
#include <cairo.h>
#include <cairo-pdf.h>
#include <cairo-svg.h>
#include <glib/gi18n.h>
#include <gds-render/output-renderers/cairo-renderer.h>
#include <sys/wait.h>
#include <unistd.h>
struct _CairoRenderer {
GdsOutputRenderer parent;
gboolean svg; /**< @brief TRUE: SVG output, FALSE: PDF output */
};
G_DEFINE_TYPE(CairoRenderer, cairo_renderer, GDS_RENDER_TYPE_OUTPUT_RENDERER)
/**
* @brief The cairo_layer struct
* Each rendered layer is represented by this struct.
*/
struct cairo_layer {
cairo_t *cr; /**< @brief cairo context for layer*/
cairo_surface_t *rec; /**< @brief Recording surface to hold the layer */
struct layer_info *linfo; /**< @brief Reference to layer information */
};
/**
* @brief Revert the last transformation on all layers
* @param layers Pointer to #cairo_layer structures
*/
static void revert_inherited_transform(struct cairo_layer *layers)
{
int i;
for (i = 0; i < MAX_LAYERS; i++) {
if (layers[i].cr == NULL)
continue;
cairo_restore(layers[i].cr);
}
}
/**
* @brief Applies transformation to all layers
* @param layers Array of layers
* @param origin Origin translation
* @param magnification Scaling
* @param flipping Mirror image on x-axis before rotating
* @param rotation Rotation in degrees
* @param scale Scale the image down by. Only used for sclaing origin coordinates. Not applied to layer.
*/
static void apply_inherited_transform_to_all_layers(struct cairo_layer *layers,
const struct gds_point *origin,
double magnification,
gboolean flipping,
double rotation,
double scale)
{
int i;
cairo_t *temp_layer_cr;
for (i = 0; i < MAX_LAYERS; i++) {
temp_layer_cr = layers[i].cr;
if (temp_layer_cr == NULL)
continue;
/* Save the state and apply transformation */
cairo_save(temp_layer_cr);
cairo_translate(temp_layer_cr, (double)origin->x/scale, (double)origin->y/scale);
cairo_rotate(temp_layer_cr, M_PI*rotation/180.0);
cairo_scale(temp_layer_cr, magnification,
(flipping == TRUE ? -magnification : magnification));
}
}
/**
* @brief render_cell Render a cell with its sub-cells
* @param cell Cell to render
* @param layers Cell will be rendered into these layers
* @param scale sclae image down by this factor
*/
static void render_cell(struct gds_cell *cell, struct cairo_layer *layers, double scale)
{
GList *instance_list;
struct gds_cell *temp_cell;
struct gds_cell_instance *cell_instance;
GList *gfx_list;
struct gds_graphics *gfx;
GList *vertex_list;
struct gds_point *vertex;
cairo_t *cr;
/* Render child cells */
for (instance_list = cell->child_cells; instance_list != NULL; instance_list = instance_list->next) {
cell_instance = (struct gds_cell_instance *)instance_list->data;
temp_cell = cell_instance->cell_ref;
if (temp_cell != NULL) {
apply_inherited_transform_to_all_layers(layers,
&cell_instance->origin,
cell_instance->magnification,
cell_instance->flipped,
cell_instance->angle,
scale);
render_cell(temp_cell, layers, scale);
revert_inherited_transform(layers);
}
}
/* Render graphics */
for (gfx_list = cell->graphic_objs; gfx_list != NULL; gfx_list = gfx_list->next) {
gfx = (struct gds_graphics *)gfx_list->data;
/* Get layer renderer */
if (gfx->layer >= MAX_LAYERS)
continue;
cr = layers[gfx->layer].cr;
if (cr == NULL)
continue;
/* Apply settings */
cairo_set_line_width(cr, (gfx->width_absolute ? gfx->width_absolute/scale : 1));
switch (gfx->path_render_type) {
case PATH_FLUSH:
cairo_set_line_cap(cr, CAIRO_LINE_CAP_BUTT);
break;
case PATH_ROUNDED:
cairo_set_line_cap(cr, CAIRO_LINE_CAP_ROUND);
break;
case PATH_SQUARED:
cairo_set_line_cap(cr, CAIRO_LINE_CAP_SQUARE);
break;
}
/* Add vertices */
for (vertex_list = gfx->vertices; vertex_list != NULL; vertex_list = vertex_list->next) {
vertex = (struct gds_point *)vertex_list->data;
/* If first point -> move to, else line to */
if (vertex_list->prev == NULL)
cairo_move_to(cr, vertex->x/scale, vertex->y/scale);
else
cairo_line_to(cr, vertex->x/scale, vertex->y/scale);
}
/* Create graphics object */
switch (gfx->gfx_type) {
case GRAPHIC_PATH:
cairo_stroke(cr);
break;
case GRAPHIC_BOX:
/* Expected fallthrough */
case GRAPHIC_POLYGON:
cairo_set_line_width(cr, 0.1/scale);
cairo_close_path(cr);
cairo_stroke_preserve(cr); // Prevent graphic glitches
cairo_fill(cr);
break;
}
} /* for gfx list */
}
/**
* @brief Read a line from a file descriptor
*
* In case of a broken pipe / closed writing end, it will terminate
*
* @param fd File descriptor to read from
* @param buff Buffer to write data in
* @param buff_size Buffer size
* @return length of read data
*/
static int read_line_from_fd(int fd, char *buff, size_t buff_size)
{
ssize_t cnt;
char c;
unsigned int buff_cnt = 0;
while ((cnt = read(fd, &c, 1)) == 1) {
if (buff_cnt < (buff_size-1)) {
buff[buff_cnt++] = c;
if (c == '\n')
break;
} else {
break;
}
}
buff[buff_cnt] = 0;
return (int)buff_cnt;
}
/**
* @brief Render \p cell to a PDF file specified by \p pdf_file
* @param renderer The current renderer this function is running from
* @param cell Toplevel cell to @ref Cairo-Renderer
* @param layer_infos List of layer information. Specifies color and layer stacking
* @param pdf_file PDF output file. Set to NULL if no PDF file has to be generated
* @param svg_file SVG output file. Set to NULL if no SVG file has to be generated
* @param scale Scale the output image down by \p scale
* @return Error
*/
static int cairo_renderer_render_cell_to_vector_file(GdsOutputRenderer *renderer,
struct gds_cell *cell,
GList *layer_infos,
const char *pdf_file,
const char *svg_file,
double scale)
{
cairo_surface_t *pdf_surface = NULL, *svg_surface = NULL;
cairo_t *pdf_cr = NULL, *svg_cr = NULL;
struct layer_info *linfo;
struct cairo_layer *layers;
struct cairo_layer *lay;
GList *info_list;
int i;
double rec_x0, rec_y0, rec_width, rec_height;
double xmin = INT32_MAX, xmax = INT32_MIN, ymin = INT32_MAX, ymax = INT32_MIN;
pid_t process_id;
int comm_pipe[2];
char receive_message[200];
if (pdf_file == NULL && svg_file == NULL) {
/* No output specified */
return -1;
}
/* Generate communication pipe for status updates */
if (pipe(comm_pipe) == -1)
return -2;
/* Fork to a new child process. This ensures the memory leaks (see issue #16) in Cairo don't
* brick everything.
*
* And by the way: This now bricks all Windows compatibility. Deal with it.
*/
process_id = fork();
//process_id = -1;
if (process_id < 0) {
/* This should not happen */
fprintf(stderr, _("Fatal error: Cairo Renderer: Could not spawn child process!"));
exit(-2);
} else if (process_id > 0) {
/* Woohoo... Successfully dumped the shitty code to an unknowing victim */
goto ret_parent;
}
/* Close stdin and (stdout and stderr may live on) */
close(0);
//close(1);
close(comm_pipe[0]);
layers = (struct cairo_layer *)calloc(MAX_LAYERS, sizeof(struct cairo_layer));
/* Clear layers */
for (i = 0; i < MAX_LAYERS; i++) {
layers[i].cr = NULL;
layers[i].rec = NULL;
}
/* Create recording surface for each layer */
for (info_list = layer_infos; info_list != NULL; info_list = g_list_next(info_list)) {
linfo = (struct layer_info *)info_list->data;
if (linfo->layer < MAX_LAYERS) {
/* Layer shall not be rendered */
if (!linfo->render)
continue;
lay = &(layers[(unsigned int)linfo->layer]);
lay->linfo = linfo;
lay->rec = cairo_recording_surface_create(CAIRO_CONTENT_COLOR_ALPHA,
NULL);
lay->cr = cairo_create(layers[(unsigned int)linfo->layer].rec);
cairo_scale(lay->cr, 1, -1); // Fix coordinate system
cairo_set_source_rgb(lay->cr, linfo->color.red, linfo->color.green, linfo->color.blue);
} else {
printf("Layer number (%d) too high!\n", linfo->layer);
goto ret_clear_layers;
}
}
dprintf(comm_pipe[1], "Rendering layers\n");
render_cell(cell, layers, scale);
/* get size of image and top left coordinate */
for (info_list = layer_infos; info_list != NULL; info_list = g_list_next(info_list)) {
linfo = (struct layer_info *)info_list->data;
if (linfo->layer >= MAX_LAYERS) {
printf(_("Layer number too high / outside of spec.\n"));
continue;
}
if (!linfo->render)
continue;
/* Print size */
cairo_recording_surface_ink_extents(layers[linfo->layer].rec, &rec_x0, &rec_y0,
&rec_width, &rec_height);
dprintf(comm_pipe[1], _("Size of layer %d%s%s%s: <%lf x %lf> @ (%lf | %lf)\n"),
linfo->layer,
(linfo->name && linfo->name[0] ? " (" : ""),
(linfo->name && linfo->name[0] ? linfo->name : ""),
(linfo->name && linfo->name[0] ? ")" : ""),
rec_width, rec_height, rec_x0, rec_y0);
/* update bounding box */
xmin = MIN(xmin, rec_x0);
xmax = MAX(xmax, rec_x0);
ymin = MIN(ymin, rec_y0);
ymax = MAX(ymax, rec_y0);
xmin = MIN(xmin, rec_x0+rec_width);
xmax = MAX(xmax, rec_x0+rec_width);
ymin = MIN(ymin, rec_y0+rec_height);
ymax = MAX(ymax, rec_y0+rec_height);
}
/* printf("Cell bounding box: (%lf | %lf) -- (%lf | %lf)\n", xmin, ymin, xmax, ymax); */
if (pdf_file) {
pdf_surface = cairo_pdf_surface_create(pdf_file, xmax-xmin, ymax-ymin);
pdf_cr = cairo_create(pdf_surface);
}
if (svg_file) {
svg_surface = cairo_svg_surface_create(svg_file, xmax-xmin, ymax-ymin);
svg_cr = cairo_create(svg_surface);
}
/* Write layers to PDF */
for (info_list = layer_infos; info_list != NULL; info_list = g_list_next(info_list)) {
linfo = (struct layer_info *)info_list->data;
dprintf(comm_pipe[1], _("Exporting layer %d to file\n"), linfo->layer);
if (linfo->layer >= MAX_LAYERS) {
printf(_("Layer outside of spec.\n"));
continue;
}
if (!linfo->render)
continue;
if (pdf_file && pdf_cr) {
cairo_set_source_surface(pdf_cr, layers[linfo->layer].rec, -xmin, -ymin);
cairo_paint_with_alpha(pdf_cr, linfo->color.alpha);
}
if (svg_file && svg_cr) {
cairo_set_source_surface(svg_cr, layers[linfo->layer].rec, -xmin, -ymin);
cairo_paint_with_alpha(svg_cr, linfo->color.alpha);
}
}
if (pdf_file) {
cairo_show_page(pdf_cr);
cairo_destroy(pdf_cr);
cairo_surface_destroy(pdf_surface);
}
if (svg_file) {
cairo_show_page(svg_cr);
cairo_destroy(svg_cr);
cairo_surface_destroy(svg_surface);
}
ret_clear_layers:
for (i = 0; i < MAX_LAYERS; i++) {
lay = &layers[i];
if (lay->cr) {
cairo_destroy(lay->cr);
cairo_surface_destroy(lay->rec);
}
}
free(layers);
printf(_("Cairo export finished. It might still be buggy!\n"));
/* Suspend child process */
exit(0);
ret_parent:
close(comm_pipe[1]);
while (read_line_from_fd(comm_pipe[0], receive_message, sizeof(receive_message)) > 0) {
/* Strip \n from string and replace with ' ' */
for (i = 0; receive_message[i] != '\0'; i++) {
if (receive_message[i] == '\n')
receive_message[i] = ' ';
}
/* Update asyc progress*/
gds_output_renderer_update_async_progress(renderer, receive_message);
}
waitpid(process_id, NULL, 0);
close(comm_pipe[0]);
return 0;
}
static void cairo_renderer_init(CairoRenderer *self)
{
/* PDF default */
self->svg = FALSE;
}
static int cairo_renderer_render_output(GdsOutputRenderer *renderer,
struct gds_cell *cell,
double scale)
{
CairoRenderer *c_renderer = GDS_RENDER_CAIRO_RENDERER(renderer);
const char *pdf_file = NULL;
const char *svg_file = NULL;
LayerSettings *settings;
GList *layer_infos = NULL;
const char *output_file;
int ret;
if (!c_renderer)
return -2000;
output_file = gds_output_renderer_get_output_file(renderer);
settings = gds_output_renderer_get_and_ref_layer_settings(renderer);
/* Set layer info list. In case of failure it remains NULL */
if (settings)
layer_infos = layer_settings_get_layer_info_list(settings);
if (c_renderer->svg == TRUE)
svg_file = output_file;
else
pdf_file = output_file;
gds_output_renderer_update_async_progress(renderer, _("Rendering Cairo Output..."));
ret = cairo_renderer_render_cell_to_vector_file(renderer, cell, layer_infos, pdf_file, svg_file, scale);
if (settings)
g_object_unref(settings);
return ret;
}
static void cairo_renderer_class_init(CairoRendererClass *klass)
{
GdsOutputRendererClass *renderer_class = GDS_RENDER_OUTPUT_RENDERER_CLASS(klass);
renderer_class->render_output = cairo_renderer_render_output;
}
CairoRenderer *cairo_renderer_new_pdf()
{
CairoRenderer *renderer;
renderer = GDS_RENDER_CAIRO_RENDERER(g_object_new(GDS_RENDER_TYPE_CAIRO_RENDERER, NULL));
renderer->svg = FALSE;
return renderer;
}
CairoRenderer *cairo_renderer_new_svg()
{
CairoRenderer *renderer;
renderer = GDS_RENDER_CAIRO_RENDERER(g_object_new(GDS_RENDER_TYPE_CAIRO_RENDERER, NULL));
renderer->svg = TRUE;
return renderer;
}
/** @} */

View File

@@ -0,0 +1,281 @@
/*
* GDSII-Converter
* Copyright (C) 2018 Mario Hüttel <mario.huettel@gmx.net>
*
* This file is part of GDSII-Converter.
*
* GDSII-Converter is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*
* GDSII-Converter is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with GDSII-Converter. If not, see <http://www.gnu.org/licenses/>.
*/
/**
* @file external-renderer.c
* @brief This file implements the dynamic library loading for the external rendering feature
* @author Mario Hüttel <mario.huettel@gmx.net>
*/
/**
* @addtogroup ExternalRenderer
* @{
*/
#include <dlfcn.h>
#include <stdio.h>
#include <sys/wait.h>
#include <glib/gi18n.h>
#include <gds-render/output-renderers/external-renderer.h>
#include <gds-render/version.h>
#define FORCE_FORK 0U /**< @brief if != 0, then forking is forced regardless of the shared object's settings */
struct _ExternalRenderer {
GdsOutputRenderer parent;
char *shared_object_path;
char *cli_param_string;
};
enum {
PROP_SO_PATH = 1, /**< @brief Shared object path property */
PROP_PARAM_STRING, /** @brief Shared object renderer parameter string from CLI */
N_PROPERTIES /**< @brief Used to get property count */
};
G_DEFINE_TYPE(ExternalRenderer, external_renderer, GDS_RENDER_TYPE_OUTPUT_RENDERER)
/**
* @brief Execute render function in shared object to render the supplied cell
* @param toplevel_cell Cell to render
* @param layer_info_list Layer information (Color etc.)
* @param output_file Destination file
* @param scale the scaling value to scale the output cell down by.
* @param so_path Path to shared object
* @param params Parameters passed to EXTERNAL_LIBRARY_INIT_FUNCTION
* @return 0 if successful
*/
static int external_renderer_render_cell(struct gds_cell *toplevel_cell, GList *layer_info_list,
const char *output_file, double scale, const char *so_path, const char *params)
{
int (*so_render_func)(struct gds_cell *, GList *, const char *, double) = NULL;
int (*so_init_func)(const char *, const char *) = NULL;
void *so_handle = NULL;
char *error_msg;
int forking_req;
int ret = 0;
pid_t fork_pid = 0;
int forked_status;
if (!so_path) {
fprintf(stderr, _("Path to shared object not set!\n"));
return -3000;
}
/* Check parameter sanity */
if (!output_file || !toplevel_cell || !layer_info_list)
return -3000;
/* Load shared object */
so_handle = dlopen(so_path, RTLD_LAZY);
if (!so_handle) {
fprintf(stderr, _("Could not load external library '%s'\nDetailed error is:\n%s\n"), so_path, dlerror());
return -2000;
}
/* Load rendering symbol from library */
so_render_func = (int (*)(struct gds_cell *, GList *, const char *, double))
dlsym(so_handle, xstr(EXTERNAL_LIBRARY_RENDER_FUNCTION));
error_msg = dlerror();
if (error_msg != NULL) {
fprintf(stderr, _("Rendering function not found in library:\n%s\n"), error_msg);
goto ret_close_so_handle;
}
/* Load the init function */
so_init_func = (int (*)(const char *, const char *))dlsym(so_handle, xstr(EXTERNAL_LIBRARY_INIT_FUNCTION));
error_msg = dlerror();
if (error_msg != NULL) {
fprintf(stderr, _("Init function not found in library:\n%s\n"), error_msg);
goto ret_close_so_handle;
}
/* Check if forking is requested */
if (dlsym(so_handle, xstr(EXTERNAL_LIBRARY_FORK_REQUEST)))
forking_req = 1;
else if (FORCE_FORK)
forking_req = 1;
else
forking_req = 0;
/* Execute */
g_message(_("Calling external renderer."));
if (forking_req)
fork_pid = fork();
if (fork_pid != 0)
goto end_forked;
ret = so_init_func(params, _app_version_string);
if (!ret)
ret = so_render_func(toplevel_cell, layer_info_list, output_file, scale);
/* If we are in a separate process, terminate here */
if (forking_req)
exit(ret);
/* The forked paths end here */
end_forked:
if (forking_req) {
waitpid(fork_pid, &forked_status, 0);
ret = WEXITSTATUS(forked_status);
}
g_message(_("External renderer finished."));
ret_close_so_handle:
dlclose(so_handle);
return ret;
}
static int external_renderer_render_output(GdsOutputRenderer *renderer,
struct gds_cell *cell,
double scale)
{
ExternalRenderer *ext_renderer = GDS_RENDER_EXTERNAL_RENDERER(renderer);
LayerSettings *settings;
GList *layer_infos = NULL;
const char *output_file;
int ret;
output_file = gds_output_renderer_get_output_file(renderer);
settings = gds_output_renderer_get_and_ref_layer_settings(renderer);
/* Set layer info list. In case of failure it remains NULL */
if (settings)
layer_infos = layer_settings_get_layer_info_list(settings);
ret = external_renderer_render_cell(cell, layer_infos, output_file, scale, ext_renderer->shared_object_path,
ext_renderer->cli_param_string);
if (settings)
g_object_unref(settings);
return ret;
}
static void external_renderer_get_property(GObject *obj, guint property_id, GValue *value, GParamSpec *pspec)
{
ExternalRenderer *self;
self = GDS_RENDER_EXTERNAL_RENDERER(obj);
switch (property_id) {
case PROP_SO_PATH:
g_value_set_string(value, self->shared_object_path);
break;
case PROP_PARAM_STRING:
g_value_set_string(value, self->cli_param_string);
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID(obj, property_id, pspec);
break;
}
}
static void external_renderer_set_property(GObject *obj, guint property_id, const GValue *value, GParamSpec *pspec)
{
ExternalRenderer *self;
self = GDS_RENDER_EXTERNAL_RENDERER(obj);
switch (property_id) {
case PROP_SO_PATH:
if (self->shared_object_path)
g_free(self->shared_object_path);
self->shared_object_path = g_value_dup_string(value);
break;
case PROP_PARAM_STRING:
if (self->cli_param_string)
g_free(self->cli_param_string);
self->cli_param_string = g_value_dup_string(value);
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID(obj, property_id, pspec);
break;
}
}
static void external_renderer_dispose(GObject *self_obj)
{
ExternalRenderer *self;
self = GDS_RENDER_EXTERNAL_RENDERER(self_obj);
if (self->shared_object_path) {
g_free(self->shared_object_path);
self->shared_object_path = NULL;
}
G_OBJECT_CLASS(external_renderer_parent_class)->dispose(self_obj);
}
static GParamSpec *external_renderer_properties[N_PROPERTIES] = {NULL};
static void external_renderer_class_init(ExternalRendererClass *klass)
{
GdsOutputRendererClass *inherited_parent_class;
GObjectClass *oclass;
inherited_parent_class = GDS_RENDER_OUTPUT_RENDERER_CLASS(klass);
oclass = G_OBJECT_CLASS(klass);
/* Override virtual function */
inherited_parent_class->render_output = external_renderer_render_output;
/* Setup Gobject callbacks */
oclass->set_property = external_renderer_set_property;
oclass->get_property = external_renderer_get_property;
oclass->dispose = external_renderer_dispose;
/* Setup properties */
external_renderer_properties[PROP_SO_PATH] =
g_param_spec_string(N_("shared-object-path"),
N_("Shared object file path"),
N_("Path to the shared object to search rendering function in."),
NULL,
G_PARAM_READWRITE);
external_renderer_properties[PROP_PARAM_STRING] =
g_param_spec_string(N_("param-string"),
N_("Shared object renderer parameter string"),
N_("Command line arguments passed to the external shared object renderer"),
NULL,
G_PARAM_READWRITE);
g_object_class_install_properties(oclass, N_PROPERTIES, external_renderer_properties);
}
static void external_renderer_init(ExternalRenderer *self)
{
self->shared_object_path = NULL;
self->cli_param_string = NULL;
}
ExternalRenderer *external_renderer_new()
{
return g_object_new(GDS_RENDER_TYPE_EXTERNAL_RENDERER, NULL);
}
ExternalRenderer *external_renderer_new_with_so_and_param(const char *so_path, const char *param_string)
{
return g_object_new(GDS_RENDER_TYPE_EXTERNAL_RENDERER, N_("shared-object-path"), so_path,
N_("param-string"), param_string, NULL);
}
/** @} */

View File

@@ -0,0 +1,450 @@
/*
* GDSII-Converter
* Copyright (C) 2019 Mario Hüttel <mario.huettel@gmx.net>
*
* This file is part of GDSII-Converter.
*
* GDSII-Converter is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*
* GDSII-Converter is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with GDSII-Converter. If not, see <http://www.gnu.org/licenses/>.
*/
/**
* @file gds-output-renderer.c
* @brief Base GObject class for output renderers
* @author Mario Hüttel <mario.huettel@gmx.net>
*/
/** @addtogroup GdsOutputRenderer
* @{
*/
#include <gds-render/output-renderers/gds-output-renderer.h>
#include <glib/gi18n.h>
struct renderer_params {
struct gds_cell *cell;
double scale;
};
struct idle_function_params {
GMutex message_lock;
char *status_message;
};
typedef struct {
gchar *output_file;
LayerSettings *layer_settings;
GMutex settings_lock;
gboolean mutex_init_status;
GTask *task;
GMainContext *main_context;
struct renderer_params async_params;
struct idle_function_params idle_function_parameters;
gpointer padding[11];
} GdsOutputRendererPrivate;
enum {
PROP_OUTPUT_FILE = 1,
PROP_LAYER_SETTINGS,
N_PROPERTIES
};
G_DEFINE_TYPE_WITH_PRIVATE(GdsOutputRenderer, gds_output_renderer, G_TYPE_OBJECT)
enum gds_output_renderer_signal_ids {ASYNC_FINISHED = 0, ASYNC_PROGRESS_CHANGED, GDS_OUTPUT_RENDERER_SIGNAL_COUNT};
static guint gds_output_renderer_signals[GDS_OUTPUT_RENDERER_SIGNAL_COUNT];
static int gds_output_renderer_render_dummy(GdsOutputRenderer *renderer,
struct gds_cell *cell,
double scale)
{
(void)renderer;
(void)cell;
(void)scale;
g_warning(_("Output renderer does not define a render_output function!"));
return 0;
}
static void gds_output_renderer_dispose(GObject *self_obj)
{
GdsOutputRenderer *renderer = GDS_RENDER_OUTPUT_RENDERER(self_obj);
GdsOutputRendererPrivate *priv;
priv = gds_output_renderer_get_instance_private(renderer);
if (priv->mutex_init_status) {
/* Try locking the mutex, to test if it's free */
g_mutex_lock(&priv->settings_lock);
g_mutex_unlock(&priv->settings_lock);
g_mutex_clear(&priv->settings_lock);
g_mutex_lock(&priv->idle_function_parameters.message_lock);
g_mutex_unlock(&priv->idle_function_parameters.message_lock);
g_mutex_clear(&priv->idle_function_parameters.message_lock);
priv->mutex_init_status = FALSE;
}
g_clear_object(&priv->task);
if (priv->output_file)
g_free(priv->output_file);
g_clear_object(&priv->layer_settings);
/* Chain up to parent class */
G_OBJECT_CLASS(gds_output_renderer_parent_class)->dispose(self_obj);
}
static void gds_output_renderer_get_property(GObject *obj, guint property_id, GValue *value, GParamSpec *pspec)
{
GdsOutputRenderer *self = GDS_RENDER_OUTPUT_RENDERER(obj);
GdsOutputRendererPrivate *priv;
priv = gds_output_renderer_get_instance_private(self);
switch (property_id) {
case PROP_OUTPUT_FILE:
g_value_set_string(value, priv->output_file);
break;
case PROP_LAYER_SETTINGS:
g_value_set_object(value, priv->layer_settings);
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID(obj, property_id, pspec);
break;
}
}
static void gds_output_renderer_set_property(GObject *obj, guint property_id, const GValue *value, GParamSpec *pspec)
{
GdsOutputRenderer *self = GDS_RENDER_OUTPUT_RENDERER(obj);
GdsOutputRendererPrivate *priv;
priv = gds_output_renderer_get_instance_private(self);
switch (property_id) {
case PROP_OUTPUT_FILE:
g_mutex_lock(&priv->settings_lock);
if (priv->output_file)
g_free(priv->output_file);
priv->output_file = g_strdup(g_value_get_string(value));
g_mutex_unlock(&priv->settings_lock);
break;
case PROP_LAYER_SETTINGS:
g_mutex_lock(&priv->settings_lock);
g_clear_object(&priv->layer_settings);
priv->layer_settings = g_value_get_object(value);
g_object_ref(priv->layer_settings);
g_mutex_unlock(&priv->settings_lock);
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID(obj, property_id, pspec);
break;
}
}
static GParamSpec *gds_output_renderer_properties[N_PROPERTIES] = {NULL};
static void gds_output_renderer_class_init(GdsOutputRendererClass *klass)
{
GObjectClass *oclass = G_OBJECT_CLASS(klass);
GType progress_changed_param_types[1] = {G_TYPE_POINTER};
klass->render_output = gds_output_renderer_render_dummy;
oclass->dispose = gds_output_renderer_dispose;
oclass->set_property = gds_output_renderer_set_property;
oclass->get_property = gds_output_renderer_get_property;
/* Setup properties */
gds_output_renderer_properties[PROP_OUTPUT_FILE] =
g_param_spec_string(N_("output-file"), N_("output file"), N_("Output file for renderer"),
NULL, G_PARAM_READWRITE);
gds_output_renderer_properties[PROP_LAYER_SETTINGS] =
g_param_spec_object(N_("layer-settings"), N_("Layer Settings object"),
N_("Object containing the layer rendering information"),
GDS_RENDER_TYPE_LAYER_SETTINGS, G_PARAM_READWRITE);
g_object_class_install_properties(oclass, N_PROPERTIES, gds_output_renderer_properties);
/* Setup output signals */
gds_output_renderer_signals[ASYNC_FINISHED] =
g_signal_newv(N_("async-finished"), GDS_RENDER_TYPE_OUTPUT_RENDERER,
G_SIGNAL_RUN_LAST | G_SIGNAL_NO_RECURSE,
NULL,
NULL,
NULL,
NULL,
G_TYPE_NONE,
0,
NULL);
gds_output_renderer_signals[ASYNC_PROGRESS_CHANGED] =
g_signal_newv(N_("progress-changed"), GDS_RENDER_TYPE_OUTPUT_RENDERER,
G_SIGNAL_RUN_LAST | G_SIGNAL_NO_RECURSE,
NULL,
NULL,
NULL,
NULL,
G_TYPE_NONE,
1,
progress_changed_param_types);
}
void gds_output_renderer_init(GdsOutputRenderer *self)
{
GdsOutputRendererPrivate *priv;
priv = gds_output_renderer_get_instance_private(self);
priv->layer_settings = NULL;
priv->output_file = NULL;
priv->task = NULL;
priv->mutex_init_status = TRUE;
priv->main_context = NULL;
priv->idle_function_parameters.status_message = NULL;
g_mutex_init(&priv->settings_lock);
g_mutex_init(&priv->idle_function_parameters.message_lock);
}
GdsOutputRenderer *gds_output_renderer_new()
{
return GDS_RENDER_OUTPUT_RENDERER(g_object_new(GDS_RENDER_TYPE_OUTPUT_RENDERER, NULL));
}
GdsOutputRenderer *gds_output_renderer_new_with_props(const char *output_file, LayerSettings *layer_settings)
{
return GDS_RENDER_OUTPUT_RENDERER(g_object_new(GDS_RENDER_TYPE_OUTPUT_RENDERER,
N_("layer-settings"), layer_settings,
N_("output-file"), output_file,
NULL));
}
void gds_output_renderer_set_output_file(GdsOutputRenderer *renderer, const gchar *file_name)
{
g_return_if_fail(GDS_RENDER_IS_OUTPUT_RENDERER(renderer));
/* Check if the filename is actually filled */
if (!file_name || !file_name[0])
return;
g_object_set(renderer, N_("output-file"), file_name, NULL);
}
const char *gds_output_renderer_get_output_file(GdsOutputRenderer *renderer)
{
const char *file = NULL;
g_object_get(renderer, N_("output-file"), &file, NULL);
return file;
}
LayerSettings *gds_output_renderer_get_and_ref_layer_settings(GdsOutputRenderer *renderer)
{
LayerSettings *ret = NULL;
GdsOutputRendererPrivate *priv;
priv = gds_output_renderer_get_instance_private(renderer);
/* Acquire settings lock */
g_mutex_lock(&priv->settings_lock);
/* This function seems to already reference the LayerSettings object */
g_object_get(renderer, N_("layer-settings"), &ret, NULL);
/* It is now safe to clear the lock */
g_mutex_unlock(&priv->settings_lock);
return ret;
}
void gds_output_renderer_set_layer_settings(GdsOutputRenderer *renderer, LayerSettings *settings)
{
g_return_if_fail(GDS_RENDER_IS_LAYER_SETTINGS(settings));
g_object_set(renderer, N_("layer-settings"), settings, NULL);
}
int gds_output_renderer_render_output(GdsOutputRenderer *renderer, struct gds_cell *cell, double scale)
{
int ret;
GdsOutputRendererClass *klass;
GdsOutputRendererPrivate *priv = gds_output_renderer_get_instance_private(renderer);
if (GDS_RENDER_IS_OUTPUT_RENDERER(renderer) == FALSE) {
g_error(_("Output Renderer not valid."));
return GDS_OUTPUT_RENDERER_GEN_ERR;
}
if (!priv->output_file || !priv->output_file[0]) {
g_error(_("No/invalid output file set."));
return GDS_OUTPUT_RENDERER_GEN_ERR;
}
if (!priv->layer_settings) {
g_error(_("No layer specification supplied."));
return GDS_OUTPUT_RENDERER_GEN_ERR;
}
if (!cell) {
g_error(_("Output renderer called without cell to render."));
return GDS_OUTPUT_RENDERER_PARAM_ERR;
}
klass = GDS_RENDER_OUTPUT_RENDERER_GET_CLASS(renderer);
if (klass->render_output == NULL) {
g_critical(_("Output Renderer: Rendering function broken. This is a bug."));
return GDS_OUTPUT_RENDERER_GEN_ERR;
}
ret = klass->render_output(renderer, cell, scale);
return ret;
}
static void gds_output_renderer_async_wrapper(GTask *task,
gpointer source_object,
gpointer task_data,
GCancellable *cancellable)
{
GdsOutputRenderer *renderer;
GdsOutputRendererPrivate *priv;
int ret;
(void)task_data;
(void)cancellable;
renderer = GDS_RENDER_OUTPUT_RENDERER(source_object);
priv = gds_output_renderer_get_instance_private(renderer);
if (!priv) {
ret = -1000;
goto ret_from_task;
}
if (!priv->mutex_init_status) {
ret = -1001;
goto ret_from_task;
}
ret = gds_output_renderer_render_output(renderer, priv->async_params.cell, priv->async_params.scale);
ret_from_task:
g_task_return_int(task, ret);
}
static void gds_output_renderer_async_finished(GObject *src_obj, GAsyncResult *res, gpointer user_data)
{
GdsOutputRendererPrivate *priv;
(void)user_data;
(void)res; /* Will hopefully be destroyed later */
priv = gds_output_renderer_get_instance_private(GDS_RENDER_OUTPUT_RENDERER(src_obj));
priv->main_context = NULL;
g_signal_emit(src_obj, gds_output_renderer_signals[ASYNC_FINISHED], 0);
g_clear_object(&priv->task);
/* Clear reference set in gds_output_renderer_render_output_async() */
g_object_unref(src_obj);
}
int gds_output_renderer_render_output_async(GdsOutputRenderer *renderer, struct gds_cell *cell, double scale)
{
GdsOutputRendererPrivate *priv;
int ret = -1;
priv = gds_output_renderer_get_instance_private(renderer);
if (priv->task) {
g_warning(_("Renderer already started asynchronously"));
return -2000;
}
priv->task = g_task_new(renderer, NULL, gds_output_renderer_async_finished, NULL);
/* This function is not available on current debian distros. */
/* g_task_set_name(priv->task, "Rendering Thread"); */
g_mutex_lock(&priv->settings_lock);
priv->async_params.cell = cell;
priv->async_params.scale = scale;
priv->main_context = g_main_context_default();
g_mutex_unlock(&priv->settings_lock);
/* Self reference. This could end up being nasty... */
g_object_ref(renderer);
/* Do the magic */
g_task_run_in_thread(priv->task, gds_output_renderer_async_wrapper);
return ret;
}
static gboolean idle_event_processor_callback(gpointer user_data)
{
GdsOutputRenderer *renderer;
GdsOutputRendererPrivate *priv;
char *status_message;
/* If the rendering is finished before the mainloop gets to this point
* the renderer is already disposed. Catch this!
*/
if (!GDS_RENDER_IS_OUTPUT_RENDERER(user_data))
return FALSE;
renderer = GDS_RENDER_OUTPUT_RENDERER(user_data);
priv = gds_output_renderer_get_instance_private(renderer);
if (g_mutex_trylock(&priv->idle_function_parameters.message_lock)) {
status_message = priv->idle_function_parameters.status_message;
g_signal_emit(renderer, gds_output_renderer_signals[ASYNC_PROGRESS_CHANGED], 0, status_message);
g_free(priv->idle_function_parameters.status_message);
priv->idle_function_parameters.status_message = NULL;
g_mutex_unlock(&priv->idle_function_parameters.message_lock);
} else {
return TRUE;
}
return FALSE;
}
void gds_output_renderer_update_async_progress(GdsOutputRenderer *renderer, const char *status)
{
GSource *idle_event_processor;
GdsOutputRendererPrivate *priv;
gboolean skip_source = FALSE;
g_return_if_fail(GDS_RENDER_IS_OUTPUT_RENDERER(renderer));
if (!status)
return;
priv = gds_output_renderer_get_instance_private(renderer);
/* If rendering is not async */
if (!priv->main_context)
return;
g_mutex_lock(&priv->idle_function_parameters.message_lock);
if (priv->idle_function_parameters.status_message) {
g_free(priv->idle_function_parameters.status_message);
/* Skip adding new idle source because there's already an active one */
skip_source = TRUE;
}
priv->idle_function_parameters.status_message = g_strdup(status);
g_mutex_unlock(&priv->idle_function_parameters.message_lock);
if (!skip_source) {
idle_event_processor = g_idle_source_new();
g_source_set_callback(idle_event_processor, idle_event_processor_callback, (gpointer)renderer, NULL);
g_source_attach(idle_event_processor, priv->main_context);
}
}
/** @} */

View File

@@ -0,0 +1,465 @@
/*
* GDSII-Converter
* Copyright (C) 2018 Mario Hüttel <mario.huettel@gmx.net>
*
* This file is part of GDSII-Converter.
*
* GDSII-Converter is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*
* GDSII-Converter is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with GDSII-Converter. If not, see <http://www.gnu.org/licenses/>.
*/
/**
* @file latex-renderer.c
* @brief LaTeX Output Renderer
* @author Mario Hüttel <mario.huettel@gmx.net>
*/
#include <math.h>
#include <stdio.h>
#include <gds-render/output-renderers/latex-renderer.h>
#include <gdk/gdk.h>
#include <glib/gi18n.h>
/**
* @addtogroup LaTeX-Renderer
* @{
*/
/**
* @brief Struct representing the LaTeX-Renderer object.
*
* This struct holds the LaTeX renderer internal data. It is only used inside the @ref LaTeX-Renderer class.
*/
struct _LatexRenderer {
GdsOutputRenderer parent;
gboolean tex_standalone;
gboolean pdf_layers;
};
G_DEFINE_TYPE(LatexRenderer, latex_renderer, GDS_RENDER_TYPE_OUTPUT_RENDERER)
enum {
PROP_STANDALONE = 1,
PROP_PDF_LAYERS,
N_PROPERTIES
};
/**
* @brief Writes a GString \p buffer to the fixed file tex_file
* @note This is a convinience macro. Do not use this anywhere else. It might change behavior in futurtre releases
*/
#define WRITEOUT_BUFFER(buff) fwrite((buff)->str, sizeof(char), (buff)->len, tex_file)
/**
* @brief Write the layer declarration to TeX file
*
* This writes the declaration of the layers and the mapping in which order
* the layers shall be rendered by TikZ. Layers are written in the order they are
* positioned inside the \p layer_infos list.
*
* @param tex_file TeX-File to write to
* @param layer_infos List containing layer_info structs.
* @param buffer
* @note The field layer_info::stacked_position is ignored. Stack depends on list order.
*/
static void write_layer_definitions(FILE *tex_file, GList *layer_infos, GString *buffer)
{
GList *list;
struct layer_info *lifo;
for (list = layer_infos; list != NULL; list = list->next) {
lifo = (struct layer_info *)list->data;
if (!lifo->render)
continue;
g_string_printf(buffer, "\\pgfdeclarelayer{l%d}\n\\definecolor{c%d}{rgb}{%lf,%lf,%lf}\n",
lifo->layer, lifo->layer,
lifo->color.red, lifo->color.green, lifo->color.blue);
WRITEOUT_BUFFER(buffer);
}
g_string_printf(buffer, "\\pgfsetlayers{");
WRITEOUT_BUFFER(buffer);
for (list = layer_infos; list != NULL; list = list->next) {
lifo = (struct layer_info *)list->data;
if (!lifo->render)
continue;
g_string_printf(buffer, "l%d,", lifo->layer);
WRITEOUT_BUFFER(buffer);
}
g_string_printf(buffer, "main}\n");
WRITEOUT_BUFFER(buffer);
}
/**
* @brief Write layer Envirmonment
*
* If the requested layer shall be rendered, this code writes the necessary code
* to open the layer. It also returns the color the layer shall be rendered in.
*
* The followingenvironments are generated:
*
* @code{.tex}
* \begin{pgfonlayer}{<layer>}
* % If pdf layers shall be used also this is enabled:
* \begin{scope}[ocg={ref=<layer>, status=visible,name={<Layer Name>}}]
* @endcode
*
*
* If the layer shall not be rendered, FALSE is returned and the color is not filled in and
* the cod eis not written to the file.
*
* @param tex_file TeX file to write to
* @param color Return of the layer's color
* @param layer Requested layer number
* @param linfo Layer information list containing layer_info structs
* @param buffer Some working buffer
* @return TRUE, if the layer shall be rendered.
* @note The opened environments have to be closed afterwards
*/
static gboolean write_layer_env(FILE *tex_file, GdkRGBA *color, int layer, GList *linfo, GString *buffer)
{
GList *temp;
struct layer_info *inf;
for (temp = linfo; temp != NULL; temp = temp->next) {
inf = (struct layer_info *)temp->data;
if (inf->layer == layer && inf->render) {
color->alpha = inf->color.alpha;
color->red = inf->color.red;
color->green = inf->color.green;
color->blue = inf->color.blue;
g_string_printf(buffer,
"\\begin{pgfonlayer}{l%d}\n\\ifcreatepdflayers\n\\begin{scope}[ocg={ref=%d, status=visible,name={%s}}]\n\\fi\n",
layer, layer, inf->name);
WRITEOUT_BUFFER(buffer);
return TRUE;
}
}
return FALSE;
}
/**
* @brief Writes a graphics object to the specified tex_file
*
* This function opens the layer, writes a graphics object and closes the layer
*
* @param tex_file File to write to
* @param graphics Object to render
* @param linfo Layer information
* @param buffer Working buffer
* @param scale Scale abject down by this value
*/
static void generate_graphics(FILE *tex_file, GList *graphics, GList *linfo, GString *buffer, double scale)
{
GList *temp;
GList *temp_vertex;
struct gds_graphics *gfx;
struct gds_point *pt;
GdkRGBA color;
static const char * const line_caps[] = {"butt", "round", "rect"};
for (temp = graphics; temp != NULL; temp = temp->next) {
gfx = (struct gds_graphics *)temp->data;
if (write_layer_env(tex_file, &color, (int)gfx->layer, linfo, buffer) == TRUE) {
/* Layer is defined => create graphics */
if (gfx->gfx_type == GRAPHIC_POLYGON || gfx->gfx_type == GRAPHIC_BOX) {
g_string_printf(buffer,
"\\draw[line width=0.00001 pt, draw={c%d}, fill={c%d}, fill opacity={%lf}] ",
gfx->layer, gfx->layer, color.alpha);
WRITEOUT_BUFFER(buffer);
/* Append vertices */
for (temp_vertex = gfx->vertices;
temp_vertex != NULL;
temp_vertex = temp_vertex->next) {
pt = (struct gds_point *)temp_vertex->data;
g_string_printf(buffer, "(%lf pt, %lf pt) -- ",
((double)pt->x)/scale,
((double)pt->y)/scale);
WRITEOUT_BUFFER(buffer);
}
g_string_printf(buffer, "cycle;\n");
WRITEOUT_BUFFER(buffer);
} else if (gfx->gfx_type == GRAPHIC_PATH) {
if (g_list_length(gfx->vertices) < 2) {
printf("Cannot write path with less than 2 points\n");
break;
}
if (gfx->path_render_type < 0 || gfx->path_render_type > 2) {
printf("Path type unrecognized. Setting to 'flushed'\n");
gfx->path_render_type = PATH_FLUSH;
}
g_string_printf(buffer, "\\draw[line width=%lf pt, draw={c%d}, opacity={%lf}, cap=%s] ",
gfx->width_absolute/scale, gfx->layer, color.alpha,
line_caps[gfx->path_render_type]);
WRITEOUT_BUFFER(buffer);
/* Append vertices */
for (temp_vertex = gfx->vertices;
temp_vertex != NULL;
temp_vertex = temp_vertex->next) {
pt = (struct gds_point *)temp_vertex->data;
g_string_printf(buffer, "(%lf pt, %lf pt)%s",
((double)pt->x)/scale,
((double)pt->y)/scale,
(temp_vertex->next ? " -- " : ""));
WRITEOUT_BUFFER(buffer);
}
g_string_printf(buffer, ";\n");
WRITEOUT_BUFFER(buffer);
}
g_string_printf(buffer, "\\ifcreatepdflayers\n\\end{scope}\n\\fi\n\\end{pgfonlayer}\n");
WRITEOUT_BUFFER(buffer);
}
} /* For graphics */
}
/**
* @brief Render cell to file
* @param cell Cell to render
* @param layer_infos Layer information
* @param tex_file File to write to
* @param buffer Working buffer
* @param scale Scale output down by this value
* @param renderer The current renderer as GdsOutputRenderer. This is used to emit the status updates to the GUI
*/
static void render_cell(struct gds_cell *cell, GList *layer_infos, FILE *tex_file, GString *buffer, double scale,
GdsOutputRenderer *renderer)
{
GString *status;
GList *list_child;
struct gds_cell_instance *inst;
status = g_string_new(NULL);
g_string_printf(status, _("Generating cell %s"), cell->name);
gds_output_renderer_update_async_progress(renderer, status->str);
g_string_free(status, TRUE);
/* Draw polygons of current cell */
generate_graphics(tex_file, cell->graphic_objs, layer_infos, buffer, scale);
/* Draw polygons of childs */
for (list_child = cell->child_cells; list_child != NULL; list_child = list_child->next) {
inst = (struct gds_cell_instance *)list_child->data;
/* Abort if cell has no reference */
if (!inst->cell_ref)
continue;
/* generate translation scope */
g_string_printf(buffer, "\\begin{scope}[shift={(%lf pt,%lf pt)}]\n",
((double)inst->origin.x) / scale, ((double)inst->origin.y) / scale);
WRITEOUT_BUFFER(buffer);
g_string_printf(buffer, "\\begin{scope}[rotate=%lf]\n", inst->angle);
WRITEOUT_BUFFER(buffer);
g_string_printf(buffer, "\\begin{scope}[yscale=%lf, xscale=%lf]\n",
(inst->flipped ? -1*inst->magnification : inst->magnification),
inst->magnification);
WRITEOUT_BUFFER(buffer);
render_cell(inst->cell_ref, layer_infos, tex_file, buffer, scale, renderer);
g_string_printf(buffer, "\\end{scope}\n");
WRITEOUT_BUFFER(buffer);
g_string_printf(buffer, "\\end{scope}\n");
WRITEOUT_BUFFER(buffer);
g_string_printf(buffer, "\\end{scope}\n");
WRITEOUT_BUFFER(buffer);
}
}
static int latex_render_cell_to_code(struct gds_cell *cell, GList *layer_infos, FILE *tex_file, double scale,
gboolean create_pdf_layers, gboolean standalone_document, GdsOutputRenderer *renderer)
{
GString *working_line;
if (!tex_file || !layer_infos || !cell)
return -1;
/* 10 kB Line working buffer should be enough */
working_line = g_string_new_len(NULL, LATEX_LINE_BUFFER_KB*1024);
/* standalone foo */
g_string_printf(working_line, "\\newif\\iftestmode\n\\testmode%s\n",
(standalone_document ? "true" : "false"));
WRITEOUT_BUFFER(working_line);
g_string_printf(working_line, "\\newif\\ifcreatepdflayers\n\\createpdflayers%s\n",
(create_pdf_layers ? "true" : "false"));
WRITEOUT_BUFFER(working_line);
g_string_printf(working_line, "\\iftestmode\n");
WRITEOUT_BUFFER(working_line);
g_string_printf(working_line,
"\\documentclass[tikz]{standalone}\n\\usepackage{xcolor}\n\\usetikzlibrary{ocgx}\n\\begin{document}\n");
WRITEOUT_BUFFER(working_line);
g_string_printf(working_line, "\\fi\n");
WRITEOUT_BUFFER(working_line);
/* Write layer definitions */
write_layer_definitions(tex_file, layer_infos, working_line);
/* Open tikz Pictute */
g_string_printf(working_line, "\\begin{tikzpicture}\n");
WRITEOUT_BUFFER(working_line);
/* Generate graphics output */
render_cell(cell, layer_infos, tex_file, working_line, scale, renderer);
g_string_printf(working_line, "\\end{tikzpicture}\n");
WRITEOUT_BUFFER(working_line);
g_string_printf(working_line, "\\iftestmode\n");
WRITEOUT_BUFFER(working_line);
g_string_printf(working_line, "\\end{document}\n");
WRITEOUT_BUFFER(working_line);
g_string_printf(working_line, "\\fi\n");
WRITEOUT_BUFFER(working_line);
fflush(tex_file);
g_string_free(working_line, TRUE);
return 0;
}
static int latex_renderer_render_output(GdsOutputRenderer *renderer,
struct gds_cell *cell,
double scale)
{
LatexRenderer *l_renderer = GDS_RENDER_LATEX_RENDERER(renderer);
FILE *tex_file;
int ret = -2;
LayerSettings *settings;
GList *layer_infos = NULL;
const char *output_file;
output_file = gds_output_renderer_get_output_file(renderer);
settings = gds_output_renderer_get_and_ref_layer_settings(renderer);
/* Set layer info list. In case of failure it remains NULL */
if (settings)
layer_infos = layer_settings_get_layer_info_list(settings);
tex_file = fopen(output_file, "w");
if (tex_file) {
ret = latex_render_cell_to_code(cell, layer_infos, tex_file, scale,
l_renderer->pdf_layers, l_renderer->tex_standalone, renderer);
fclose(tex_file);
} else {
g_error(_("Could not open LaTeX output file"));
}
if (settings)
g_object_unref(settings);
return ret;
}
static void latex_renderer_init(LatexRenderer *self)
{
self->pdf_layers = FALSE;
self->tex_standalone = FALSE;
}
static void latex_renderer_get_property(GObject *obj, guint property_id, GValue *value, GParamSpec *pspec)
{
LatexRenderer *self = GDS_RENDER_LATEX_RENDERER(obj);
switch (property_id) {
case PROP_STANDALONE:
g_value_set_boolean(value, self->tex_standalone);
break;
case PROP_PDF_LAYERS:
g_value_set_boolean(value, self->pdf_layers);
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID(obj, property_id, pspec);
break;
}
}
static void latex_renderer_set_property(GObject *obj, guint property_id, const GValue *value, GParamSpec *pspec)
{
LatexRenderer *self = GDS_RENDER_LATEX_RENDERER(obj);
switch (property_id) {
case PROP_STANDALONE:
self->tex_standalone = g_value_get_boolean(value);
break;
case PROP_PDF_LAYERS:
self->pdf_layers = g_value_get_boolean(value);
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID(obj, property_id, pspec);
break;
}
}
static GParamSpec *latex_renderer_properties[N_PROPERTIES] = {NULL};
static void latex_renderer_class_init(LatexRendererClass *klass)
{
GdsOutputRendererClass *render_class = GDS_RENDER_OUTPUT_RENDERER_CLASS(klass);
GObjectClass *oclass = G_OBJECT_CLASS(klass);
/* Overwrite virtual function */
render_class->render_output = latex_renderer_render_output;
/* Property stuff */
oclass->get_property = latex_renderer_get_property;
oclass->set_property = latex_renderer_set_property;
latex_renderer_properties[PROP_STANDALONE] =
g_param_spec_boolean("standalone",
N_("Standalone TeX file"),
N_("Generate a standalone LaTeX file."),
FALSE,
G_PARAM_READWRITE);
latex_renderer_properties[PROP_PDF_LAYERS] =
g_param_spec_boolean("pdf-layers",
N_("PDF OCR layers"),
N_("Generate OCR layers"),
FALSE,
G_PARAM_READWRITE);
g_object_class_install_properties(oclass, N_PROPERTIES, latex_renderer_properties);
}
LatexRenderer *latex_renderer_new()
{
return GDS_RENDER_LATEX_RENDERER(g_object_new(GDS_RENDER_TYPE_LATEX_RENDERER, NULL));
}
LatexRenderer *latex_renderer_new_with_options(gboolean pdf_layers, gboolean standalone)
{
GObject *obj;
obj = g_object_new(GDS_RENDER_TYPE_LATEX_RENDERER, "standalone", standalone, "pdf-layers", pdf_layers, NULL);
return GDS_RENDER_LATEX_RENDERER(obj);
}
/** @} */

2
plugins/CMakeLists.txt Normal file
View File

@@ -0,0 +1,2 @@
add_subdirectory(plugin-example)
add_custom_target(plugins DEPENDS pluginexample)

View File

@@ -0,0 +1,14 @@
project(pluginexample)
cmake_minimum_required(VERSION 2.8)
find_package(PkgConfig REQUIRED)
pkg_search_module(PYTHON REQUIRED python3)
aux_source_directory(src SOURCES)
include_directories(${PYTHON_INCLUDE_DIRS} ${CMAKE_CURRENT_SOURCE_DIR}/include)
link_libraries(${PYTHON_LDFLAGS} version)
add_library(${PROJECT_NAME} SHARED EXCLUDE_FROM_ALL ${SOURCES})
add_dependencies(${PROJECT_NAME} version)
set_target_properties(${PROJECT_NAME} PROPERTIES C_VISIBILITY_PRESET hidden)
set_target_properties(${PROJECT_NAME} PROPERTIES CXX_VISIBILITY_PRESET hidden)

View File

@@ -0,0 +1,49 @@
/*
* GDSII-Converter example plugin
* 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/>.
*/
/**
* @defgroup example-plugin Example Plugin for External Renderer
* @ingroup plugins
* This is a template / example for an external renderer plugin
* @addtogroup example-plugin
* @{
*/
#include <stdio.h>
#include <glib.h>
#include <gds-render/gds-utils/gds-types.h>
#include <gds-render/output-renderers/external-renderer-interfaces.h>
int EXPORTED_FUNC_DECL(EXTERNAL_LIBRARY_RENDER_FUNCTION)(struct gds_cell *toplevel, GList *layer_info_list, const char *output_file_name, double scale)
{
if (!toplevel)
return -1000;
printf("Rendering %s\n", toplevel->name);
return 0;
}
int EXPORTED_FUNC_DECL(EXTERNAL_LIBRARY_INIT_FUNCTION)(const char *params, const char *version)
{
printf("Init with params: %s\ngds-render version: %s\n", params, version);
return 0;
}
/** @} */

10
resources/CMakeLists.txt Normal file
View File

@@ -0,0 +1,10 @@
add_custom_target(glib-resources DEPENDS "${CMAKE_CURRENT_BINARY_DIR}/resources.c")
add_custom_command(DEPENDS
"${CMAKE_CURRENT_SOURCE_DIR}/*.glade"
"${CMAKE_CURRENT_SOURCE_DIR}/resources.xml"
"${CMAKE_CURRENT_SOURCE_DIR}/color-palette.txt"
OUTPUT
"${CMAKE_CURRENT_BINARY_DIR}/resources.c"
COMMAND
glib-compile-resources --target="${CMAKE_CURRENT_BINARY_DIR}/resources.c" --sourcedir="${CMAKE_CURRENT_SOURCE_DIR}" --generate-source "${CMAKE_CURRENT_SOURCE_DIR}/resources.xml"
)

44
resources/about.glade Normal file
View File

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

255
resources/color-palette.txt Normal file
View File

@@ -0,0 +1,255 @@
800000
008000
808000
000080
800080
008080
c0c0c0
808080
ff0000
00ff00
ffff00
0000ff
ff00ff
00ffff
f105f5
000000
00005f
000087
0000af
0000d7
0000ff
005f00
005f5f
005f87
005faf
005fd7
005fff
008700
00875f
008787
0087af
0087d7
0087ff
00af00
00af5f
00af87
00afaf
00afd7
00afff
00d700
00d75f
00d787
00d7af
00d7d7
00d7ff
00ff00
00ff5f
00ff87
00ffaf
00ffd7
00ffff
5f0000
5f005f
5f0087
5f00af
5f00d7
5f00ff
5f5f00
5f5f5f
5f5f87
5f5faf
5f5fd7
5f5fff
5f8700
5f875f
5f8787
5f87af
5f87d7
5f87ff
5faf00
5faf5f
5faf87
5fafaf
5fafd7
5fafff
5fd700
5fd75f
5fd787
5fd7af
5fd7d7
5fd7ff
5fff00
5fff5f
5fff87
5fffaf
5fffd7
5fffff
870000
87005f
870087
8700af
8700d7
8700ff
875f00
875f5f
875f87
875faf
875fd7
875fff
878700
87875f
878787
8787af
8787d7
8787ff
87af00
87af5f
87af87
87afaf
87afd7
87afff
87d700
87d75f
87d787
87d7af
87d7d7
87d7ff
87ff00
87ff5f
87ff87
87ffaf
87ffd7
87ffff
af0000
af005f
af0087
af00af
af00d7
af00ff
af5f00
af5f5f
af5f87
af5faf
af5fd7
af5fff
af8700
af875f
af8787
af87af
af87d7
af87ff
afaf00
afaf5f
afaf87
afafaf
afafd7
afafff
afd700
afd75f
afd787
afd7af
afd7d7
afd7ff
afff00
afff5f
afff87
afffaf
afffd7
afffff
d70000
d7005f
d70087
d700af
d700d7
d700ff
d75f00
d75f5f
d75f87
d75faf
d75fd7
d75fff
d78700
d7875f
d78787
d787af
d787d7
d787ff
d7af00
d7af5f
d7af87
d7afaf
d7afd7
d7afff
d7d700
d7d75f
d7d787
d7d7af
d7d7d7
d7d7ff
d7ff00
d7ff5f
d7ff87
d7ffaf
d7ffd7
d7ffff
ff0000
ff005f
ff0087
ff00af
ff00d7
ff00ff
ff5f00
ff5f5f
ff5f87
ff5faf
ff5fd7
ff5fff
ff8700
ff875f
ff8787
ff87af
ff87d7
ff87ff
ffaf00
ffaf5f
ffaf87
ffafaf
ffafd7
ffafff
ffd700
ffd75f
ffd787
ffd7af
ffd7d7
ffd7ff
ffff00
ffff5f
ffff87
ffffaf
ffffd7
ffffff
080808
121212
1c1c1c
262626
303030
3a3a3a
444444
4e4e4e
585858
626262
6c6c6c
767676
808080
8a8a8a
949494
9e9e9e
a8a8a8
b2b2b2
bcbcbc
c6c6c6
d0d0d0
dadada
e4e4e4
eeeeee

184
resources/dialog.glade Normal file
View File

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

331
resources/main.glade Normal file
View File

@@ -0,0 +1,331 @@
<?xml version="1.0" encoding="UTF-8"?>
<!-- Generated with glade 3.22.1 -->
<interface>
<requires lib="gtk+" version="3.20"/>
<object class="GtkImage" id="auto-name-img">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="stock">gtk-edit</property>
</object>
<object class="GtkImage" id="color-img">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="stock">gtk-select-color</property>
</object>
<object class="GtkImage" id="load-mapping-img">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="stock">gtk-open</property>
</object>
<object class="GtkImage" id="save-mapping-img">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="tooltip_text" translatable="yes">Save the current layer configuration to CSV</property>
<property name="stock">gtk-save-as</property>
</object>
<object class="GtkImage" id="select-all-img">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="stock">gtk-apply</property>
</object>
<object class="GtkImage" id="sort-down-img">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="stock">gtk-sort-ascending</property>
</object>
<object class="GtkImage" id="sort-up-img">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="stock">gtk-sort-descending</property>
</object>
<object class="GtkWindow" id="main-window">
<property name="height_request">250</property>
<property name="can_focus">False</property>
<property name="icon_name">gds-render</property>
<child type="titlebar">
<object class="GtkHeaderBar" id="header-bar">
<property name="name">header</property>
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="title" translatable="yes">GDS-Render</property>
<property name="show_close_button">True</property>
<child>
<object class="GtkButton" id="button-load-gds">
<property name="label">gtk-open</property>
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="receives_default">True</property>
<property name="tooltip_text" translatable="yes">Open GDS2 Database</property>
<property name="use_stock">True</property>
<property name="always_show_image">True</property>
<style>
<class name="suggested-action"/>
</style>
</object>
</child>
<child>
<object class="GtkButton" id="button-load-mapping">
<property name="label" translatable="yes">Load Mapping</property>
<property name="visible">True</property>
<property name="sensitive">False</property>
<property name="can_focus">True</property>
<property name="receives_default">True</property>
<property name="tooltip_text" translatable="yes">Load the current layer configuration from CSV</property>
<property name="image">load-mapping-img</property>
<property name="always_show_image">True</property>
<style>
<class name="suggested-action"/>
</style>
</object>
<packing>
<property name="position">1</property>
</packing>
</child>
<child>
<object class="GtkButton" id="button-save-mapping">
<property name="label" translatable="yes">Save Mapping</property>
<property name="visible">True</property>
<property name="sensitive">False</property>
<property name="can_focus">True</property>
<property name="receives_default">True</property>
<property name="image">save-mapping-img</property>
<property name="always_show_image">True</property>
<style>
<class name="suggested-action"/>
</style>
</object>
<packing>
<property name="position">2</property>
</packing>
</child>
<child>
<object class="GtkButton" id="convert-button">
<property name="label">gtk-convert</property>
<property name="name">button-convert</property>
<property name="visible">True</property>
<property name="sensitive">False</property>
<property name="can_focus">True</property>
<property name="receives_default">True</property>
<property name="tooltip_text" translatable="yes">Convert selected cell</property>
<property name="use_stock">True</property>
<property name="always_show_image">True</property>
<style>
<class name="suggested-action"/>
</style>
</object>
<packing>
<property name="position">3</property>
</packing>
</child>
</object>
</child>
<child>
<object class="GtkBox">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="orientation">vertical</property>
<child>
<object class="GtkBox">
<property name="visible">True</property>
<property name="can_focus">False</property>
<child>
<object class="GtkBox">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="orientation">vertical</property>
<child>
<object class="GtkSearchEntry" id="cell-search">
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="primary_icon_name">edit-find-symbolic</property>
<property name="primary_icon_activatable">False</property>
<property name="primary_icon_sensitive">False</property>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="position">0</property>
</packing>
</child>
<child>
<object class="GtkScrolledWindow">
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="hscrollbar_policy">never</property>
<property name="shadow_type">in</property>
<child>
<object class="GtkTreeView" id="cell-tree">
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="enable_search">False</property>
<property name="enable_grid_lines">both</property>
<child internal-child="selection">
<object class="GtkTreeSelection"/>
</child>
</object>
</child>
</object>
<packing>
<property name="expand">True</property>
<property name="fill">True</property>
<property name="position">1</property>
</packing>
</child>
</object>
<packing>
<property name="expand">True</property>
<property name="fill">True</property>
<property name="position">0</property>
</packing>
</child>
<child>
<object class="GtkBox">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="orientation">vertical</property>
<child>
<object class="GtkBox">
<property name="visible">True</property>
<property name="can_focus">False</property>
<child>
<object class="GtkButton" id="button-up-sort">
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="receives_default">True</property>
<property name="tooltip_text" translatable="yes">Sort layers ascending</property>
<property name="image">sort-up-img</property>
<property name="always_show_image">True</property>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="position">0</property>
</packing>
</child>
<child>
<object class="GtkButton" id="button-down-sort">
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="receives_default">True</property>
<property name="tooltip_text" translatable="yes">Sort layers descending</property>
<property name="image">sort-down-img</property>
<property name="always_show_image">True</property>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="position">1</property>
</packing>
</child>
<child>
<object class="GtkButton" id="auto-color-button">
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="receives_default">True</property>
<property name="tooltip_text" translatable="yes">Automatically color layers</property>
<property name="image">color-img</property>
<property name="always_show_image">True</property>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="position">2</property>
</packing>
</child>
<child>
<object class="GtkButton" id="button-select-all">
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="receives_default">True</property>
<property name="tooltip_text" translatable="yes">Select all layers for export</property>
<property name="image">select-all-img</property>
<property name="always_show_image">True</property>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="position">3</property>
</packing>
</child>
<child>
<object class="GtkButton" id="button-auto-name">
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="receives_default">True</property>
<property name="tooltip_text" translatable="yes">Automatically name layers</property>
<property name="image">auto-name-img</property>
<property name="always_show_image">True</property>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="position">4</property>
</packing>
</child>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">False</property>
<property name="position">0</property>
</packing>
</child>
<child>
<object class="GtkScrolledWindow">
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="margin_top">1</property>
<property name="hscrollbar_policy">never</property>
<property name="shadow_type">in</property>
<child>
<object class="GtkViewport">
<property name="visible">True</property>
<property name="can_focus">False</property>
<child>
<object class="GtkListBox" id="layer-list">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="selection_mode">none</property>
</object>
</child>
</object>
</child>
</object>
<packing>
<property name="expand">True</property>
<property name="fill">True</property>
<property name="position">1</property>
</packing>
</child>
</object>
<packing>
<property name="expand">True</property>
<property name="fill">True</property>
<property name="position">1</property>
</packing>
</child>
</object>
<packing>
<property name="expand">True</property>
<property name="fill">True</property>
<property name="position">0</property>
</packing>
</child>
<child>
<object class="GtkBox" id="activity-bar">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="orientation">vertical</property>
<child>
<placeholder/>
</child>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">False</property>
<property name="position">1</property>
</packing>
</child>
</object>
</child>
</object>
</interface>

17
resources/resources.xml Normal file
View File

@@ -0,0 +1,17 @@
<?xml version="1.0" encoding="UTF-8"?>
<gresources>
<gresource prefix="/gui">
<file compressed="true">main.glade</file>
<file compressed="true">about.glade</file>
<file>layer-widget.glade</file>
<file>dialog.glade</file>
</gresource>
<gresource prefix="/data">
<file compressed="true">color-palette.txt</file>
</gresource>
<gresource prefix="/images">
<file compressed="true" alias="logo.svg">../icon/gds-render.svg</file>
</gresource>
</gresources>

View File

@@ -0,0 +1,16 @@
add_custom_target(translations
DEPENDS
"${PROJECT_BINARY_DIR}/translations/output/"
)
add_custom_command(DEPENDS
"${CMAKE_CURRENT_SOURCE_DIR}/pot/po/*"
OUTPUT
"${PROJECT_BINARY_DIR}/translations/output/"
COMMAND
COMMAND ./generate-mo.sh "${PROJECT_BINARY_DIR}/translations/output"
WORKING_DIRECTORY
${CMAKE_CURRENT_SOURCE_DIR}
COMMENT
"Generating translation locales"
)

24
translations/generate-mo.sh Executable file
View File

@@ -0,0 +1,24 @@
#!/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"
if [ -z $1 ]; then
echo "Must supply an output name"
exit -2
fi
for langdir in `find ./pot/po -mindepth 1 -maxdepth 1 -type d`; do
lang=`basename "$langdir"`
dest="$1/locale/$lang/LC_MESSAGES"
mkdir -p "$dest"
pofiles=`find "$langdir" -name "*.po" | tr '\n' ' '`
comb=`msgcat $pofiles`
echo "$comb" | msgfmt --output-file="$dest/gds-render.mo" -
done

View File

@@ -0,0 +1,39 @@
#!/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"
files=`find ../ -name "*.c"`
mkdir -p "pot"
# C Files
pot="pot/gds-render.pot"
for file in $files; do
echo "Parsing C file $file"
# pot="pot/"$(echo "${file#*/}" | sed -e "s/\//_/g")
# pot="${pot%.c}.pot"
if [[ -f "$pot" ]]; then
xgettext --package-name="gds-render" --join-existing --keyword=_ --language=C --add-comments --sort-output -o "$pot" "$file"
else
xgettext --package-name="gds-render" --keyword=_ --language=C --add-comments --sort-output -o "$pot" "$file"
fi
done
# Glade files
glade_files=`find ../resources/ -name "*.glade"`
for glade in $glade_files; do
echo "Parsing Glade file $glade"
if [[ -f "$pot" ]]; then
xgettext --package-name="gds-render" --join-existing --keyword=_ -L Glade --sort-output -o "$pot" "$glade"
else
xgettext --package-name="gds-render" --keyword=_ -L Glade --sort-output -o "$pot" "$glade"
fi
done

View File

@@ -0,0 +1,456 @@
# SOME DESCRIPTIVE TITLE.
# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER
# This file is distributed under the same license as the gds-render package.
# FIRST AUTHOR <EMAIL@ADDRESS>, YEAR.
#
#, fuzzy
msgid ""
msgstr ""
"Project-Id-Version: gds-render\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2019-12-16 18:27+0100\n"
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
"Language-Team: LANGUAGE <LL@li.org>\n"
"Language: \n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
#: ../main.c:97
#, c-format
msgid ""
"\n"
"\n"
"Full git commit: %s"
msgstr ""
#: ../main.c:294
msgid " FILE - Convert GDS file <FILE> to graphic"
msgstr ""
#: ../resources/about.glade:10
msgid "!! Replaced during runtime !!"
msgstr ""
#: ../command-line.c:205
#, c-format
msgid "%d reference loops found.\n"
msgstr ""
#: ../main.c:220
msgid "About"
msgstr ""
#: ../main.c:290
msgid "Argument string passed to render lib"
msgstr ""
#: ../resources/main.glade:225
msgid "Automatically color layers"
msgstr ""
#: ../resources/main.glade:255
msgid "Automatically name layers"
msgstr ""
#: ../gds-utils/gds-tree-checker.c:71
#, c-format
msgid "Broken cell list item found in cell %s. Will continue.\n"
msgstr ""
#: ../gds-utils/gds-tree-checker.c:57
#, c-format
msgid "Broken cell list item found. Will continue.\n"
msgstr ""
#: ../output-renderers/cairo-renderer.c:409
#, c-format
msgid "Cairo export finished. It might still be buggy!\n"
msgstr ""
#. Execute
#: ../output-renderers/external-renderer.c:120
msgid "Calling external renderer."
msgstr ""
#: ../gds-render-gui.c:286 ../widgets/conv-settings-dialog.c:291
msgid "Cancel"
msgstr ""
#: ../gds-render-gui.c:244
msgid "Cell"
msgstr ""
#: ../command-line.c:209
#, c-format
msgid "Cell is affected by reference loop. Abort!\n"
msgstr ""
#: ../main.c:284
msgid "Cell to render"
msgstr ""
#: ../command-line.c:215
#, c-format
msgid ""
"Cell was not checked. This should not happen. Please report this issue. Will "
"continue either way.\n"
msgstr ""
#: ../command-line.c:202
#, c-format
msgid "Checking library %s failed.\n"
msgstr ""
#: ../resources/dialog.glade:79
msgid "Configure LaTeX as standalone document"
msgstr ""
#: ../resources/main.glade:109
msgid "Convert selected cell"
msgstr ""
#: ../output-renderers/external-renderer.c:89
#, c-format
msgid ""
"Could not load external library '%s'\n"
"Detailed error is:\n"
"%s\n"
msgstr ""
#: ../output-renderers/latex-renderer.c:373
msgid "Could not open LaTeX output file"
msgstr ""
#: ../command-line.c:195
#, c-format
msgid "Couldn't find cell in first library!\n"
msgstr ""
#: ../command-line.c:81
#, c-format
msgid "Count of renderers %d does not match count of output file names %d\n"
msgstr ""
#: ../main.c:286
msgid "Create PDF Layers (OCG)"
msgstr ""
#: ../main.c:285
msgid "Create standalone TeX"
msgstr ""
#: ../main.c:280
msgid "Divide output coordinates by <SCALE>"
msgstr ""
#: ../resources/layer-widget.glade:62
msgid "Export Layer"
msgstr ""
#: ../output-renderers/cairo-renderer.c:366
#, c-format
msgid "Exporting layer %d to file\n"
msgstr ""
#: ../output-renderers/external-renderer.c:142
msgid "External renderer finished."
msgstr ""
#. This should not happen
#: ../output-renderers/cairo-renderer.c:271
#, c-format
msgid "Fatal error: Cairo Renderer: Could not spawn child process!"
msgstr ""
#: ../resources/main.glade:50
msgid "GDS-Render"
msgstr ""
#: ../gds-render-gui.c:294
msgid "GDSII-Files"
msgstr ""
#: ../resources/dialog.glade:18
msgid "Generate LaTeX/TikZ output"
msgstr ""
#: ../resources/dialog.glade:93
msgid "Generate PDF Layers"
msgstr ""
#: ../output-renderers/latex-renderer.c:253
#, c-format
msgid "Generating cell %s"
msgstr ""
#: ../resources/about.glade:12
msgid "Git Repository"
msgstr ""
#: ../widgets/conv-settings-dialog.c:246
#, c-format
msgid "Height: %.3lf %sm"
msgstr ""
#: ../main.c:321
#, c-format
msgid "Ignored argument: %s"
msgstr ""
#: ../output-renderers/external-renderer.c:106
#, c-format
msgid ""
"Init function not found in library:\n"
"%s\n"
msgstr ""
#: ../output-renderers/cairo-renderer.c:321
#, c-format
msgid "Layer number too high / outside of spec.\n"
msgstr ""
#: ../output-renderers/cairo-renderer.c:369
#, c-format
msgid "Layer outside of spec.\n"
msgstr ""
#: ../widgets/layer-element.c:102
#, c-format
msgid "Layer: %d"
msgstr ""
#: ../gds-render-gui.c:241
msgid "Library"
msgstr ""
#: ../resources/main.glade:68
msgid "Load Mapping"
msgstr ""
#: ../resources/main.glade:73
msgid "Load the current layer configuration from CSV"
msgstr ""
#: ../main.c:116
#, c-format
msgid "Logo could not be displayed: %s\n"
msgstr ""
#: ../output-renderers/gds-output-renderer.c:293
msgid "No layer specification supplied."
msgstr ""
#: ../command-line.c:186
#, c-format
msgid "No library in library list. This should not happen.\n"
msgstr ""
#: ../output-renderers/gds-output-renderer.c:288
msgid "No/invalid output file set."
msgstr ""
#: ../widgets/conv-settings-dialog.c:291
msgid "OK"
msgstr ""
#: ../resources/main.glade:58
msgid "Open GDS2 Database"
msgstr ""
#: ../gds-render-gui.c:287
msgid "Open GDSII"
msgstr ""
#: ../gds-render-gui.c:284
msgid "Open GDSII File"
msgstr ""
#: ../main.c:299
#, c-format
msgid "Option parsing failed: %s\n"
msgstr ""
#: ../widgets/conv-settings-dialog.c:255
#, c-format
msgid "Output Height: %u px"
msgstr ""
#: ../output-renderers/gds-output-renderer.c:283
msgid "Output Renderer not valid."
msgstr ""
#: ../output-renderers/gds-output-renderer.c:304
msgid "Output Renderer: Rendering function broken. This is a bug."
msgstr ""
#. Set the pixel sizes
#: ../widgets/conv-settings-dialog.c:252
#, c-format
msgid "Output Width: %u px"
msgstr ""
#: ../main.c:282
msgid "Output file path. Can be used multiple times."
msgstr ""
#: ../output-renderers/gds-output-renderer.c:298
msgid "Output renderer called without cell to render."
msgstr ""
#: ../output-renderers/gds-output-renderer.c:74
msgid "Output renderer does not define a render_output function!"
msgstr ""
#: ../main.c:283
msgid "Path for Layer Mapping File"
msgstr ""
#: ../main.c:288
msgid ""
"Path to a custom shared object, that implements the necessary rendering "
"functions"
msgstr ""
#: ../output-renderers/external-renderer.c:78
#, c-format
msgid "Path to shared object not set!\n"
msgstr ""
#: ../command-line.c:74
#, c-format
msgid "Please specify renderers and file names\n"
msgstr ""
#: ../command-line.c:104
#, c-format
msgid ""
"Please specify shared object for external renderer. Will ignore this "
"renderer.\n"
msgstr ""
#: ../main.c:277
msgid "Print version"
msgstr ""
#: ../command-line.c:160
#, c-format
msgid "Probably missing argument. Check --help option\n"
msgstr ""
#: ../main.c:219
msgid "Quit"
msgstr ""
#: ../widgets/activity-bar.c:104
msgid "Ready"
msgstr ""
#: ../resources/dialog.glade:33
msgid "Render PDF using Cairographics"
msgstr ""
#: ../resources/dialog.glade:48
msgid "Render SVG using Cairographics (too buggy at the moment)"
msgstr ""
#: ../widgets/conv-settings-dialog.c:293
msgid "Renderer Settings"
msgstr ""
#: ../output-renderers/gds-output-renderer.c:365
msgid "Renderer already started asynchronously"
msgstr ""
#: ../main.c:279
msgid "Renderer to use. Can be used multiple times."
msgstr ""
#: ../output-renderers/cairo-renderer.c:467
msgid "Rendering Cairo Output..."
msgstr ""
#: ../gds-render-gui.c:554
msgid "Rendering cell..."
msgstr ""
#: ../output-renderers/external-renderer.c:98
#, c-format
msgid ""
"Rendering function not found in library:\n"
"%s\n"
msgstr ""
#: ../resources/main.glade:86
msgid "Save Mapping"
msgstr ""
#: ../resources/main.glade:23
msgid "Save the current layer configuration to CSV"
msgstr ""
#: ../main.c:312
#, c-format
msgid "Scale < 1 not allowed. Setting to 1\n"
msgstr ""
#: ../resources/layer-widget.glade:51
msgid "Select Layer Color and Opacity"
msgstr ""
#: ../resources/main.glade:240
msgid "Select all layers for export"
msgstr ""
#: ../output-renderers/cairo-renderer.c:331
#, c-format
msgid "Size of layer %d%s%s%s: <%lf x %lf> @ (%lf | %lf)\n"
msgstr ""
#: ../resources/main.glade:195
msgid "Sort layers ascending"
msgstr ""
#: ../resources/main.glade:210
msgid "Sort layers descending"
msgstr ""
#: ../main.c:212
#, c-format
msgid ""
"There is already an open instance. Will open second window in that "
"instance.\n"
msgstr ""
#: ../main.c:244
#, c-format
msgid ""
"This is gds-render, version: %s\n"
"\n"
"For a list of supported commands execute with --help option.\n"
msgstr ""
#: ../gds-utils/gds-tree-checker.c:188
#, c-format
msgid "Visited cell list should be empty. This is a bug. Please report this.\n"
msgstr ""
#: ../widgets/conv-settings-dialog.c:244
#, c-format
msgid "Width: %.3lf %sm"
msgstr ""
#: ../widgets/activity-bar.c:110
msgid "Working..."
msgstr ""
#: ../main.c:96
msgid ""
"gds-render is a free tool for rendering GDS2 layout files into vector "
"graphics."
msgstr ""
#: ../resources/layer-widget.glade:37
msgid "label"
msgstr ""

View File

@@ -0,0 +1,487 @@
# German translations for gds-render package.
# Copyright (C) 2019 THE gds-render'S COPYRIGHT HOLDER
# This file is distributed under the same license as the gds-render package.
# マリオ <mario.huettel@gmx.net>, 2019.
#
msgid ""
msgstr ""
"Project-Id-Version: gds-render\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2019-12-16 18:27+0100\n"
"PO-Revision-Date: 2019-12-16 22:00+0100\n"
"Last-Translator: Mario Hüttel <mario.huettel@gmx.net>\n"
"Language-Team: German <translation-team-de@lists.sourceforge.net>\n"
"Language: de\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"Plural-Forms: nplurals=2; plural=(n != 1);\n"
"X-Generator: Poedit 2.2.4\n"
#: ../main.c:97
#, c-format
msgid ""
"\n"
"\n"
"Full git commit: %s"
msgstr ""
"\n"
"\n"
"Vollständiger git-Commit: %s"
#: ../main.c:294
msgid " FILE - Convert GDS file <FILE> to graphic"
msgstr " DATEI - Konvertiere GDS-Datei <DATEI> in Grafik"
#: ../resources/about.glade:10
msgid "!! Replaced during runtime !!"
msgstr "!! Ersetzt zur Laufzeit !!"
#: ../command-line.c:205
#, c-format
msgid "%d reference loops found.\n"
msgstr "%d Referenzschleifen gefunden.\n"
#: ../main.c:220
msgid "About"
msgstr "Info"
#: ../main.c:290
msgid "Argument string passed to render lib"
msgstr "An Render-Bibliothek übergebener Argument-String"
#: ../resources/main.glade:225
msgid "Automatically color layers"
msgstr "Färbe Layer automatisch"
#: ../resources/main.glade:255
msgid "Automatically name layers"
msgstr "Bename Layer automatisch"
#: ../gds-utils/gds-tree-checker.c:71
#, c-format
msgid "Broken cell list item found in cell %s. Will continue.\n"
msgstr "Defektes Listenelement in Zelle %s. Ignoriere.\n"
#: ../gds-utils/gds-tree-checker.c:57
#, c-format
msgid "Broken cell list item found. Will continue.\n"
msgstr "Defektes Zellenelement in Liste gefunden. Ignoriere.\n"
#: ../output-renderers/cairo-renderer.c:409
#, c-format
msgid "Cairo export finished. It might still be buggy!\n"
msgstr "Cairo-Export abgeschlossen. Möglicherweise fehlerhaft!\n"
#. Execute
#: ../output-renderers/external-renderer.c:120
msgid "Calling external renderer."
msgstr "Rufe externen Renderer auf."
#: ../gds-render-gui.c:286 ../widgets/conv-settings-dialog.c:291
msgid "Cancel"
msgstr "Abbruch"
#: ../gds-render-gui.c:244
msgid "Cell"
msgstr "Zelle"
#: ../command-line.c:209
#, c-format
msgid "Cell is affected by reference loop. Abort!\n"
msgstr "Zelle ist von referenzschleife betroffen. Abbruch!\n"
#: ../main.c:284
msgid "Cell to render"
msgstr "Zu rendernde Zelle"
#: ../command-line.c:215
#, c-format
msgid ""
"Cell was not checked. This should not happen. Please report this issue. Will "
"continue either way.\n"
msgstr ""
"Zelle wurde nicht überprüft. Das sollte nicht passieren. Bitte melden Sie "
"dieses Problem. Es wird dennoch fortgefahren.\n"
#: ../command-line.c:202
#, c-format
msgid "Checking library %s failed.\n"
msgstr "Überprüfung von Bibliothek %s fehlgeschlagen.\n"
#: ../resources/dialog.glade:79
msgid "Configure LaTeX as standalone document"
msgstr "Konfiguriere LaTeX als eigenständiges Dokument"
#: ../resources/main.glade:109
msgid "Convert selected cell"
msgstr "Konvertiere ausgewählte Zelle"
#: ../output-renderers/external-renderer.c:89
#, c-format
msgid ""
"Could not load external library '%s'\n"
"Detailed error is:\n"
"%s\n"
msgstr ""
"Externe Bibliothek '%s' konnte nicht geladen werden.\n"
"Detailierter Fehler:\n"
"%s\n"
#: ../output-renderers/latex-renderer.c:373
msgid "Could not open LaTeX output file"
msgstr "LaTeX-Ausgabedatei konnte nicht geöffnet werden"
#: ../command-line.c:195
#, c-format
msgid "Couldn't find cell in first library!\n"
msgstr "Zelle nicht in erster Bibliothek gefunden!\n"
#: ../command-line.c:81
#, c-format
msgid "Count of renderers %d does not match count of output file names %d\n"
msgstr ""
"Anzahl der Renderer %d stimmt nicht mit der Anzahl der angegebenen "
"Ausgabedateinamen %d überein\n"
#: ../main.c:286
msgid "Create PDF Layers (OCG)"
msgstr "Generiere PDF-Layer (OCG)"
#: ../main.c:285
msgid "Create standalone TeX"
msgstr "Generiere eingenständiges TeX"
#: ../main.c:280
msgid "Divide output coordinates by <SCALE>"
msgstr "Dividiere Ausgabekoordinaten durch <SCALE>"
#: ../resources/layer-widget.glade:62
msgid "Export Layer"
msgstr "Exportiere Layer"
#: ../output-renderers/cairo-renderer.c:366
#, c-format
msgid "Exporting layer %d to file\n"
msgstr "Exportiere Layer %d in Datei\n"
#: ../output-renderers/external-renderer.c:142
msgid "External renderer finished."
msgstr "Externer Renderer beendet."
#. This should not happen
#: ../output-renderers/cairo-renderer.c:271
#, c-format
msgid "Fatal error: Cairo Renderer: Could not spawn child process!"
msgstr ""
"Fataler Fehler: Cairo Renderer: Sub-Prozess konnte nicht gestartet werden!"
#: ../resources/main.glade:50
msgid "GDS-Render"
msgstr "GDS-Render"
#: ../gds-render-gui.c:294
msgid "GDSII-Files"
msgstr "GDSII-Dateien"
#: ../resources/dialog.glade:18
msgid "Generate LaTeX/TikZ output"
msgstr "Generiere LaTeX/TikZ Ausgabe"
#: ../resources/dialog.glade:93
msgid "Generate PDF Layers"
msgstr "Generiere PDF Layers"
#: ../output-renderers/latex-renderer.c:253
#, c-format
msgid "Generating cell %s"
msgstr "Generiere Zelle %s"
#: ../resources/about.glade:12
msgid "Git Repository"
msgstr "Git Repository"
#: ../widgets/conv-settings-dialog.c:246
#, c-format
msgid "Height: %.3lf %sm"
msgstr "Höhe: %.3lf %sm"
#: ../main.c:321
#, c-format
msgid "Ignored argument: %s"
msgstr "Ignoriertes Argument: %s"
#: ../output-renderers/external-renderer.c:106
#, c-format
msgid ""
"Init function not found in library:\n"
"%s\n"
msgstr ""
"Init-Funktion nicht in Bibliothek gefunden:\n"
"%s\n"
#: ../output-renderers/cairo-renderer.c:321
#, c-format
msgid "Layer number too high / outside of spec.\n"
msgstr "Layer-Nummer zu hoch / Außerhalb der Spezifikation.\n"
#: ../output-renderers/cairo-renderer.c:369
#, c-format
msgid "Layer outside of spec.\n"
msgstr "Layer außerhalb der Spezifikation\n"
#: ../widgets/layer-element.c:102
#, c-format
msgid "Layer: %d"
msgstr "Layer: %d"
#: ../gds-render-gui.c:241
msgid "Library"
msgstr "Bibliothek"
#: ../resources/main.glade:68
msgid "Load Mapping"
msgstr "Zuordnung laden"
#: ../resources/main.glade:73
msgid "Load the current layer configuration from CSV"
msgstr "Lade die aktuelle Layer-Zuordnung aus einer CSV-Datei"
#: ../main.c:116
#, c-format
msgid "Logo could not be displayed: %s\n"
msgstr "Logo konnte nicht angezeigt werden: %s\n"
#: ../output-renderers/gds-output-renderer.c:293
msgid "No layer specification supplied."
msgstr "Keine Layer-Spezifikation angegeben."
#: ../command-line.c:186
#, c-format
msgid "No library in library list. This should not happen.\n"
msgstr "Keine Bibliothek in Bibliotheksliste. Das sollte nicht passieren.\n"
#: ../output-renderers/gds-output-renderer.c:288
msgid "No/invalid output file set."
msgstr "Keine oder invalide Ausgabedatei angegeben."
#: ../widgets/conv-settings-dialog.c:291
msgid "OK"
msgstr "OK"
#: ../resources/main.glade:58
msgid "Open GDS2 Database"
msgstr "Öffne GDS2 Datenbank"
#: ../gds-render-gui.c:287
msgid "Open GDSII"
msgstr "Öffne GDSII"
#: ../gds-render-gui.c:284
msgid "Open GDSII File"
msgstr "Öffne GDSII-Datei"
#: ../main.c:299
#, c-format
msgid "Option parsing failed: %s\n"
msgstr "Optionsverarbeitung fehlgeschlagen: %s\n"
#: ../widgets/conv-settings-dialog.c:255
#, c-format
msgid "Output Height: %u px"
msgstr "Ausgabehöhe: %u px"
#: ../output-renderers/gds-output-renderer.c:283
msgid "Output Renderer not valid."
msgstr "Ausgaberenderer invalide."
#: ../output-renderers/gds-output-renderer.c:304
msgid "Output Renderer: Rendering function broken. This is a bug."
msgstr ""
"Ausgaberenderer: Render-Funktion defekt. Dies ist ein interner "
"Programmfehler."
#. Set the pixel sizes
#: ../widgets/conv-settings-dialog.c:252
#, c-format
msgid "Output Width: %u px"
msgstr "Ausgabebreite: %u px"
#: ../main.c:282
msgid "Output file path. Can be used multiple times."
msgstr "Ausgabepfad. Kann mehrfach angegeben werden."
#: ../output-renderers/gds-output-renderer.c:298
msgid "Output renderer called without cell to render."
msgstr "Ausgaberenderer ohne zu rendernde Zelle aufgerufen."
#: ../output-renderers/gds-output-renderer.c:74
msgid "Output renderer does not define a render_output function!"
msgstr "Ausgaberenderer definiert keine render_output Funktion!"
#: ../main.c:283
msgid "Path for Layer Mapping File"
msgstr "Pfad zur Lagenzuordnungsdatei"
#: ../main.c:288
msgid ""
"Path to a custom shared object, that implements the necessary rendering "
"functions"
msgstr ""
"Pfad zu einem benutzerdefiniertem Shared-Object, welches die notwendigen "
"Funktionen implementiert"
#: ../output-renderers/external-renderer.c:78
#, c-format
msgid "Path to shared object not set!\n"
msgstr "Kein Pfad zu einem Shared-Object gesetzt!\n"
#: ../command-line.c:74
#, c-format
msgid "Please specify renderers and file names\n"
msgstr "Bitte Renderer und Dateinamen angeben.\n"
#: ../command-line.c:104
#, c-format
msgid ""
"Please specify shared object for external renderer. Will ignore this "
"renderer.\n"
msgstr ""
"Bitte Shares-Object für externen Renderer angeben. Dieser Renderer wird "
"ignoriert.\n"
#: ../main.c:277
msgid "Print version"
msgstr "Zeige Versionsnummer"
#: ../command-line.c:160
#, c-format
msgid "Probably missing argument. Check --help option\n"
msgstr "Vermutlich ein fehlendes Argument. Bitte --help überprüfen\n"
#: ../main.c:219
msgid "Quit"
msgstr "Beenden"
#: ../widgets/activity-bar.c:104
msgid "Ready"
msgstr "Bereit"
#: ../resources/dialog.glade:33
msgid "Render PDF using Cairographics"
msgstr "Rendere PDF mit Cairographics"
#: ../resources/dialog.glade:48
msgid "Render SVG using Cairographics (too buggy at the moment)"
msgstr "Rendere SVG mit Cairographics (Experimentell)"
#: ../widgets/conv-settings-dialog.c:293
msgid "Renderer Settings"
msgstr "Renderer Einstellungen"
#: ../output-renderers/gds-output-renderer.c:365
msgid "Renderer already started asynchronously"
msgstr "Renderer wird bereits asynchron ausgeführt"
#: ../main.c:279
msgid "Renderer to use. Can be used multiple times."
msgstr "Zu nutzender Renderer. Kann mehrfach angegeben werden."
#: ../output-renderers/cairo-renderer.c:467
msgid "Rendering Cairo Output..."
msgstr "Rendere Cairo-Ausgabe..."
#: ../gds-render-gui.c:554
msgid "Rendering cell..."
msgstr "Renderere Zelle..."
#: ../output-renderers/external-renderer.c:98
#, c-format
msgid ""
"Rendering function not found in library:\n"
"%s\n"
msgstr ""
"Render Funktion nicht in Bibliothek gefunden:\n"
"%s\n"
#: ../resources/main.glade:86
msgid "Save Mapping"
msgstr "Zuordnung speichern"
#: ../resources/main.glade:23
msgid "Save the current layer configuration to CSV"
msgstr "Die aktuelle Lagenkonfiguration als CSV-Datei speichern"
#: ../main.c:312
#, c-format
msgid "Scale < 1 not allowed. Setting to 1\n"
msgstr "Skaliereung < 1 nicht erlaubt. Setze auf 1\n"
#: ../resources/layer-widget.glade:51
msgid "Select Layer Color and Opacity"
msgstr "Wähle Layer-Farbe und Transparenz"
#: ../resources/main.glade:240
msgid "Select all layers for export"
msgstr "Wähle alle Layer zum Exporieren"
#: ../output-renderers/cairo-renderer.c:331
#, c-format
msgid "Size of layer %d%s%s%s: <%lf x %lf> @ (%lf | %lf)\n"
msgstr "Größe von Layer %d%s%s%s: <%lf x %lf> @ (%lf | %lf)\n"
#: ../resources/main.glade:195
msgid "Sort layers ascending"
msgstr "Sortiere Layer aufsteigend"
#: ../resources/main.glade:210
msgid "Sort layers descending"
msgstr "Sortiere Layer absteigend"
#: ../main.c:212
#, c-format
msgid ""
"There is already an open instance. Will open second window in that "
"instance.\n"
msgstr ""
"Es ist bereits eine Instanz dieses Programms geöffnet. Es wird ein zweites "
"Fenster in jener Instanz geöffnet.\n"
#: ../main.c:244
#, c-format
msgid ""
"This is gds-render, version: %s\n"
"\n"
"For a list of supported commands execute with --help option.\n"
msgstr ""
"Dies ist gds-render, Version: %s\n"
"\n"
"Für eine Liste der unterstützten Kommandos mit der Option --help ausführen.\n"
#: ../gds-utils/gds-tree-checker.c:188
#, c-format
msgid "Visited cell list should be empty. This is a bug. Please report this.\n"
msgstr ""
"Liste markierter Zellen sollte leer sein. Dies ist ein Fehler. Bitte "
"melden.\n"
#: ../widgets/conv-settings-dialog.c:244
#, c-format
msgid "Width: %.3lf %sm"
msgstr "Breite: %.3lf %sm"
#: ../widgets/activity-bar.c:110
msgid "Working..."
msgstr "Arbeite..."
#: ../main.c:96
msgid ""
"gds-render is a free tool for rendering GDS2 layout files into vector "
"graphics."
msgstr ""
"gds-render ist ein freies Programm, um GDS2-Layouts in Vektorgrafiken zu "
"konvertieren."
#: ../resources/layer-widget.glade:37
msgid "label"
msgstr "label"

View File

@@ -0,0 +1,34 @@
#!/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"
if [ -z $1 ]; then
echo "Please specify language code to generate/update"
exit -1
fi
locale="$1"
podir="./po/$locale"
echo "Selected locale: $locale"
mkdir -p "$podir"
pots=`find . -name '*.pot'`
for pot in $pots; do
po=`echo "$podir/${pot%.pot}.po" | sed -e "s/\/.\//\//g"`
echo -n "$po: "
if [ -f "$po" ]; then
echo "update"
msgmerge --update "$po" "$pot"
else
echo "generate"
msginit --input="$pot" --locale="$locale" --output="$po"
fi
done

View File

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

View File

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

36
version/CMakeLists.txt Normal file
View File

@@ -0,0 +1,36 @@
project(libversion)
if(NOT WIN32)
string(ASCII 27 Esc)
set(ColorReset "${Esc}[m")
set(ColorBold "${Esc}[1m")
set(Red "${Esc}[31m")
set(Green "${Esc}[32m")
set(Yellow "${Esc}[33m")
set(Blue "${Esc}[34m")
set(Magenta "${Esc}[35m")
set(Cyan "${Esc}[36m")
set(White "${Esc}[37m")
set(BoldRed "${Esc}[1;31m")
set(BoldGreen "${Esc}[1;32m")
set(BoldYellow "${Esc}[1;33m")
set(BoldBlue "${Esc}[1;34m")
set(BoldMagenta "${Esc}[1;35m")
set(BoldCyan "${Esc}[1;36m")
set(BoldWhite "${Esc}[1;37m")
endif()
add_library(version STATIC "version.c")
execute_process(COMMAND bash ./generate-version-string.sh
WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}
OUTPUT_VARIABLE GIT_VER)
execute_process(COMMAND bash ./generate-git-commit-string.sh
WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}
OUTPUT_VARIABLE GIT_COMMIT)
message("${BoldGreen}Commit: ${GIT_COMMIT}")
message("Version: ${GIT_VER}${ColorReset}")
IF(GIT_VER MATCHES "-dirty")
message("${BoldRed}Build is dirty! Commit your changes before releasing this version!${ColorReset}")
ENDIF(GIT_VER MATCHES "-dirty")
target_compile_definitions(version PRIVATE PROJECT_GIT_VERSION=${GIT_VER} PROJECT_GIT_COMMIT=${GIT_COMMIT})

View File

@@ -0,0 +1,3 @@
#!/bin/bash
git rev-parse --verify HEAD | tr -d '\n'

View File

@@ -0,0 +1 @@
git describe --tags --dirty | tr -d '\n'

View File

@@ -17,16 +17,27 @@
* along with GDSII-Converter. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef __LATEX_OUTPUT_H__
#define __LATEX_OUTPUT_H__
/**
* @defgroup version Version Number
* See @ref git-version-num
* @addtogroup version
* @{
*/
#include "../gds-parser/gds-types.h"
#include <glib.h>
#include <stdio.h>
#include "../layer-selector.h"
#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
#define LATEX_LINE_BUFFER_KB (10)
#ifdef PROJECT_GIT_COMMIT
#define xstr(a) str(a)
#define str(a) #a
const char *_app_git_commit = xstr(PROJECT_GIT_COMMIT);
#else
const char *_app_git_commit = "! Commit hash not available !";
#endif
void render_cell_to_code(struct gds_cell *cell, GList *layer_infos, FILE *tex_file);
#endif /* __LATEX_OUTPUT_H__ */
/** @} */

115
widgets/activity-bar.c Normal file
View File

@@ -0,0 +1,115 @@
/*
* GDSII-Converter
* Copyright (C) 2019 Mario Hüttel <mario.huettel@gmx.net>
*
* This file is part of GDSII-Converter.
*
* GDSII-Converter is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*
* GDSII-Converter is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with GDSII-Converter. If not, see <http://www.gnu.org/licenses/>.
*/
/*
* The drag and drop implementation is adapted from
* https://gitlab.gnome.org/GNOME/gtk/blob/gtk-3-22/tests/testlist3.c
*
* Thanks to the GTK3 people for creating these examples.
*/
/**
* @file activity-bar.c
* @brief Status bar indicating activity of the program
* @author Mario Hüttel <mario.huettel@gmx.net>
*/
/**
* @addtogroup ActivityBar
* @ingroup Widgets
* @{
*/
#include <gds-render/widgets/activity-bar.h>
#include <glib/gi18n.h>
/** @brief Opaque ActivityBar object. Not viewable outside this source file. */
struct _ActivityBar {
GtkBox super;
/* Private stuff */
GtkWidget *spinner;
GtkWidget *label;
};
G_DEFINE_TYPE(ActivityBar, activity_bar, GTK_TYPE_BOX)
static void activity_bar_dispose(GObject *obj)
{
ActivityBar *bar;
bar = ACTIVITY_BAR(obj);
/* Clear references on owned objects */
g_clear_object(&bar->label);
g_clear_object(&bar->spinner);
/* Chain up */
G_OBJECT_CLASS(activity_bar_parent_class)->dispose(obj);
}
static void activity_bar_class_init(ActivityBarClass *klass)
{
GObjectClass *oclass = G_OBJECT_CLASS(klass);
oclass->dispose = activity_bar_dispose;
}
static void activity_bar_init(ActivityBar *self)
{
GtkContainer *box = GTK_CONTAINER(self);
/* Create Widgets */
self->label = gtk_label_new("");
self->spinner = gtk_spinner_new();
/* Add to this widget and show */
gtk_container_add(box, self->spinner);
gtk_container_add(box, self->label);
gtk_widget_show(self->label);
gtk_widget_show(self->spinner);
g_object_ref(self->spinner);
g_object_ref(self->label);
}
ActivityBar *activity_bar_new()
{
ActivityBar *bar;
bar = ACTIVITY_BAR(g_object_new(TYPE_ACTIVITY_BAR, "orientation", GTK_ORIENTATION_HORIZONTAL, NULL));
if (bar)
activity_bar_set_ready(bar);
return bar;
}
void activity_bar_set_ready(ActivityBar *bar)
{
gtk_label_set_text(GTK_LABEL(bar->label), _("Ready"));
gtk_spinner_stop(GTK_SPINNER(bar->spinner));
}
void activity_bar_set_busy(ActivityBar *bar, const char *text)
{
gtk_label_set_text(GTK_LABEL(bar->label), (text ? text : _("Working...")));
gtk_spinner_start(GTK_SPINNER(bar->spinner));
}
/** @} */

View File

@@ -0,0 +1,401 @@
/*
* 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 conv-settings-dialog.c
* @brief Implementation of the setting dialog
* @author Mario Hüttel <mario.huettel@gmx.net>
*/
/**
* @addtogroup RendererSettingsDialog
* @ingroup Widgets
* @{
*/
#include <gds-render/widgets/conv-settings-dialog.h>
#include <glib/gi18n.h>
struct _RendererSettingsDialog {
GtkDialog parent;
/* Private loot */
GtkWidget *radio_latex;
GtkWidget *radio_cairo_pdf;
GtkWidget *radio_cairo_svg;
GtkWidget *scale;
GtkWidget *layer_check;
GtkWidget *standalone_check;
GtkDrawingArea *shape_drawing;
GtkLabel *x_label;
GtkLabel *y_label;
GtkLabel *x_output_label;
GtkLabel *y_output_label;
unsigned int cell_height;
unsigned int cell_width;
double unit_in_meters;
};
G_DEFINE_TYPE(RendererSettingsDialog, renderer_settings_dialog, GTK_TYPE_DIALOG)
enum {
PROP_CELL_NAME = 1,
PROP_COUNT
};
static GParamSpec *properties[PROP_COUNT];
static void renderer_settings_dialog_set_property(GObject *object, guint property_id,
const GValue *value, GParamSpec *pspec)
{
const gchar *title = NULL;
switch (property_id) {
case PROP_CELL_NAME:
title = g_value_get_string(value);
if (title)
gtk_window_set_title(GTK_WINDOW(object), title);
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID(object, property_id, pspec);
break;
}
}
static void renderer_settings_dialog_get_property(GObject *object, guint property_id,
GValue *value, GParamSpec *pspec)
{
const gchar *title;
switch (property_id) {
case PROP_CELL_NAME:
title = gtk_window_get_title(GTK_WINDOW(object));
g_value_set_string(value, title);
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID(object, property_id, pspec);
break;
}
}
static void renderer_settings_dialog_class_init(RendererSettingsDialogClass *klass)
{
GObjectClass *oclass = G_OBJECT_CLASS(klass);
/* Override virtual functions */
oclass->set_property = renderer_settings_dialog_set_property;
oclass->get_property = renderer_settings_dialog_get_property;
properties[PROP_CELL_NAME] = g_param_spec_string(N_("cell-name"),
N_("cell-name"),
N_("Cell name to be displayed in header bar"),
"",
G_PARAM_READWRITE);
g_object_class_install_properties(oclass, PROP_COUNT, properties);
}
static void show_tex_options(RendererSettingsDialog *self)
{
gtk_widget_show(self->layer_check);
gtk_widget_show(self->standalone_check);
}
static void hide_tex_options(RendererSettingsDialog *self)
{
gtk_widget_hide(self->layer_check);
gtk_widget_hide(self->standalone_check);
}
static void latex_render_callback(GtkToggleButton *radio, RendererSettingsDialog *dialog)
{
if (gtk_toggle_button_get_active(radio))
show_tex_options(dialog);
else
hide_tex_options(dialog);
}
static 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;
static const char * const prefixes[] = {"y", "z", "a", "f", "p", "n", "u", "m", "c", "d", /* < 1 */
"", /* 1 */
"h", "k", "M", "G", "T", "P", "E", "Z", "Y"}; /* > 1 */
static const double scale[] = {1E-24, 1E-21, 1E-18, 1E-15, 1E-12, 1E-9, 1E-6, 1E-3, 1E-2, 1E-1,
1,
1E2, 1E3, 1E6, 1E9, 1E12, 1E15, 1E18, 1E21, 1E24};
const int prefix_count = (int)(sizeof(prefixes)/sizeof(char *));
/* If pointer is invalid, return NaN */
if (!out_prefix)
return (0.0 / 0.0);
/* Start with the 2nd smallest prefix */
for (idx = 1; idx < prefix_count; idx++) {
if (input < scale[idx]) {
/* This prefix is bigger than the number. Take the previous one */
selected_prefix = prefixes[idx-1];
return_val = input / scale[idx-1];
break;
}
}
/* Check if prefix was set by loop. Else take the largest in the list */
if (selected_prefix == NULL) {
selected_prefix = prefixes[prefix_count-1];
return_val = input / scale[prefix_count-1];
}
if (out_prefix)
*out_prefix = selected_prefix;
return return_val;
}
static void renderer_settings_dialog_update_labels(RendererSettingsDialog *self)
{
char default_buff[100];
double scale;
double width_meters;
double height_meters;
double width_engineering;
const char *width_prefix;
double height_engineering;
const char *height_prefix;
if (!self)
return;
width_meters = (double)self->cell_width * self->unit_in_meters;
height_meters = (double)self->cell_height * self->unit_in_meters;
width_engineering = convert_number_to_engineering(width_meters, &width_prefix);
height_engineering = convert_number_to_engineering(height_meters, &height_prefix);
snprintf(default_buff, sizeof(default_buff), _("Width: %.3lf %sm"), width_engineering, width_prefix);
gtk_label_set_text(self->x_label, default_buff);
snprintf(default_buff, sizeof(default_buff), _("Height: %.3lf %sm"), height_engineering, height_prefix);
gtk_label_set_text(self->y_label, default_buff);
scale = gtk_range_get_value(GTK_RANGE(self->scale));
/* Set the pixel sizes */
snprintf(default_buff, sizeof(default_buff), _("Output Width: %u px"),
(unsigned int)((double)self->cell_width / scale));
gtk_label_set_text(self->x_output_label, default_buff);
snprintf(default_buff, sizeof(default_buff), _("Output Height: %u px"),
(unsigned int)((double)self->cell_height / scale));
gtk_label_set_text(self->y_output_label, default_buff);
}
static void scale_value_changed(GtkRange *range, gpointer user_data)
{
(void)range;
RendererSettingsDialog *dialog;
dialog = RENDERER_SETTINGS_DIALOG(user_data);
renderer_settings_dialog_update_labels(dialog);
}
static void renderer_settings_dialog_init(RendererSettingsDialog *self)
{
GtkBuilder *builder;
GtkWidget *box;
GtkDialog *dialog;
dialog = &self->parent;
builder = gtk_builder_new_from_resource("/gui/dialog.glade");
box = GTK_WIDGET(gtk_builder_get_object(builder, "dialog-box"));
self->radio_latex = GTK_WIDGET(gtk_builder_get_object(builder, "latex-radio"));
self->radio_cairo_pdf = GTK_WIDGET(gtk_builder_get_object(builder, "cairo-pdf-radio"));
self->radio_cairo_svg = GTK_WIDGET(gtk_builder_get_object(builder, "cairo-svg-radio"));
self->scale = GTK_WIDGET(gtk_builder_get_object(builder, "dialog-scale"));
self->standalone_check = GTK_WIDGET(gtk_builder_get_object(builder, "standalone-check"));
self->layer_check = GTK_WIDGET(gtk_builder_get_object(builder, "layer-check"));
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);
}
RendererSettingsDialog *renderer_settings_dialog_new(GtkWindow *parent)
{
RendererSettingsDialog *res;
res = RENDERER_SETTINGS_DIALOG(g_object_new(RENDERER_TYPE_SETTINGS_DIALOG, NULL));
if (res && parent)
gtk_window_set_transient_for(GTK_WINDOW(res), parent);
return res;
}
void renderer_settings_dialog_get_settings(RendererSettingsDialog *dialog, struct render_settings *settings)
{
if (!settings || !dialog)
return;
settings->scale = gtk_range_get_value(GTK_RANGE(dialog->scale));
/* Get active radio button selection */
if (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(dialog->radio_latex)) == TRUE)
settings->renderer = RENDERER_LATEX_TIKZ;
else if (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(dialog->radio_cairo_pdf)) == TRUE)
settings->renderer = RENDERER_CAIROGRAPHICS_PDF;
else if (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(dialog->radio_cairo_svg)) == TRUE)
settings->renderer = RENDERER_CAIROGRAPHICS_SVG;
settings->tex_pdf_layers = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(dialog->layer_check));
settings->tex_standalone = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(dialog->standalone_check));
}
void renderer_settings_dialog_set_settings(RendererSettingsDialog *dialog, struct render_settings *settings)
{
if (!settings || !dialog)
return;
gtk_range_set_value(GTK_RANGE(dialog->scale), settings->scale);
gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(dialog->layer_check), settings->tex_pdf_layers);
gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(dialog->standalone_check), settings->tex_standalone);
switch (settings->renderer) {
case RENDERER_LATEX_TIKZ:
gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(dialog->radio_latex), TRUE);
show_tex_options(dialog);
break;
case RENDERER_CAIROGRAPHICS_PDF:
hide_tex_options(dialog);
gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(dialog->radio_cairo_pdf), TRUE);
break;
case RENDERER_CAIROGRAPHICS_SVG:
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);
}
/** @} */

Some files were not shown because too many files have changed in this diff Show More