Compare commits

..

15 Commits

Author SHA1 Message Date
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
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
18 changed files with 1138 additions and 925 deletions

View File

@ -20,8 +20,8 @@ aux_source_directory("gds-parser" PARSER_SOURCES)
aux_source_directory("latex-output" LATEX_SOURCES) aux_source_directory("latex-output" LATEX_SOURCES)
aux_source_directory("cairo-output" CAIRO_SOURCES) aux_source_directory("cairo-output" CAIRO_SOURCES)
aux_source_directory("trigonometric" TRIG_SOURCES) aux_source_directory("trigonometric" TRIG_SOURCES)
aux_source_directory("layer-selector" LAYER_SELECTOR_SOURCES) aux_source_directory("layer" LAYER_SELECTOR_SOURCES)
set(SOURCE "main.c" "mapping-parser.c" "command-line.c" "main-window.c" "external-renderer.c") set(SOURCE "main.c" "mapping-parser.c" "command-line.c" "gds-render-gui.c" "external-renderer.c")
set(SOURCE set(SOURCE
${SOURCE} ${SOURCE}

View File

@ -24,7 +24,7 @@
#ifndef __CAIRO_OUTPUT_H__ #ifndef __CAIRO_OUTPUT_H__
#define __CAIRO_OUTPUT_H__ #define __CAIRO_OUTPUT_H__
#include "../layer-selector/layer-selector.h" #include "../layer/layer-info.h"
#include "../gds-parser/gds-types.h" #include "../gds-parser/gds-types.h"
/** @addtogroup Cairo-Renderer /** @addtogroup Cairo-Renderer

View File

@ -32,6 +32,7 @@
#include "command-line.h" #include "command-line.h"
#include "gds-parser/gds-parser.h" #include "gds-parser/gds-parser.h"
#include "mapping-parser.h" #include "mapping-parser.h"
#include "layer/layer-info.h"
#include "cairo-output/cairo-output.h" #include "cairo-output/cairo-output.h"
#include "latex-output/latex-output.h" #include "latex-output/latex-output.h"
#include "external-renderer.h" #include "external-renderer.h"

View File

@ -18,7 +18,7 @@
*/ */
/** /**
* @file main-window.c * @file gds-render-gui.c
* @brief Handling of GUI * @brief Handling of GUI
* @author Mario Hüttel <mario.huettel@gmx.net> * @author Mario Hüttel <mario.huettel@gmx.net>
*/ */
@ -27,12 +27,11 @@
* @{ * @{
*/ */
#include "main-window.h" #include "gds-render-gui.h"
#include <stdio.h> #include <stdio.h>
#include "gds-parser/gds-parser.h" #include "gds-parser/gds-parser.h"
#include <gtk/gtk.h> #include <gtk/gtk.h>
#include "layer-selector/layer-selector.h" #include "layer/layer-selector.h"
#include "layer-selector/layer-selector-dnd.h"
#include "tree-renderer/tree-store.h" #include "tree-renderer/tree-store.h"
#include "latex-output/latex-output.h" #include "latex-output/latex-output.h"
#include "widgets/conv-settings-dialog.h" #include "widgets/conv-settings-dialog.h"
@ -41,24 +40,26 @@
#include "version/version.h" #include "version/version.h"
#include "tree-renderer/lib-cell-renderer.h" #include "tree-renderer/lib-cell-renderer.h"
#include "gds-parser/gds-tree-checker.h" #include "gds-parser/gds-tree-checker.h"
/**
* @brief User data supplied to callback function of the open button enum gds_render_gui_signal_sig_ids {SIGNAL_WINDOW_CLOSED = 0, SIGNAL_COUNT};
*/
struct open_button_data { static guint gds_render_gui_signals[SIGNAL_COUNT];
struct _GdsRenderGui {
/* Parent GObject */
GObject parent;
/* Custom fields */
GtkWindow *main_window; GtkWindow *main_window;
GList **list_ptr; GtkWidget *convert_button;
GtkTreeStore *cell_store; GtkTreeStore *cell_tree_store;
GtkListBox *layer_box; GtkWidget *cell_search_entry;
GtkSearchEntry *search_entry; LayerSelector *layer_selector;
GtkTreeView *cell_tree_view;
GList *gds_libraries;
}; };
/** G_DEFINE_TYPE(GdsRenderGui, gds_render_gui, G_TYPE_OBJECT)
* @brief User data supplied to callback function of the convert button
*/
struct convert_button_data {
GtkTreeView *tree_view;
GtkWindow *main_window;
};
/** /**
* @brief Window close event of main window * @brief Window close event of main window
@ -68,9 +69,24 @@ struct convert_button_data {
* @param user not used * @param user not used
* @return TRUE. This indicates that the event has been fully handled * @return TRUE. This indicates that the event has been fully handled
*/ */
static gboolean on_window_close(gpointer window, gpointer user) static gboolean on_window_close(gpointer window, GdkEvent *event, gpointer user)
{ {
GdsRenderGui *self;
self = RENDERER_GUI(user);
/* Don't close window in case of error */
if (!self)
return TRUE;
/* Close Window. Leads to termination of the program/the current instance */
g_clear_object(&self->main_window);
gtk_widget_destroy(GTK_WIDGET(window)); 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; return TRUE;
} }
@ -106,8 +122,7 @@ static void on_load_gds(gpointer button, gpointer user)
GList *lib; GList *lib;
struct gds_library *gds_lib; struct gds_library *gds_lib;
struct gds_cell *gds_c; struct gds_cell *gds_c;
struct open_button_data *ptr = (struct open_button_data *)user; GdsRenderGui *self;
GtkTreeStore *store = ptr->cell_store;
GtkWidget *open_dialog; GtkWidget *open_dialog;
GtkFileChooser *file_chooser; GtkFileChooser *file_chooser;
GtkFileFilter *filter; GtkFileFilter *filter;
@ -119,7 +134,11 @@ static void on_load_gds(gpointer button, gpointer user)
GString *acc_date; GString *acc_date;
unsigned int cell_error_level; unsigned int cell_error_level;
open_dialog = gtk_file_chooser_dialog_new("Open GDSII File", ptr->main_window, 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, GTK_FILE_CHOOSER_ACTION_OPEN,
"Cancel", GTK_RESPONSE_CANCEL, "Cancel", GTK_RESPONSE_CANCEL,
"Open GDSII", GTK_RESPONSE_ACCEPT, "Open GDSII", GTK_RESPONSE_ACCEPT,
@ -138,11 +157,11 @@ static void on_load_gds(gpointer button, gpointer user)
/* Get File name */ /* Get File name */
filename = gtk_file_chooser_get_filename(file_chooser); filename = gtk_file_chooser_get_filename(file_chooser);
gtk_tree_store_clear(store); gtk_tree_store_clear(self->cell_tree_store);
clear_lib_list(ptr->list_ptr); clear_lib_list(&self->gds_libraries);
/* Parse new GDSII file */ /* Parse new GDSII file */
gds_result = parse_gds_from_file(filename, ptr->list_ptr); gds_result = parse_gds_from_file(filename, &self->gds_libraries);
/* Delete file name afterwards */ /* Delete file name afterwards */
g_free(filename); g_free(filename);
@ -153,16 +172,16 @@ static void on_load_gds(gpointer button, gpointer user)
button_style = gtk_widget_get_style_context(GTK_WIDGET(button)); button_style = gtk_widget_get_style_context(GTK_WIDGET(button));
gtk_style_context_remove_class(button_style, "suggested-action"); gtk_style_context_remove_class(button_style, "suggested-action");
for (lib = *(ptr->list_ptr); lib != NULL; lib = lib->next) { for (lib = self->gds_libraries; lib != NULL; lib = lib->next) {
gds_lib = (struct gds_library *)lib->data; gds_lib = (struct gds_library *)lib->data;
/* Create top level iter */ /* Create top level iter */
gtk_tree_store_append(store, &libiter, NULL); gtk_tree_store_append(self->cell_tree_store, &libiter, NULL);
/* Convert dates to String */ /* Convert dates to String */
mod_date = generate_string_from_date(&gds_lib->mod_time); mod_date = generate_string_from_date(&gds_lib->mod_time);
acc_date = generate_string_from_date(&gds_lib->access_time); acc_date = generate_string_from_date(&gds_lib->access_time);
gtk_tree_store_set(store, &libiter, gtk_tree_store_set(self->cell_tree_store, &libiter,
CELL_SEL_LIBRARY, gds_lib, CELL_SEL_LIBRARY, gds_lib,
CELL_SEL_MODDATE, mod_date->str, CELL_SEL_MODDATE, mod_date->str,
CELL_SEL_ACCESSDATE, acc_date->str, CELL_SEL_ACCESSDATE, acc_date->str,
@ -179,7 +198,7 @@ static void on_load_gds(gpointer button, gpointer user)
for (cell = gds_lib->cells; cell != NULL; cell = cell->next) { for (cell = gds_lib->cells; cell != NULL; cell = cell->next) {
gds_c = (struct gds_cell *)cell->data; gds_c = (struct gds_cell *)cell->data;
gtk_tree_store_append(store, &celliter, &libiter); gtk_tree_store_append(self->cell_tree_store, &celliter, &libiter);
/* Convert dates to String */ /* Convert dates to String */
mod_date = generate_string_from_date(&gds_c->mod_time); mod_date = generate_string_from_date(&gds_c->mod_time);
@ -195,7 +214,7 @@ static void on_load_gds(gpointer button, gpointer user)
cell_error_level |= LIB_CELL_RENDERER_ERROR_ERR; cell_error_level |= LIB_CELL_RENDERER_ERROR_ERR;
/* Add cell to tree store model */ /* Add cell to tree store model */
gtk_tree_store_set(store, &celliter, gtk_tree_store_set(self->cell_tree_store, &celliter,
CELL_SEL_CELL, gds_c, CELL_SEL_CELL, gds_c,
CELL_SEL_MODDATE, mod_date->str, CELL_SEL_MODDATE, mod_date->str,
CELL_SEL_ACCESSDATE, acc_date->str, CELL_SEL_ACCESSDATE, acc_date->str,
@ -210,7 +229,7 @@ static void on_load_gds(gpointer button, gpointer user)
} }
/* Create Layers in Layer Box */ /* Create Layers in Layer Box */
generate_layer_widgets(ptr->layer_box, *(ptr->list_ptr)); layer_selector_generate_layer_widgets(self->layer_selector, self->gds_libraries);
} }
end_destroy: end_destroy:
@ -230,7 +249,7 @@ static void on_convert_clicked(gpointer button, gpointer user)
.scale = 1000.0, .scale = 1000.0,
.renderer = RENDERER_LATEX_TIKZ, .renderer = RENDERER_LATEX_TIKZ,
}; };
struct convert_button_data *data = (struct convert_button_data *)user; GdsRenderGui *self;
GtkTreeSelection *selection; GtkTreeSelection *selection;
GtkTreeIter iter; GtkTreeIter iter;
GtkTreeModel *model; GtkTreeModel *model;
@ -245,11 +264,13 @@ static void on_convert_clicked(gpointer button, gpointer user)
union bounding_box cell_box; union bounding_box cell_box;
unsigned int height, width; unsigned int height, width;
if (!data) self = RENDERER_GUI(user);
if (!self)
return; return;
/* Get selected cell */ /* Get selected cell */
selection = gtk_tree_view_get_selection(data->tree_view); selection = gtk_tree_view_get_selection(self->cell_tree_view);
if (gtk_tree_selection_get_selected(selection, &model, &iter) == FALSE) if (gtk_tree_selection_get_selected(selection, &model, &iter) == FALSE)
return; return;
@ -259,7 +280,7 @@ static void on_convert_clicked(gpointer button, gpointer user)
return; return;
/* Get layers that are rendered */ /* Get layers that are rendered */
layer_list = export_rendered_layer_info(); layer_list = layer_selector_export_rendered_layer_info(self->layer_selector);
/* Calculate cell size in DB units */ /* Calculate cell size in DB units */
bounding_box_prepare_empty(&cell_box); bounding_box_prepare_empty(&cell_box);
@ -267,13 +288,13 @@ static void on_convert_clicked(gpointer button, gpointer user)
/* Calculate size in database units /* Calculate size in database units
* Note that the results are bound to be positive, * Note that the results are bound to be positive,
* so casting them to unsigned int is asbsolutely valid * so casting them to unsigned int is absolutely valid
*/ */
height = (unsigned int)(cell_box.vectors.upper_right.y - cell_box.vectors.lower_left.y); 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); width = (unsigned int)(cell_box.vectors.upper_right.x - cell_box.vectors.lower_left.x);
/* Show settings dialog */ /* Show settings dialog */
settings = renderer_settings_dialog_new(GTK_WINDOW(data->main_window)); settings = renderer_settings_dialog_new(GTK_WINDOW(self->main_window));
renderer_settings_dialog_set_settings(settings, &sett); 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_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_height(settings, height);
@ -291,7 +312,7 @@ static void on_convert_clicked(gpointer button, gpointer user)
/* save file dialog */ /* save file dialog */
dialog = gtk_file_chooser_dialog_new((sett.renderer == RENDERER_LATEX_TIKZ dialog = gtk_file_chooser_dialog_new((sett.renderer == RENDERER_LATEX_TIKZ
? "Save LaTeX File" : "Save PDF"), ? "Save LaTeX File" : "Save PDF"),
GTK_WINDOW(data->main_window), GTK_FILE_CHOOSER_ACTION_SAVE, GTK_WINDOW(self->main_window), GTK_FILE_CHOOSER_ACTION_SAVE,
"Cancel", GTK_RESPONSE_CANCEL, "Save", GTK_RESPONSE_ACCEPT, NULL); "Cancel", GTK_RESPONSE_CANCEL, "Save", GTK_RESPONSE_ACCEPT, NULL);
/* Set file filter according to settings */ /* Set file filter according to settings */
filter = gtk_file_filter_new(); filter = gtk_file_filter_new();
@ -344,7 +365,7 @@ static void on_convert_clicked(gpointer button, gpointer user)
gtk_widget_destroy(dialog); gtk_widget_destroy(dialog);
} }
ret_layer_destroy: ret_layer_destroy:
g_list_free_full(layer_list, (GDestroyNotify)delete_layer_info_struct); g_list_free_full(layer_list, (GDestroyNotify)layer_info_delete_struct);
} }
/** /**
@ -369,48 +390,95 @@ static void cell_tree_view_activated(gpointer tree_view, GtkTreePath *path,
* This function activates/deactivates the convert button depending on whether * This function activates/deactivates the convert button depending on whether
* a cell is selected for conversion or not * a cell is selected for conversion or not
* @param sel * @param sel
* @param convert_button * @param self
*/ */
static void cell_selection_changed(GtkTreeSelection *sel, GtkWidget *convert_button) static void cell_selection_changed(GtkTreeSelection *sel, GdsRenderGui *self)
{ {
GtkTreeModel *model = NULL; GtkTreeModel *model = NULL;
GtkTreeIter iter; GtkTreeIter iter;
if (gtk_tree_selection_get_selected(sel, &model, &iter)) { if (gtk_tree_selection_get_selected(sel, &model, &iter)) {
/* Node selected. Show button */ /* Node selected. Show button */
gtk_widget_set_sensitive(convert_button, TRUE); gtk_widget_set_sensitive(self->convert_button, TRUE);
} else { } else {
gtk_widget_set_sensitive(convert_button, FALSE); gtk_widget_set_sensitive(self->convert_button, FALSE);
} }
} }
static void sort_up_callback(GtkWidget *widget, gpointer user) static void sort_up_callback(GtkWidget *widget, gpointer user)
{ {
(void)widget; (void)widget;
(void)user; GdsRenderGui *self;
layer_selector_force_sort(LAYER_SELECTOR_SORT_UP); 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) static void sort_down_callback(GtkWidget *widget, gpointer user)
{ {
(void)widget; (void)widget;
(void)user; GdsRenderGui *self;
layer_selector_force_sort(LAYER_SELECTOR_SORT_DOWN); self = RENDERER_GUI(user);
if (!self)
return;
layer_selector_force_sort(self->layer_selector, LAYER_SELECTOR_SORT_DOWN);
} }
GtkWindow *create_main_window() static void gds_render_gui_dispose(GObject *gobject)
{
GdsRenderGui *self;
self = RENDERER_GUI(gobject);
clear_lib_list(&self->gds_libraries);
g_clear_object(&self->cell_tree_view);
g_clear_object(&self->convert_button);
g_clear_object(&self->layer_selector);
g_clear_object(&self->cell_tree_store);
g_clear_object(&self->cell_search_entry);
if (self->main_window) {
g_signal_handlers_destroy(self->main_window);
gtk_widget_destroy(GTK_WIDGET(self->main_window));
self->main_window = NULL;
}
/* Chain up */
G_OBJECT_CLASS(gds_render_gui_parent_class)->dispose(gobject);
}
static void gds_render_gui_class_init(GdsRenderGuiClass *klass)
{
GObjectClass *gobject_class = G_OBJECT_CLASS(klass);
gds_render_gui_signals[SIGNAL_WINDOW_CLOSED] =
g_signal_newv("window-closed", RENDERER_TYPE_GUI,
G_SIGNAL_RUN_LAST | G_SIGNAL_NO_RECURSE,
NULL,
NULL,
NULL,
NULL,
G_TYPE_NONE,
0,
NULL);
gobject_class->dispose = gds_render_gui_dispose;
}
GtkWindow *gds_render_gui_get_main_window(GdsRenderGui *gui)
{
return gui->main_window;
}
static void gds_render_gui_init(GdsRenderGui *self)
{ {
GtkBuilder *main_builder; GtkBuilder *main_builder;
GtkTreeView *cell_tree;
GtkWidget *listbox; GtkWidget *listbox;
GtkWidget *conv_button;
GtkWidget *search_entry;
GtkHeaderBar *header_bar; GtkHeaderBar *header_bar;
static GList *gds_libs;
static struct open_button_data open_data;
static struct convert_button_data conv_data;
struct tree_stores *cell_selector_stores; struct tree_stores *cell_selector_stores;
GtkWidget *sort_up_button; GtkWidget *sort_up_button;
GtkWidget *sort_down_button; GtkWidget *sort_down_button;
@ -418,44 +486,29 @@ GtkWindow *create_main_window()
main_builder = gtk_builder_new_from_resource("/main.glade"); main_builder = gtk_builder_new_from_resource("/main.glade");
gtk_builder_connect_signals(main_builder, NULL); gtk_builder_connect_signals(main_builder, NULL);
cell_tree = 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"));
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"));
open_data.search_entry = GTK_SEARCH_ENTRY(search_entry);
cell_selector_stores = setup_cell_selector(cell_tree, GTK_ENTRY(search_entry));
open_data.cell_store = cell_selector_stores->base_store; cell_selector_stores = setup_cell_selector(self->cell_tree_view, GTK_ENTRY(self->cell_search_entry));
open_data.list_ptr = &gds_libs;
open_data.main_window = GTK_WINDOW(gtk_builder_get_object(main_builder, "main-window")); self->cell_tree_store = cell_selector_stores->base_store;
self->main_window = GTK_WINDOW(gtk_builder_get_object(main_builder, "main-window"));
g_signal_connect(GTK_WIDGET(gtk_builder_get_object(main_builder, "button-load-gds")), g_signal_connect(GTK_WIDGET(gtk_builder_get_object(main_builder, "button-load-gds")),
"clicked", G_CALLBACK(on_load_gds), (gpointer)&open_data); "clicked", G_CALLBACK(on_load_gds), (gpointer)self);
/* Connect delete-event */ self->convert_button = GTK_WIDGET(gtk_builder_get_object(main_builder, "convert-button"));
g_signal_connect(GTK_WIDGET(open_data.main_window), "delete-event", g_signal_connect(self->convert_button, "clicked", G_CALLBACK(on_convert_clicked), (gpointer)self);
G_CALLBACK(on_window_close), NULL);
/* Connect Convert button */
conv_data.tree_view = cell_tree;
conv_data.main_window = open_data.main_window;
conv_button = GTK_WIDGET(gtk_builder_get_object(main_builder, "convert-button"));
g_signal_connect(conv_button, "clicked", G_CALLBACK(on_convert_clicked), &conv_data);
listbox = GTK_WIDGET(gtk_builder_get_object(main_builder, "layer-list")); listbox = GTK_WIDGET(gtk_builder_get_object(main_builder, "layer-list"));
/* Set up the list box sided callbacks for drag and drop */ /* Create layer selector */
layer_selector_list_box_setup_dnd(GTK_LIST_BOX(listbox)); self->layer_selector = layer_selector_new(GTK_LIST_BOX(listbox));
open_data.layer_box = GTK_LIST_BOX(listbox);
/* Set buttons fpr layer mapping GUI */
setup_load_mapping_callback(GTK_WIDGET(gtk_builder_get_object(main_builder, "button-load-mapping")),
open_data.main_window);
setup_save_mapping_callback(GTK_WIDGET(gtk_builder_get_object(main_builder, "button-save-mapping")),
open_data.main_window);
/* Callback for selection change of cell selector */ /* Callback for selection change of cell selector */
g_signal_connect(G_OBJECT(gtk_tree_view_get_selection(cell_tree)), "changed", g_signal_connect(G_OBJECT(gtk_tree_view_get_selection(self->cell_tree_view)), "changed",
G_CALLBACK(cell_selection_changed), conv_button); G_CALLBACK(cell_selection_changed), self);
g_signal_connect(cell_tree, "row-activated", G_CALLBACK(cell_tree_view_activated), &conv_data); g_signal_connect(self->cell_tree_view, "row-activated", G_CALLBACK(cell_tree_view_activated), self);
/* Set version in main window subtitle */ /* Set version in main window subtitle */
header_bar = GTK_HEADER_BAR(gtk_builder_get_object(main_builder, "header-bar")); header_bar = GTK_HEADER_BAR(gtk_builder_get_object(main_builder, "header-bar"));
@ -465,12 +518,34 @@ GtkWindow *create_main_window()
sort_up_button = GTK_WIDGET(gtk_builder_get_object(main_builder, "button-up-sort")); 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")); sort_down_button = GTK_WIDGET(gtk_builder_get_object(main_builder, "button-down-sort"));
g_signal_connect(sort_up_button, "clicked", G_CALLBACK(sort_up_callback), NULL); g_signal_connect(sort_up_button, "clicked", G_CALLBACK(sort_up_callback), self);
g_signal_connect(sort_down_button, "clicked", G_CALLBACK(sort_down_callback), NULL); g_signal_connect(sort_down_button, "clicked", G_CALLBACK(sort_down_callback), self);
/* Set buttons for loading and saving */
layer_selector_set_load_mapping_button(self->layer_selector,
GTK_WIDGET(gtk_builder_get_object(main_builder, "button-load-mapping")),
self->main_window);
layer_selector_set_save_mapping_button(self->layer_selector, GTK_WIDGET(gtk_builder_get_object(main_builder, "button-save-mapping")),
self->main_window);
/* Connect delete-event */
g_signal_connect(GTK_WIDGET(self->main_window), "delete-event",
G_CALLBACK(on_window_close), self);
g_object_unref(main_builder); g_object_unref(main_builder);
return conv_data.main_window; /* Reference all objects referenced by this object */
g_object_ref(self->main_window);
g_object_ref(self->cell_tree_view);
g_object_ref(self->convert_button);
g_object_ref(self->layer_selector);
g_object_ref(self->cell_tree_store);
g_object_ref(self->cell_search_entry);
}
GdsRenderGui *gds_render_gui_new()
{
return RENDERER_GUI(g_object_new(RENDERER_TYPE_GUI, NULL));
} }
/** @} */ /** @} */

View File

@ -18,13 +18,13 @@
*/ */
/** /**
* @file main-window.h * @file gds-render-gui.h
* @brief Header for main-window * @brief Header for GdsRenderGui Object
* @author Mario Hüttel <mario.huettel@gmx.net> * @author Mario Hüttel <mario.huettel@gmx.net>
*/ */
#ifndef _MAIN_WINDOW_H_ #ifndef _GDS_RENDER_GUI_
#define _MAIN_WINDOW_H_ #define _GDS_RENDER_GUI_
/** /**
* @addtogroup MainApplication * @addtogroup MainApplication
@ -33,14 +33,29 @@
#include <gtk/gtk.h> #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 main window * @brief Create new GdsRenderGui Object
*
* This function creates the main window and sets the necessary callback routines.
* @return * @return
*/ */
GtkWindow *create_main_window(); 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
*/
GtkWindow *gds_render_gui_get_main_window(GdsRenderGui *gui);
G_END_DECLS
/** @} */ /** @} */
#endif /* _MAIN_WINDOW_H_ */ #endif /* _GDS_RENDER_GUI_ */

View File

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

View File

@ -1,231 +0,0 @@
/*
* GDSII-Converter
* Copyright (C) 2019 Mario Hüttel <mario.huettel@gmx.net>
*
* This file is part of GDSII-Converter.
*
* GDSII-Converter is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*
* GDSII-Converter is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with GDSII-Converter. If not, see <http://www.gnu.org/licenses/>.
*/
/*
* Original Drag and Drop Code taken from:
* https://gitlab.gnome.org/GNOME/gtk/blob/gtk-3-22/tests/testlist3.c
*/
/**
* @file layer-selector-dnd.c
* @brief This file implements the drag and drop functions regarding the list box containing the layer elements
* @author Mario Hüttel <mario.huettel@gmx.net>
*/
#include "layer-selector-dnd.h"
static GtkTargetEntry entries[] = {
{ "GTK_LIST_BOX_ROW", GTK_TARGET_SAME_APP, 0 }
};
static GtkListBoxRow *layer_selector_get_last_row (GtkListBox *list)
{
int i;
GtkListBoxRow *row;
row = NULL;
for (i = 0; ; i++) {
GtkListBoxRow *tmp;
tmp = gtk_list_box_get_row_at_index(list, i);
if (tmp == NULL)
break;
row = tmp;
}
return row;
}
static GtkListBoxRow *layer_selector_get_row_before (GtkListBox *list, GtkListBoxRow *row)
{
int pos;
pos = gtk_list_box_row_get_index (row);
return gtk_list_box_get_row_at_index (list, pos - 1);
}
static GtkListBoxRow *layer_selector_get_row_after (GtkListBox *list, GtkListBoxRow *row)
{
int pos;
pos = gtk_list_box_row_get_index(row);
return gtk_list_box_get_row_at_index(list, pos + 1);
}
static void layer_selector_drag_data_received(GtkWidget *widget, GdkDragContext *context, gint x, gint y,
GtkSelectionData *selection_data, guint info, guint32 time,
gpointer data)
{
GtkWidget *row_before, *row_after;
GtkWidget *row;
GtkWidget *source;
int pos;
row_before = GTK_WIDGET(g_object_get_data(G_OBJECT(widget), "row-before"));
row_after = GTK_WIDGET(g_object_get_data(G_OBJECT(widget), "row-after"));
g_object_set_data(G_OBJECT(widget), "row-before", NULL);
g_object_set_data(G_OBJECT(widget), "row-after", NULL);
if (row_before)
gtk_style_context_remove_class(gtk_widget_get_style_context(row_before), "drag-hover-bottom");
if (row_after)
gtk_style_context_remove_class(gtk_widget_get_style_context(row_after), "drag-hover-top");
row = (gpointer) *((gpointer *)gtk_selection_data_get_data(selection_data));
source = gtk_widget_get_ancestor(row, GTK_TYPE_LIST_BOX_ROW);
if (source == row_after)
return;
g_object_ref(source);
gtk_container_remove(GTK_CONTAINER(gtk_widget_get_parent(source)), source);
if (row_after)
pos = gtk_list_box_row_get_index(GTK_LIST_BOX_ROW(row_after));
else
pos = gtk_list_box_row_get_index(GTK_LIST_BOX_ROW(row_before)) + 1;
gtk_list_box_insert(GTK_LIST_BOX(widget), source, pos);
g_object_unref(source);
}
static gboolean layer_selector_drag_motion(GtkWidget *widget, GdkDragContext *context, int x, int y, guint time)
{
GtkAllocation alloc;
GtkWidget *row;
int hover_row_y;
int hover_row_height;
GtkWidget *drag_row;
GtkWidget *row_before;
GtkWidget *row_after;
row = GTK_WIDGET(gtk_list_box_get_row_at_y(GTK_LIST_BOX(widget), y));
drag_row = GTK_WIDGET(g_object_get_data(G_OBJECT(widget), "drag-row"));
row_after = GTK_WIDGET(g_object_get_data(G_OBJECT(widget), "row-after"));
row_before = GTK_WIDGET(g_object_get_data(G_OBJECT(widget), "row-before"));
gtk_style_context_remove_class(gtk_widget_get_style_context(drag_row), "drag-hover");
if (row_before)
gtk_style_context_remove_class(gtk_widget_get_style_context(row_before), "drag-hover-bottom");
if (row_after)
gtk_style_context_remove_class(gtk_widget_get_style_context(row_after), "drag-hover-top");
if (row) {
gtk_widget_get_allocation(row, &alloc);
hover_row_y = alloc.y;
hover_row_height = alloc.height;
if (y < hover_row_y + hover_row_height/2) {
row_after = row;
row_before = GTK_WIDGET(layer_selector_get_row_before(GTK_LIST_BOX(widget), GTK_LIST_BOX_ROW(row)));
} else {
row_before = row;
row_after = GTK_WIDGET(layer_selector_get_row_after(GTK_LIST_BOX(widget), GTK_LIST_BOX_ROW(row)));
}
} else {
row_before = GTK_WIDGET(layer_selector_get_last_row(GTK_LIST_BOX(widget)));
row_after = NULL;
}
g_object_set_data(G_OBJECT(widget), "row-before", row_before);
g_object_set_data(G_OBJECT(widget), "row-after", row_after);
if (drag_row == row_before || drag_row == row_after) {
gtk_style_context_add_class(gtk_widget_get_style_context(drag_row), "drag-hover");
return FALSE;
}
if (row_before)
gtk_style_context_add_class(gtk_widget_get_style_context(row_before), "drag-hover-bottom");
if (row_after)
gtk_style_context_add_class(gtk_widget_get_style_context(row_after), "drag-hover-top");
return TRUE;
}
static void layer_selector_drag_leave(GtkWidget *widget, GdkDragContext *context, guint time)
{
GtkWidget *drag_row;
GtkWidget *row_before;
GtkWidget *row_after;
drag_row = GTK_WIDGET(g_object_get_data(G_OBJECT(widget), "drag-row"));
row_before = GTK_WIDGET(g_object_get_data(G_OBJECT(widget), "row-before"));
row_after = GTK_WIDGET(g_object_get_data(G_OBJECT(widget), "row-after"));
gtk_style_context_remove_class(gtk_widget_get_style_context(drag_row), "drag-hover");
if (row_before)
gtk_style_context_remove_class(gtk_widget_get_style_context(row_before), "drag-hover-bottom");
if (row_after)
gtk_style_context_remove_class(gtk_widget_get_style_context(row_after), "drag-hover-top");
}
static const char *dnd_additional_css =
".row:not(:first-child) { "
" border-top: 1px solid alpha(gray,0.5); "
" border-bottom: 1px solid transparent; "
"}"
".row:first-child { "
" border-top: 1px solid transparent; "
" border-bottom: 1px solid transparent; "
"}"
".row:last-child { "
" border-top: 1px solid alpha(gray,0.5); "
" border-bottom: 1px solid alpha(gray,0.5); "
"}"
".row.drag-icon { "
" background: #282828; "
" border: 1px solid blue; "
"}"
".row.drag-row { "
" color: gray; "
" background: alpha(gray,0.2); "
"}"
".row.drag-row.drag-hover { "
" border-top: 1px solid #4e9a06; "
" border-bottom: 1px solid #4e9a06; "
"}"
".row.drag-hover image, "
".row.drag-hover label { "
" color: #4e9a06; "
"}"
".row.drag-hover-top {"
" border-top: 1px solid #4e9a06; "
"}"
".row.drag-hover-bottom {"
" border-bottom: 1px solid #4e9a06; "
"}";
void layer_selector_list_box_setup_dnd(GtkListBox *box)
{
GtkCssProvider *provider;
provider = gtk_css_provider_new ();
gtk_css_provider_load_from_data (provider, dnd_additional_css, -1, NULL);
gtk_style_context_add_provider_for_screen (gdk_screen_get_default (), GTK_STYLE_PROVIDER (provider), 800);
gtk_drag_dest_set(GTK_WIDGET(box), GTK_DEST_DEFAULT_MOTION | GTK_DEST_DEFAULT_DROP, entries, 1, GDK_ACTION_MOVE);
g_signal_connect(box, "drag-data-received", G_CALLBACK(layer_selector_drag_data_received), NULL);
g_signal_connect(box, "drag-motion", G_CALLBACK(layer_selector_drag_motion), NULL);
g_signal_connect(box, "drag-leave", G_CALLBACK(layer_selector_drag_leave), NULL);
}

View File

@ -1,33 +0,0 @@
/*
* GDSII-Converter
* Copyright (C) 2019 Mario Hüttel <mario.huettel@gmx.net>
*
* This file is part of GDSII-Converter.
*
* GDSII-Converter is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*
* GDSII-Converter is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with GDSII-Converter. If not, see <http://www.gnu.org/licenses/>.
*/
/**
* @file layer-selector-dnd.h
* @brief Header for drag and drop of layer selector
* @author Mario Hüttel <mario.huettel@gmx.net>
*/
#ifndef _LAYER_SELECTOR_DND_H_
#define _LAYER_SELECTOR_DND_H_
#include <gtk/gtk.h>
void layer_selector_list_box_setup_dnd(GtkListBox *box);
#endif /* _LAYER_SELECTOR_DND_H_ */

View File

@ -1,456 +0,0 @@
/*
* GDSII-Converter
* Copyright (C) 2018 Mario Hüttel <mario.huettel@gmx.net>
*
* This file is part of GDSII-Converter.
*
* GDSII-Converter is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*
* GDSII-Converter is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with GDSII-Converter. If not, see <http://www.gnu.org/licenses/>.
*/
/**
* @file layer-selector.c
* @brief Implementation of the layer selector
* @author Mario Hüttel <mario.huettel@gmx.net>
*/
/**
* @addtogroup MainApplication
* @{
*/
#include "layer-selector.h"
#include "../gds-parser/gds-parser.h"
#include "../widgets/layer-element.h"
#include <glib.h>
#include <string.h>
#include <stdio.h>
#include <stdlib.h>
static GtkWidget *global_load_button;
static GtkWidget *global_save_button;
static GtkListBox *global_list_box;
void delete_layer_info_struct(struct layer_info *info)
{
if (info)
free(info);
}
/**
* @brief export_rendered_layer_info
* @return new list with all info elements needed to render cells
*/
GList *export_rendered_layer_info()
{
GList *info_list = NULL;
LayerElement *le;
struct layer_info *linfo;
GList *row_list;
GList *temp;
int i;
row_list = gtk_container_get_children(GTK_CONTAINER(global_list_box));
/* Iterate through widgets and add layers that shall be exported */
for (i = 0, temp = row_list; temp != NULL; temp = temp->next, i++) {
le = LAYER_ELEMENT(temp->data);
if (layer_element_get_export(le) == TRUE) {
/* Allocate new info and fill with info */
linfo = (struct layer_info *)malloc(sizeof(struct layer_info));
layer_element_get_color(le, &linfo->color);
linfo->layer = layer_element_get_layer(le);
linfo->stacked_position = i;
linfo->name = (char *)layer_element_get_name(le);
/* Append to list */
info_list = g_list_append(info_list, (gpointer)linfo);
}
}
return info_list;
}
void clear_list_box_widgets(GtkListBox *box)
{
GList *list;
GList *temp;
list = gtk_container_get_children(GTK_CONTAINER(box));
for (temp = list; temp != NULL; temp = temp->next) {
gtk_container_remove(GTK_CONTAINER(box), GTK_WIDGET(temp->data));
}
/* Widgets are already destroyed when removed from box because they are only referenced inside the container */
g_list_free(list);
/* Deactivate buttons */
gtk_widget_set_sensitive(global_load_button, FALSE);
gtk_widget_set_sensitive(global_save_button, FALSE);
}
/**
* @brief Check if specific layer number is present in list box
* @param layer Layer nu,ber
* @return TRUE if present
*/
static gboolean check_if_layer_widget_exists(int layer) {
GList *list;
GList *temp;
LayerElement *widget;
gboolean ret = FALSE;
list = gtk_container_get_children(GTK_CONTAINER(global_list_box));
for (temp = list; temp != NULL; temp = temp->next) {
widget = LAYER_ELEMENT(temp->data);
if (layer_element_get_layer(widget) == layer) {
ret = TRUE;
break;
}
}
g_list_free(list);
return ret;
}
/**
* @brief Analyze \p cell and append used layers to list box
* @param listbox listbox to add layer
* @param cell Cell to analyze
*/
static void analyze_cell_layers(GtkListBox *listbox, struct gds_cell *cell)
{
GList *graphics;
struct gds_graphics *gfx;
int layer;
GtkWidget *le;
for (graphics = cell->graphic_objs; graphics != NULL; graphics = graphics->next) {
gfx = (struct gds_graphics *)graphics->data;
layer = (int)gfx->layer;
if (check_if_layer_widget_exists(layer) == FALSE) {
le = layer_element_new();
layer_element_set_layer(LAYER_ELEMENT(le), layer);
gtk_list_box_insert(listbox, le, -1);
gtk_widget_show(le);
}
}
}
/**
* @brief sort_func Sort callback for list box
* @param row1
* @param row2
* @param unused
* @note Do not use this function. This is an internal callback
* @return See sort function documentation of GTK+
*/
static gint sort_func(GtkListBoxRow *row1, GtkListBoxRow *row2, gpointer unused)
{
LayerElement *le1, *le2;
gint ret;
static const enum layer_selector_sort_algo default_sort = LAYER_SELECTOR_SORT_DOWN;
const enum layer_selector_sort_algo *algo = (const enum layer_selector_sort_algo *)unused;
/* Assume downward sorting */
/* TODO: This is nasty. Find a better way */
if (!algo)
algo = &default_sort;
le1 = LAYER_ELEMENT(row1);
le2 = LAYER_ELEMENT(row2);
/* Determine sort fow downward sort */
ret = layer_element_get_layer(le1) - layer_element_get_layer(le2);
/* Change order if upward sort is requested */
ret *= (*algo == LAYER_SELECTOR_SORT_DOWN ? 1 : -1);
return ret;
}
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);
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 */
/* Sort the layers */
layer_selector_force_sort(LAYER_SELECTOR_SORT_DOWN);
/* Activate Buttons */
gtk_widget_set_sensitive(global_load_button, TRUE);
gtk_widget_set_sensitive(global_save_button, TRUE);
}
/**
* @brief Find LayerElement in list with specified layer number
* @param el_list List with elements of type LayerElement
* @param layer Layer number
* @return Found LayerElement. If nothing is found, NULL.
*/
static LayerElement *find_layer_element_in_list(GList *el_list, int layer)
{
LayerElement *ret = NULL;
for (; el_list != NULL; el_list = el_list->next) {
if (layer_element_get_layer(LAYER_ELEMENT(el_list->data)) == layer) {
ret = LAYER_ELEMENT(el_list->data);
break;
}
}
return ret;
}
/**
* @brief Load file and apply layer definitions to listbox
* @param file_name CSV Layer Mapping File
*/
static void load_layer_mapping_from_file(gchar *file_name)
{
GFile *file;
GFileInputStream *stream;
GDataInputStream *dstream;
LayerElement *le;
char *name;
gboolean export;
int layer;
GdkRGBA color;
int result;
GList *rows;
GList *temp;
file = g_file_new_for_path(file_name);
stream = g_file_read(file, NULL, NULL);
if (!stream)
goto destroy_file;
dstream = g_data_input_stream_new(G_INPUT_STREAM(stream));
rows = gtk_container_get_children(GTK_CONTAINER(global_list_box));
/* Reference and remove all rows from box */
for (temp = rows; temp != NULL; temp = temp->next) {
le = LAYER_ELEMENT(temp->data);
/* Referencing protets the widget from being deleted when removed */
g_object_ref(G_OBJECT(le));
gtk_container_remove(GTK_CONTAINER(global_list_box), GTK_WIDGET(le));
}
while((result = load_csv_line(dstream, &export, &name, &layer, &color)) >= 0) {
/* skip broken line */
if (result == 1)
continue;
/* Add rows in the same order as in file */
if ((le = find_layer_element_in_list(rows, layer))) {
gtk_list_box_insert(global_list_box, GTK_WIDGET(le), -1);
layer_element_set_color(le, &color);
layer_element_set_export(le, export);
layer_element_set_name(le, name);
g_free(name);
/* Dereference and remove from list */
g_object_unref(G_OBJECT(le));
rows = g_list_remove(rows, le);
}
}
/* Add remaining elements */
for (temp = rows; temp != NULL; temp = temp->next) {
le = LAYER_ELEMENT(temp->data);
/* Referencing protets the widget from being deleted when removed */
gtk_list_box_insert(global_list_box, GTK_WIDGET(le), -1);
g_object_unref(G_OBJECT(le));
}
/* Delete list */
g_list_free(rows);
/* read line */
g_object_unref(dstream);
g_object_unref(stream);
destroy_file:
g_object_unref(file);
}
/**
* @brief Callback for Load Mapping Button
* @param button
* @param user_data
*/
static void load_mapping_clicked(GtkWidget *button, gpointer user_data)
{
GtkWidget *dialog;
gint res;
gchar *file_name;
dialog = gtk_file_chooser_dialog_new("Load Mapping File", GTK_WINDOW(user_data), GTK_FILE_CHOOSER_ACTION_OPEN,
"Cancel", GTK_RESPONSE_CANCEL, "Load Mapping", GTK_RESPONSE_ACCEPT, NULL);
res = gtk_dialog_run(GTK_DIALOG(dialog));
if (res == GTK_RESPONSE_ACCEPT) {
file_name = gtk_file_chooser_get_filename(GTK_FILE_CHOOSER(dialog));
load_layer_mapping_from_file(file_name);
g_free(file_name);
}
gtk_widget_destroy(dialog);
}
/**
* @brief Create Line for LayerMapping file with supplied information
* @param layer_element information
* @param line_buffer buffer to write to
* @param max_len Maximum length that cna be used in \p line_buffer
*/
static void create_csv_line(LayerElement *layer_element, char *line_buffer, size_t max_len)
{
int i;
GString *string;
gboolean export;
const gchar *name;
int layer;
GdkRGBA color;
string = g_string_new_len(NULL, max_len-1);
/* Extract values */
export = layer_element_get_export(layer_element);
name = (const gchar*)layer_element_get_name(layer_element);
layer = layer_element_get_layer(layer_element);
layer_element_get_color(layer_element, &color);
/* print values to line */
g_string_printf(string, "%d:%lf:%lf:%lf:%lf:%d:%s\n",
layer, color.red, color.green,
color.blue, color.alpha, (export == TRUE ? 1 : 0), name);
/* Fix broken locale settings */
for (i = 0; string->str[i]; i++) {
if (string->str[i] == ',')
string->str[i] = '.';
}
for (i = 0; string->str[i]; i++) {
if (string->str[i] == ':')
string->str[i] = ',';
}
if (string->len > (max_len-1)) {
printf("Layer Definition too long. Please shorten Layer Name!!\n");
line_buffer[0] = 0x0;
return;
}
/* copy max_len bytes of string */
strncpy(line_buffer, (char *)string->str, max_len-1);
line_buffer[max_len-1] = 0;
/* Completely remove string */
g_string_free(string, TRUE);
}
/**
* @brief Save layer mapping of whole list box into file
* @param file_name layer mapping file
* @param list_box listbox
*/
static void save_layer_mapping_data(const gchar *file_name, GtkListBox *list_box)
{
FILE *file;
char workbuff[512];
GList *le_list;
GList *temp;
/* Overwrite existing file */
file = fopen((const char *)file_name, "w");
le_list = gtk_container_get_children(GTK_CONTAINER(list_box));
/* File format is CSV: <Layer>,<target_pos>,<R>,<G>,<B>,<Alpha>,<Export?>,<Name> */
for (temp = le_list; temp != NULL; temp = temp->next) {
/* To be sure it is a valid string */
workbuff[0] = 0;
create_csv_line(LAYER_ELEMENT(temp->data), workbuff, sizeof(workbuff));
fwrite(workbuff, sizeof(char), strlen(workbuff), file);
}
g_list_free(le_list);
/* Save File */
fflush(file);
fclose(file);
}
/**
* @brief Callback for Save Layer Mapping Button
* @param button
* @param user_data
*/
static void save_mapping_clicked(GtkWidget *button, gpointer user_data)
{
GtkWidget *dialog;
gint res;
gchar *file_name;
dialog = gtk_file_chooser_dialog_new("Save Mapping File", GTK_WINDOW(user_data), GTK_FILE_CHOOSER_ACTION_SAVE,
"Cancel", GTK_RESPONSE_CANCEL, "Save Mapping", GTK_RESPONSE_ACCEPT, NULL);
gtk_file_chooser_set_do_overwrite_confirmation(GTK_FILE_CHOOSER(dialog), TRUE);
res = gtk_dialog_run(GTK_DIALOG(dialog));
if (res == GTK_RESPONSE_ACCEPT) {
file_name = gtk_file_chooser_get_filename(GTK_FILE_CHOOSER(dialog));
save_layer_mapping_data(file_name, global_list_box);
g_free(file_name);
}
gtk_widget_destroy(dialog);
}
void setup_load_mapping_callback(GtkWidget *button, GtkWindow *main_window)
{
g_object_ref(G_OBJECT(button));
global_load_button = button;
g_signal_connect(button, "clicked", G_CALLBACK(load_mapping_clicked), main_window);
}
void setup_save_mapping_callback(GtkWidget *button, GtkWindow *main_window)
{
g_object_ref(G_OBJECT(button));
global_save_button = button;
g_signal_connect(button, "clicked", G_CALLBACK(save_mapping_clicked), main_window);
}
void layer_selector_force_sort(enum layer_selector_sort_algo sort_function)
{
if (!global_list_box)
return;
/* Set dorting function, sort, and disable sorting function */
gtk_list_box_set_sort_func(global_list_box, sort_func, (gpointer)&sort_function, NULL);
gtk_list_box_invalidate_sort(global_list_box);
gtk_list_box_set_sort_func(global_list_box, NULL, NULL, NULL);
}
/** @} */

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

@ -0,0 +1,9 @@
#include "layer-info.h"
void layer_info_delete_struct(struct layer_info *info)
{
if (info)
free(info);
}

26
layer/layer-info.h Normal file
View File

@ -0,0 +1,26 @@
#ifndef _LAYER_INFO_H_
#define _LAYER_INFO_H_
#include <gtk/gtk.h>
/**
* @brief Layer information.
*
* This structs contains information on how to render a layer
*/
struct layer_info
{
int layer; /**< @brief Layer number */
char *name; /**< @brief Layer name */
int stacked_position; ///< @brief Position of layer in output @warning This parameter is not used by any renderer so far @note Lower is bottom, higher is top
GdkRGBA color; /**< @brief RGBA color used to render this layer */
};
/**
* @brief Delete a layer_info struct
* @param info Struct to be deleted.
* @note The layer_info::name Element has to be freed manually
*/
void layer_info_delete_struct(struct layer_info *info);
#endif // _LAYER_INFO_H_

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

@ -0,0 +1,758 @@
/*
* GDSII-Converter
* Copyright (C) 2018 Mario Hüttel <mario.huettel@gmx.net>
*
* This file is part of GDSII-Converter.
*
* GDSII-Converter is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*
* GDSII-Converter is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with GDSII-Converter. If not, see <http://www.gnu.org/licenses/>.
*/
/**
* @file layer-selector.c
* @brief Implementation of the layer selector
* @author Mario Hüttel <mario.huettel@gmx.net>
*/
/**
* @addtogroup MainApplication
* @{
*/
#include "layer-selector.h"
#include "layer-info.h"
#include "../gds-parser/gds-parser.h"
#include "../widgets/layer-element.h"
#include "../mapping-parser.h"
#include <glib.h>
#include <string.h>
#include <stdio.h>
#include <stdlib.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 */
static void sel_layer_element_drag_begin(GtkWidget *widget, GdkDragContext *context, gpointer data)
{
GtkWidget *row;
GtkAllocation alloc;
cairo_surface_t *surface;
cairo_t *cr;
int x, y;
(void)data;
row = gtk_widget_get_ancestor(widget, GTK_TYPE_LIST_BOX_ROW);
gtk_widget_get_allocation(row, &alloc);
surface = cairo_image_surface_create(CAIRO_FORMAT_ARGB32, alloc.width, alloc.height);
cr = cairo_create(surface);
gtk_style_context_add_class (gtk_widget_get_style_context(row), "drag-icon");
gtk_widget_draw (row, cr);
gtk_style_context_remove_class(gtk_widget_get_style_context(row), "drag-icon");
gtk_widget_translate_coordinates (widget, row, 0, 0, &x, &y);
cairo_surface_set_device_offset (surface, -x, -y);
gtk_drag_set_icon_surface (context, surface);
cairo_destroy (cr);
cairo_surface_destroy (surface);
g_object_set_data(G_OBJECT(gtk_widget_get_parent(row)), "drag-row", row);
gtk_style_context_add_class(gtk_widget_get_style_context(row), "drag-row");
}
static void sel_layer_element_drag_end(GtkWidget *widget, GdkDragContext *context, gpointer data)
{
GtkWidget *row;
(void)context;
(void)data;
row = gtk_widget_get_ancestor(widget, GTK_TYPE_LIST_BOX_ROW);
g_object_set_data(G_OBJECT(gtk_widget_get_parent(row)), "drag-row", NULL);
gtk_style_context_remove_class(gtk_widget_get_style_context(row), "drag-row");
gtk_style_context_remove_class(gtk_widget_get_style_context(row), "drag-hover");
}
static void sel_layer_element_drag_data_get(GtkWidget *widget, GdkDragContext *context, GtkSelectionData *selection_data,
guint info, guint time, gpointer data)
{
(void)context;
(void)info;
(void)time;
(void)data;
GdkAtom atom;
atom = gdk_atom_intern_static_string("GTK_LIST_BOX_ROW");
gtk_selection_data_set(selection_data, atom,
32, (const guchar *)&widget, sizeof(gpointer));
}
static GtkListBoxRow *layer_selector_get_last_row (GtkListBox *list)
{
int i;
GtkListBoxRow *row;
row = NULL;
for (i = 0; ; i++) {
GtkListBoxRow *tmp;
tmp = gtk_list_box_get_row_at_index(list, i);
if (tmp == NULL)
break;
row = tmp;
}
return row;
}
static GtkListBoxRow *layer_selector_get_row_before (GtkListBox *list, GtkListBoxRow *row)
{
int pos;
pos = gtk_list_box_row_get_index (row);
return gtk_list_box_get_row_at_index (list, pos - 1);
}
static GtkListBoxRow *layer_selector_get_row_after (GtkListBox *list, GtkListBoxRow *row)
{
int pos;
pos = gtk_list_box_row_get_index(row);
return gtk_list_box_get_row_at_index(list, pos + 1);
}
static void layer_selector_drag_data_received(GtkWidget *widget, GdkDragContext *context, gint x, gint y,
GtkSelectionData *selection_data, guint info, guint32 time,
gpointer data)
{
GtkWidget *row_before, *row_after;
GtkWidget *row;
GtkWidget *source;
int pos;
row_before = GTK_WIDGET(g_object_get_data(G_OBJECT(widget), "row-before"));
row_after = GTK_WIDGET(g_object_get_data(G_OBJECT(widget), "row-after"));
g_object_set_data(G_OBJECT(widget), "row-before", NULL);
g_object_set_data(G_OBJECT(widget), "row-after", NULL);
if (row_before)
gtk_style_context_remove_class(gtk_widget_get_style_context(row_before), "drag-hover-bottom");
if (row_after)
gtk_style_context_remove_class(gtk_widget_get_style_context(row_after), "drag-hover-top");
row = (gpointer) *((gpointer *)gtk_selection_data_get_data(selection_data));
source = gtk_widget_get_ancestor(row, GTK_TYPE_LIST_BOX_ROW);
if (source == row_after)
return;
g_object_ref(source);
gtk_container_remove(GTK_CONTAINER(gtk_widget_get_parent(source)), source);
if (row_after)
pos = gtk_list_box_row_get_index(GTK_LIST_BOX_ROW(row_after));
else
pos = gtk_list_box_row_get_index(GTK_LIST_BOX_ROW(row_before)) + 1;
gtk_list_box_insert(GTK_LIST_BOX(widget), source, pos);
g_object_unref(source);
}
static gboolean layer_selector_drag_motion(GtkWidget *widget, GdkDragContext *context, int x, int y, guint time)
{
GtkAllocation alloc;
GtkWidget *row;
int hover_row_y;
int hover_row_height;
GtkWidget *drag_row;
GtkWidget *row_before;
GtkWidget *row_after;
row = GTK_WIDGET(gtk_list_box_get_row_at_y(GTK_LIST_BOX(widget), y));
drag_row = GTK_WIDGET(g_object_get_data(G_OBJECT(widget), "drag-row"));
row_after = GTK_WIDGET(g_object_get_data(G_OBJECT(widget), "row-after"));
row_before = GTK_WIDGET(g_object_get_data(G_OBJECT(widget), "row-before"));
gtk_style_context_remove_class(gtk_widget_get_style_context(drag_row), "drag-hover");
if (row_before)
gtk_style_context_remove_class(gtk_widget_get_style_context(row_before), "drag-hover-bottom");
if (row_after)
gtk_style_context_remove_class(gtk_widget_get_style_context(row_after), "drag-hover-top");
if (row) {
gtk_widget_get_allocation(row, &alloc);
hover_row_y = alloc.y;
hover_row_height = alloc.height;
if (y < hover_row_y + hover_row_height/2) {
row_after = row;
row_before = GTK_WIDGET(layer_selector_get_row_before(GTK_LIST_BOX(widget), GTK_LIST_BOX_ROW(row)));
} else {
row_before = row;
row_after = GTK_WIDGET(layer_selector_get_row_after(GTK_LIST_BOX(widget), GTK_LIST_BOX_ROW(row)));
}
} else {
row_before = GTK_WIDGET(layer_selector_get_last_row(GTK_LIST_BOX(widget)));
row_after = NULL;
}
g_object_set_data(G_OBJECT(widget), "row-before", row_before);
g_object_set_data(G_OBJECT(widget), "row-after", row_after);
if (drag_row == row_before || drag_row == row_after) {
gtk_style_context_add_class(gtk_widget_get_style_context(drag_row), "drag-hover");
return FALSE;
}
if (row_before)
gtk_style_context_add_class(gtk_widget_get_style_context(row_before), "drag-hover-bottom");
if (row_after)
gtk_style_context_add_class(gtk_widget_get_style_context(row_after), "drag-hover-top");
return TRUE;
}
static void layer_selector_drag_leave(GtkWidget *widget, GdkDragContext *context, guint time)
{
GtkWidget *drag_row;
GtkWidget *row_before;
GtkWidget *row_after;
drag_row = GTK_WIDGET(g_object_get_data(G_OBJECT(widget), "drag-row"));
row_before = GTK_WIDGET(g_object_get_data(G_OBJECT(widget), "row-before"));
row_after = GTK_WIDGET(g_object_get_data(G_OBJECT(widget), "row-after"));
gtk_style_context_remove_class(gtk_widget_get_style_context(drag_row), "drag-hover");
if (row_before)
gtk_style_context_remove_class(gtk_widget_get_style_context(row_before), "drag-hover-bottom");
if (row_after)
gtk_style_context_remove_class(gtk_widget_get_style_context(row_after), "drag-hover-top");
}
static const char *dnd_additional_css =
".row:not(:first-child) { "
" border-top: 1px solid alpha(gray,0.5); "
" border-bottom: 1px solid transparent; "
"}"
".row:first-child { "
" border-top: 1px solid transparent; "
" border-bottom: 1px solid transparent; "
"}"
".row:last-child { "
" border-top: 1px solid alpha(gray,0.5); "
" border-bottom: 1px solid alpha(gray,0.5); "
"}"
".row.drag-icon { "
" background: #282828; "
" border: 1px solid blue; "
"}"
".row.drag-row { "
" color: gray; "
" background: alpha(gray,0.2); "
"}"
".row.drag-row.drag-hover { "
" border-top: 1px solid #4e9a06; "
" border-bottom: 1px solid #4e9a06; "
"}"
".row.drag-hover image, "
".row.drag-hover label { "
" color: #4e9a06; "
"}"
".row.drag-hover-top {"
" border-top: 1px solid #4e9a06; "
"}"
".row.drag-hover-bottom {"
" border-bottom: 1px solid #4e9a06; "
"}";
static void layer_selector_dispose(GObject *self)
{
LayerSelector *sel = LAYER_SELECTOR(self);
g_clear_object(&sel->list_box);
g_clear_object(&sel->load_parent_window);
g_clear_object(&sel->save_parent_window);
g_clear_object(&sel->associated_load_button);
g_clear_object(&sel->associated_save_button);
if (sel->dnd_target.target) {
g_free(sel->dnd_target.target);
sel->dnd_target.target = NULL;
}
/* Chain up to parent's dispose function */
G_OBJECT_CLASS(layer_selector_parent_class)->dispose(self);
}
static void layer_selector_class_init(LayerSelectorClass *klass)
{
GObjectClass *object_class = G_OBJECT_CLASS(klass);
GtkCssProvider *provider;
/* Implement handles to virtual functions */
object_class->dispose = layer_selector_dispose;
/* Setup the CSS provider for the drag and drop animations once */
provider = gtk_css_provider_new();
gtk_css_provider_load_from_data(provider, dnd_additional_css, -1, NULL);
gtk_style_context_add_provider_for_screen(gdk_screen_get_default(), GTK_STYLE_PROVIDER(provider), 800);
g_object_unref(provider);
}
static void layer_selector_setup_dnd(LayerSelector *self)
{
gtk_drag_dest_set(GTK_WIDGET(self->list_box), GTK_DEST_DEFAULT_MOTION | GTK_DEST_DEFAULT_DROP, &self->dnd_target, 1, GDK_ACTION_MOVE);
g_signal_connect(self->list_box, "drag-data-received", G_CALLBACK(layer_selector_drag_data_received), NULL);
g_signal_connect(self->list_box, "drag-motion", G_CALLBACK(layer_selector_drag_motion), NULL);
g_signal_connect(self->list_box, "drag-leave", G_CALLBACK(layer_selector_drag_leave), NULL);
}
/* Drag and drop end */
static void layer_selector_init(LayerSelector *self)
{
self->load_parent_window = NULL;
self->save_parent_window = NULL;
self->associated_load_button = NULL;
self->associated_save_button = NULL;
self->dnd_target.target = g_strdup_printf("LAYER_SELECTOR_DND_%p", self);
self->dnd_target.info = 0;
self->dnd_target.flags = GTK_TARGET_SAME_APP;
}
LayerSelector *layer_selector_new(GtkListBox *list_box)
{
LayerSelector *selector;
if (GTK_IS_LIST_BOX(list_box) == FALSE)
return NULL;
selector = LAYER_SELECTOR(g_object_new(TYPE_LAYER_SELECTOR, NULL));
selector->list_box = list_box;
layer_selector_setup_dnd(selector);
g_object_ref(G_OBJECT(list_box));
return selector;
}
GList *layer_selector_export_rendered_layer_info(LayerSelector *selector)
{
GList *info_list = NULL;
LayerElement *le;
struct layer_info *linfo;
GList *row_list;
GList *temp;
int i;
if (!selector)
return NULL;
row_list = gtk_container_get_children(GTK_CONTAINER(selector->list_box));
/* Iterate through widgets and add layers that shall be exported */
for (i = 0, temp = row_list; temp != NULL; temp = temp->next, i++) {
le = LAYER_ELEMENT(temp->data);
if (layer_element_get_export(le) == TRUE) {
/* Allocate new info and fill with info */
linfo = (struct layer_info *)malloc(sizeof(struct layer_info));
layer_element_get_color(le, &linfo->color);
linfo->layer = layer_element_get_layer(le);
linfo->stacked_position = i;
linfo->name = (char *)layer_element_get_name(le);
/* Append to list */
info_list = g_list_append(info_list, (gpointer)linfo);
}
}
return info_list;
}
static void layer_selector_clear_widgets(LayerSelector *self)
{
GList *list;
GList *temp;
list = gtk_container_get_children(GTK_CONTAINER(self->list_box));
for (temp = list; temp != NULL; temp = temp->next) {
gtk_container_remove(GTK_CONTAINER(self->list_box), GTK_WIDGET(temp->data));
}
/* Widgets are already destroyed when removed from box because they are only referenced inside the container */
g_list_free(list);
/* Deactivate buttons */
if (self->associated_load_button)
gtk_widget_set_sensitive(self->associated_load_button, FALSE);
if (self->associated_save_button)
gtk_widget_set_sensitive(self->associated_save_button, FALSE);
}
/**
* @brief Check if specific layer number is present in list box
* @param layer Layer nu,ber
* @return TRUE if present
*/
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;
}
static void sel_layer_element_setup_dnd_callbacks(LayerSelector *self, LayerElement *element)
{
layer_element_set_dnd_callbacks(element, &self->dnd_target, 1,
sel_layer_element_drag_begin,
sel_layer_element_drag_data_get,
sel_layer_element_drag_end);
}
/**
* @brief Analyze \p cell and append used layers to list box
* @param listbox listbox to add layer
* @param cell Cell to analyze
*/
static void layer_selector_analyze_cell_layers(LayerSelector *self, struct gds_cell *cell)
{
GList *graphics;
struct gds_graphics *gfx;
int layer;
GtkWidget *le;
for (graphics = cell->graphic_objs; graphics != NULL; graphics = graphics->next) {
gfx = (struct gds_graphics *)graphics->data;
layer = (int)gfx->layer;
if (layer_selector_check_if_layer_widget_exists(self, layer) == FALSE) {
le = layer_element_new();
sel_layer_element_setup_dnd_callbacks(self, LAYER_ELEMENT(le));
layer_element_set_layer(LAYER_ELEMENT(le), layer);
gtk_list_box_insert(self->list_box, le, -1);
gtk_widget_show(le);
}
}
}
/**
* @brief sort_func Sort callback for list box
* @param row1
* @param row2
* @param unused
* @note Do not use this function. This is an internal callback
* @return See sort function documentation of GTK+
*/
static gint layer_selector_sort_func(GtkListBoxRow *row1, GtkListBoxRow *row2, gpointer unused)
{
LayerElement *le1, *le2;
gint ret;
static const enum layer_selector_sort_algo default_sort = LAYER_SELECTOR_SORT_DOWN;
const enum layer_selector_sort_algo *algo = (const enum layer_selector_sort_algo *)unused;
/* Assume downward sorting */
/* TODO: This is nasty. Find a better way */
if (!algo)
algo = &default_sort;
le1 = LAYER_ELEMENT(row1);
le2 = LAYER_ELEMENT(row2);
/* Determine sort fow downward sort */
ret = layer_element_get_layer(le1) - layer_element_get_layer(le2);
/* Change order if upward sort is requested */
ret *= (*algo == LAYER_SELECTOR_SORT_DOWN ? 1 : -1);
return ret;
}
void layer_selector_generate_layer_widgets(LayerSelector *selector, GList *libs)
{
GList *cell_list = NULL;
struct gds_library *lib;
layer_selector_clear_widgets(selector);
for (; libs != NULL; libs = libs->next) {
lib = (struct gds_library *)libs->data;
for (cell_list = lib->cells; cell_list != NULL; cell_list = cell_list->next) {
layer_selector_analyze_cell_layers(selector, (struct gds_cell *)cell_list->data);
} /* For Cell List */
} /* For libs */
/* Sort the layers */
layer_selector_force_sort(selector, LAYER_SELECTOR_SORT_DOWN);
/* Activate Buttons */
if (selector->associated_load_button)
gtk_widget_set_sensitive(selector->associated_load_button, TRUE);
if (selector->associated_save_button)
gtk_widget_set_sensitive(selector->associated_save_button, TRUE);
}
/**
* @brief Find LayerElement in list with specified layer number
* @param el_list List with elements of type LayerElement
* @param layer Layer number
* @return Found LayerElement. If nothing is found, NULL.
*/
static LayerElement *layer_selector_find_layer_element_in_list(GList *el_list, int layer)
{
LayerElement *ret = NULL;
for (; el_list != NULL; el_list = el_list->next) {
if (layer_element_get_layer(LAYER_ELEMENT(el_list->data)) == layer) {
ret = LAYER_ELEMENT(el_list->data);
break;
}
}
return ret;
}
/**
* @brief Load file and apply layer definitions to listbox
* @param file_name CSV Layer Mapping File
*/
static void layer_selector_load_layer_mapping_from_file(LayerSelector *self, gchar *file_name)
{
GFile *file;
GFileInputStream *stream;
GDataInputStream *dstream;
LayerElement *le;
char *name;
gboolean export;
int layer;
GdkRGBA color;
int result;
GList *rows;
GList *temp;
file = g_file_new_for_path(file_name);
stream = g_file_read(file, NULL, NULL);
if (!stream)
goto destroy_file;
dstream = g_data_input_stream_new(G_INPUT_STREAM(stream));
rows = gtk_container_get_children(GTK_CONTAINER(self->list_box));
/* Reference and remove all rows from box */
for (temp = rows; temp != NULL; temp = temp->next) {
le = LAYER_ELEMENT(temp->data);
/* Referencing protets the widget from being deleted when removed */
g_object_ref(G_OBJECT(le));
gtk_container_remove(GTK_CONTAINER(self->list_box), GTK_WIDGET(le));
}
while((result = 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 = layer_selector_find_layer_element_in_list(rows, layer))) {
gtk_list_box_insert(self->list_box, GTK_WIDGET(le), -1);
layer_element_set_color(le, &color);
layer_element_set_export(le, export);
layer_element_set_name(le, name);
g_free(name);
/* Dereference and remove from list */
g_object_unref(G_OBJECT(le));
rows = g_list_remove(rows, le);
}
}
/* Add remaining elements */
for (temp = rows; temp != NULL; temp = temp->next) {
le = LAYER_ELEMENT(temp->data);
/* Referencing protets the widget from being deleted when removed */
gtk_list_box_insert(self->list_box, GTK_WIDGET(le), -1);
g_object_unref(G_OBJECT(le));
}
/* Delete list */
g_list_free(rows);
/* read line */
g_object_unref(dstream);
g_object_unref(stream);
destroy_file:
g_object_unref(file);
}
/**
* @brief Callback for Load Mapping Button
* @param button
* @param user_data
*/
static void layer_selector_load_mapping_clicked(GtkWidget *button, gpointer user_data)
{
LayerSelector *sel;
GtkWidget *dialog;
gint res;
gchar *file_name;
sel = LAYER_SELECTOR(user_data);
dialog = gtk_file_chooser_dialog_new("Load Mapping File", GTK_WINDOW(sel->load_parent_window), GTK_FILE_CHOOSER_ACTION_OPEN,
"Cancel", GTK_RESPONSE_CANCEL, "Load Mapping", GTK_RESPONSE_ACCEPT, NULL);
res = gtk_dialog_run(GTK_DIALOG(dialog));
if (res == GTK_RESPONSE_ACCEPT) {
file_name = gtk_file_chooser_get_filename(GTK_FILE_CHOOSER(dialog));
layer_selector_load_layer_mapping_from_file(sel, file_name);
g_free(file_name);
}
gtk_widget_destroy(dialog);
}
/**
* @brief Save layer mapping of whole list box into file
* @param file_name layer mapping file
* @param list_box listbox
*/
static void layer_selector_save_layer_mapping_data(LayerSelector *self, const gchar *file_name)
{
FILE *file;
char workbuff[512];
GList *le_list;
GList *temp;
/* Overwrite existing file */
file = fopen((const char *)file_name, "w");
le_list = gtk_container_get_children(GTK_CONTAINER(self->list_box));
/* File format is CSV: <Layer>,<target_pos>,<R>,<G>,<B>,<Alpha>,<Export?>,<Name> */
for (temp = le_list; temp != NULL; temp = temp->next) {
/* To be sure it is a valid string */
workbuff[0] = 0;
create_csv_line(LAYER_ELEMENT(temp->data), workbuff, sizeof(workbuff));
fwrite(workbuff, sizeof(char), strlen(workbuff), file);
}
g_list_free(le_list);
/* Save File */
fflush(file);
fclose(file);
}
/**
* @brief Callback for Save Layer Mapping Button
* @param button
* @param user_data
*/
static void layer_selector_save_mapping_clicked(GtkWidget *button, gpointer user_data)
{
GtkWidget *dialog;
gint res;
gchar *file_name;
LayerSelector *sel;
sel = LAYER_SELECTOR(user_data);
dialog = gtk_file_chooser_dialog_new("Save Mapping File", GTK_WINDOW(sel->save_parent_window), GTK_FILE_CHOOSER_ACTION_SAVE,
"Cancel", GTK_RESPONSE_CANCEL, "Save Mapping", GTK_RESPONSE_ACCEPT, NULL);
gtk_file_chooser_set_do_overwrite_confirmation(GTK_FILE_CHOOSER(dialog), TRUE);
res = gtk_dialog_run(GTK_DIALOG(dialog));
if (res == GTK_RESPONSE_ACCEPT) {
file_name = gtk_file_chooser_get_filename(GTK_FILE_CHOOSER(dialog));
layer_selector_save_layer_mapping_data(sel, file_name);
g_free(file_name);
}
gtk_widget_destroy(dialog);
}
void layer_selector_set_load_mapping_button(LayerSelector *selector, GtkWidget *button, GtkWindow *main_window)
{
g_clear_object(&selector->load_parent_window);
g_clear_object(&selector->associated_load_button);
g_object_ref(G_OBJECT(button));
g_object_ref(G_OBJECT(main_window));
selector->associated_load_button = button;
selector->load_parent_window = main_window;
g_signal_connect(button, "clicked", G_CALLBACK(layer_selector_load_mapping_clicked), selector);
}
void layer_selector_set_save_mapping_button(LayerSelector *selector, GtkWidget *button, GtkWindow *main_window)
{
g_clear_object(&selector->save_parent_window);
g_clear_object(&selector->associated_save_button);
g_object_ref(G_OBJECT(button));
g_object_ref(G_OBJECT(main_window));
selector->associated_save_button = button;
selector->save_parent_window = main_window;
g_signal_connect(button, "clicked", G_CALLBACK(layer_selector_save_mapping_clicked), selector);
}
void layer_selector_force_sort(LayerSelector *selector, enum layer_selector_sort_algo sort_function)
{
GtkListBox *box;
if (!selector)
return;
box = selector->list_box;
if (!box)
return;
/* Set sorting function, sort, and disable sorting function */
gtk_list_box_set_sort_func(box, layer_selector_sort_func, (gpointer)&sort_function, NULL);
gtk_list_box_invalidate_sort(box);
gtk_list_box_set_sort_func(box, NULL, NULL, NULL);
}
/** @} */

