rework layer selector. This commit is compilable. Layer selector is now a separate GObject

This commit is contained in:
Mario Hüttel 2019-03-14 23:40:26 +01:00
parent c9e2c2a76d
commit c94c3d591e
5 changed files with 399 additions and 317 deletions

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

@ -28,6 +28,4 @@
#include <gtk/gtk.h> #include <gtk/gtk.h>
void layer_selector_list_box_setup_dnd(GtkListBox *box);
#endif /* _LAYER_SELECTOR_DND_H_ */ #endif /* _LAYER_SELECTOR_DND_H_ */

View File

@ -29,6 +29,7 @@
*/ */
#include "layer-selector.h" #include "layer-selector.h"
#include "layer-selector-dnd.h"
#include "layer-info.h" #include "layer-info.h"
#include "../gds-parser/gds-parser.h" #include "../gds-parser/gds-parser.h"
#include "../widgets/layer-element.h" #include "../widgets/layer-element.h"
@ -38,15 +39,272 @@
#include <stdio.h> #include <stdio.h>
#include <stdlib.h> #include <stdlib.h>
static GtkWidget *global_load_button; struct _LayerSelector {
static GtkWidget *global_save_button; /* Parent */
static GtkListBox *global_list_box; GObject parent;
/* Own fields */
GtkWidget *associated_load_button;
GtkWidget *associated_save_button;
GtkWindow *load_parent_window;
GtkWindow *save_parent_window;
GtkListBox *list_box;
/** gpointer dummy[4];
* @brief export_rendered_layer_info };
* @return new list with all info elements needed to render cells
*/ G_DEFINE_TYPE(LayerSelector, layer_selector, G_TYPE_OBJECT)
GList *export_rendered_layer_info()
/* Drag and drop code */
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; "
"}";
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);
/* 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(GtkListBox *box)
{
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);
}
/* Drag and drop end */
static void layer_selector_init(LayerSelector *self)
{
/* Setup drag and drop for associated list box */
self->load_parent_window = NULL;
self->save_parent_window = NULL;
self->associated_load_button = NULL;
self->associated_save_button = NULL;
}
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(list_box);
g_object_ref(G_OBJECT(list_box));
return selector;
}
GList *layer_selector_export_rendered_layer_info(LayerSelector *selector)
{ {
GList *info_list = NULL; GList *info_list = NULL;
LayerElement *le; LayerElement *le;
@ -55,7 +313,10 @@ GList *export_rendered_layer_info()
GList *temp; GList *temp;
int i; int i;
row_list = gtk_container_get_children(GTK_CONTAINER(global_list_box)); 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 */ /* Iterate through widgets and add layers that shall be exported */
for (i = 0, temp = row_list; temp != NULL; temp = temp->next, i++) { for (i = 0, temp = row_list; temp != NULL; temp = temp->next, i++) {
@ -78,22 +339,24 @@ GList *export_rendered_layer_info()
return info_list; return info_list;
} }
void clear_list_box_widgets(GtkListBox *box) static void layer_selector_clear_widgets(LayerSelector *self)
{ {
GList *list; GList *list;
GList *temp; GList *temp;
list = gtk_container_get_children(GTK_CONTAINER(box)); list = gtk_container_get_children(GTK_CONTAINER(self->list_box));
for (temp = list; temp != NULL; temp = temp->next) { for (temp = list; temp != NULL; temp = temp->next) {
gtk_container_remove(GTK_CONTAINER(box), GTK_WIDGET(temp->data)); gtk_container_remove(GTK_CONTAINER(self->list_box), GTK_WIDGET(temp->data));
} }
/* Widgets are already destroyed when removed from box because they are only referenced inside the container */ /* Widgets are already destroyed when removed from box because they are only referenced inside the container */
g_list_free(list); g_list_free(list);
/* Deactivate buttons */ /* Deactivate buttons */
gtk_widget_set_sensitive(global_load_button, FALSE); if (self->associated_load_button)
gtk_widget_set_sensitive(global_save_button, FALSE); gtk_widget_set_sensitive(self->associated_load_button, FALSE);
if (self->associated_save_button)
gtk_widget_set_sensitive(self->associated_save_button, FALSE);
} }
/** /**
@ -101,13 +364,13 @@ void clear_list_box_widgets(GtkListBox *box)
* @param layer Layer nu,ber * @param layer Layer nu,ber
* @return TRUE if present * @return TRUE if present
*/ */
static gboolean check_if_layer_widget_exists(int layer) { static gboolean layer_selector_check_if_layer_widget_exists(LayerSelector *self, int layer) {
GList *list; GList *list;
GList *temp; GList *temp;
LayerElement *widget; LayerElement *widget;
gboolean ret = FALSE; gboolean ret = FALSE;
list = gtk_container_get_children(GTK_CONTAINER(global_list_box)); list = gtk_container_get_children(GTK_CONTAINER(self->list_box));
for (temp = list; temp != NULL; temp = temp->next) { for (temp = list; temp != NULL; temp = temp->next) {
widget = LAYER_ELEMENT(temp->data); widget = LAYER_ELEMENT(temp->data);
@ -127,7 +390,7 @@ static gboolean check_if_layer_widget_exists(int layer) {
* @param listbox listbox to add layer * @param listbox listbox to add layer
* @param cell Cell to analyze * @param cell Cell to analyze
*/ */
static void analyze_cell_layers(GtkListBox *listbox, struct gds_cell *cell) static void layer_selector_analyze_cell_layers(LayerSelector *self, struct gds_cell *cell)
{ {
GList *graphics; GList *graphics;
struct gds_graphics *gfx; struct gds_graphics *gfx;
@ -137,10 +400,10 @@ static void analyze_cell_layers(GtkListBox *listbox, struct gds_cell *cell)
for (graphics = cell->graphic_objs; graphics != NULL; graphics = graphics->next) { for (graphics = cell->graphic_objs; graphics != NULL; graphics = graphics->next) {
gfx = (struct gds_graphics *)graphics->data; gfx = (struct gds_graphics *)graphics->data;
layer = (int)gfx->layer; layer = (int)gfx->layer;
if (check_if_layer_widget_exists(layer) == FALSE) { if (layer_selector_check_if_layer_widget_exists(self, layer) == FALSE) {
le = layer_element_new(); le = layer_element_new();
layer_element_set_layer(LAYER_ELEMENT(le), layer); layer_element_set_layer(LAYER_ELEMENT(le), layer);
gtk_list_box_insert(listbox, le, -1); gtk_list_box_insert(self->list_box, le, -1);
gtk_widget_show(le); gtk_widget_show(le);
} }
} }
@ -154,7 +417,7 @@ static void analyze_cell_layers(GtkListBox *listbox, struct gds_cell *cell)
* @note Do not use this function. This is an internal callback * @note Do not use this function. This is an internal callback
* @return See sort function documentation of GTK+ * @return See sort function documentation of GTK+
*/ */
static gint sort_func(GtkListBoxRow *row1, GtkListBoxRow *row2, gpointer unused) static gint layer_selector_sort_func(GtkListBoxRow *row1, GtkListBoxRow *row2, gpointer unused)
{ {
LayerElement *le1, *le2; LayerElement *le1, *le2;
gint ret; gint ret;
@ -178,28 +441,28 @@ static gint sort_func(GtkListBoxRow *row1, GtkListBoxRow *row2, gpointer unused)
return ret; return ret;
} }
void generate_layer_widgets(GtkListBox *listbox, GList *libs) void layer_selector_generate_layer_widgets(LayerSelector *selector, GList *libs)
{ {
GList *cell_list = NULL; GList *cell_list = NULL;
struct gds_library *lib; struct gds_library *lib;
global_list_box = listbox; layer_selector_clear_widgets(selector);
clear_list_box_widgets(listbox);
for (; libs != NULL; libs = libs->next) { for (; libs != NULL; libs = libs->next) {
lib = (struct gds_library *)libs->data; lib = (struct gds_library *)libs->data;
for (cell_list = lib->cells; cell_list != NULL; cell_list = cell_list->next) { for (cell_list = lib->cells; cell_list != NULL; cell_list = cell_list->next) {
analyze_cell_layers(listbox, (struct gds_cell *)cell_list->data); layer_selector_analyze_cell_layers(selector, (struct gds_cell *)cell_list->data);
} /* For Cell List */ } /* For Cell List */
} /* For libs */ } /* For libs */
/* Sort the layers */ /* Sort the layers */
layer_selector_force_sort(LAYER_SELECTOR_SORT_DOWN); layer_selector_force_sort(selector, LAYER_SELECTOR_SORT_DOWN);
/* Activate Buttons */ /* Activate Buttons */
gtk_widget_set_sensitive(global_load_button, TRUE); if (selector->associated_load_button)
gtk_widget_set_sensitive(global_save_button, TRUE); gtk_widget_set_sensitive(selector->associated_load_button, TRUE);
if (selector->associated_save_button)
gtk_widget_set_sensitive(selector->associated_save_button, TRUE);
} }
/** /**
@ -208,7 +471,7 @@ void generate_layer_widgets(GtkListBox *listbox, GList *libs)
* @param layer Layer number * @param layer Layer number
* @return Found LayerElement. If nothing is found, NULL. * @return Found LayerElement. If nothing is found, NULL.
*/ */
static LayerElement *find_layer_element_in_list(GList *el_list, int layer) static LayerElement *layer_selector_find_layer_element_in_list(GList *el_list, int layer)
{ {
LayerElement *ret = NULL; LayerElement *ret = NULL;
for (; el_list != NULL; el_list = el_list->next) { for (; el_list != NULL; el_list = el_list->next) {
@ -224,7 +487,7 @@ static LayerElement *find_layer_element_in_list(GList *el_list, int layer)
* @brief Load file and apply layer definitions to listbox * @brief Load file and apply layer definitions to listbox
* @param file_name CSV Layer Mapping File * @param file_name CSV Layer Mapping File
*/ */
static void load_layer_mapping_from_file(gchar *file_name) static void layer_selector_load_layer_mapping_from_file(LayerSelector *self, gchar *file_name)
{ {
GFile *file; GFile *file;
GFileInputStream *stream; GFileInputStream *stream;
@ -246,14 +509,14 @@ static void load_layer_mapping_from_file(gchar *file_name)
dstream = g_data_input_stream_new(G_INPUT_STREAM(stream)); dstream = g_data_input_stream_new(G_INPUT_STREAM(stream));
rows = gtk_container_get_children(GTK_CONTAINER(global_list_box)); rows = gtk_container_get_children(GTK_CONTAINER(self->list_box));
/* Reference and remove all rows from box */ /* Reference and remove all rows from box */
for (temp = rows; temp != NULL; temp = temp->next) { for (temp = rows; temp != NULL; temp = temp->next) {
le = LAYER_ELEMENT(temp->data); le = LAYER_ELEMENT(temp->data);
/* Referencing protets the widget from being deleted when removed */ /* Referencing protets the widget from being deleted when removed */
g_object_ref(G_OBJECT(le)); g_object_ref(G_OBJECT(le));
gtk_container_remove(GTK_CONTAINER(global_list_box), GTK_WIDGET(le)); gtk_container_remove(GTK_CONTAINER(self->list_box), GTK_WIDGET(le));
} }
while((result = load_csv_line(dstream, &export, &name, &layer, &color)) >= 0) { while((result = load_csv_line(dstream, &export, &name, &layer, &color)) >= 0) {
@ -262,8 +525,8 @@ static void load_layer_mapping_from_file(gchar *file_name)
continue; continue;
/* Add rows in the same order as in file */ /* Add rows in the same order as in file */
if ((le = find_layer_element_in_list(rows, layer))) { if ((le = layer_selector_find_layer_element_in_list(rows, layer))) {
gtk_list_box_insert(global_list_box, GTK_WIDGET(le), -1); gtk_list_box_insert(self->list_box, GTK_WIDGET(le), -1);
layer_element_set_color(le, &color); layer_element_set_color(le, &color);
layer_element_set_export(le, export); layer_element_set_export(le, export);
@ -280,7 +543,7 @@ static void load_layer_mapping_from_file(gchar *file_name)
for (temp = rows; temp != NULL; temp = temp->next) { for (temp = rows; temp != NULL; temp = temp->next) {
le = LAYER_ELEMENT(temp->data); le = LAYER_ELEMENT(temp->data);
/* Referencing protets the widget from being deleted when removed */ /* Referencing protets the widget from being deleted when removed */
gtk_list_box_insert(global_list_box, GTK_WIDGET(le), -1); gtk_list_box_insert(self->list_box, GTK_WIDGET(le), -1);
g_object_unref(G_OBJECT(le)); g_object_unref(G_OBJECT(le));
} }
@ -299,18 +562,21 @@ destroy_file:
* @param button * @param button
* @param user_data * @param user_data
*/ */
static void load_mapping_clicked(GtkWidget *button, gpointer user_data) static void layer_selector_load_mapping_clicked(GtkWidget *button, gpointer user_data)
{ {
LayerSelector *sel;
GtkWidget *dialog; GtkWidget *dialog;
gint res; gint res;
gchar *file_name; gchar *file_name;
dialog = gtk_file_chooser_dialog_new("Load Mapping File", GTK_WINDOW(user_data), GTK_FILE_CHOOSER_ACTION_OPEN, 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); "Cancel", GTK_RESPONSE_CANCEL, "Load Mapping", GTK_RESPONSE_ACCEPT, NULL);
res = gtk_dialog_run(GTK_DIALOG(dialog)); res = gtk_dialog_run(GTK_DIALOG(dialog));
if (res == GTK_RESPONSE_ACCEPT) { if (res == GTK_RESPONSE_ACCEPT) {
file_name = gtk_file_chooser_get_filename(GTK_FILE_CHOOSER(dialog)); file_name = gtk_file_chooser_get_filename(GTK_FILE_CHOOSER(dialog));
load_layer_mapping_from_file(file_name); layer_selector_load_layer_mapping_from_file(sel, file_name);
g_free(file_name); g_free(file_name);
} }
gtk_widget_destroy(dialog); gtk_widget_destroy(dialog);
@ -323,7 +589,7 @@ static void load_mapping_clicked(GtkWidget *button, gpointer user_data)
* @param file_name layer mapping file * @param file_name layer mapping file
* @param list_box listbox * @param list_box listbox
*/ */
static void save_layer_mapping_data(const gchar *file_name, GtkListBox *list_box) static void layer_selector_save_layer_mapping_data(LayerSelector *self, const gchar *file_name)
{ {
FILE *file; FILE *file;
char workbuff[512]; char workbuff[512];
@ -333,7 +599,7 @@ static void save_layer_mapping_data(const gchar *file_name, GtkListBox *list_box
/* Overwrite existing file */ /* Overwrite existing file */
file = fopen((const char *)file_name, "w"); file = fopen((const char *)file_name, "w");
le_list = gtk_container_get_children(GTK_CONTAINER(list_box)); le_list = gtk_container_get_children(GTK_CONTAINER(self->list_box));
/* File format is CSV: <Layer>,<target_pos>,<R>,<G>,<B>,<Alpha>,<Export?>,<Name> */ /* File format is CSV: <Layer>,<target_pos>,<R>,<G>,<B>,<Alpha>,<Export?>,<Name> */
for (temp = le_list; temp != NULL; temp = temp->next) { for (temp = le_list; temp != NULL; temp = temp->next) {
@ -355,48 +621,67 @@ static void save_layer_mapping_data(const gchar *file_name, GtkListBox *list_box
* @param button * @param button
* @param user_data * @param user_data
*/ */
static void save_mapping_clicked(GtkWidget *button, gpointer user_data) static void layer_selector_save_mapping_clicked(GtkWidget *button, gpointer user_data)
{ {
GtkWidget *dialog; GtkWidget *dialog;
gint res; gint res;
gchar *file_name; gchar *file_name;
LayerSelector *sel;
dialog = gtk_file_chooser_dialog_new("Save Mapping File", GTK_WINDOW(user_data), GTK_FILE_CHOOSER_ACTION_SAVE, 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); "Cancel", GTK_RESPONSE_CANCEL, "Save Mapping", GTK_RESPONSE_ACCEPT, NULL);
gtk_file_chooser_set_do_overwrite_confirmation(GTK_FILE_CHOOSER(dialog), TRUE); gtk_file_chooser_set_do_overwrite_confirmation(GTK_FILE_CHOOSER(dialog), TRUE);
res = gtk_dialog_run(GTK_DIALOG(dialog)); res = gtk_dialog_run(GTK_DIALOG(dialog));
if (res == GTK_RESPONSE_ACCEPT) { if (res == GTK_RESPONSE_ACCEPT) {
file_name = gtk_file_chooser_get_filename(GTK_FILE_CHOOSER(dialog)); file_name = gtk_file_chooser_get_filename(GTK_FILE_CHOOSER(dialog));
save_layer_mapping_data(file_name, global_list_box); layer_selector_save_layer_mapping_data(sel, file_name);
g_free(file_name); g_free(file_name);
} }
gtk_widget_destroy(dialog); gtk_widget_destroy(dialog);
} }
void setup_load_mapping_callback(GtkWidget *button, GtkWindow *main_window) 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(button));
global_load_button = button; g_object_ref(G_OBJECT(main_window));
g_signal_connect(button, "clicked", G_CALLBACK(load_mapping_clicked), 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 setup_save_mapping_callback(GtkWidget *button, GtkWindow *main_window) 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(button));
global_save_button = button; g_object_ref(G_OBJECT(main_window));
g_signal_connect(button, "clicked", G_CALLBACK(save_mapping_clicked), 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(enum layer_selector_sort_algo sort_function) void layer_selector_force_sort(LayerSelector *selector, enum layer_selector_sort_algo sort_function)
{ {
if (!global_list_box) GtkListBox *box;
if (!selector)
return;
box = selector->list_box;
if (!box)
return; return;
/* Set dorting function, sort, and disable sorting function */ /* 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_set_sort_func(box, layer_selector_sort_func, (gpointer)&sort_function, NULL);
gtk_list_box_invalidate_sort(global_list_box); gtk_list_box_invalidate_sort(box);
gtk_list_box_set_sort_func(global_list_box, NULL, NULL, NULL); gtk_list_box_set_sort_func(box, NULL, NULL, NULL);
} }
/** @} */ /** @} */

View File

@ -29,38 +29,51 @@
#include <gtk/gtk.h> #include <gtk/gtk.h>
#include <glib.h> #include <glib.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 libraries to add * @param libs The libraries to add
*/ */
void layer_selector_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 layer_selector_set_load_mapping_button(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 Parent window for dialogs * @param main_window Parent window for dialogs
*/ */
void layer_selector_set_save_mapping_button(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 *layer_selector_export_rendered_layer_info(void); GList *layer_selector_export_rendered_layer_info(LayerSelector *selector);
/** /**
* @brief Force sorting of the layer selector in a specified way * @brief Force sorting of the layer selector in a specified way
@ -69,6 +82,8 @@ GList *layer_selector_export_rendered_layer_info(void);
* *
* @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__ */

View File

@ -48,8 +48,8 @@ struct open_button_data {
GtkWindow *main_window; GtkWindow *main_window;
GList **list_ptr; GList **list_ptr;
GtkTreeStore *cell_store; GtkTreeStore *cell_store;
GtkListBox *layer_box;
GtkSearchEntry *search_entry; GtkSearchEntry *search_entry;
LayerSelector *layer_selector;
}; };
/** /**
@ -58,6 +58,7 @@ struct open_button_data {
struct convert_button_data { struct convert_button_data {
GtkTreeView *tree_view; GtkTreeView *tree_view;
GtkWindow *main_window; GtkWindow *main_window;
LayerSelector *layer_selector;
}; };
/** /**
@ -68,8 +69,12 @@ 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)
{ {
/* Destroy all objects helb by this module, that are not part of the GUI itself */
g_object_unref(LAYER_SELECTOR(user));
/* Close Window. Leads to termination of the program */
gtk_widget_destroy(GTK_WIDGET(window)); gtk_widget_destroy(GTK_WIDGET(window));
return TRUE; return TRUE;
} }
@ -210,7 +215,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(ptr->layer_selector, *(ptr->list_ptr));
} }
end_destroy: end_destroy:
@ -259,7 +264,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(data->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,7 +272,7 @@ 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);
@ -387,17 +392,23 @@ static void cell_selection_changed(GtkTreeSelection *sel, GtkWidget *convert_but
static void sort_up_callback(GtkWidget *widget, gpointer user) static void sort_up_callback(GtkWidget *widget, gpointer user)
{ {
(void)widget; (void)widget;
(void)user; LayerSelector *sel;
layer_selector_force_sort(LAYER_SELECTOR_SORT_UP); sel = LAYER_SELECTOR(user);
if (!sel)
return;
layer_selector_force_sort(sel, 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; LayerSelector *sel;
layer_selector_force_sort(LAYER_SELECTOR_SORT_DOWN); sel = LAYER_SELECTOR(user);
if (!sel)
return;
layer_selector_force_sort(sel, LAYER_SELECTOR_SORT_DOWN);
} }
GtkWindow *create_main_window() GtkWindow *create_main_window()
@ -408,6 +419,7 @@ GtkWindow *create_main_window()
GtkWidget *conv_button; GtkWidget *conv_button;
GtkWidget *search_entry; GtkWidget *search_entry;
GtkHeaderBar *header_bar; GtkHeaderBar *header_bar;
LayerSelector *layer_selector;
static GList *gds_libs; static GList *gds_libs;
static struct open_button_data open_data; static struct open_button_data open_data;
static struct convert_button_data conv_data; static struct convert_button_data conv_data;
@ -429,10 +441,6 @@ GtkWindow *create_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)&open_data);
/* Connect delete-event */
g_signal_connect(GTK_WIDGET(open_data.main_window), "delete-event",
G_CALLBACK(on_window_close), NULL);
/* Connect Convert button */ /* Connect Convert button */
conv_data.tree_view = cell_tree; conv_data.tree_view = cell_tree;
conv_data.main_window = open_data.main_window; conv_data.main_window = open_data.main_window;
@ -441,16 +449,10 @@ GtkWindow *create_main_window()
g_signal_connect(conv_button, "clicked", G_CALLBACK(on_convert_clicked), &conv_data); 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)); layer_selector = layer_selector_new(GTK_LIST_BOX(listbox));
conv_data.layer_selector = layer_selector;
open_data.layer_box = GTK_LIST_BOX(listbox); open_data.layer_selector = layer_selector;
/* 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(cell_tree)), "changed",
@ -465,8 +467,21 @@ 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), layer_selector);
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), layer_selector);
/* Set buttons for loading and saving */
layer_selector_set_load_mapping_button(layer_selector,
GTK_WIDGET(gtk_builder_get_object(main_builder, "button-load-mapping")),
conv_data.main_window);
layer_selector_set_save_mapping_button(layer_selector, GTK_WIDGET(gtk_builder_get_object(main_builder, "button-save-mapping")),
conv_data.main_window);
/* Connect delete-event */
g_signal_connect(GTK_WIDGET(open_data.main_window), "delete-event",
G_CALLBACK(on_window_close), layer_selector);
g_object_unref(main_builder); g_object_unref(main_builder);