# HG changeset patch # User nadvornik # Date 1236122227 0 # Node ID 27ba259d3496c75e90bd110a6072ad5f4ed58450 # Parent 168e5597ddc7fb766575153535de20fa2bc839ad reorder exif pane entries with drag and drop diff -r 168e5597ddc7 -r 27ba259d3496 src/bar_exif.c --- a/src/bar_exif.c Mon Mar 02 22:48:04 2009 +0000 +++ b/src/bar_exif.c Tue Mar 03 23:17:07 2009 +0000 @@ -22,6 +22,7 @@ #include "ui_misc.h" #include "bar.h" #include "rcfile.h" +#include "dnd.h" #include @@ -36,6 +37,7 @@ typedef struct _ExifEntry ExifEntry; struct _ExifEntry { + GtkWidget *ebox; GtkWidget *hbox; GtkWidget *title_label; GtkWidget *value_label; @@ -60,6 +62,7 @@ FileData *fd; }; +static void bar_pane_exif_entry_dnd_init(GtkWidget *entry); static void bar_pane_exif_update_entry(PaneExifData *ped, GtkWidget *entry, gboolean update_title); static void bar_pane_exif_entry_destroy(GtkWidget *widget, gpointer data) @@ -72,7 +75,7 @@ } -static void bar_pane_exif_add_entry(PaneExifData *ped, const gchar *key, const gchar *title, gint if_set) +static GtkWidget *bar_pane_exif_add_entry(PaneExifData *ped, const gchar *key, const gchar *title, gint if_set) { ExifEntry *ee = g_new0(ExifEntry, 1); @@ -89,11 +92,15 @@ ee->if_set = if_set; - ee->hbox = gtk_hbox_new(FALSE, 0); - g_object_set_data(G_OBJECT(ee->hbox), "entry_data", ee); - g_signal_connect_after(G_OBJECT(ee->hbox), "destroy", + ee->ebox = gtk_event_box_new(); + g_object_set_data(G_OBJECT(ee->ebox), "entry_data", ee); + g_signal_connect_after(G_OBJECT(ee->ebox), "destroy", G_CALLBACK(bar_pane_exif_entry_destroy), ee); + ee->hbox = gtk_hbox_new(FALSE, 0); + gtk_container_add(GTK_CONTAINER(ee->ebox), ee->hbox); + gtk_widget_show(ee->hbox); + ee->title_label = gtk_label_new(NULL); gtk_misc_set_alignment(GTK_MISC(ee->title_label), 1.0, 0.5); gtk_size_group_add_widget(ped->size_group, ee->title_label); @@ -107,11 +114,31 @@ gtk_misc_set_alignment(GTK_MISC(ee->value_label), 0.0, 0.5); gtk_box_pack_start(GTK_BOX(ee->hbox), ee->value_label, TRUE, TRUE, 1); gtk_widget_show(ee->value_label); + gtk_box_pack_start(GTK_BOX(ped->vbox), ee->ebox, TRUE, TRUE, 0); + + bar_pane_exif_entry_dnd_init(ee->ebox); - gtk_box_pack_start(GTK_BOX(ped->vbox), ee->hbox, TRUE, TRUE, 0); - bar_pane_exif_update_entry(ped, ee->hbox, TRUE); + bar_pane_exif_update_entry(ped, ee->ebox, TRUE); + return ee->ebox; } + +static void bar_pane_exif_reparent_entry(GtkWidget *entry, GtkWidget *pane) +{ + GtkWidget *old_pane = entry->parent; + PaneExifData *ped = g_object_get_data(G_OBJECT(pane), "pane_data"); + PaneExifData *old_ped = g_object_get_data(G_OBJECT(old_pane), "pane_data"); + ExifEntry *ee = g_object_get_data(G_OBJECT(entry), "entry_data"); + if (!ped || !old_ped || !ee) return; + g_object_ref(entry); + + gtk_size_group_remove_widget(old_ped->size_group, ee->title_label); + gtk_container_remove(GTK_CONTAINER(old_ped->vbox), entry); + + gtk_size_group_add_widget(ped->size_group, ee->title_label); + gtk_box_pack_start(GTK_BOX(ped->vbox), entry, TRUE, TRUE, 0); +} + static void bar_pane_exif_entry_update_title(ExifEntry *ee) { gchar *markup; @@ -131,7 +158,7 @@ if (ee->if_set && (!text || !*text)) { gtk_label_set_text(GTK_LABEL(ee->value_label), NULL); - gtk_widget_hide(ee->hbox); + gtk_widget_hide(entry); } else { @@ -139,7 +166,7 @@ #if GTK_CHECK_VERSION(2,12,0) gtk_widget_set_tooltip_text(ee->hbox, text); #endif - gtk_widget_show(ee->hbox); + gtk_widget_show(entry); } g_free(text); @@ -177,6 +204,7 @@ { GtkWidget *entry = work->data; work = work->next; + bar_pane_exif_update_entry(ped, entry, FALSE); } @@ -196,6 +224,131 @@ bar_pane_exif_update(ped); } +/* + *------------------------------------------------------------------- + * dnd + *------------------------------------------------------------------- + */ + +static GtkTargetEntry bar_pane_exif_drag_types[] = { + { TARGET_APP_EXIF_ENTRY_STRING, GTK_TARGET_SAME_APP, TARGET_APP_EXIF_ENTRY }, + { "text/plain", 0, TARGET_TEXT_PLAIN } +}; +static gint n_exif_entry_drag_types = 2; + +static GtkTargetEntry bar_pane_exif_drop_types[] = { + { TARGET_APP_EXIF_ENTRY_STRING, GTK_TARGET_SAME_APP, TARGET_APP_EXIF_ENTRY }, + { "text/plain", 0, TARGET_TEXT_PLAIN } +}; +static gint n_exif_entry_drop_types = 2; + + +static void bar_pane_exif_entry_dnd_get(GtkWidget *entry, GdkDragContext *context, + GtkSelectionData *selection_data, guint info, + guint time, gpointer data) +{ + ExifEntry *ee = g_object_get_data(G_OBJECT(entry), "entry_data"); + + switch (info) + { + + case TARGET_APP_EXIF_ENTRY: + gtk_selection_data_set(selection_data, selection_data->target, + 8, (gpointer) &entry, sizeof(entry)); + break; + + case TARGET_TEXT_PLAIN: + default: + gtk_selection_data_set_text(selection_data, ee->key, -1); + break; + } + +} + +static void bar_pane_exif_dnd_receive(GtkWidget *pane, GdkDragContext *context, + gint x, gint y, + GtkSelectionData *selection_data, guint info, + guint time, gpointer data) +{ + PaneExifData *ped; + GList *work, *list; + gint pos; + GtkWidget *new_entry = NULL; + ped = g_object_get_data(G_OBJECT(pane), "pane_data"); + if (!ped) return; + + switch (info) + { + case TARGET_APP_EXIF_ENTRY: + new_entry = *(gpointer *)selection_data->data; + + if (new_entry->parent && new_entry->parent != ped->vbox) bar_pane_exif_reparent_entry(new_entry, pane); + + break; + default: + /* FIXME: this needs a check for valid exif keys */ + new_entry = bar_pane_exif_add_entry(ped, (gchar *)selection_data->data, NULL, TRUE); + break; + } + + + list = gtk_container_get_children(GTK_CONTAINER(ped->vbox)); + work = list; + pos = 0; + while (work) + { + gint nx, ny; + GtkWidget *entry = work->data; + work = work->next; + + if (entry == new_entry) continue; + + if (GTK_WIDGET_DRAWABLE(entry) && + gtk_widget_translate_coordinates(pane, entry, x, y, &nx, &ny) && + ny < entry->allocation.height / 2) break; + pos++; + } + g_list_free(list); + + gtk_box_reorder_child(GTK_BOX(ped->vbox), new_entry, pos); +} + +static void bar_pane_exif_entry_dnd_begin(GtkWidget *widget, GdkDragContext *context, gpointer data) +{ +// gtk_drag_set_icon_default(context); +} + +static void bar_pane_exif_entry_dnd_end(GtkWidget *widget, GdkDragContext *context, gpointer data) +{ +} + +static void bar_pane_exif_entry_dnd_init(GtkWidget *entry) +{ + ExifEntry *ee = g_object_get_data(G_OBJECT(entry), "entry_data"); + + gtk_drag_source_set(entry, GDK_BUTTON1_MASK | GDK_BUTTON2_MASK, + bar_pane_exif_drag_types, n_exif_entry_drag_types, + GDK_ACTION_COPY | GDK_ACTION_MOVE | GDK_ACTION_LINK); + g_signal_connect(G_OBJECT(entry), "drag_data_get", + G_CALLBACK(bar_pane_exif_entry_dnd_get), ee); + + g_signal_connect(G_OBJECT(entry), "drag_begin", + G_CALLBACK(bar_pane_exif_entry_dnd_begin), ee); + g_signal_connect(G_OBJECT(entry), "drag_end", + G_CALLBACK(bar_pane_exif_entry_dnd_end), ee); +} + +static void bar_pane_exif_dnd_init(GtkWidget *pane) +{ + gtk_drag_dest_set(pane, + GTK_DEST_DEFAULT_MOTION | GTK_DEST_DEFAULT_HIGHLIGHT | GTK_DEST_DEFAULT_DROP, + bar_pane_exif_drop_types, n_exif_entry_drop_types, + GDK_ACTION_COPY | GDK_ACTION_MOVE | GDK_ACTION_ASK); + g_signal_connect(G_OBJECT(pane), "drag_data_received", + G_CALLBACK(bar_pane_exif_dnd_receive), NULL); +} + + static void bar_pane_exif_entry_write_config(GtkWidget *entry, GString *outstr, gint indent) { ExifEntry *ee = g_object_get_data(G_OBJECT(entry), "entry_data"); @@ -297,6 +450,8 @@ G_CALLBACK(bar_pane_exif_size_request), ped); g_signal_connect(G_OBJECT(ped->widget), "size-allocate", G_CALLBACK(bar_pane_exif_size_allocate), ped); + + bar_pane_exif_dnd_init(ped->widget); if (populate) { diff -r 168e5597ddc7 -r 27ba259d3496 src/dnd.h --- a/src/dnd.h Mon Mar 02 22:48:04 2009 +0000 +++ b/src/dnd.h Tue Mar 03 23:17:07 2009 +0000 @@ -15,9 +15,11 @@ #define DND_H #define TARGET_APP_COLLECTION_MEMBER_STRING "application/x-" GQ_APPNAME_LC "-collection-member" +#define TARGET_APP_EXIF_ENTRY_STRING "application/x-" GQ_APPNAME_LC "-exif-entry" enum { TARGET_APP_COLLECTION_MEMBER, + TARGET_APP_EXIF_ENTRY, TARGET_URI_LIST, TARGET_TEXT_PLAIN };