View File

@ -28,47 +28,52 @@
#include <gtk/gtk.h> #include <gtk/gtk.h>
#include <glib.h> #include <glib.h>
#include "../mapping-parser.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. * @brief Defines how to sort the layer selector list box.
*/ */
enum layer_selector_sort_algo {LAYER_SELECTOR_SORT_DOWN = 0, LAYER_SELECTOR_SORT_UP}; 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 \p listbox * @brief Generate layer widgets in \p listbox
* @note This clears all previously inserted elements * @note This clears all previously inserted elements
* @param listbox * @param listbox
* @param libs The library to add * @param libs The libraries to add
*/ */
void generate_layer_widgets(GtkListBox *listbox, GList *libs); void layer_selector_generate_layer_widgets(LayerSelector *selector, GList *libs);
/** /**
* @brief Supply button for loading the layer mapping * @brief Supply button for loading the layer mapping
* @param button * @param button
* @param main_window Parent window for dialogs * @param main_window Parent window for dialogs
*/ */
void setup_load_mapping_callback(GtkWidget *button, GtkWindow *main_window); void layer_selector_set_load_mapping_button(LayerSelector *selector, GtkWidget *button, GtkWindow *main_window);
/** /**
* @brief Supply button for saving the layer mapping * @brief Supply button for saving the layer mapping
* @param button * @param button
* @param main_window * @param main_window Parent window for dialogs
*/ */
void setup_save_mapping_callback(GtkWidget *button, GtkWindow *main_window); void layer_selector_set_save_mapping_button(LayerSelector *selector, GtkWidget *button, GtkWindow *main_window);
/** /**
* @brief get the layer information present in the listbox of the selector * @brief get the layer information present in the listbox of the selector
* @return List with layer_info elements * @return List with layer_info elements
*/ */
GList *export_rendered_layer_info(); GList *layer_selector_export_rendered_layer_info(LayerSelector *selector);
/**
* @brief Delete a layer_info struct
* @param info Struct to be deleted.
* @note The layer_info::name Element has to be freed manually
*/
void delete_layer_info_struct(struct layer_info *info);
/** /**
* @brief Force sorting of the layer selector in a specified way * @brief Force sorting of the layer selector in a specified way
@ -77,6 +82,8 @@ void delete_layer_info_struct(struct layer_info *info);
* *
* @param sort_function Sorting direction * @param sort_function Sorting direction
*/ */
void layer_selector_force_sort(enum layer_selector_sort_algo sort_function); void layer_selector_force_sort(LayerSelector *selector, enum layer_selector_sort_algo sort_function);
G_END_DECLS
#endif /* __LAYER_SELECTOR_H__ */ #endif /* __LAYER_SELECTOR_H__ */

