Merge branch 'dev'

This commit is contained in:
Mario Hüttel 2019-11-09 01:50:37 +01:00
commit 74eb17b2dc
22 changed files with 467 additions and 648 deletions

View File

@ -6,6 +6,8 @@ pkg_search_module(GLIB REQUIRED glib-2.0)
pkg_check_modules(GTK3 REQUIRED gtk+-3.0) pkg_check_modules(GTK3 REQUIRED gtk+-3.0)
pkg_check_modules(CAIRO REQUIRED cairo) pkg_check_modules(CAIRO REQUIRED cairo)
add_compile_options(-Wall -Wold-style-declaration -Wuninitialized -Wmaybe-uninitialized -Wunused-parameter)
add_subdirectory(resources) add_subdirectory(resources)
add_subdirectory(doxygen) add_subdirectory(doxygen)
add_subdirectory(version) add_subdirectory(version)
@ -32,8 +34,6 @@ set(SOURCE
${LAYER_SELECTOR_SOURCES} ${LAYER_SELECTOR_SOURCES}
) )
add_compile_options(-Wall -Wold-style-declaration -Wuninitialized -Wmaybe-uninitialized -Wunused-parameter)
add_executable(${PROJECT_NAME} ${SOURCE} ${CMAKE_CURRENT_BINARY_DIR}/resources/resources.c) add_executable(${PROJECT_NAME} ${SOURCE} ${CMAKE_CURRENT_BINARY_DIR}/resources/resources.c)
add_dependencies(${PROJECT_NAME} glib-resources) add_dependencies(${PROJECT_NAME} glib-resources)
add_dependencies(${PROJECT_NAME} version) add_dependencies(${PROJECT_NAME} version)

View File

