2018-07-23 15:26:51 +02:00
|
|
|
/*
|
|
|
|
* 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/>.
|
|
|
|
*/
|
|
|
|
|
2018-07-24 18:47:29 +02:00
|
|
|
/**
|
2019-03-15 20:02:03 +01:00
|
|
|
* @file gds-render-gui.c
|
2018-07-24 18:47:29 +02:00
|
|
|
* @brief Handling of GUI
|
|
|
|
* @author Mario Hüttel <mario.huettel@gmx.net>
|
|
|
|
*/
|
|
|
|
|
|
|
|
/** @addtogroup MainApplication
|
|
|
|
* @{
|
|
|
|
*/
|
|
|
|
|
2018-07-23 13:10:34 +02:00
|
|
|
#include <stdio.h>
|
|
|
|
#include <gtk/gtk.h>
|
2019-03-26 19:57:19 +01:00
|
|
|
|
|
|
|
#include <gds-render/gds-render-gui.h>
|
|
|
|
#include <gds-render/gds-utils/gds-parser.h>
|
|
|
|
#include <gds-render/gds-utils/gds-tree-checker.h>
|
|
|
|
#include <gds-render/layer/layer-selector.h>
|
|
|
|
#include <gds-render/tree-renderer/tree-store.h>
|
|
|
|
#include <gds-render/tree-renderer/lib-cell-renderer.h>
|
|
|
|
#include <gds-render/latex-renderer/latex-output.h>
|
|
|
|
#include <gds-render/cairo-renderer/cairo-output.h>
|
|
|
|
#include <gds-render/widgets/conv-settings-dialog.h>
|
|
|
|
#include <gds-render/geometric/cell-geometrics.h>
|
|
|
|
#include <gds-render/version.h>
|
2018-07-23 13:10:34 +02:00
|
|
|
|
2019-03-16 16:09:29 +01:00
|
|
|
enum gds_render_gui_signal_sig_ids {SIGNAL_WINDOW_CLOSED = 0, SIGNAL_COUNT};
|
|
|
|
|
|
|
|
static guint gds_render_gui_signals[SIGNAL_COUNT];
|
|
|
|
|
2019-03-15 20:02:03 +01:00
|
|
|
struct _GdsRenderGui {
|
|
|
|
/* Parent GObject */
|
|
|
|
GObject parent;
|
|
|
|
|
|
|
|
/* Custom fields */
|
2018-07-23 13:10:34 +02:00
|
|
|
GtkWindow *main_window;
|
2019-03-15 20:02:03 +01:00
|
|
|
GtkWidget *convert_button;
|
|
|
|
GtkTreeStore *cell_tree_store;
|
|
|
|
GtkWidget *cell_search_entry;
|
2019-03-14 23:40:26 +01:00
|
|
|
LayerSelector *layer_selector;
|
2019-03-15 20:02:03 +01:00
|
|
|
GtkTreeView *cell_tree_view;
|
|
|
|
GList *gds_libraries;
|
2019-03-22 21:59:27 +01:00
|
|
|
struct render_settings render_dialog_settings;
|
2018-07-23 13:10:34 +02:00
|
|
|
};
|
|
|
|
|
2019-03-15 20:02:03 +01:00
|
|
|
G_DEFINE_TYPE(GdsRenderGui, gds_render_gui, G_TYPE_OBJECT)
|
|
|
|
|
2018-07-24 18:47:29 +02:00
|
|
|
/**
|
2019-03-25 18:47:12 +01:00
|
|
|
* @brief Main window close event
|
|
|
|
* @param window GtkWindow which is closed
|
|
|
|
* @param event unused event
|
|
|
|
* @param user GdsRenderGui instance
|
|
|
|
* @return Status of the event handling. Always true.
|
2018-07-24 18:47:29 +02:00
|
|
|
*/
|
2019-03-14 23:40:26 +01:00
|
|
|
static gboolean on_window_close(gpointer window, GdkEvent *event, gpointer user)
|
2018-07-23 13:10:34 +02:00
|
|
|
{
|
2019-03-15 20:02:03 +01:00
|
|
|
GdsRenderGui *self;
|
|
|
|
|
|
|
|
self = RENDERER_GUI(user);
|
|
|
|
/* Don't close window in case of error */
|
|
|
|
if (!self)
|
|
|
|
return TRUE;
|
2019-03-14 23:40:26 +01:00
|
|
|
|
2019-03-15 20:02:03 +01:00
|
|
|
/* Close Window. Leads to termination of the program/the current instance */
|
2019-03-15 20:36:23 +01:00
|
|
|
g_clear_object(&self->main_window);
|
2018-07-23 13:10:34 +02:00
|
|
|
gtk_widget_destroy(GTK_WIDGET(window));
|
2019-03-15 20:36:23 +01:00
|
|
|
|
2019-03-16 16:09:29 +01:00
|
|
|
/* Delete loaded library data */
|
|
|
|
clear_lib_list(&self->gds_libraries);
|
|
|
|
|
|
|
|
g_signal_emit(self, gds_render_gui_signals[SIGNAL_WINDOW_CLOSED], 0);
|
|
|
|
|
2018-07-23 13:10:34 +02:00
|
|
|
return TRUE;
|
|
|
|
}
|
|
|
|
|
2018-07-24 18:47:29 +02:00
|
|
|
/**
|
|
|
|
* @brief generate string from gds_time_field
|
|
|
|
* @param date Date to convert
|
|
|
|
* @return String with date
|
|
|
|
*/
|
2018-07-23 13:10:34 +02:00
|
|
|
static GString *generate_string_from_date(struct gds_time_field *date)
|
|
|
|
{
|
|
|
|
GString *str;
|
|
|
|
|
|
|
|
str = g_string_new_len(NULL, 50);
|
|
|
|
g_string_printf(str, "%02u.%02u.%u - %02u:%02u",
|
|
|
|
(unsigned int)date->day,
|
|
|
|
(unsigned int)date->month,
|
|
|
|
(unsigned int)date->year,
|
|
|
|
(unsigned int)date->hour,
|
|
|
|
(unsigned int)date->minute);
|
|
|
|
return str;
|
|
|
|
}
|
|
|
|
|
2018-07-24 18:47:29 +02:00
|
|
|
/**
|
|
|
|
* @brief Callback function of Load GDS button
|
|
|
|
* @param button
|
2019-03-25 18:47:12 +01:00
|
|
|
* @param user GdsRenderGui instance
|
2018-07-24 18:47:29 +02:00
|
|
|
*/
|
2018-07-23 13:10:34 +02:00
|
|
|
static void on_load_gds(gpointer button, gpointer user)
|
|
|
|
{
|
|
|
|
GList *cell;
|
|
|
|
GtkTreeIter libiter;
|
|
|
|
GtkTreeIter celliter;
|
|
|
|
GList *lib;
|
|
|
|
struct gds_library *gds_lib;
|
|
|
|
struct gds_cell *gds_c;
|
2019-03-15 20:02:03 +01:00
|
|
|
GdsRenderGui *self;
|
2018-07-23 13:10:34 +02:00
|
|
|
GtkWidget *open_dialog;
|
|
|
|
GtkFileChooser *file_chooser;
|
|
|
|
GtkFileFilter *filter;
|
|
|
|
GtkStyleContext *button_style;
|
|
|
|
gint dialog_result;
|
|
|
|
int gds_result;
|
|
|
|
char *filename;
|
|
|
|
GString *mod_date;
|
|
|
|
GString *acc_date;
|
2019-03-06 20:07:26 +01:00
|
|
|
unsigned int cell_error_level;
|
2018-07-23 13:10:34 +02:00
|
|
|
|
2019-03-15 20:02:03 +01:00
|
|
|
self = RENDERER_GUI(user);
|
|
|
|
if (!self)
|
|
|
|
return;
|
|
|
|
|
|
|
|
open_dialog = gtk_file_chooser_dialog_new("Open GDSII File", self->main_window,
|
2019-03-07 20:32:55 +01:00
|
|
|
GTK_FILE_CHOOSER_ACTION_OPEN,
|
|
|
|
"Cancel", GTK_RESPONSE_CANCEL,
|
|
|
|
"Open GDSII", GTK_RESPONSE_ACCEPT,
|
|
|
|
NULL);
|
2018-07-23 13:10:34 +02:00
|
|
|
file_chooser = GTK_FILE_CHOOSER(open_dialog);
|
|
|
|
/* Add GDS II Filter */
|
|
|
|
filter = gtk_file_filter_new();
|
|
|
|
gtk_file_filter_add_pattern(filter, "*.gds");
|
|
|
|
gtk_file_filter_set_name(filter, "GDSII-Files");
|
|
|
|
gtk_file_chooser_add_filter(file_chooser, filter);
|
|
|
|
|
|
|
|
dialog_result = gtk_dialog_run(GTK_DIALOG(open_dialog));
|
|
|
|
|
2019-03-22 22:24:48 +01:00
|
|
|
if (dialog_result != GTK_RESPONSE_ACCEPT)
|
|
|
|
goto end_destroy;
|
2018-07-23 13:10:34 +02:00
|
|
|
|
2019-03-22 22:24:48 +01:00
|
|
|
/* Get File name */
|
|
|
|
filename = gtk_file_chooser_get_filename(file_chooser);
|
2018-07-23 13:10:34 +02:00
|
|
|
|
2019-03-22 22:24:48 +01:00
|
|
|
gtk_tree_store_clear(self->cell_tree_store);
|
|
|
|
clear_lib_list(&self->gds_libraries);
|
2018-07-23 13:10:34 +02:00
|
|
|
|
2019-03-22 22:24:48 +01:00
|
|
|
/* Parse new GDSII file */
|
|
|
|
gds_result = parse_gds_from_file(filename, &self->gds_libraries);
|
|
|
|
|
|
|
|
/* Delete file name afterwards */
|
|
|
|
g_free(filename);
|
|
|
|
if (gds_result)
|
|
|
|
goto end_destroy;
|
|
|
|
|
|
|
|
/* remove suggested action from Open button */
|
|
|
|
button_style = gtk_widget_get_style_context(GTK_WIDGET(button));
|
|
|
|
gtk_style_context_remove_class(button_style, "suggested-action");
|
|
|
|
|
|
|
|
for (lib = self->gds_libraries; lib != NULL; lib = lib->next) {
|
|
|
|
gds_lib = (struct gds_library *)lib->data;
|
|
|
|
/* Create top level iter */
|
|
|
|
gtk_tree_store_append(self->cell_tree_store, &libiter, NULL);
|
|
|
|
|
|
|
|
/* Convert dates to String */
|
|
|
|
mod_date = generate_string_from_date(&gds_lib->mod_time);
|
|
|
|
acc_date = generate_string_from_date(&gds_lib->access_time);
|
|
|
|
|
|
|
|
gtk_tree_store_set(self->cell_tree_store, &libiter,
|
|
|
|
CELL_SEL_LIBRARY, gds_lib,
|
|
|
|
CELL_SEL_MODDATE, mod_date->str,
|
|
|
|
CELL_SEL_ACCESSDATE, acc_date->str,
|
|
|
|
-1);
|
|
|
|
|
|
|
|
/* Check this library. This might take a while */
|
|
|
|
(void)gds_tree_check_cell_references(gds_lib);
|
|
|
|
(void)gds_tree_check_reference_loops(gds_lib);
|
|
|
|
/* Delete GStrings including string data. */
|
|
|
|
/* Cell store copies String type data items */
|
|
|
|
g_string_free(mod_date, TRUE);
|
|
|
|
g_string_free(acc_date, TRUE);
|
|
|
|
|
|
|
|
for (cell = gds_lib->cells; cell != NULL; cell = cell->next) {
|
|
|
|
gds_c = (struct gds_cell *)cell->data;
|
|
|
|
gtk_tree_store_append(self->cell_tree_store, &celliter, &libiter);
|
|
|
|
/* Convert dates to String */
|
|
|
|
mod_date = generate_string_from_date(&gds_c->mod_time);
|
|
|
|
acc_date = generate_string_from_date(&gds_c->access_time);
|
2018-07-23 13:10:34 +02:00
|
|
|
|
2019-03-22 22:24:48 +01:00
|
|
|
/* Get the checking results for this cell */
|
|
|
|
cell_error_level = 0;
|
|
|
|
if (gds_c->checks.unresolved_child_count)
|
|
|
|
cell_error_level |= LIB_CELL_RENDERER_ERROR_WARN;
|
2018-07-23 13:10:34 +02:00
|
|
|
|
2019-03-22 22:24:48 +01:00
|
|
|
/* Check if it is completely b0rken */
|
|
|
|
if (gds_c->checks.affected_by_reference_loop)
|
|
|
|
cell_error_level |= LIB_CELL_RENDERER_ERROR_ERR;
|
2018-07-23 13:10:34 +02:00
|
|
|
|
2019-03-22 22:24:48 +01:00
|
|
|
/* Add cell to tree store model */
|
|
|
|
gtk_tree_store_set(self->cell_tree_store, &celliter,
|
|
|
|
CELL_SEL_CELL, gds_c,
|
2019-03-07 20:32:55 +01:00
|
|
|
CELL_SEL_MODDATE, mod_date->str,
|
|
|
|
CELL_SEL_ACCESSDATE, acc_date->str,
|
2019-03-22 22:24:48 +01:00
|
|
|
CELL_SEL_CELL_ERROR_STATE, cell_error_level,
|
2019-03-07 20:32:55 +01:00
|
|
|
-1);
|
2018-07-23 13:10:34 +02:00
|
|
|
|
|
|
|
/* Delete GStrings including string data. */
|
|
|
|
/* Cell store copies String type data items */
|
|
|
|
g_string_free(mod_date, TRUE);
|
|
|
|
g_string_free(acc_date, TRUE);
|
2019-03-22 22:24:48 +01:00
|
|
|
} /* for cells */
|
|
|
|
} /* for libraries */
|
2018-07-23 13:10:34 +02:00
|
|
|
|
2019-03-22 22:24:48 +01:00
|
|
|
/* Create Layers in Layer Box */
|
|
|
|
layer_selector_generate_layer_widgets(self->layer_selector, self->gds_libraries);
|
2018-07-23 13:10:34 +02:00
|
|
|
|
|
|
|
end_destroy:
|
|
|
|
/* Destroy dialog and filter */
|
|
|
|
gtk_widget_destroy(open_dialog);
|
|
|
|
}
|
|
|
|
|
2018-07-24 18:47:29 +02:00
|
|
|
/**
|
|
|
|
* @brief Convert button callback
|
|
|
|
* @param button
|
|
|
|
* @param user
|
|
|
|
*/
|
2018-07-23 13:10:34 +02:00
|
|
|
static void on_convert_clicked(gpointer button, gpointer user)
|
|
|
|
{
|
2019-03-11 23:33:51 +01:00
|
|
|
(void)button;
|
2019-03-15 20:02:03 +01:00
|
|
|
GdsRenderGui *self;
|
2018-07-23 13:10:34 +02:00
|
|
|
GtkTreeSelection *selection;
|
|
|
|
GtkTreeIter iter;
|
|
|
|
GtkTreeModel *model;
|
|
|
|
GList *layer_list;
|
|
|
|
struct gds_cell *cell_to_render;
|
|
|
|
FILE *output_file;
|
|
|
|
GtkWidget *dialog;
|
|
|
|
RendererSettingsDialog *settings;
|
|
|
|
GtkFileFilter *filter;
|
|
|
|
gint res;
|
|
|
|
char *file_name;
|
2019-02-27 21:30:41 +01:00
|
|
|
union bounding_box cell_box;
|
2019-03-08 20:46:48 +01:00
|
|
|
unsigned int height, width;
|
2019-03-22 21:59:27 +01:00
|
|
|
struct render_settings *sett;
|
2018-07-23 13:10:34 +02:00
|
|
|
|
2019-03-15 20:02:03 +01:00
|
|
|
self = RENDERER_GUI(user);
|
|
|
|
|
|
|
|
if (!self)
|
2019-03-11 23:33:51 +01:00
|
|
|
return;
|
|
|
|
|
2019-03-22 21:59:27 +01:00
|
|
|
sett = &self->render_dialog_settings;
|
|
|
|
|
2018-07-23 13:10:34 +02:00
|
|
|
/* Get selected cell */
|
2019-03-15 20:02:03 +01:00
|
|
|
selection = gtk_tree_view_get_selection(self->cell_tree_view);
|
2018-07-23 13:10:34 +02:00
|
|
|
if (gtk_tree_selection_get_selected(selection, &model, &iter) == FALSE)
|
|
|
|
return;
|
|
|
|
|
|
|
|
gtk_tree_model_get(model, &iter, CELL_SEL_CELL, &cell_to_render, -1);
|
|
|
|
|
|
|
|
if (!cell_to_render)
|
|
|
|
return;
|
|
|
|
|
|
|
|
/* Get layers that are rendered */
|
2019-03-15 20:02:03 +01:00
|
|
|
layer_list = layer_selector_export_rendered_layer_info(self->layer_selector);
|
2018-07-23 13:10:34 +02:00
|
|
|
|
2018-12-29 01:13:33 +01:00
|
|
|
/* Calculate cell size in DB units */
|
2019-02-27 21:30:41 +01:00
|
|
|
bounding_box_prepare_empty(&cell_box);
|
|
|
|
calculate_cell_bounding_box(&cell_box, cell_to_render);
|
|
|
|
|
2019-03-08 20:46:48 +01:00
|
|
|
/* Calculate size in database units
|
|
|
|
* Note that the results are bound to be positive,
|
2019-03-14 23:40:26 +01:00
|
|
|
* so casting them to unsigned int is absolutely valid
|
2019-03-08 20:46:48 +01:00
|
|
|
*/
|
|
|
|
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);
|
2018-12-29 01:13:33 +01:00
|
|
|
|
|
|
|
/* Show settings dialog */
|
2019-03-15 20:02:03 +01:00
|
|
|
settings = renderer_settings_dialog_new(GTK_WINDOW(self->main_window));
|
2019-03-22 21:59:27 +01:00
|
|
|
renderer_settings_dialog_set_settings(settings, sett);
|
2019-03-04 20:14:21 +01:00
|
|
|
renderer_settings_dialog_set_database_unit_scale(settings, cell_to_render->parent_library->unit_in_meters);
|
2019-02-27 21:30:41 +01:00
|
|
|
renderer_settings_dialog_set_cell_height(settings, height);
|
|
|
|
renderer_settings_dialog_set_cell_width(settings, width);
|
|
|
|
|
2018-07-23 13:10:34 +02:00
|
|
|
res = gtk_dialog_run(GTK_DIALOG(settings));
|
|
|
|
if (res == GTK_RESPONSE_OK) {
|
2019-03-22 21:59:27 +01:00
|
|
|
renderer_settings_dialog_get_settings(settings, sett);
|
2018-07-23 13:10:34 +02:00
|
|
|
gtk_widget_destroy(GTK_WIDGET(settings));
|
|
|
|
} else {
|
|
|
|
gtk_widget_destroy(GTK_WIDGET(settings));
|
|
|
|
goto ret_layer_destroy;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* save file dialog */
|
2019-03-22 21:59:27 +01:00
|
|
|
dialog = gtk_file_chooser_dialog_new((sett->renderer == RENDERER_LATEX_TIKZ
|
2018-07-23 13:10:34 +02:00
|
|
|
? "Save LaTeX File" : "Save PDF"),
|
2019-03-15 20:02:03 +01:00
|
|
|
GTK_WINDOW(self->main_window), GTK_FILE_CHOOSER_ACTION_SAVE,
|
2018-07-23 13:10:34 +02:00
|
|
|
"Cancel", GTK_RESPONSE_CANCEL, "Save", GTK_RESPONSE_ACCEPT, NULL);
|
|
|
|
/* Set file filter according to settings */
|
|
|
|
filter = gtk_file_filter_new();
|
2019-03-22 21:59:27 +01:00
|
|
|
switch (sett->renderer) {
|
2018-07-30 12:35:30 +02:00
|
|
|
case RENDERER_LATEX_TIKZ:
|
2018-07-23 13:10:34 +02:00
|
|
|
gtk_file_filter_add_pattern(filter, "*.tex");
|
|
|
|
gtk_file_filter_set_name(filter, "LaTeX-Files");
|
2018-07-30 12:35:30 +02:00
|
|
|
break;
|
|
|
|
case RENDERER_CAIROGRAPHICS_PDF:
|
2018-07-23 13:10:34 +02:00
|
|
|
gtk_file_filter_add_pattern(filter, "*.pdf");
|
|
|
|
gtk_file_filter_set_name(filter, "PDF-Files");
|
2018-07-30 12:35:30 +02:00
|
|
|
break;
|
|
|
|
case RENDERER_CAIROGRAPHICS_SVG:
|
|
|
|
gtk_file_filter_add_pattern(filter, "*.svg");
|
|
|
|
gtk_file_filter_set_name(filter, "SVG-Files");
|
|
|
|
break;
|
2018-07-23 13:10:34 +02:00
|
|
|
}
|
2018-07-30 12:35:30 +02:00
|
|
|
|
2018-07-23 13:10:34 +02:00
|
|
|
gtk_file_chooser_add_filter(GTK_FILE_CHOOSER(dialog), filter);
|
|
|
|
|
2018-07-28 10:01:02 +02:00
|
|
|
gtk_file_chooser_set_do_overwrite_confirmation(GTK_FILE_CHOOSER(dialog), TRUE);
|
|
|
|
|
2018-07-23 13:10:34 +02:00
|
|
|
res = gtk_dialog_run(GTK_DIALOG(dialog));
|
|
|
|
if (res == GTK_RESPONSE_ACCEPT) {
|
|
|
|
file_name = gtk_file_chooser_get_filename(GTK_FILE_CHOOSER(dialog));
|
|
|
|
gtk_widget_destroy(dialog);
|
|
|
|
|
2019-03-22 21:59:27 +01:00
|
|
|
switch (sett->renderer) {
|
2018-07-23 13:10:34 +02:00
|
|
|
case RENDERER_LATEX_TIKZ:
|
|
|
|
output_file = fopen(file_name, "w");
|
2019-03-22 21:59:27 +01:00
|
|
|
latex_render_cell_to_code(cell_to_render, layer_list, output_file, sett->scale,
|
|
|
|
sett->tex_pdf_layers, sett->tex_standalone);
|
2018-07-23 13:10:34 +02:00
|
|
|
fclose(output_file);
|
|
|
|
break;
|
2018-07-30 12:35:30 +02:00
|
|
|
case RENDERER_CAIROGRAPHICS_SVG:
|
|
|
|
case RENDERER_CAIROGRAPHICS_PDF:
|
|
|
|
cairo_render_cell_to_vector_file(cell_to_render, layer_list,
|
2019-03-22 21:59:27 +01:00
|
|
|
(sett->renderer == RENDERER_CAIROGRAPHICS_PDF
|
2019-03-22 22:24:48 +01:00
|
|
|
? file_name
|
|
|
|
: NULL),
|
2019-03-22 21:59:27 +01:00
|
|
|
(sett->renderer == RENDERER_CAIROGRAPHICS_SVG
|
2019-03-22 22:24:48 +01:00
|
|
|
? file_name
|
|
|
|
: NULL),
|
2019-03-22 21:59:27 +01:00
|
|
|
sett->scale);
|
2018-07-23 13:10:34 +02:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
g_free(file_name);
|
|
|
|
|
|
|
|
} else {
|
|
|
|
gtk_widget_destroy(dialog);
|
|
|
|
}
|
|
|
|
ret_layer_destroy:
|
2019-03-14 21:39:12 +01:00
|
|
|
g_list_free_full(layer_list, (GDestroyNotify)layer_info_delete_struct);
|
2018-07-23 13:10:34 +02:00
|
|
|
}
|
|
|
|
|
2019-03-11 23:33:51 +01:00
|
|
|
/**
|
2019-03-25 18:47:12 +01:00
|
|
|
* @brief cell_tree_view_activated Callback for 'double click' on cell selector element
|
|
|
|
* @param tree_view The tree view the event occured in
|
|
|
|
* @param path path to the selected row
|
|
|
|
* @param column The clicked column
|
|
|
|
* @param user pointer to GdsRenderGui object
|
2019-03-11 23:33:51 +01:00
|
|
|
*/
|
|
|
|
static void cell_tree_view_activated(gpointer tree_view, GtkTreePath *path,
|
|
|
|
GtkTreeViewColumn *column, gpointer user)
|
|
|
|
{
|
|
|
|
(void)tree_view;
|
|
|
|
(void)path;
|
|
|
|
(void)column;
|
|
|
|
|
|
|
|
on_convert_clicked(NULL, user);
|
|
|
|
}
|
|
|
|
|
2018-07-24 18:47:29 +02:00
|
|
|
|
|
|
|
/**
|
|
|
|
* @brief Callback for cell-selection change event
|
|
|
|
*
|
|
|
|
* This function activates/deactivates the convert button depending on whether
|
|
|
|
* a cell is selected for conversion or not
|
|
|
|
* @param sel
|
2019-03-15 20:02:03 +01:00
|
|
|
* @param self
|
2018-07-24 18:47:29 +02:00
|
|
|
*/
|
2019-03-15 20:02:03 +01:00
|
|
|
static void cell_selection_changed(GtkTreeSelection *sel, GdsRenderGui *self)
|
2018-07-23 13:10:34 +02:00
|
|
|
{
|
|
|
|
GtkTreeModel *model = NULL;
|
|
|
|
GtkTreeIter iter;
|
|
|
|
|
|
|
|
if (gtk_tree_selection_get_selected(sel, &model, &iter)) {
|
|
|
|
/* Node selected. Show button */
|
2019-03-15 20:02:03 +01:00
|
|
|
gtk_widget_set_sensitive(self->convert_button, TRUE);
|
2018-07-23 13:10:34 +02:00
|
|
|
} else {
|
2019-03-15 20:02:03 +01:00
|
|
|
gtk_widget_set_sensitive(self->convert_button, FALSE);
|
2018-07-23 13:10:34 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-03-12 19:47:39 +01:00
|
|
|
static void sort_up_callback(GtkWidget *widget, gpointer user)
|
|
|
|
{
|
|
|
|
(void)widget;
|
2019-03-15 20:02:03 +01:00
|
|
|
GdsRenderGui *self;
|
2019-03-12 19:47:39 +01:00
|
|
|
|
2019-03-15 20:02:03 +01:00
|
|
|
self = RENDERER_GUI(user);
|
|
|
|
if (!self)
|
2019-03-14 23:40:26 +01:00
|
|
|
return;
|
2019-03-15 20:02:03 +01:00
|
|
|
layer_selector_force_sort(self->layer_selector, LAYER_SELECTOR_SORT_UP);
|
2019-03-12 19:47:39 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
static void sort_down_callback(GtkWidget *widget, gpointer user)
|
|
|
|
{
|
|
|
|
(void)widget;
|
2019-03-15 20:02:03 +01:00
|
|
|
GdsRenderGui *self;
|
2019-03-12 19:47:39 +01:00
|
|
|
|
2019-03-15 20:02:03 +01:00
|
|
|
self = RENDERER_GUI(user);
|
|
|
|
if (!self)
|
2019-03-14 23:40:26 +01:00
|
|
|
return;
|
2019-03-15 20:02:03 +01:00
|
|
|
layer_selector_force_sort(self->layer_selector, LAYER_SELECTOR_SORT_DOWN);
|
2019-03-12 19:47:39 +01:00
|
|
|
}
|
|
|
|
|
2019-03-15 20:02:03 +01:00
|
|
|
static void gds_render_gui_dispose(GObject *gobject)
|
|
|
|
{
|
|
|
|
GdsRenderGui *self;
|
|
|
|
|
|
|
|
self = RENDERER_GUI(gobject);
|
|
|
|
|
2019-03-16 16:09:29 +01:00
|
|
|
clear_lib_list(&self->gds_libraries);
|
|
|
|
|
2019-03-15 20:02:03 +01:00
|
|
|
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);
|
|
|
|
|
2019-03-15 20:36:23 +01:00
|
|
|
if (self->main_window) {
|
|
|
|
g_signal_handlers_destroy(self->main_window);
|
|
|
|
gtk_widget_destroy(GTK_WIDGET(self->main_window));
|
|
|
|
self->main_window = NULL;
|
|
|
|
}
|
|
|
|
|
2019-03-15 20:02:03 +01:00
|
|
|
/* 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);
|
|
|
|
|
2019-03-16 16:09:29 +01:00
|
|
|
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);
|
|
|
|
|
2019-03-15 20:02:03 +01:00
|
|
|
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)
|
2018-07-23 13:10:34 +02:00
|
|
|
{
|
|
|
|
GtkBuilder *main_builder;
|
|
|
|
GtkWidget *listbox;
|
2019-03-11 10:36:02 +01:00
|
|
|
GtkHeaderBar *header_bar;
|
2019-02-05 19:44:29 +01:00
|
|
|
struct tree_stores *cell_selector_stores;
|
2019-03-12 19:47:39 +01:00
|
|
|
GtkWidget *sort_up_button;
|
|
|
|
GtkWidget *sort_down_button;
|
2018-07-23 13:10:34 +02:00
|
|
|
|
|
|
|
main_builder = gtk_builder_new_from_resource("/main.glade");
|
|
|
|
|
2019-03-15 20:02:03 +01:00
|
|
|
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"));
|
2018-07-23 13:10:34 +02:00
|
|
|
|
2019-03-15 20:02:03 +01:00
|
|
|
cell_selector_stores = setup_cell_selector(self->cell_tree_view, GTK_ENTRY(self->cell_search_entry));
|
|
|
|
|
|
|
|
self->cell_tree_store = cell_selector_stores->base_store;
|
2018-07-23 13:10:34 +02:00
|
|
|
|
2019-03-15 20:02:03 +01:00
|
|
|
self->main_window = GTK_WINDOW(gtk_builder_get_object(main_builder, "main-window"));
|
|
|
|
g_signal_connect(GTK_WIDGET(gtk_builder_get_object(main_builder, "button-load-gds")),
|
|
|
|
"clicked", G_CALLBACK(on_load_gds), (gpointer)self);
|
2018-07-23 13:10:34 +02:00
|
|
|
|
2019-03-15 20:02:03 +01:00
|
|
|
self->convert_button = GTK_WIDGET(gtk_builder_get_object(main_builder, "convert-button"));
|
|
|
|
g_signal_connect(self->convert_button, "clicked", G_CALLBACK(on_convert_clicked), (gpointer)self);
|
2018-07-23 13:10:34 +02:00
|
|
|
|
|
|
|
listbox = GTK_WIDGET(gtk_builder_get_object(main_builder, "layer-list"));
|
2019-03-14 23:40:26 +01:00
|
|
|
/* Create layer selector */
|
2019-03-15 20:02:03 +01:00
|
|
|
self->layer_selector = layer_selector_new(GTK_LIST_BOX(listbox));
|
|
|
|
|
2018-07-23 13:10:34 +02:00
|
|
|
|
|
|
|
/* Callback for selection change of cell selector */
|
2019-03-15 20:02:03 +01:00
|
|
|
g_signal_connect(G_OBJECT(gtk_tree_view_get_selection(self->cell_tree_view)), "changed",
|
|
|
|
G_CALLBACK(cell_selection_changed), self);
|
|
|
|
g_signal_connect(self->cell_tree_view, "row-activated", G_CALLBACK(cell_tree_view_activated), self);
|
2018-07-23 13:10:34 +02:00
|
|
|
|
2019-03-11 10:36:02 +01:00
|
|
|
/* Set version in main window subtitle */
|
|
|
|
header_bar = GTK_HEADER_BAR(gtk_builder_get_object(main_builder, "header-bar"));
|
|
|
|
gtk_header_bar_set_subtitle(header_bar, _app_version_string);
|
|
|
|
|
2019-03-12 19:47:39 +01:00
|
|
|
/* Get layer sorting buttons and set callbacks */
|
|
|
|
sort_up_button = GTK_WIDGET(gtk_builder_get_object(main_builder, "button-up-sort"));
|
|
|
|
sort_down_button = GTK_WIDGET(gtk_builder_get_object(main_builder, "button-down-sort"));
|
|
|
|
|
2019-03-15 20:02:03 +01:00
|
|
|
g_signal_connect(sort_up_button, "clicked", G_CALLBACK(sort_up_callback), self);
|
|
|
|
g_signal_connect(sort_down_button, "clicked", G_CALLBACK(sort_down_callback), self);
|
2019-03-14 23:40:26 +01:00
|
|
|
|
|
|
|
/* Set buttons for loading and saving */
|
2019-03-15 20:02:03 +01:00
|
|
|
layer_selector_set_load_mapping_button(self->layer_selector,
|
2019-03-22 22:24:48 +01:00
|
|
|
GTK_WIDGET(gtk_builder_get_object(main_builder, "button-load-mapping")),
|
|
|
|
self->main_window);
|
2019-03-15 20:02:03 +01:00
|
|
|
layer_selector_set_save_mapping_button(self->layer_selector, GTK_WIDGET(gtk_builder_get_object(main_builder, "button-save-mapping")),
|
2019-03-22 22:24:48 +01:00
|
|
|
self->main_window);
|
2019-03-14 23:40:26 +01:00
|
|
|
|
|
|
|
/* Connect delete-event */
|
2019-03-15 20:02:03 +01:00
|
|
|
g_signal_connect(GTK_WIDGET(self->main_window), "delete-event",
|
|
|
|
G_CALLBACK(on_window_close), self);
|
2019-03-12 19:47:39 +01:00
|
|
|
|
2019-02-04 20:02:10 +01:00
|
|
|
g_object_unref(main_builder);
|
|
|
|
|
2019-03-22 21:59:27 +01:00
|
|
|
/* Set default conversion/rendering settings */
|
|
|
|
self->render_dialog_settings.scale = 1000;
|
|
|
|
self->render_dialog_settings.renderer = RENDERER_LATEX_TIKZ;
|
|
|
|
self->render_dialog_settings.tex_pdf_layers = FALSE;
|
|
|
|
self->render_dialog_settings.tex_standalone = FALSE;
|
|
|
|
|
|
|
|
|
2019-03-15 20:02:03 +01:00
|
|
|
/* 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));
|
2018-07-23 13:10:34 +02:00
|
|
|
}
|
2018-07-24 18:47:29 +02:00
|
|
|
|
|
|
|
/** @} */
|