59
main.c
View File

@ -20,36 +20,45 @@
#include <stdio.h> #include <stdio.h>
#include <gtk/gtk.h> #include <gtk/gtk.h>
#include <glib.h> #include <glib.h>
#include "main-window.h" #include "gds-render-gui.h"
#include "command-line.h" #include "command-line.h"
#include "external-renderer.h" #include "external-renderer.h"
#include "version/version.h" #include "version/version.h"
struct application_data { struct application_data {
GtkApplication *app; GtkApplication *app;
GtkWindow *main_window; GList *gui_list;
}; };
static void app_quit(GSimpleAction *action, GVariant *parameter, gpointer user_data) static void app_quit(GSimpleAction *action, GVariant *parameter, gpointer user_data)
{ {
const struct application_data * const appdata = (const struct application_data *)user_data; struct application_data * const appdata = (struct application_data *)user_data;
(void)action; (void)action;
(void)parameter; (void)parameter;
GList *list_iter;
GdsRenderGui *gui;
gtk_widget_destroy(GTK_WIDGET(appdata->main_window)); /* Dispose all GUIs */
for (list_iter = appdata->gui_list; list_iter != NULL; list_iter = g_list_next(list_iter)) {
gui = RENDERER_GUI(list_iter->data);
g_object_unref(gui);
}
g_list_free(appdata->gui_list);
appdata->gui_list = NULL;
} }
static void app_about(GSimpleAction *action, GVariant *parameter, gpointer user_data) static void app_about(GSimpleAction *action, GVariant *parameter, gpointer user_data)
{ {
GtkBuilder *builder; GtkBuilder *builder;
GtkDialog *dialog; GtkDialog *dialog;
const struct application_data * const appdata = (const struct application_data *)user_data; (void)user_data;
(void)action; (void)action;
(void)parameter; (void)parameter;
builder = gtk_builder_new_from_resource("/about.glade"); builder = gtk_builder_new_from_resource("/about.glade");
dialog = GTK_DIALOG(gtk_builder_get_object(builder, "about-dialog")); dialog = GTK_DIALOG(gtk_builder_get_object(builder, "about-dialog"));
gtk_window_set_transient_for(GTK_WINDOW(dialog), appdata->main_window); gtk_window_set_transient_for(GTK_WINDOW(dialog), NULL);
gtk_about_dialog_set_version(GTK_ABOUT_DIALOG(dialog), _app_version_string); gtk_about_dialog_set_version(GTK_ABOUT_DIALOG(dialog), _app_version_string);
gtk_dialog_run(dialog); gtk_dialog_run(dialog);
@ -62,13 +71,29 @@ const static GActionEntry app_actions[] = {
{"about", app_about, NULL, NULL, NULL, {0}} {"about", app_about, NULL, NULL, NULL, {0}}
}; };
static void gui_window_closed_callback(GdsRenderGui *gui, gpointer user_data)
{
GList **gui_list = (GList **)user_data;
/* Dispose of Gui element */
*gui_list = g_list_remove(*gui_list, gui);
g_object_unref(gui);
}
static void gapp_activate(GApplication *app, gpointer user_data) static void gapp_activate(GApplication *app, gpointer user_data)
{ {
GtkWindow *main_window; GtkWindow *main_window;
GdsRenderGui *gui;
struct application_data * const appdata = (struct application_data *)user_data; struct application_data * const appdata = (struct application_data *)user_data;
main_window = create_main_window(); gui = gds_render_gui_new();
appdata->main_window = main_window; 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_application_add_window(GTK_APPLICATION(app), main_window);
gtk_widget_show(GTK_WIDGET(main_window)); gtk_widget_show(GTK_WIDGET(main_window));
} }
@ -78,15 +103,21 @@ static int start_gui(int argc, char **argv)
GtkApplication *gapp; GtkApplication *gapp;
int app_status; int app_status;
static struct application_data appdata; static struct application_data appdata = {.gui_list = NULL};
GMenu *menu; GMenu *menu;
GMenu *m_quit; GMenu *m_quit;
GMenu *m_about; GMenu *m_about;
gapp = gtk_application_new("de.shimatta.gds-render", G_APPLICATION_NON_UNIQUE); gapp = gtk_application_new("de.shimatta.gds-render", G_APPLICATION_FLAGS_NONE);
g_application_register(G_APPLICATION(gapp), NULL, NULL); g_application_register(G_APPLICATION(gapp), NULL, NULL);
g_signal_connect(gapp, "activate", G_CALLBACK(gapp_activate), &appdata); g_signal_connect(gapp, "activate", G_CALLBACK(gapp_activate), &appdata);
if (g_application_get_is_remote(G_APPLICATION(gapp)) == TRUE) {
g_application_activate(G_APPLICATION(gapp));
printf("There is already an open instance. Will open second window in said instance.\n");
return 0;
}
menu = g_menu_new(); menu = g_menu_new();
m_quit = g_menu_new(); m_quit = g_menu_new();
m_about = g_menu_new(); m_about = g_menu_new();
@ -105,6 +136,8 @@ static int start_gui(int argc, char **argv)
app_status = g_application_run(G_APPLICATION(gapp), argc, argv); app_status = g_application_run(G_APPLICATION(gapp), argc, argv);
g_object_unref(gapp); g_object_unref(gapp);
g_list_free(appdata.gui_list);
return app_status; return app_status;
} }
@ -116,6 +149,7 @@ static void print_version()
int main(int argc, char **argv) int main(int argc, char **argv)
{ {
int i;
GError *error = NULL; GError *error = NULL;
GOptionContext *context; GOptionContext *context;
gchar *gds_name; gchar *gds_name;
@ -173,6 +207,11 @@ int main(int argc, char **argv)
/* Get gds name */ /* Get gds name */
gds_name = argv[1]; gds_name = argv[1];
/* Print out additional arguments as ignored */
for (i = 2; i < argc; i++) {
printf("Ignored argument: %s", argv[i]);
}
/* Check if PDF/TeX names are supplied. if not generate */ /* Check if PDF/TeX names are supplied. if not generate */
basename = g_path_get_basename(gds_name); basename = g_path_get_basename(gds_name);

View File

@ -94,5 +94,51 @@ ret_direct:
} }
void create_csv_line(LayerElement *layer_element, char *line_buffer, size_t max_len)
{
int i;
GString *string;
gboolean export;
const gchar *name;
int layer;
GdkRGBA color;
string = g_string_new_len(NULL, max_len-1);
/* Extract values */
export = layer_element_get_export(layer_element);
name = (const gchar*)layer_element_get_name(layer_element);
layer = layer_element_get_layer(layer_element);
layer_element_get_color(layer_element, &color);
/* print values to line */
g_string_printf(string, "%d:%lf:%lf:%lf:%lf:%d:%s\n",
layer, color.red, color.green,
color.blue, color.alpha, (export == TRUE ? 1 : 0), name);
/* Fix broken locale settings */
for (i = 0; string->str[i]; i++) {
if (string->str[i] == ',')
string->str[i] = '.';
}
for (i = 0; string->str[i]; i++) {
if (string->str[i] == ':')
string->str[i] = ',';
}
if (string->len > (max_len-1)) {
printf("Layer Definition too long. Please shorten Layer Name!!\n");
line_buffer[0] = 0x0;
return;
}
/* copy max_len bytes of string */
strncpy(line_buffer, (char *)string->str, max_len-1);
line_buffer[max_len-1] = 0;
/* Completely remove string */
g_string_free(string, TRUE);
}
/** @} */ /** @} */

