changeset 1374:27ba259d3496

reorder exif pane entries with drag and drop
author nadvornik
date Tue, 03 Mar 2009 23:17:07 +0000
parents 168e5597ddc7
children df58e511d90e
files src/bar_exif.c src/dnd.h
diffstat 2 files changed, 165 insertions(+), 8 deletions(-) [+]
line wrap: on
line diff
--- 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 <math.h>
@@ -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)
 		{
--- 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
 };