diff --git a/glade/layer-widget.glade b/glade/layer-widget.glade index bc68892..3b20036 100644 --- a/glade/layer-widget.glade +++ b/glade/layer-widget.glade @@ -12,6 +12,24 @@ True False 3 + + + True + False + + + True + False + gtk-justify-fill + + + + + False + True + 0 + + True @@ -21,7 +39,7 @@ False True - 0 + 1 @@ -36,7 +54,7 @@ False True - 1 + 2 @@ -47,21 +65,6 @@ False True - - False - True - 2 - - - - - True - True - 5 - 5 - 4 - number - False True diff --git a/layer-selector.c b/layer-selector.c index 2b09451..b3fc654 100644 --- a/layer-selector.c +++ b/layer-selector.c @@ -24,9 +24,9 @@ #include #include -static GList *layer_widgets = NULL; -static GtkWidget *load_button; -static GtkWidget *save_button; +static GtkWidget *global_load_button; +static GtkWidget *global_save_button; +static GtkListBox *global_list_box; static void delete_layer_widget(GtkWidget *widget) { @@ -50,19 +50,23 @@ GList *export_rendered_layer_info() GList *info_list = NULL; LayerElement *le; struct layer_info *linfo; - GList *widget_list; + 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 (widget_list = layer_widgets; widget_list != NULL; widget_list = widget_list->next) { + for (i = 0, temp = row_list; temp != NULL; temp = temp->next, i++) { - le = LAYER_ELEMENT(widget_list->data); + 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 = layer_element_get_stack(le); + linfo->stacked_position = i; /* Append to list */ info_list = g_list_append(info_list, (gpointer)linfo); @@ -75,32 +79,39 @@ GList *export_rendered_layer_info() void clear_list_box_widgets(GtkListBox *box) { GList *list; + GList *temp; list = gtk_container_get_children(GTK_CONTAINER(box)); - for (;list != NULL; list = list->next) { - gtk_container_remove(GTK_CONTAINER(box), GTK_WIDGET(list->data)); + 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(layer_widgets); - layer_widgets = NULL; + + g_list_free(list); /* Deactivate buttons */ - gtk_widget_set_sensitive(load_button, FALSE); - gtk_widget_set_sensitive(save_button, FALSE); + gtk_widget_set_sensitive(global_load_button, FALSE); + gtk_widget_set_sensitive(global_save_button, FALSE); } static gboolean check_if_layer_widget_exists(int layer) { GList *list; + GList *temp; LayerElement *widget; gboolean ret = FALSE; - for (list = layer_widgets; list != NULL; list = list->next) { - widget = (LayerElement *)list->data; + 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; } @@ -117,31 +128,22 @@ static void analyze_cell_layers(GtkListBox *listbox, struct gds_cell *cell) if (check_if_layer_widget_exists(layer) == FALSE) { le = layer_element_new(); layer_element_set_layer(LAYER_ELEMENT(le), layer); - layer_element_set_stack(LAYER_ELEMENT(le), layer); gtk_list_box_insert(listbox, le, -1); gtk_widget_show(le); - layer_widgets = g_list_append(layer_widgets, le); } } } - gint sort_func(GtkListBoxRow *row1, GtkListBoxRow *row2, gpointer unused) { - GList *children1, *children2; LayerElement *le1, *le2; gint ret; - children1 = gtk_container_get_children(GTK_CONTAINER(row1)); - children2 = gtk_container_get_children(GTK_CONTAINER(row2)); - le1 = LAYER_ELEMENT(children1->data); - le2 = LAYER_ELEMENT(children2->data); + le1 = LAYER_ELEMENT(row1); + le2 = LAYER_ELEMENT(row2); ret = layer_element_get_layer(le1) - layer_element_get_layer(le2); - g_list_free(children1); - g_list_free(children2); - return ret; } @@ -150,6 +152,8 @@ void generate_layer_widgets(GtkListBox *listbox, GList *libs) GList *cell_list = NULL; struct gds_library *lib; + global_list_box = listbox; + clear_list_box_widgets(listbox); gtk_list_box_set_sort_func(listbox, sort_func, NULL, NULL); @@ -163,9 +167,12 @@ void generate_layer_widgets(GtkListBox *listbox, GList *libs) /* Force sort */ gtk_list_box_invalidate_sort(listbox); + /* Disable sort, so user can sort layers */ + gtk_list_box_set_sort_func(listbox, NULL, NULL, NULL); + /* Activate Buttons */ - gtk_widget_set_sensitive(load_button, TRUE); - gtk_widget_set_sensitive(save_button, TRUE); + gtk_widget_set_sensitive(global_load_button, TRUE); + gtk_widget_set_sensitive(global_save_button, TRUE); } /** @@ -178,7 +185,7 @@ void generate_layer_widgets(GtkListBox *listbox, GList *libs) * @param opacity * @return 0 if succesfull, 1 if line was malformatted or parameters are broken, -1 if file end */ -static int load_csv_line(GDataInputStream *stream, gboolean *export, char **name, int *layer, int *target_layer, GdkRGBA *color) +static int load_csv_line(GDataInputStream *stream, gboolean *export, char **name, int *layer, GdkRGBA *color) { int ret; gsize len; @@ -192,7 +199,7 @@ static int load_csv_line(GDataInputStream *stream, gboolean *export, char **name goto ret_direct; } - regex = g_regex_new("^(?[0-9]+),(?[0-9]+),(?[0-9\\.]+),(?[0-9\\.]+),(?[0-9\\.]+),(?[0-9\\.]+),(?[01]),(?.*)$", 0, 0, NULL); + regex = g_regex_new("^(?[0-9]+),(?[0-9\\.]+),(?[0-9\\.]+),(?[0-9\\.]+),(?[0-9\\.]+),(?[01]),(?.*)$", 0, 0, NULL); line = g_data_input_stream_read_line(stream, &len, NULL, NULL); if (!line) { @@ -207,9 +214,6 @@ static int load_csv_line(GDataInputStream *stream, gboolean *export, char **name match = g_match_info_fetch_named(mi, "layer"); *layer = (int)g_ascii_strtoll(match, NULL, 10); g_free(match); - match = g_match_info_fetch_named(mi, "target"); - *target_layer = (int)g_ascii_strtoll(match, NULL, 10); - g_free(match); match = g_match_info_fetch_named(mi, "r"); color->red = g_ascii_strtod(match, NULL); g_free(match); @@ -244,28 +248,23 @@ ret_direct: } -static LayerElement *find_layer_in_list(GList *list, int layer) +static LayerElement *find_layer_element_in_list(GList *el_list, int layer) { - LayerElement *le_found, *temp; - - for (le_found = NULL; list != NULL; list = list->next) { - temp = LAYER_ELEMENT(list->data); - if (layer_element_get_layer(temp) == layer) { - le_found = temp; + 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 le_found; + return ret; } - static void load_layer_mapping_from_file(gchar *file_name) { GFile *file; GFileInputStream *stream; GDataInputStream *dstream; - LayerElement *le; char *name; gboolean export; @@ -273,6 +272,8 @@ static void load_layer_mapping_from_file(gchar *file_name) int target_layer; GdkRGBA color; int result; + GList *rows; + GList *temp; file = g_file_new_for_path(file_name); stream = g_file_read(file, NULL, NULL); @@ -282,21 +283,48 @@ static void load_layer_mapping_from_file(gchar *file_name) dstream = g_data_input_stream_new(G_INPUT_STREAM(stream)); - while((result = load_csv_line(dstream, &export, &name, &layer, &target_layer, &color)) >= 0) { + 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)); + } + + target_layer = 0; + + while((result = load_csv_line(dstream, &export, &name, &layer, &color)) >= 0) { /* skip broken line */ if (result == 1) continue; - /* search for layer widget */ - if (le = find_layer_in_list(layer_widgets, layer)) { - layer_element_set_name(le, name); + /* 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_stack(le, target_layer); + layer_element_set_name(le, name); + + /* Dereference and remove from list */ + g_object_unref(G_OBJECT(le)); + rows = g_list_remove(rows, le); } - g_free(name); } + /* 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); @@ -327,7 +355,6 @@ static void create_csv_line(LayerElement *layer_element, char *line_buffer, size gboolean export; const gchar *name; int layer; - int target_layer; GdkRGBA color; string = g_string_new_len(NULL, max_len-1); @@ -336,12 +363,12 @@ static void create_csv_line(LayerElement *layer_element, char *line_buffer, size export = layer_element_get_export(layer_element); name = (const gchar*)layer_element_get_name(layer_element); layer = layer_element_get_layer(layer_element); - target_layer = layer_element_get_stack(layer_element); layer_element_get_color(layer_element, &color); + printf("Foo\n"); /* print values to line */ - g_string_printf(string, "%d,%d,%lf,%lf,%lf,%lf,%d,%s\n", - layer, target_layer, color.red, color.green, + g_string_printf(string, "%d,%lf,%lf,%lf,%lf,%d,%s\n", + layer, color.red, color.green, color.blue, color.alpha, (export == TRUE ? 1 : 0), name); if (string->len > (max_len-1)) { @@ -358,23 +385,28 @@ static void create_csv_line(LayerElement *layer_element, char *line_buffer, size g_string_free(string, TRUE); } -static void save_layer_mapping_data(const gchar *file_name) +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"); - /* File format is CSV: ,,,,,,, */ - for (le_list = layer_widgets; le_list != NULL; le_list = le_list->next) { + le_list = gtk_container_get_children(GTK_CONTAINER(list_box)); + + /* File format is CSV: ,,,,,,, */ + for (temp = le_list; temp != NULL; temp = temp->next) { /* To be sure it is a valid string */ workbuff[0] = 0; - create_csv_line((LayerElement *)le_list->data, workbuff, sizeof(workbuff)); + 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); @@ -391,7 +423,7 @@ static void save_mapping_clicked(GtkWidget *button, gpointer user_data) 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); + save_layer_mapping_data(file_name, global_list_box); g_free(file_name); } gtk_widget_destroy(dialog); @@ -400,13 +432,13 @@ static void save_mapping_clicked(GtkWidget *button, gpointer user_data) void setup_load_mapping_callback(GtkWidget *button, GtkWindow *main_window) { g_object_ref(G_OBJECT(button)); - load_button = 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)); - save_button = button; + global_save_button = button; g_signal_connect(button, "clicked", G_CALLBACK(save_mapping_clicked), main_window); } diff --git a/layer-widget/layer-element.c b/layer-widget/layer-element.c index 72d16f8..b219a4d 100644 --- a/layer-widget/layer-element.c +++ b/layer-widget/layer-element.c @@ -19,7 +19,7 @@ #include "layer-element.h" -G_DEFINE_TYPE(LayerElement, layer_element, GTK_TYPE_BOX) +G_DEFINE_TYPE(LayerElement, layer_element, GTK_TYPE_LIST_BOX_ROW) static void layer_element_dispose(GObject *obj) { @@ -39,23 +39,98 @@ static void layer_element_class_init(LayerElementClass *klass) 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; + + 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); +} + +static void layer_element_drag_data_get(GtkWidget *widget, + GdkDragContext *context, + GtkSelectionData *selection_data, + guint info, + guint time, + gpointer 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_drag_data_received(GtkWidget *widget, + GdkDragContext *context, + gint x, + gint y, + GtkSelectionData *selection_data, + guint info, + guint32 time, + gpointer data) +{ + GtkWidget *target; + GtkWidget *row; + GtkWidget *source; + int pos; + + target = widget; + + pos = gtk_list_box_row_get_index (GTK_LIST_BOX_ROW (target)); + row = (gpointer) *(gpointer *)gtk_selection_data_get_data (selection_data); + source = gtk_widget_get_ancestor (row, GTK_TYPE_LIST_BOX_ROW); + + if (source == target) + return; + + g_object_ref (source); + gtk_container_remove (GTK_CONTAINER (gtk_widget_get_parent (source)), source); + gtk_list_box_insert (GTK_LIST_BOX (gtk_widget_get_parent (target)), source, pos); + g_object_unref (source); +} + static void layer_element_init(LayerElement *self) { GtkBuilder *builder; GtkWidget *glade_box; builder = gtk_builder_new_from_resource("/layer-widget.glade"); glade_box = GTK_WIDGET(gtk_builder_get_object(builder, "box")); - gtk_box_pack_start(GTK_BOX(self), glade_box, TRUE, TRUE, 0); + gtk_container_add(GTK_CONTAINER(self), glade_box); /* Get Elements */ self->priv.color = GTK_COLOR_BUTTON(gtk_builder_get_object(builder, "color")); self->priv.export = GTK_CHECK_BUTTON(gtk_builder_get_object(builder, "export")); self->priv.layer = GTK_LABEL(gtk_builder_get_object(builder, "layer")); self->priv.name = GTK_ENTRY(gtk_builder_get_object(builder, "entry")); - self->priv.stack = GTK_ENTRY(gtk_builder_get_object(builder, "entry-stack")); + self->priv.event_handle = GTK_EVENT_BOX(gtk_builder_get_object(builder, "event-box")); - /* Connect signals */ - /* None */ + /* Setup drag and drop */ + 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); + gtk_drag_dest_set(GTK_WIDGET(self), GTK_DEST_DEFAULT_ALL, entries, 1, GDK_ACTION_MOVE); + g_signal_connect(GTK_WIDGET(self), "drag-data-received", G_CALLBACK(layer_element_drag_data_received), NULL); g_object_unref(builder); } @@ -91,25 +166,6 @@ int layer_element_get_layer(LayerElement *elem) return elem->priv.layer_num; } - -void layer_element_set_stack(LayerElement *elem, int layer) -{ - GString *string; - - string = g_string_new_len(NULL, 20); - g_string_printf(string, "%d", layer); - gtk_entry_set_text(elem->priv.stack, (const gchar *)string->str); - g_string_free(string, TRUE); -} - -int layer_element_get_stack(LayerElement *elem) -{ - const char *txt; - - txt = gtk_entry_get_text(elem->priv.stack); - return (int)g_ascii_strtoll(txt, NULL, 10); -} - void layer_element_set_export(LayerElement *elem, gboolean export) { gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(elem->priv.export), export); diff --git a/layer-widget/layer-element.h b/layer-widget/layer-element.h index 42709b4..4c98de3 100644 --- a/layer-widget/layer-element.h +++ b/layer-widget/layer-element.h @@ -25,7 +25,7 @@ G_BEGIN_DECLS /* Creates Class structure etc */ -G_DECLARE_FINAL_TYPE(LayerElement, layer_element, LAYER, ELEMENT, GtkBox) +G_DECLARE_FINAL_TYPE(LayerElement, layer_element, LAYER, ELEMENT, GtkListBoxRow) #define TYPE_LAYER_ELEMENT (layer_element_get_type()) @@ -33,14 +33,14 @@ typedef struct _LayerElementPriv { GtkEntry *name; GtkLabel *layer; int layer_num; + GtkEventBox *event_handle; GtkColorButton *color; GtkCheckButton *export; - GtkEntry *stack; } LayerElementPriv; typedef struct _LayerElement { /* Inheritance */ - GtkBox hbox; + GtkListBoxRow parent; /* Custom Elements */ LayerElementPriv priv; } LayerElement; @@ -51,10 +51,6 @@ const char *layer_element_get_name(LayerElement *elem); void layer_element_set_name(LayerElement *elem, const char* name); void layer_element_set_layer(LayerElement *elem, int layer); int layer_element_get_layer(LayerElement *elem); - -void layer_element_set_stack(LayerElement *elem, int layer); -int layer_element_get_stack(LayerElement *elem); - void layer_element_set_export(LayerElement *elem, gboolean export); gboolean layer_element_get_export(LayerElement *elem); void layer_element_get_color(LayerElement *elem, GdkRGBA *rgba);