@ -1,176 +0,0 @@
/*
* GDSII-Converter
* Copyright (C) 2018 Mario Hüttel <mario.huettel@gmx.net>
*
* This file is part of GDSII-Converter.
*
* GDSII-Converter is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*
* GDSII-Converter is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with GDSII-Converter. If not, see <http://www.gnu.org/licenses/>.
*/
/**
* @file tree-store.h
* @brief Tree store implementation
* @author Mario Hüttel <mario.huettel@gmx.net>
*/
/**
* @addtogroup GUI
* @{
*/
#include <gds-render/cell-selector/tree-store.h>
#include <gds-render/cell-selector/lib-cell-renderer.h>
#include <gds-render/gds-utils/gds-types.h>
/**
* @brief this function olny allows 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 cell_store_filter_visible_func Decides whether an element of the tree model @p model is visible.
* @param model Tree model
* @param iter Current element / iter in Model to check
* @param data Data. Set to static stores variable
* @return TRUE if visible, else FALSE
* @note TODO: Maybe implement Damerau-Levenshtein distance matching
*/
static gboolean cell_store_filter_visible_func(GtkTreeModel *model, GtkTreeIter *iter, gpointer data)
{
struct tree_stores *stores = (struct tree_stores *)data;
struct gds_cell *cell;
struct gds_library *lib;
gboolean result = FALSE;
const char *search_string;
if (!model || !iter || !stores)
goto exit_filter;
gtk_tree_model_get(model, iter, CELL_SEL_CELL, &cell, CELL_SEL_LIBRARY, &lib, -1);
if (lib) {
result = TRUE;
goto exit_filter;
}
if (!cell)
goto exit_filter;
search_string = gtk_entry_get_text(stores->search_entry);
/* Show all, if field is empty */
if (!strlen(search_string))
result = TRUE;
if (strstr(cell->name, search_string))
result = TRUE;
gtk_tree_view_expand_all(stores->base_tree_view);
exit_filter:
return result;
}
static void change_filter(GtkWidget *entry, gpointer data)
{
struct tree_stores *stores = (struct tree_stores *)data;
(void)entry;
gtk_tree_model_filter_refilter(stores->filter);
}
/**
* @brief Setup a GtkTreeView with the necessary columns
* @param view Tree view to set up
* @param search_entry Entry field for search
* @return Tree stores for storing data inside the GtkTreeView
*/
struct tree_stores *setup_cell_selector(GtkTreeView* view, GtkEntry *search_entry)
{
static struct tree_stores stores;
GtkCellRenderer *render_dates;
GtkCellRenderer *render_cell;
GtkCellRenderer *render_lib;
GtkTreeViewColumn *column;
stores.base_tree_view = view;
stores.search_entry = search_entry;
stores.base_store = gtk_tree_store_new(CELL_SEL_COLUMN_COUNT, G_TYPE_POINTER, G_TYPE_POINTER, G_TYPE_UINT, G_TYPE_STRING, G_TYPE_STRING);
/* Searching */
if (search_entry) {
stores.filter = GTK_TREE_MODEL_FILTER(gtk_tree_model_filter_new(GTK_TREE_MODEL(stores.base_store), NULL));
gtk_tree_model_filter_set_visible_func (stores.filter,
(GtkTreeModelFilterVisibleFunc)cell_store_filter_visible_func,
&stores, NULL);
g_signal_connect(GTK_SEARCH_ENTRY(search_entry), "search-changed", G_CALLBACK(change_filter), &stores);
}
gtk_tree_view_set_model(view, GTK_TREE_MODEL(stores.filter));
render_dates = gtk_cell_renderer_text_new();
render_cell = lib_cell_renderer_new();
render_lib = lib_cell_renderer_new();
column = gtk_tree_view_column_new_with_attributes("Library", render_lib, "gds-lib", CELL_SEL_LIBRARY, NULL);
gtk_tree_view_append_column(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(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 &stores;
}
/** @} */

View File

@ -32,7 +32,6 @@
#include <gds-render/command-line.h> #include <gds-render/command-line.h>
#include <gds-render/gds-utils/gds-parser.h> #include <gds-render/gds-utils/gds-parser.h>
#include <gds-render/layer/mapping-parser.h>
#include <gds-render/layer/layer-settings.h> #include <gds-render/layer/layer-settings.h>
#include <gds-render/output-renderers/cairo-renderer.h> #include <gds-render/output-renderers/cairo-renderer.h>
#include <gds-render/output-renderers/latex-renderer.h> #include <gds-render/output-renderers/latex-renderer.h>
@ -225,9 +224,8 @@ int command_line_convert_gds(const char *gds_name,
ret_destroy_library_list: ret_destroy_library_list:
clear_lib_list(&libs); clear_lib_list(&libs);
ret_clear_renderers: ret_clear_renderers:
for (list_iter = renderer_list; list_iter; list_iter = list_iter->next) { for (list_iter = renderer_list; list_iter; list_iter = list_iter->next)
g_object_unref(list_iter->data); g_object_unref(list_iter->data);
}
ret_destroy_layer_mapping: ret_destroy_layer_mapping:
g_object_unref(layer_sett); g_object_unref(layer_sett);
return ret; return ret;

View File

@ -9,7 +9,7 @@
* @warning Although the GdsOutputRenderer class provides compatibility for asynchronous rendering, * @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. * 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_gui_status_from_async and the get functions for the properties. * 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. * @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.
* *

View File

@ -35,7 +35,6 @@
#include <gds-render/gds-utils/gds-tree-checker.h> #include <gds-render/gds-utils/gds-tree-checker.h>
#include <gds-render/layer/layer-selector.h> #include <gds-render/layer/layer-selector.h>
#include <gds-render/widgets/activity-bar.h> #include <gds-render/widgets/activity-bar.h>
#include <gds-render/cell-selector/tree-store.h>
#include <gds-render/cell-selector/lib-cell-renderer.h> #include <gds-render/cell-selector/lib-cell-renderer.h>
#include <gds-render/output-renderers/latex-renderer.h> #include <gds-render/output-renderers/latex-renderer.h>
#include <gds-render/output-renderers/cairo-renderer.h> #include <gds-render/output-renderers/cairo-renderer.h>
@ -43,6 +42,16 @@
#include <gds-render/geometric/cell-geometrics.h> #include <gds-render/geometric/cell-geometrics.h>
#include <gds-render/version.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_MODDATE,
CELL_SEL_ACCESSDATE,
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}; enum gds_render_gui_signal_sig_ids {SIGNAL_WINDOW_CLOSED = 0, SIGNAL_COUNT};
static guint gds_render_gui_signals[SIGNAL_COUNT]; static guint gds_render_gui_signals[SIGNAL_COUNT];
@ -64,6 +73,7 @@ struct _GdsRenderGui {
GtkWidget *save_layer_button; GtkWidget *save_layer_button;
GtkWidget *select_all_button; GtkWidget *select_all_button;
GtkTreeStore *cell_tree_store; GtkTreeStore *cell_tree_store;
GtkTreeModelFilter *cell_filter;
GtkWidget *cell_search_entry; GtkWidget *cell_search_entry;
LayerSelector *layer_selector; LayerSelector *layer_selector;
GtkTreeView *cell_tree_view; GtkTreeView *cell_tree_view;
@ -124,6 +134,155 @@ static GString *generate_string_from_date(struct gds_time_field *date)
return str; return str;
} }
/**
* @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_dates;
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,
G_TYPE_STRING, G_TYPE_STRING);
/* 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_dates = gtk_cell_renderer_text_new();
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);
column = gtk_tree_view_column_new_with_attributes("Mod. Date", render_dates, "text", CELL_SEL_MODDATE, NULL);
gtk_tree_view_append_column(self->cell_tree_view, column);
column = gtk_tree_view_column_new_with_attributes("Acc. Date", render_dates, "text", CELL_SEL_ACCESSDATE, 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 * @brief Callback function of Load GDS button
* @param button * @param button
@ -295,7 +454,9 @@ static void async_rendering_finished_callback(GdsOutputRenderer *renderer, gpoin
g_object_unref(renderer); g_object_unref(renderer);
} }
static void async_rendering_status_update_callback(GdsOutputRenderer *renderer, const char *status_message, gpointer data) static void async_rendering_status_update_callback(GdsOutputRenderer *renderer,
const char *status_message,
gpointer data)
{ {
GdsRenderGui *gui; GdsRenderGui *gui;
(void)renderer; (void)renderer;
@ -536,6 +697,7 @@ static void gds_render_gui_dispose(GObject *gobject)
g_clear_object(&self->convert_button); g_clear_object(&self->convert_button);
g_clear_object(&self->layer_selector); g_clear_object(&self->layer_selector);
g_clear_object(&self->cell_tree_store); g_clear_object(&self->cell_tree_store);
g_clear_object(&self->cell_filter);
g_clear_object(&self->cell_search_entry); g_clear_object(&self->cell_search_entry);
g_clear_object(&self->activity_status_bar); g_clear_object(&self->activity_status_bar);
g_clear_object(&self->palette); g_clear_object(&self->palette);
@ -624,7 +786,6 @@ static void gds_render_gui_init(GdsRenderGui *self)
GtkBuilder *main_builder; GtkBuilder *main_builder;
GtkWidget *listbox; GtkWidget *listbox;
GtkHeaderBar *header_bar; GtkHeaderBar *header_bar;
struct tree_stores *cell_selector_stores;
GtkWidget *sort_up_button; GtkWidget *sort_up_button;
GtkWidget *sort_down_button; GtkWidget *sort_down_button;
GtkWidget *activity_bar_box; GtkWidget *activity_bar_box;
@ -636,9 +797,7 @@ static void gds_render_gui_init(GdsRenderGui *self)
self->cell_tree_view = GTK_TREE_VIEW(gtk_builder_get_object(main_builder, "cell-tree")); 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")); self->cell_search_entry = GTK_WIDGET(gtk_builder_get_object(main_builder, "cell-search"));
cell_selector_stores = setup_cell_selector(self->cell_tree_view, GTK_ENTRY(self->cell_search_entry)); gds_render_gui_setup_cell_selector(self);
self->cell_tree_store = cell_selector_stores->base_store;
self->main_window = GTK_WINDOW(gtk_builder_get_object(main_builder, "main-window")); 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")); self->open_button = GTK_WIDGET(gtk_builder_get_object(main_builder, "button-load-gds"));
@ -716,10 +875,9 @@ static void gds_render_gui_init(GdsRenderGui *self)
g_object_ref(self->main_window); g_object_ref(self->main_window);
g_object_ref(self->cell_tree_view); g_object_ref(self->cell_tree_view);
g_object_ref(self->convert_button); g_object_ref(self->convert_button);
g_object_ref(self->layer_selector); /* g_object_ref(self->layer_selector); <= This is already referenced by the _new() function */
g_object_ref(self->cell_tree_store);
g_object_ref(self->cell_search_entry); g_object_ref(self->cell_search_entry);
g_object_ref(self->palette); /* g_object_ref(self->palette); */
g_object_ref(self->open_button); g_object_ref(self->open_button);
g_object_ref(self->load_layer_button); g_object_ref(self->load_layer_button);
g_object_ref(self->save_layer_button); g_object_ref(self->save_layer_button);

View File

@ -151,7 +151,7 @@ void bounding_box_calculate_path_box(GList *vertices, double thickness,
GList *vertex_iterator; GList *vertex_iterator;
struct vector_2d pt; struct vector_2d pt;
printf("Warning! Function %s not yet implemented correctly!\n", __func__); /* printf("Warning! Function %s not yet implemented correctly!\n", __func__); */
if (!vertices || !box) if (!vertices || !box)
return; return;

View File

@ -1,57 +0,0 @@
/*
* GDSII-Converter
* Copyright (C) 2018 Mario Hüttel <mario.huettel@gmx.net>
*
* This file is part of GDSII-Converter.
*
* GDSII-Converter is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*
* GDSII-Converter is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with GDSII-Converter. If not, see <http://www.gnu.org/licenses/>.
*/
/**
* @file tree-store.h
* @brief Header file for Tree store implementation
* @author Mario Hüttel <mario.huettel@gmx.net>
*/
/**
* @addtogroup GUI
* @{
*/
#ifndef __TREE_STORE_H__
#define __TREE_STORE_H__
#include <gtk/gtk.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_MODDATE,
CELL_SEL_ACCESSDATE,
CELL_SEL_COLUMN_COUNT /**< @brief Not a column. Used to determine count of columns */
};
struct tree_stores {
GtkTreeView *base_tree_view;
GtkTreeStore *base_store;
GtkTreeModelFilter *filter;
GtkEntry *search_entry;
};
struct tree_stores *setup_cell_selector(GtkTreeView* view, GtkEntry *search_entry);
#endif /* __TREE_STORE_H__ */
/** @} */

View File

@ -1,60 +0,0 @@
/*
* GDSII-Converter
* Copyright (C) 2018 Mario Hüttel <mario.huettel@gmx.net>
*
* This file is part of GDSII-Converter.
*
* GDSII-Converter is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*
* GDSII-Converter is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with GDSII-Converter. If not, see <http://www.gnu.org/licenses/>.
*/
/**
* @file mapping-parser.h
* @brief Function to read a mapping file line and parse it.
* @author Mario Hüttel <mario.huettel@gmx.net>
*/
#ifndef __MAPPING_PARSER_H__
#define __MAPPING_PARSER_H__
/**
* @addtogroup Mapping-Parser
* @{
*/
#include <glib.h>
#include <gds-render/widgets/layer-element.h>
#include <gds-render/layer/layer-settings.h>
/**
* @brief Load a line from \p stream and parse try to parse it as layer information
* @param stream Input data stream
* @param export Layer shall be exported
* @param name Layer name. Free returned pointer after using.
* @param layer Layer number
* @param color RGBA color.
* @return 1 if malformatted line, 0 if parsing was successful and parameters are valid, -1 if file end
*/
int mapping_parser_load_line(GDataInputStream *stream, gboolean *export, char **name, int *layer, GdkRGBA *color);
/**
* @brief Create Line for LayerMapping file with supplied information
* @param layer_element information
* @param line_buffer buffer to write to
* @param max_len Maximum length that cna be used in \p line_buffer
*/
void mapping_parser_gen_csv_line(LayerElement *layer_element, char *line_buffer, size_t max_len);
/** @} */
#endif /* __MAPPING_PARSER_H__ */

View File

@ -152,7 +152,7 @@ int gds_output_renderer_render_output_async(GdsOutputRenderer *renderer, struct
* @param renderer GdsOutputrenderer object * @param renderer GdsOutputrenderer object
* @param status Status to supply to signal emission * @param status Status to supply to signal emission
*/ */
void gds_output_renderer_update_gui_status_from_async(GdsOutputRenderer *renderer, const char *status); void gds_output_renderer_update_async_progress(GdsOutputRenderer *renderer, const char *status);
G_END_DECLS G_END_DECLS

View File

@ -26,17 +26,17 @@
#include <gds-render/layer/color-palette.h> #include <gds-render/layer/color-palette.h>
struct _ColorPalette { struct _ColorPalette {
/* Inheritance */ /* Inheritance */
GObject parent; GObject parent;
/* Custom fields */ /* Custom fields */
/** @brief The internal array to store the colors */ /** @brief The internal array to store the colors */
GdkRGBA *color_array; GdkRGBA *color_array;
/** @brief The length of the _ColorPalette::color_array array */ /** @brief The length of the _ColorPalette::color_array array */
unsigned int color_array_length; unsigned int color_array_length;
/* Dummy bytes to ensure ABI compatibility in future versions */ /* Dummy bytes to ensure ABI compatibility in future versions */
gpointer dummy[4]; gpointer dummy[4];
}; };
G_DEFINE_TYPE(ColorPalette, color_palette, G_TYPE_OBJECT) G_DEFINE_TYPE(ColorPalette, color_palette, G_TYPE_OBJECT)
@ -141,13 +141,16 @@ static int color_palette_fill_with_resource(ColorPalette *palette, char *resourc
g_regex_match(regex, line, 0, &mi); g_regex_match(regex, line, 0, &mi);
if (g_match_info_matches(mi) && color_idx < lines) { if (g_match_info_matches(mi) && color_idx < lines) {
match = g_match_info_fetch_named(mi, "red"); match = g_match_info_fetch_named(mi, "red");
palette->color_array[color_idx].red = (double)g_ascii_strtoll(match, NULL, 16) / 255.0; palette->color_array[color_idx].red =
(double)g_ascii_strtoll(match, NULL, 16) / 255.0;
g_free(match); g_free(match);
match = g_match_info_fetch_named(mi, "green"); match = g_match_info_fetch_named(mi, "green");
palette->color_array[color_idx].green = (double)g_ascii_strtoll(match, NULL, 16) / 255.0; palette->color_array[color_idx].green =
(double)g_ascii_strtoll(match, NULL, 16) / 255.0;
g_free(match); g_free(match);
match = g_match_info_fetch_named(mi, "blue"); match = g_match_info_fetch_named(mi, "blue");
palette->color_array[color_idx].blue = (double)g_ascii_strtoll(match, NULL, 16) / 255.0; palette->color_array[color_idx].blue =
(double)g_ascii_strtoll(match, NULL, 16) / 255.0;
g_free(match); g_free(match);
/* Only RGB supported so far. Fix alpha channel to 1.0 */ /* Only RGB supported so far. Fix alpha channel to 1.0 */
@ -233,8 +236,7 @@ static void color_palette_dispose(GObject *gobj)
ColorPalette *palette; ColorPalette *palette;
palette = GDS_RENDER_COLOR_PALETTE(gobj); palette = GDS_RENDER_COLOR_PALETTE(gobj);
if (palette->color_array) if (palette->color_array) {
{
palette->color_array_length = 0; palette->color_array_length = 0;
free(palette->color_array); free(palette->color_array);
} }

View File

@ -36,7 +36,6 @@
#include <gds-render/layer/layer-selector.h> #include <gds-render/layer/layer-selector.h>
#include <gds-render/gds-utils/gds-parser.h> #include <gds-render/gds-utils/gds-parser.h>
#include <gds-render/widgets/layer-element.h> #include <gds-render/widgets/layer-element.h>
#include <gds-render/layer/mapping-parser.h>
struct _LayerSelector { struct _LayerSelector {
/* Parent */ /* Parent */
@ -55,7 +54,8 @@ struct _LayerSelector {
G_DEFINE_TYPE(LayerSelector, layer_selector, G_TYPE_OBJECT) G_DEFINE_TYPE(LayerSelector, layer_selector, G_TYPE_OBJECT)
/* Drag and drop code /*
* Drag and drop code
* Original code from https://blog.gtk.org/2017/06/01/drag-and-drop-in-lists-revisited/ * Original code from https://blog.gtk.org/2017/06/01/drag-and-drop-in-lists-revisited/
*/ */
@ -73,16 +73,16 @@ static void sel_layer_element_drag_begin(GtkWidget *widget, GdkDragContext *cont
surface = cairo_image_surface_create(CAIRO_FORMAT_ARGB32, alloc.width, alloc.height); surface = cairo_image_surface_create(CAIRO_FORMAT_ARGB32, alloc.width, alloc.height);
cr = cairo_create(surface); cr = cairo_create(surface);
gtk_style_context_add_class (gtk_widget_get_style_context(row), "drag-icon"); gtk_style_context_add_class(gtk_widget_get_style_context(row), "drag-icon");
gtk_widget_draw (row, cr); gtk_widget_draw(row, cr);
gtk_style_context_remove_class(gtk_widget_get_style_context(row), "drag-icon"); gtk_style_context_remove_class(gtk_widget_get_style_context(row), "drag-icon");
gtk_widget_translate_coordinates (widget, row, 0, 0, &x, &y); gtk_widget_translate_coordinates(widget, row, 0, 0, &x, &y);
cairo_surface_set_device_offset (surface, -x, -y); cairo_surface_set_device_offset(surface, -x, -y);
gtk_drag_set_icon_surface (context, surface); gtk_drag_set_icon_surface(context, surface);
cairo_destroy (cr); cairo_destroy(cr);
cairo_surface_destroy (surface); cairo_surface_destroy(surface);
g_object_set_data(G_OBJECT(gtk_widget_get_parent(row)), "drag-row", row); 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"); gtk_style_context_add_class(gtk_widget_get_style_context(row), "drag-row");
@ -116,14 +116,14 @@ static void sel_layer_element_drag_data_get(GtkWidget *widget, GdkDragContext *c
32, (const guchar *)&widget, sizeof(gpointer)); 32, (const guchar *)&widget, sizeof(gpointer));
} }
static GtkListBoxRow *layer_selector_get_last_row (GtkListBox *list) static GtkListBoxRow *layer_selector_get_last_row(GtkListBox *list)
{ {
int i; int i;
GtkListBoxRow *row; GtkListBoxRow *row;
GtkListBoxRow *tmp;
row = NULL; row = NULL;
for (i = 0; ; i++) { for (i = 0; ; i++) {
GtkListBoxRow *tmp;
tmp = gtk_list_box_get_row_at_index(list, i); tmp = gtk_list_box_get_row_at_index(list, i);
if (tmp == NULL) if (tmp == NULL)
break; break;
@ -133,15 +133,15 @@ static GtkListBoxRow *layer_selector_get_last_row (GtkListBox *list)
return row; return row;
} }
static GtkListBoxRow *layer_selector_get_row_before (GtkListBox *list, GtkListBoxRow *row) static GtkListBoxRow *layer_selector_get_row_before(GtkListBox *list, GtkListBoxRow *row)
{ {
int pos; int pos;
pos = gtk_list_box_row_get_index (row); pos = gtk_list_box_row_get_index(row);
return gtk_list_box_get_row_at_index (list, pos - 1); return gtk_list_box_get_row_at_index(list, pos - 1);
} }
static GtkListBoxRow *layer_selector_get_row_after (GtkListBox *list, GtkListBoxRow *row) static GtkListBoxRow *layer_selector_get_row_after(GtkListBox *list, GtkListBoxRow *row)
{ {
int pos; int pos;
@ -277,40 +277,40 @@ static void layer_selector_drag_leave(GtkWidget *widget, GdkDragContext *context
} }
static const char *dnd_additional_css = static const char *dnd_additional_css =
".row:not(:first-child) { " ".row:not(:first-child) { "
" border-top: 1px solid alpha(gray,0.5); " " border-top: 1px solid alpha(gray,0.5); "
" border-bottom: 1px solid transparent; " " border-bottom: 1px solid transparent; "
"}" "}"
".row:first-child { " ".row:first-child { "
" border-top: 1px solid transparent; " " border-top: 1px solid transparent; "
" border-bottom: 1px solid transparent; " " border-bottom: 1px solid transparent; "
"}" "}"
".row:last-child { " ".row:last-child { "
" border-top: 1px solid alpha(gray,0.5); " " border-top: 1px solid alpha(gray,0.5); "
" border-bottom: 1px solid alpha(gray,0.5); " " border-bottom: 1px solid alpha(gray,0.5); "
"}" "}"
".row.drag-icon { " ".row.drag-icon { "
" background: #282828; " " background: #282828; "
" border: 1px solid blue; " " border: 1px solid blue; "
"}" "}"
".row.drag-row { " ".row.drag-row { "
" color: gray; " " color: gray; "
" background: alpha(gray,0.2); " " background: alpha(gray,0.2); "
"}" "}"
".row.drag-row.drag-hover { " ".row.drag-row.drag-hover { "
" border-top: 1px solid #4e9a06; " " border-top: 1px solid #4e9a06; "
" border-bottom: 1px solid #4e9a06; " " border-bottom: 1px solid #4e9a06; "
"}" "}"
".row.drag-hover image, " ".row.drag-hover image, "
".row.drag-hover label { " ".row.drag-hover label { "
" color: #4e9a06; " " color: #4e9a06; "
"}" "}"
".row.drag-hover-top {" ".row.drag-hover-top {"
" border-top: 1px solid #4e9a06; " " border-top: 1px solid #4e9a06; "
"}" "}"
".row.drag-hover-bottom {" ".row.drag-hover-bottom {"
" border-bottom: 1px solid #4e9a06; " " border-bottom: 1px solid #4e9a06; "
"}"; "}";
static void layer_selector_dispose(GObject *self) static void layer_selector_dispose(GObject *self)
{ {
@ -349,7 +349,8 @@ static void layer_selector_class_init(LayerSelectorClass *klass)
static void layer_selector_setup_dnd(LayerSelector *self) 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); 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-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-motion", G_CALLBACK(layer_selector_drag_motion), NULL);
g_signal_connect(self->list_box, "drag-leave", G_CALLBACK(layer_selector_drag_leave), NULL); g_signal_connect(self->list_box, "drag-leave", G_CALLBACK(layer_selector_drag_leave), NULL);
@ -399,11 +400,11 @@ LayerSettings *layer_selector_export_rendered_layer_info(LayerSelector *selector
row_list = gtk_container_get_children(GTK_CONTAINER(selector->list_box)); 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++) { for (i = 0, iterator = row_list; iterator != NULL; iterator = g_list_next(iterator), i++) {
le = LAYER_ELEMENT(iterator->data); le = LAYER_ELEMENT(iterator->data);
/* Get name from layer element. This must not be freed */ /* Get name from layer element. This must not be freed */
linfo.name =(char *)layer_element_get_name(le); linfo.name = (char *)layer_element_get_name(le);
layer_element_get_color(le, &linfo.color); layer_element_get_color(le, &linfo.color);
linfo.render = (layer_element_get_export(le) ? 1 : 0); linfo.render = (layer_element_get_export(le) ? 1 : 0);
@ -425,9 +426,9 @@ static void layer_selector_clear_widgets(LayerSelector *self)
GList *temp; GList *temp;
list = gtk_container_get_children(GTK_CONTAINER(self->list_box)); list = gtk_container_get_children(GTK_CONTAINER(self->list_box));
for (temp = list; temp != NULL; temp = temp->next) { for (temp = list; temp != NULL; temp = temp->next)
gtk_container_remove(GTK_CONTAINER(self->list_box), GTK_WIDGET(temp->data)); 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 */ /* Widgets are already destroyed when removed from box because they are only referenced inside the container */
g_list_free(list); g_list_free(list);
@ -445,7 +446,8 @@ static void layer_selector_clear_widgets(LayerSelector *self)
* @param layer Layer number to check for * @param layer Layer number to check for
* @return TRUE if layer is present, else FALSE * @return TRUE if layer is present, else FALSE
*/ */
static gboolean layer_selector_check_if_layer_widget_exists(LayerSelector *self, int layer) { static gboolean layer_selector_check_if_layer_widget_exists(LayerSelector *self, int layer)
{
GList *list; GList *list;
GList *temp; GList *temp;
LayerElement *widget; LayerElement *widget;
@ -553,9 +555,8 @@ void layer_selector_generate_layer_widgets(LayerSelector *selector, GList *libs)
for (; libs != NULL; libs = libs->next) { for (; libs != NULL; libs = libs->next) {
lib = (struct gds_library *)libs->data; lib = (struct gds_library *)libs->data;
for (cell_list = lib->cells; cell_list != NULL; cell_list = cell_list->next) { 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); layer_selector_analyze_cell_layers(selector, (struct gds_cell *)cell_list->data);
} /* For Cell List */
} /* For libs */ } /* For libs */
/* Sort the layers */ /* Sort the layers */
@ -577,6 +578,7 @@ void layer_selector_generate_layer_widgets(LayerSelector *selector, GList *libs)
static LayerElement *layer_selector_find_layer_element_in_list(GList *el_list, int layer) static LayerElement *layer_selector_find_layer_element_in_list(GList *el_list, int layer)
{ {
LayerElement *ret = NULL; LayerElement *ret = NULL;
for (; el_list != NULL; el_list = el_list->next) { for (; el_list != NULL; el_list = el_list->next) {
if (layer_element_get_layer(LAYER_ELEMENT(el_list->data)) == layer) { if (layer_element_get_layer(LAYER_ELEMENT(el_list->data)) == layer) {
ret = LAYER_ELEMENT(el_list->data); ret = LAYER_ELEMENT(el_list->data);
@ -597,19 +599,18 @@ static LayerElement *layer_selector_find_layer_element_in_list(GList *el_list, i
* @param self LayerSelector instance * @param self LayerSelector instance
* @param file_name File name to load from * @param file_name File name to load from
*/ */
static void layer_selector_load_layer_mapping_from_file(LayerSelector *self, gchar *file_name) static void layer_selector_load_layer_mapping_from_file(LayerSelector *self, const gchar *file_name)
{ {
GFile *file; GFile *file;
GFileInputStream *stream; GFileInputStream *stream;
GDataInputStream *dstream; GDataInputStream *dstream;
LayerElement *le; LayerElement *le;
char *name;
gboolean export;
int layer;
GdkRGBA color;
int result;
GList *rows; GList *rows;
GList *temp; GList *temp;
GList *layer_infos;
int status;
LayerSettings *layer_settings;
struct layer_info *linfo;
file = g_file_new_for_path(file_name); file = g_file_new_for_path(file_name);
stream = g_file_read(file, NULL, NULL); stream = g_file_read(file, NULL, NULL);
@ -624,31 +625,40 @@ static void layer_selector_load_layer_mapping_from_file(LayerSelector *self, gch
/* Reference and remove all rows from box */ /* Reference and remove all rows from box */
for (temp = rows; temp != NULL; temp = temp->next) { for (temp = rows; temp != NULL; temp = temp->next) {
le = LAYER_ELEMENT(temp->data); le = LAYER_ELEMENT(temp->data);
/* Referencing protets the widget from being deleted when removed */ /* Referencing protects the widget from being deleted when removed */
g_object_ref(G_OBJECT(le)); g_object_ref(G_OBJECT(le));
gtk_container_remove(GTK_CONTAINER(self->list_box), GTK_WIDGET(le)); gtk_container_remove(GTK_CONTAINER(self->list_box), GTK_WIDGET(le));
} }
while((result = mapping_parser_load_line(dstream, &export, &name, &layer, &color)) >= 0) { /* Load Layer settings. No need to check pointer, will be checked by load csv func. */
/* skip broken line */ layer_settings = layer_settings_new();
if (result == 1)
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; continue;
/* Add rows in the same order as in file */ layer_element_set_name(le, linfo->name);
if ((le = layer_selector_find_layer_element_in_list(rows, layer))) { layer_element_set_export(le, (linfo->render ? TRUE : FALSE));
gtk_list_box_insert(self->list_box, GTK_WIDGET(le), -1); layer_element_set_color(le, &linfo->color);
gtk_container_add(GTK_CONTAINER(self->list_box), GTK_WIDGET(le));
layer_element_set_color(le, &color); rows = g_list_remove(rows, le);
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);
}
} }
abort_layer_settings:
/* Destroy layer settings. Not needed for adding remaining elements */
g_object_unref(layer_settings);
/* Add remaining elements */ /* Add remaining elements */
for (temp = rows; temp != NULL; temp = temp->next) { for (temp = rows; temp != NULL; temp = temp->next) {
le = LAYER_ELEMENT(temp->data); le = LAYER_ELEMENT(temp->data);
@ -682,7 +692,8 @@ static void layer_selector_load_mapping_clicked(GtkWidget *button, gpointer user
sel = LAYER_SELECTOR(user_data); 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, 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); "Cancel", GTK_RESPONSE_CANCEL, "Load Mapping", GTK_RESPONSE_ACCEPT, NULL);
res = gtk_dialog_run(GTK_DIALOG(dialog)); res = gtk_dialog_run(GTK_DIALOG(dialog));
if (res == GTK_RESPONSE_ACCEPT) { if (res == GTK_RESPONSE_ACCEPT) {
@ -702,29 +713,14 @@ static void layer_selector_load_mapping_clicked(GtkWidget *button, gpointer user
*/ */
static void layer_selector_save_layer_mapping_data(LayerSelector *self, const gchar *file_name) static void layer_selector_save_layer_mapping_data(LayerSelector *self, const gchar *file_name)
{ {
FILE *file; LayerSettings *layer_settings;
char workbuff[512];
GList *le_list;
GList *temp;
/* Overwrite existing file */ g_return_if_fail(LAYER_IS_SELECTOR(self));
file = fopen((const char *)file_name, "w"); g_return_if_fail(file_name);
le_list = gtk_container_get_children(GTK_CONTAINER(self->list_box)); /* Get layer settings. No need to check return value. to_csv func is safe */
layer_settings = layer_selector_export_rendered_layer_info(self);
/* File format is CSV: <Layer>,<target_pos>,<R>,<G>,<B>,<Alpha>,<Export?>,<Name> */ (void)layer_settings_to_csv(layer_settings, file_name);
for (temp = le_list; temp != NULL; temp = temp->next) {
/* To be sure it is a valid string */
workbuff[0] = 0;
mapping_parser_gen_csv_line(LAYER_ELEMENT(temp->data), workbuff, sizeof(workbuff));
fwrite(workbuff, sizeof(char), strlen(workbuff), file);
}
g_list_free(le_list);
/* Save File */
fflush(file);
fclose(file);
} }
/** /**
@ -742,7 +738,8 @@ static void layer_selector_save_mapping_clicked(GtkWidget *button, gpointer user
sel = LAYER_SELECTOR(user_data); 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, 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); "Cancel", GTK_RESPONSE_CANCEL, "Save Mapping", GTK_RESPONSE_ACCEPT, NULL);
gtk_file_chooser_set_do_overwrite_confirmation(GTK_FILE_CHOOSER(dialog), TRUE); gtk_file_chooser_set_do_overwrite_confirmation(GTK_FILE_CHOOSER(dialog), TRUE);
@ -809,9 +806,8 @@ void layer_selector_select_all_layers(LayerSelector *layer_selector, gboolean se
for (iter = le_list; iter != NULL; iter = g_list_next(iter)) { for (iter = le_list; iter != NULL; iter = g_list_next(iter)) {
le = LAYER_ELEMENT(iter->data); le = LAYER_ELEMENT(iter->data);
if (LAYER_IS_ELEMENT(le)) { if (LAYER_IS_ELEMENT(le))
layer_element_set_export(le, select); layer_element_set_export(le, select);
}
} }
g_list_free(le_list); g_list_free(le_list);

View File

@ -223,7 +223,7 @@ int layer_settings_to_csv(LayerSettings *settings, const char *path)
linfo = (struct layer_info *)info_iter->data; linfo = (struct layer_info *)info_iter->data;
layer_settings_gen_csv_line(string, linfo); layer_settings_gen_csv_line(string, linfo);
g_output_stream_write(w_fstream, string->str, sizeof(gchar), NULL, NULL); g_output_stream_write(w_fstream, string->str, string->len * sizeof(gchar), NULL, NULL);
} }
/* Delete string */ /* Delete string */
@ -314,10 +314,14 @@ int layer_settings_load_from_csv(LayerSettings *settings, const char *path)
GInputStream *in_stream; GInputStream *in_stream;
GDataInputStream *data_stream; GDataInputStream *data_stream;
int parser_ret; int parser_ret;
int stacked_pos;
struct layer_info linfo; struct layer_info linfo;
file = g_file_new_for_path(path); file = g_file_new_for_path(path);
in_stream = G_INPUT_STREAM(g_file_read(file, NULL, NULL)); 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) { if (!in_stream) {
ret = -1; ret = -1;
goto ret_destroy_file; goto ret_destroy_file;
@ -327,11 +331,14 @@ int layer_settings_load_from_csv(LayerSettings *settings, const char *path)
data_stream = g_data_input_stream_new(in_stream); 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) { while ((parser_ret = layer_settings_load_csv_line_from_stream(data_stream, &linfo)) >= 0) {
/* Line broken */ /* Line broken */
if (parser_ret == 1) if (parser_ret == 1)
continue; continue;
linfo.stacked_position = stacked_pos++;
layer_settings_append_layer_info(settings, &linfo); layer_settings_append_layer_info(settings, &linfo);
/* Clear name to prevent memory leak */ /* Clear name to prevent memory leak */
if (linfo.name) if (linfo.name)

View File

@ -1,144 +0,0 @@
/*
*
* GDSII-Converter
* Copyright (C) 2018 Mario Hüttel <mario.huettel@gmx.net>
*
* This file is part of GDSII-Converter.
*
* GDSII-Converter is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*
* GDSII-Converter is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with GDSII-Converter. If not, see <http://www.gnu.org/licenses/>.
*/
/**
* @file mapping-parser.c
* @brief Function to read a mapping file line and parse it.
* @author Mario Hüttel <mario.huettel@gmx.net>
*/
/**
* @addtogroup Mapping-Parser
* @{
*/
#include <gds-render/layer/mapping-parser.h>
int mapping_parser_load_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;
}
void mapping_parser_gen_csv_line(LayerElement *layer_element, char *line_buffer, size_t max_len)
{
int i;
GString *string;
gboolean export;
const gchar *name;
int layer;
GdkRGBA color;
string = g_string_new_len(NULL, max_len-1);
/* Extract values */
export = layer_element_get_export(layer_element);
name = (const gchar*)layer_element_get_name(layer_element);
layer = layer_element_get_layer(layer_element);
layer_element_get_color(layer_element, &color);
/* print values to line */
g_string_printf(string, "%d:%lf:%lf:%lf:%lf:%d:%s\n",
layer, color.red, color.green,
color.blue, color.alpha, (export == TRUE ? 1 : 0), name);
/* Fix broken locale settings */
for (i = 0; string->str[i]; i++) {
if (string->str[i] == ',')
string->str[i] = '.';
}
for (i = 0; string->str[i]; i++) {
if (string->str[i] == ':')
string->str[i] = ',';
}
if (string->len > (max_len-1)) {
printf("Layer Definition too long. Please shorten Layer Name!!\n");
line_buffer[0] = 0x0;
return;
}
/* copy max_len bytes of string */
strncpy(line_buffer, (char *)string->str, max_len-1);
line_buffer[max_len-1] = 0;
/* Completely remove string */
g_string_free(string, TRUE);
}
/** @} */

34
main.c
View File

@ -125,15 +125,15 @@ static void app_about(GSimpleAction *action, GVariant *parameter, gpointer user_
* @brief Contains the application menu entries * @brief Contains the application menu entries
*/ */
static const GActionEntry app_actions[] = { static const GActionEntry app_actions[] = {
{"quit", app_quit, NULL, NULL, NULL, {0}}, { "quit", app_quit, NULL, NULL, NULL, {0} },
{"about", app_about, NULL, NULL, NULL, {0}} { "about", app_about, NULL, NULL, NULL, {0} },
}; };
/** /**
* @brief Called when a GUI main window is closed * @brief Called when a GUI main window is closed
* *
* The GdsRenderGui object associated with the closed main window * The GdsRenderGui object associated with the closed main window
* is removed from the list of open GUIs (\p user_data) and unreferenced. * 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 gui The GUI instance the closed main window belongs to
* @param user_data List of GUIs * @param user_data List of GUIs
@ -183,8 +183,8 @@ static void gapp_activate(GApplication *app, gpointer user_data)
*/ */
static int start_gui(int argc, char **argv) static int start_gui(int argc, char **argv)
{ {
GtkApplication *gapp; GtkApplication *gapp;
GString *application_domain;
int app_status; int app_status;
static struct application_data appdata = { static struct application_data appdata = {
.gui_list = NULL .gui_list = NULL
@ -193,13 +193,22 @@ static int start_gui(int argc, char **argv)
GMenu *m_quit; GMenu *m_quit;
GMenu *m_about; GMenu *m_about;
gapp = gtk_application_new("de.shimatta.gds-render", G_APPLICATION_FLAGS_NONE); /*
* 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);
gapp = gtk_application_new(application_domain->str, G_APPLICATION_FLAGS_NONE);
g_string_free(application_domain, TRUE);
g_application_register(G_APPLICATION(gapp), NULL, NULL); g_application_register(G_APPLICATION(gapp), NULL, NULL);
g_signal_connect(gapp, "activate", G_CALLBACK(gapp_activate), &appdata); g_signal_connect(gapp, "activate", G_CALLBACK(gapp_activate), &appdata);
if (g_application_get_is_remote(G_APPLICATION(gapp)) == TRUE) { if (g_application_get_is_remote(G_APPLICATION(gapp)) == TRUE) {
g_application_activate(G_APPLICATION(gapp)); g_application_activate(G_APPLICATION(gapp));
printf("There is already an open instance. Will open second window in said instance.\n"); printf("There is already an open instance. Will open second window in that instance.\n");
return 0; return 0;
} }
@ -258,14 +267,17 @@ int main(int argc, char **argv)
GOptionEntry entries[] = { GOptionEntry entries[] = {
{"version", 'v', 0, G_OPTION_ARG_NONE, &version, "Print version", NULL}, {"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"}, {"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>" }, {"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" }, {"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" }, {"mapping", 'm', 0, G_OPTION_ARG_FILENAME, &mappingname, "Path for Layer Mapping File", "PATH" },
{"cell", 'c', 0, G_OPTION_ARG_STRING, &cellname, "Cell to render", "NAME" }, {"cell", 'c', 0, G_OPTION_ARG_STRING, &cellname, "Cell to render", "NAME" },
{"tex-standalone", 'a', 0, G_OPTION_ARG_NONE, &pdf_standalone, "Create standalone PDF", NULL }, {"tex-standalone", 'a', 0, G_OPTION_ARG_NONE, &pdf_standalone, "Create standalone PDF", NULL },
{"tex-layers", 'l', 0, G_OPTION_ARG_NONE, &pdf_layers, "Create PDF Layers (OCG)", NULL }, {"tex-layers", 'l', 0, G_OPTION_ARG_NONE, &pdf_layers, "Create PDF Layers (OCG)", NULL },
{"custom-render-lib", 'P', 0, G_OPTION_ARG_FILENAME, &custom_library_path, "Path to a custom shared object, that implements the " EXTERNAL_LIBRARY_FUNCTION " function", "PATH"}, {"custom-render-lib", 'P', 0, G_OPTION_ARG_FILENAME, &custom_library_path,
"Path to a custom shared object, that implements the " EXTERNAL_LIBRARY_FUNCTION " function", "PATH"},
{NULL} {NULL}
}; };
@ -289,14 +301,12 @@ int main(int argc, char **argv)
scale = 1; scale = 1;
} }
/* Get gds name */ /* Get gds name */
gds_name = argv[1]; gds_name = argv[1];
/* Print out additional arguments as ignored */ /* Print out additional arguments as ignored */
for (i = 2; i < argc; i++) { for (i = 2; i < argc; i++)
printf("Ignored argument: %s", argv[i]); printf("Ignored argument: %s", argv[i]);
}
app_status = app_status =
command_line_convert_gds(gds_name, cellname, renderer_args, output_paths, mappingname, command_line_convert_gds(gds_name, cellname, renderer_args, output_paths, mappingname,

View File

@ -17,10 +17,10 @@
* along with GDSII-Converter. If not, see <http://www.gnu.org/licenses/>. * along with GDSII-Converter. If not, see <http://www.gnu.org/licenses/>.
*/ */
/** /**
* @file cairo-renderer.c * @file cairo-renderer.c
* @brief Output renderer for Cairo PDF export * @brief Output renderer for Cairo PDF export
* @author Mario Hüttel <mario.huettel@gmx.net> * @author Mario Hüttel <mario.huettel@gmx.net>
*/ */
/** @addtogroup Cairo-Renderer /** @addtogroup Cairo-Renderer
* @{ * @{
@ -121,7 +121,8 @@ static void render_cell(struct gds_cell *cell, struct cairo_layer *layers, doubl
/* Render child cells */ /* Render child cells */
for (instance_list = cell->child_cells; instance_list != NULL; instance_list = instance_list->next) { for (instance_list = cell->child_cells; instance_list != NULL; instance_list = instance_list->next) {
cell_instance = (struct gds_cell_instance *)instance_list->data; cell_instance = (struct gds_cell_instance *)instance_list->data;
if ((temp_cell = cell_instance->cell_ref) != NULL) { temp_cell = cell_instance->cell_ref;
if (temp_cell != NULL) {
apply_inherited_transform_to_all_layers(layers, apply_inherited_transform_to_all_layers(layers,
&cell_instance->origin, &cell_instance->origin,
cell_instance->magnification, cell_instance->magnification,
@ -177,6 +178,7 @@ static void render_cell(struct gds_cell *cell, struct cairo_layer *layers, doubl
cairo_stroke(cr); cairo_stroke(cr);
break; break;
case GRAPHIC_BOX: case GRAPHIC_BOX:
/* Expected fallthrough */
case GRAPHIC_POLYGON: case GRAPHIC_POLYGON:
cairo_set_line_width(cr, 0.1/scale); cairo_set_line_width(cr, 0.1/scale);
cairo_close_path(cr); cairo_close_path(cr);
@ -187,8 +189,39 @@ static void render_cell(struct gds_cell *cell, struct cairo_layer *layers, doubl
} /* for gfx list */ } /* 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 * @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 cell Toplevel cell to @ref Cairo-Renderer
* @param layer_infos List of layer information. Specifies color and layer stacking * @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 pdf_file PDF output file. Set to NULL if no PDF file has to be generated
@ -196,8 +229,12 @@ static void render_cell(struct gds_cell *cell, struct cairo_layer *layers, doubl
* @param scale Scale the output image down by \p scale * @param scale Scale the output image down by \p scale
* @return Error * @return Error
*/ */
static int cairo_renderer_render_cell_to_vector_file(struct gds_cell *cell, GList *layer_infos, const char *pdf_file, static int cairo_renderer_render_cell_to_vector_file(GdsOutputRenderer *renderer,
const char *svg_file, double scale) 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_surface_t *pdf_surface = NULL, *svg_surface = NULL;
cairo_t *pdf_cr = NULL, *svg_cr = NULL; cairo_t *pdf_cr = NULL, *svg_cr = NULL;
@ -209,28 +246,40 @@ static int cairo_renderer_render_cell_to_vector_file(struct gds_cell *cell, GLis
double rec_x0, rec_y0, rec_width, rec_height; double rec_x0, rec_y0, rec_width, rec_height;
double xmin = INT32_MAX, xmax = INT32_MIN, ymin = INT32_MAX, ymax = INT32_MIN; double xmin = INT32_MAX, xmax = INT32_MIN, ymin = INT32_MAX, ymax = INT32_MIN;
pid_t process_id; pid_t process_id;
int comm_pipe[2];
char receive_message[200];
if (pdf_file == NULL && svg_file == NULL) { if (pdf_file == NULL && svg_file == NULL) {
/* No output specified */ /* No output specified */
return -1; 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 /* Fork to a new child process. This ensures the memory leaks (see issue #16) in Cairo don't
* brick everything. * brick everything.
* *
* And by the way: This now bricks all Windows compatibility. Deal with it. * And by the way: This now bricks all Windows compatibility. Deal with it.
*/ */
/* Use fork for production code and -1 as value for debugging */
process_id = fork(); process_id = fork();
//process_id = -1; //process_id = -1;
if (process_id < 0) { if (process_id < 0) {
/* Well... shit... We have to run it in our process. */ /* This should not happen */
fprintf(stderr, "Fatal error: Cairo Renderer: Could not spawn child process!");
exit(-2);
} else if (process_id > 0) { } else if (process_id > 0) {
/* Woohoo... Successfully dumped the shitty code to an unknowing victim */ /* Woohoo... Successfully dumped the shitty code to an unknowing victim */
goto ret_parent; 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)); layers = (struct cairo_layer *)calloc(MAX_LAYERS, sizeof(struct cairo_layer));
/* Clear layers */ /* Clear layers */
@ -260,7 +309,7 @@ static int cairo_renderer_render_cell_to_vector_file(struct gds_cell *cell, GLis
} }
} }
dprintf(comm_pipe[1], "Rendering layers\n");
render_cell(cell, layers, scale); render_cell(cell, layers, scale);
/* get size of image and top left coordinate */ /* get size of image and top left coordinate */
@ -278,7 +327,7 @@ static int cairo_renderer_render_cell_to_vector_file(struct gds_cell *cell, GLis
/* Print size */ /* Print size */
cairo_recording_surface_ink_extents(layers[linfo->layer].rec, &rec_x0, &rec_y0, cairo_recording_surface_ink_extents(layers[linfo->layer].rec, &rec_x0, &rec_y0,
&rec_width, &rec_height); &rec_width, &rec_height);
printf("Size of layer %d%s%s%s: <%lf x %lf> @ (%lf | %lf)\n", dprintf(comm_pipe[1], "Size of layer %d%s%s%s: <%lf x %lf> @ (%lf | %lf)\n",
linfo->layer, linfo->layer,
(linfo->name && linfo->name[0] ? " (" : ""), (linfo->name && linfo->name[0] ? " (" : ""),
(linfo->name && linfo->name[0] ? linfo->name : ""), (linfo->name && linfo->name[0] ? linfo->name : ""),
@ -297,7 +346,7 @@ static int cairo_renderer_render_cell_to_vector_file(struct gds_cell *cell, GLis
} }
printf("Cell bounding box: (%lf | %lf) -- (%lf | %lf)\n", xmin, ymin, xmax, ymax); /* printf("Cell bounding box: (%lf | %lf) -- (%lf | %lf)\n", xmin, ymin, xmax, ymax); */
if (pdf_file) { if (pdf_file) {
pdf_surface = cairo_pdf_surface_create(pdf_file, xmax-xmin, ymax-ymin); pdf_surface = cairo_pdf_surface_create(pdf_file, xmax-xmin, ymax-ymin);
@ -313,6 +362,8 @@ static int cairo_renderer_render_cell_to_vector_file(struct gds_cell *cell, GLis
for (info_list = layer_infos; info_list != NULL; info_list = g_list_next(info_list)) { for (info_list = layer_infos; info_list != NULL; info_list = g_list_next(info_list)) {
linfo = (struct layer_info *)info_list->data; linfo = (struct layer_info *)info_list->data;
dprintf(comm_pipe[1], "Exporting layer %d to file\n", linfo->layer);
if (linfo->layer >= MAX_LAYERS) { if (linfo->layer >= MAX_LAYERS) {
printf("Layer outside of Spec.\n"); printf("Layer outside of Spec.\n");
continue; continue;
@ -347,7 +398,7 @@ static int cairo_renderer_render_cell_to_vector_file(struct gds_cell *cell, GLis
ret_clear_layers: ret_clear_layers:
for (i = 0; i < MAX_LAYERS; i++) { for (i = 0; i < MAX_LAYERS; i++) {
lay = &layers[i]; lay = &layers[i];
if(lay->cr) { if (lay->cr) {
cairo_destroy(lay->cr); cairo_destroy(lay->cr);
cairo_surface_destroy(lay->rec); cairo_surface_destroy(lay->rec);
} }
@ -356,14 +407,26 @@ ret_clear_layers:
printf("Cairo export finished. It might still be buggy!\n"); printf("Cairo export finished. It might still be buggy!\n");
/* If forked, suspend process */ /* Suspend child process */
if (process_id == 0) exit(0);
exit(0);
/* Fork didn't work. Just return here */
return 0;
ret_parent: 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); waitpid(process_id, NULL, 0);
close(comm_pipe[0]);
return 0; return 0;
} }
@ -400,8 +463,8 @@ static int cairo_renderer_render_output(GdsOutputRenderer *renderer,
else else
pdf_file = output_file; pdf_file = output_file;
gds_output_renderer_update_gui_status_from_async(renderer, "Rendering Cairo Output..."); gds_output_renderer_update_async_progress(renderer, "Rendering Cairo Output...");
ret = cairo_renderer_render_cell_to_vector_file(cell, layer_infos, pdf_file, svg_file, scale); ret = cairo_renderer_render_cell_to_vector_file(renderer, cell, layer_infos, pdf_file, svg_file, scale);
if (settings) if (settings)
g_object_unref(settings); g_object_unref(settings);

View File

@ -79,7 +79,8 @@ static int external_renderer_render_cell(struct gds_cell *toplevel_cell, GList *
} }
/* Load symbol from library */ /* Load symbol from library */
so_render_func = (int (*)(struct gds_cell *, GList *, const char *, double))dlsym(so_handle, EXTERNAL_LIBRARY_FUNCTION); so_render_func = (int (*)(struct gds_cell *, GList *, const char *, double))
dlsym(so_handle, EXTERNAL_LIBRARY_FUNCTION);
error_msg = dlerror(); error_msg = dlerror();
if (error_msg != NULL) { if (error_msg != NULL) {
fprintf(stderr, "Rendering function not found in library:\n%s\n", error_msg); fprintf(stderr, "Rendering function not found in library:\n%s\n", error_msg);
@ -133,7 +134,7 @@ static void external_renderer_get_property(GObject *obj, guint property_id, GVal
g_value_set_string(value, self->shared_object_path); g_value_set_string(value, self->shared_object_path);
break; break;
default: default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (obj, property_id, pspec); G_OBJECT_WARN_INVALID_PROPERTY_ID(obj, property_id, pspec);
break; break;
} }
} }

View File

@ -18,10 +18,10 @@
*/ */
/** /**
* @file gds-output-renderer.c * @file gds-output-renderer.c
* @brief Base GObject class for output renderers * @brief Base GObject class for output renderers
* @author Mario Hüttel <mario.huettel@gmx.net> * @author Mario Hüttel <mario.huettel@gmx.net>
*/ */
/** @addtogroup GdsOutputRenderer /** @addtogroup GdsOutputRenderer
* @{ * @{
@ -213,8 +213,6 @@ void gds_output_renderer_init(GdsOutputRenderer *self)
priv->idle_function_parameters.status_message = NULL; priv->idle_function_parameters.status_message = NULL;
g_mutex_init(&priv->settings_lock); g_mutex_init(&priv->settings_lock);
g_mutex_init(&priv->idle_function_parameters.message_lock); g_mutex_init(&priv->idle_function_parameters.message_lock);
return;
} }
GdsOutputRenderer *gds_output_renderer_new() GdsOutputRenderer *gds_output_renderer_new()
@ -260,8 +258,6 @@ LayerSettings *gds_output_renderer_get_and_ref_layer_settings(GdsOutputRenderer
/* This function seems to already reference the LayerSettings object */ /* This function seems to already reference the LayerSettings object */
g_object_get(renderer, "layer-settings", &ret, NULL); g_object_get(renderer, "layer-settings", &ret, NULL);
/* Reference it, so it is not cleared by another thread overwriting the property */
//g_object_ref(ret);
/* It is now safe to clear the lock */ /* It is now safe to clear the lock */
g_mutex_unlock(&priv->settings_lock); g_mutex_unlock(&priv->settings_lock);
@ -330,7 +326,7 @@ static void gds_output_renderer_async_wrapper(GTask *task,
ret = -1000; ret = -1000;
goto ret_from_task; goto ret_from_task;
} }
if(!priv->mutex_init_status) { if (!priv->mutex_init_status) {
ret = -1001; ret = -1001;
goto ret_from_task; goto ret_from_task;
} }
@ -415,7 +411,7 @@ static gboolean idle_event_processor_callback(gpointer user_data)
return FALSE; return FALSE;
} }
void gds_output_renderer_update_gui_status_from_async(GdsOutputRenderer *renderer, const char *status) void gds_output_renderer_update_async_progress(GdsOutputRenderer *renderer, const char *status)
{ {
GSource *idle_event_processor; GSource *idle_event_processor;
GdsOutputRendererPrivate *priv; GdsOutputRendererPrivate *priv;

View File

@ -140,7 +140,8 @@ static gboolean write_layer_env(FILE *tex_file, GdkRGBA *color, int layer, GList
color->red = inf->color.red; color->red = inf->color.red;
color->green = inf->color.green; color->green = inf->color.green;
color->blue = inf->color.blue; 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", 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); layer, layer, inf->name);
WRITEOUT_BUFFER(buffer); WRITEOUT_BUFFER(buffer);
return TRUE; return TRUE;
@ -167,21 +168,26 @@ static void generate_graphics(FILE *tex_file, GList *graphics, GList *linfo, GSt
struct gds_graphics *gfx; struct gds_graphics *gfx;
struct gds_point *pt; struct gds_point *pt;
GdkRGBA color; GdkRGBA color;
static const char *line_caps[] = {"butt", "round", "rect"}; static const char * const line_caps[] = {"butt", "round", "rect"};
for (temp = graphics; temp != NULL; temp = temp->next) { for (temp = graphics; temp != NULL; temp = temp->next) {
gfx = (struct gds_graphics *)temp->data; gfx = (struct gds_graphics *)temp->data;
if (write_layer_env(tex_file, &color, (int)gfx->layer, linfo, buffer) == TRUE) { if (write_layer_env(tex_file, &color, (int)gfx->layer, linfo, buffer) == TRUE) {
/* Layer is defined => create graphics */ /* Layer is defined => create graphics */
if (gfx->gfx_type == GRAPHIC_POLYGON || gfx->gfx_type == GRAPHIC_BOX ) { 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}] ", 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); gfx->layer, gfx->layer, color.alpha);
WRITEOUT_BUFFER(buffer); WRITEOUT_BUFFER(buffer);
/* Append vertices */ /* Append vertices */
for (temp_vertex = gfx->vertices; temp_vertex != NULL; temp_vertex = temp_vertex->next) { for (temp_vertex = gfx->vertices;
temp_vertex != NULL;
temp_vertex = temp_vertex->next) {
pt = (struct gds_point *)temp_vertex->data; pt = (struct gds_point *)temp_vertex->data;
g_string_printf(buffer, "(%lf pt, %lf pt) -- ", ((double)pt->x)/scale, ((double)pt->y)/scale); g_string_printf(buffer, "(%lf pt, %lf pt) -- ",
((double)pt->x)/scale,
((double)pt->y)/scale);
WRITEOUT_BUFFER(buffer); WRITEOUT_BUFFER(buffer);
} }
g_string_printf(buffer, "cycle;\n"); g_string_printf(buffer, "cycle;\n");
@ -204,7 +210,9 @@ static void generate_graphics(FILE *tex_file, GList *graphics, GList *linfo, GSt
WRITEOUT_BUFFER(buffer); WRITEOUT_BUFFER(buffer);
/* Append vertices */ /* Append vertices */
for (temp_vertex = gfx->vertices; temp_vertex != NULL; temp_vertex = temp_vertex->next) { for (temp_vertex = gfx->vertices;
temp_vertex != NULL;
temp_vertex = temp_vertex->next) {
pt = (struct gds_point *)temp_vertex->data; pt = (struct gds_point *)temp_vertex->data;
g_string_printf(buffer, "(%lf pt, %lf pt)%s", g_string_printf(buffer, "(%lf pt, %lf pt)%s",
((double)pt->x)/scale, ((double)pt->x)/scale,
@ -241,7 +249,7 @@ static void render_cell(struct gds_cell *cell, GList *layer_infos, FILE *tex_fil
status = g_string_new(NULL); status = g_string_new(NULL);
g_string_printf(status, "Generating cell %s", cell->name); g_string_printf(status, "Generating cell %s", cell->name);
gds_output_renderer_update_gui_status_from_async(renderer, status->str); gds_output_renderer_update_async_progress(renderer, status->str);
g_string_free(status, TRUE); g_string_free(status, TRUE);
/* Draw polygons of current cell */ /* Draw polygons of current cell */
@ -257,13 +265,14 @@ static void render_cell(struct gds_cell *cell, GList *layer_infos, FILE *tex_fil
/* generate translation scope */ /* generate translation scope */
g_string_printf(buffer, "\\begin{scope}[shift={(%lf pt,%lf pt)}]\n", g_string_printf(buffer, "\\begin{scope}[shift={(%lf pt,%lf pt)}]\n",
((double)inst->origin.x)/scale,((double)inst->origin.y)/scale); ((double)inst->origin.x) / scale, ((double)inst->origin.y) / scale);
WRITEOUT_BUFFER(buffer); WRITEOUT_BUFFER(buffer);
g_string_printf(buffer, "\\begin{scope}[rotate=%lf]\n", inst->angle); g_string_printf(buffer, "\\begin{scope}[rotate=%lf]\n", inst->angle);
WRITEOUT_BUFFER(buffer); WRITEOUT_BUFFER(buffer);
g_string_printf(buffer, "\\begin{scope}[yscale=%lf, xscale=%lf]\n", (inst->flipped ? -1*inst->magnification : inst->magnification), g_string_printf(buffer, "\\begin{scope}[yscale=%lf, xscale=%lf]\n",
(inst->flipped ? -1*inst->magnification : inst->magnification),
inst->magnification); inst->magnification);
WRITEOUT_BUFFER(buffer); WRITEOUT_BUFFER(buffer);
@ -302,7 +311,8 @@ static int latex_render_cell_to_code(struct gds_cell *cell, GList *layer_infos,
WRITEOUT_BUFFER(working_line); WRITEOUT_BUFFER(working_line);
g_string_printf(working_line, "\\iftestmode\n"); g_string_printf(working_line, "\\iftestmode\n");
WRITEOUT_BUFFER(working_line); WRITEOUT_BUFFER(working_line);
g_string_printf(working_line, "\\documentclass[tikz]{standalone}\n\\usepackage{xcolor}\n\\usetikzlibrary{ocgx}\n\\begin{document}\n"); g_string_printf(working_line,
"\\documentclass[tikz]{standalone}\n\\usepackage{xcolor}\n\\usetikzlibrary{ocgx}\n\\begin{document}\n");
WRITEOUT_BUFFER(working_line); WRITEOUT_BUFFER(working_line);
g_string_printf(working_line, "\\fi\n"); g_string_printf(working_line, "\\fi\n");
WRITEOUT_BUFFER(working_line); WRITEOUT_BUFFER(working_line);
@ -361,9 +371,8 @@ static int latex_renderer_render_output(GdsOutputRenderer *renderer,
g_error("Could not open LaTeX output file"); g_error("Could not open LaTeX output file");
} }
if (settings) { if (settings)
g_object_unref(settings); g_object_unref(settings);
}
return ret; return ret;
} }

View File

@ -20,6 +20,7 @@
<object class="GtkImage" id="save-mapping-img"> <object class="GtkImage" id="save-mapping-img">
<property name="visible">True</property> <property name="visible">True</property>
<property name="can_focus">False</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> <property name="stock">gtk-save-as</property>
</object> </object>
<object class="GtkImage" id="select-all-img"> <object class="GtkImage" id="select-all-img">
@ -46,7 +47,7 @@
<property name="name">header</property> <property name="name">header</property>
<property name="visible">True</property> <property name="visible">True</property>
<property name="can_focus">False</property> <property name="can_focus">False</property>
<property name="title" translatable="yes">GDS Renderer</property> <property name="title" translatable="yes">GDS-Render</property>
<property name="show_close_button">True</property> <property name="show_close_button">True</property>
<child> <child>
<object class="GtkButton" id="button-load-gds"> <object class="GtkButton" id="button-load-gds">
@ -54,6 +55,7 @@
<property name="visible">True</property> <property name="visible">True</property>
<property name="can_focus">True</property> <property name="can_focus">True</property>
<property name="receives_default">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="use_stock">True</property>
<property name="always_show_image">True</property> <property name="always_show_image">True</property>
<style> <style>
@ -68,6 +70,7 @@
<property name="sensitive">False</property> <property name="sensitive">False</property>
<property name="can_focus">True</property> <property name="can_focus">True</property>
<property name="receives_default">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="image">load-mapping-img</property>
<property name="always_show_image">True</property> <property name="always_show_image">True</property>
<style> <style>
@ -103,6 +106,7 @@
<property name="sensitive">False</property> <property name="sensitive">False</property>
<property name="can_focus">True</property> <property name="can_focus">True</property>
<property name="receives_default">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="use_stock">True</property>
<property name="always_show_image">True</property> <property name="always_show_image">True</property>
<style> <style>
@ -188,6 +192,7 @@
<property name="visible">True</property> <property name="visible">True</property>
<property name="can_focus">True</property> <property name="can_focus">True</property>
<property name="receives_default">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="image">sort-up-img</property>
<property name="always_show_image">True</property> <property name="always_show_image">True</property>
</object> </object>
@ -202,6 +207,7 @@
<property name="visible">True</property> <property name="visible">True</property>
<property name="can_focus">True</property> <property name="can_focus">True</property>
<property name="receives_default">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="image">sort-down-img</property>
<property name="always_show_image">True</property> <property name="always_show_image">True</property>
</object> </object>
@ -216,6 +222,7 @@
<property name="visible">True</property> <property name="visible">True</property>
<property name="can_focus">True</property> <property name="can_focus">True</property>
<property name="receives_default">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="image">color-img</property>
<property name="always_show_image">True</property> <property name="always_show_image">True</property>
</object> </object>
@ -230,6 +237,7 @@
<property name="visible">True</property> <property name="visible">True</property>
<property name="can_focus">True</property> <property name="can_focus">True</property>
<property name="receives_default">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="image">select-all-img</property>
<property name="always_show_image">True</property> <property name="always_show_image">True</property>
</object> </object>
@ -244,6 +252,7 @@
<property name="visible">True</property> <property name="visible">True</property>
<property name="can_focus">True</property> <property name="can_focus">True</property>
<property name="receives_default">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="image">auto-name-img</property>
<property name="always_show_image">True</property> <property name="always_show_image">True</property>
</object> </object>
@ -264,6 +273,7 @@
<object class="GtkScrolledWindow"> <object class="GtkScrolledWindow">
<property name="visible">True</property> <property name="visible">True</property>
<property name="can_focus">True</property> <property name="can_focus">True</property>
<property name="margin_top">1</property>
<property name="hscrollbar_policy">never</property> <property name="hscrollbar_policy">never</property>
<property name="shadow_type">in</property> <property name="shadow_type">in</property>
<child> <child>

View File

@ -1,3 +1,4 @@
project(libversion)
add_library(version STATIC "version.c") add_library(version STATIC "version.c")
execute_process(COMMAND bash ./generate-version-string.sh execute_process(COMMAND bash ./generate-version-string.sh
WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR} WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}

View File

@ -170,8 +170,11 @@ static gboolean shape_drawer_drawing_callback(GtkWidget *widget, cairo_t *cr, gp
final_scale_value = (width_scale < height_scale ? width_scale : height_scale); 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, cairo_rectangle(cr,
(double)dialog->cell_width*final_scale_value, (double)dialog->cell_height*final_scale_value); -(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_stroke(cr);
cairo_restore(cr); cairo_restore(cr);
@ -183,9 +186,9 @@ static double convert_number_to_engineering(double input, const char **out_prefi
const char *selected_prefix = NULL; const char *selected_prefix = NULL;
double return_val = 0.0; double return_val = 0.0;
int idx; int idx;
static const char * prefixes[] = {"y", "z", "a", "f", "p", "n", "u", "m", "c", "d", /* < 1 */ static const char * const prefixes[] = {"y", "z", "a", "f", "p", "n", "u", "m", "c", "d", /* < 1 */
"", /* 1 */ "", /* 1 */
"h", "k", "M", "G", "T", "P", "E", "Z", "Y"}; /* > 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, 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, 1,
1E2, 1E3, 1E6, 1E9, 1E12, 1E15, 1E18, 1E21, 1E24}; 1E2, 1E3, 1E6, 1E9, 1E12, 1E15, 1E18, 1E21, 1E24};
@ -193,7 +196,7 @@ static double convert_number_to_engineering(double input, const char **out_prefi
/* If pointer is invalid, return NaN */ /* If pointer is invalid, return NaN */
if (!out_prefix) if (!out_prefix)
return 0.0 / 0.0; return (0.0 / 0.0);
/* Start with the 2nd smallest prefix */ /* Start with the 2nd smallest prefix */
for (idx = 1; idx < prefix_count; idx++) { for (idx = 1; idx < prefix_count; idx++) {
@ -308,9 +311,9 @@ RendererSettingsDialog *renderer_settings_dialog_new(GtkWindow *parent)
RendererSettingsDialog *res; RendererSettingsDialog *res;
res = RENDERER_SETTINGS_DIALOG(g_object_new(RENDERER_TYPE_SETTINGS_DIALOG, NULL)); res = RENDERER_SETTINGS_DIALOG(g_object_new(RENDERER_TYPE_SETTINGS_DIALOG, NULL));
if (res && parent) { if (res && parent)
gtk_window_set_transient_for(GTK_WINDOW(res), parent); gtk_window_set_transient_for(GTK_WINDOW(res), parent);
}
return res; return res;
} }
@ -322,13 +325,12 @@ void renderer_settings_dialog_get_settings(RendererSettingsDialog *dialog, struc
settings->scale = gtk_range_get_value(GTK_RANGE(dialog->scale)); settings->scale = gtk_range_get_value(GTK_RANGE(dialog->scale));
/* Get active radio button selection */ /* Get active radio button selection */
if (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(dialog->radio_latex)) == TRUE) { if (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(dialog->radio_latex)) == TRUE)
settings->renderer = RENDERER_LATEX_TIKZ; settings->renderer = RENDERER_LATEX_TIKZ;
} else if (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(dialog->radio_cairo_pdf)) == TRUE) { else if (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(dialog->radio_cairo_pdf)) == TRUE)
settings->renderer = RENDERER_CAIROGRAPHICS_PDF; settings->renderer = RENDERER_CAIROGRAPHICS_PDF;
} else if (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(dialog->radio_cairo_svg)) == TRUE) { else if (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(dialog->radio_cairo_svg)) == TRUE)
settings->renderer = RENDERER_CAIROGRAPHICS_SVG; settings->renderer = RENDERER_CAIROGRAPHICS_SVG;
}
settings->tex_pdf_layers = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(dialog->layer_check)); 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)); settings->tex_standalone = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(dialog->standalone_check));

View File

@ -54,6 +54,7 @@ static void layer_element_constructed(GObject *obj)
static void layer_element_class_init(LayerElementClass *klass) static void layer_element_class_init(LayerElementClass *klass)
{ {
GObjectClass *oclass = G_OBJECT_CLASS(klass); GObjectClass *oclass = G_OBJECT_CLASS(klass);
oclass->dispose = layer_element_dispose; oclass->dispose = layer_element_dispose;
oclass->constructed = layer_element_constructed; oclass->constructed = layer_element_constructed;
} }
@ -62,6 +63,7 @@ static void layer_element_init(LayerElement *self)
{ {
GtkBuilder *builder; GtkBuilder *builder;
GtkWidget *glade_box; GtkWidget *glade_box;
builder = gtk_builder_new_from_resource("/gui/layer-widget.glade"); builder = gtk_builder_new_from_resource("/gui/layer-widget.glade");
glade_box = GTK_WIDGET(gtk_builder_get_object(builder, "box")); glade_box = GTK_WIDGET(gtk_builder_get_object(builder, "box"));
gtk_container_add(GTK_CONTAINER(self), glade_box); gtk_container_add(GTK_CONTAINER(self), glade_box);
@ -86,7 +88,7 @@ const char *layer_element_get_name(LayerElement *elem)
return gtk_entry_get_text(elem->priv.name); return gtk_entry_get_text(elem->priv.name);
} }
void layer_element_set_name(LayerElement *elem, const char* name) void layer_element_set_name(LayerElement *elem, const char *name)
{ {
gtk_entry_set_text(elem->priv.name, name); gtk_entry_set_text(elem->priv.name, name);
} }
@ -139,8 +141,9 @@ void layer_element_set_dnd_callbacks(LayerElement *elem, struct layer_element_dn
return; return;
/* Setup drag and drop */ /* Setup drag and drop */
gtk_style_context_add_class (gtk_widget_get_style_context(GTK_WIDGET(elem)), "row"); gtk_style_context_add_class(gtk_widget_get_style_context(GTK_WIDGET(elem)), "row");
gtk_drag_source_set(GTK_WIDGET(elem->priv.event_handle), GDK_BUTTON1_MASK, data->entries, data->entry_count, GDK_ACTION_MOVE); gtk_drag_source_set(GTK_WIDGET(elem->priv.event_handle), GDK_BUTTON1_MASK,
data->entries, data->entry_count, GDK_ACTION_MOVE);
g_signal_connect(elem->priv.event_handle, "drag-begin", G_CALLBACK(data->drag_begin), NULL); g_signal_connect(elem->priv.event_handle, "drag-begin", G_CALLBACK(data->drag_begin), NULL);
g_signal_connect(elem->priv.event_handle, "drag-data-get", G_CALLBACK(data->drag_data_get), NULL); g_signal_connect(elem->priv.event_handle, "drag-data-get", G_CALLBACK(data->drag_data_get), NULL);
g_signal_connect(elem->priv.event_handle, "drag-end", G_CALLBACK(data->drag_end), NULL); g_signal_connect(elem->priv.event_handle, "drag-end", G_CALLBACK(data->drag_end), NULL);