View File

@ -32,19 +32,7 @@
*/ */
#include <gtk/gtk.h> #include <gtk/gtk.h>
#include "widgets/layer-element.h"
/**
* @brief Layer information.
*
* This structs contains information on how to render a layer
*/
struct layer_info
{
int layer; /**< @brief Layer number */
char *name; /**< @brief Layer name */
int stacked_position; ///< @brief Position of layer in output @warning This parameter is not used by any renderer so far @note Lower is bottom, higher is top
GdkRGBA color; /**< @brief RGBA color used to render this layer */
};
/** /**
* @brief Load a line from \p stream and parse try to parse it as layer information * @brief Load a line from \p stream and parse try to parse it as layer information
@ -57,6 +45,14 @@ struct layer_info
*/ */
int load_csv_line(GDataInputStream *stream, gboolean *export, char **name, int *layer, GdkRGBA *color); int load_csv_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 create_csv_line(LayerElement *layer_element, char *line_buffer, size_t max_len);
/** @} */ /** @} */
#endif /* __MAPPING_PARSER_H__ */ #endif /* __MAPPING_PARSER_H__ */

View File

@ -57,65 +57,6 @@ static void layer_element_class_init(LayerElementClass *klass)
oclass->constructed = layer_element_constructed; oclass->constructed = layer_element_constructed;
} }
static GtkTargetEntry entries[] = {
{ "GTK_LIST_BOX_ROW", GTK_TARGET_SAME_APP, 0 }
};
static void layer_element_drag_begin(GtkWidget *widget,
GdkDragContext *context,
gpointer data)
{
GtkWidget *row;
GtkAllocation alloc;
cairo_surface_t *surface;
cairo_t *cr;
int x, y;
(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 layer_element_drag_end(GtkWidget *widget, GdkDragContext *context, gpointer data)
{
GtkWidget *row;
(void)context;
(void)data;
row = gtk_widget_get_ancestor(widget, GTK_TYPE_LIST_BOX_ROW);
g_object_set_data(G_OBJECT(gtk_widget_get_parent(row)), "drag-row", NULL);
gtk_style_context_remove_class(gtk_widget_get_style_context(row), "drag-row");
gtk_style_context_remove_class(gtk_widget_get_style_context(row), "drag-hover");
}
static void layer_element_drag_data_get(GtkWidget *widget, GdkDragContext *context, GtkSelectionData *selection_data,
guint info, guint time, gpointer data)
{
(void)context;
(void)info;
(void)time;
(void)data;
gtk_selection_data_set(selection_data, gdk_atom_intern_static_string("GTK_LIST_BOX_ROW"),
32, (const guchar *)&widget, sizeof(gpointer));
}
static void layer_element_init(LayerElement *self) static void layer_element_init(LayerElement *self)
{ {
GtkBuilder *builder; GtkBuilder *builder;
@ -131,13 +72,6 @@ static void layer_element_init(LayerElement *self)
self->priv.name = GTK_ENTRY(gtk_builder_get_object(builder, "entry")); self->priv.name = GTK_ENTRY(gtk_builder_get_object(builder, "entry"));
self->priv.event_handle = GTK_EVENT_BOX(gtk_builder_get_object(builder, "event-box")); self->priv.event_handle = GTK_EVENT_BOX(gtk_builder_get_object(builder, "event-box"));
/* Setup drag and drop */
gtk_style_context_add_class (gtk_widget_get_style_context(GTK_WIDGET(self)), "row");
gtk_drag_source_set(GTK_WIDGET(self->priv.event_handle), GDK_BUTTON1_MASK, entries, 1, GDK_ACTION_MOVE);
g_signal_connect(self->priv.event_handle, "drag-begin", G_CALLBACK(layer_element_drag_begin), NULL);
g_signal_connect(self->priv.event_handle, "drag-data-get", G_CALLBACK(layer_element_drag_data_get), NULL);
g_signal_connect(self->priv.event_handle, "drag-end", G_CALLBACK(layer_element_drag_end), NULL);
g_object_unref(builder); g_object_unref(builder);
} }
@ -194,4 +128,19 @@ void layer_element_set_color(LayerElement *elem, GdkRGBA *rgba)
gtk_color_chooser_set_rgba(GTK_COLOR_CHOOSER(elem->priv.color), rgba); gtk_color_chooser_set_rgba(GTK_COLOR_CHOOSER(elem->priv.color), rgba);
} }
void layer_element_set_dnd_callbacks(LayerElement *elem, GtkTargetEntry *entries, int entry_count,
void (*drag_begin)(GtkWidget *, GdkDragContext *, gpointer),
void (*drag_data_get)(GtkWidget *, GdkDragContext *,
GtkSelectionData *, guint , guint, gpointer),
void (*drag_end)(GtkWidget *, GdkDragContext *, gpointer))
{
/* Setup drag and drop */
gtk_style_context_add_class (gtk_widget_get_style_context(GTK_WIDGET(elem)), "row");
gtk_drag_source_set(GTK_WIDGET(elem->priv.event_handle), GDK_BUTTON1_MASK, entries, entry_count, GDK_ACTION_MOVE);
g_signal_connect(elem->priv.event_handle, "drag-begin", G_CALLBACK(drag_begin), NULL);
g_signal_connect(elem->priv.event_handle, "drag-data-get", G_CALLBACK(drag_data_get), NULL);
g_signal_connect(elem->priv.event_handle, "drag-end", G_CALLBACK(drag_end), NULL);
}
/** @} */ /** @} */

View File

@ -118,6 +118,18 @@ void layer_element_get_color(LayerElement *elem, GdkRGBA *rgba);
*/ */
void layer_element_set_color(LayerElement *elem, GdkRGBA *rgba); void layer_element_set_color(LayerElement *elem, GdkRGBA *rgba);
/**
* @brief layer_element_set_dnd_callbacks
* @param elem
* @param entries
* @param entry_count
*/
void layer_element_set_dnd_callbacks(LayerElement *elem, GtkTargetEntry *entries, int entry_count,
void (*drag_begin)(GtkWidget *, GdkDragContext *, gpointer),
void (*drag_data_get)(GtkWidget *, GdkDragContext *,
GtkSelectionData *, guint , guint, gpointer),
void (*drag_end)(GtkWidget *, GdkDragContext *, gpointer));
G_END_DECLS G_END_DECLS
#endif /* __LAYER_ELEMENT_H__ */ #endif /* __LAYER_ELEMENT_H__ */