diff finch/libgnt/gntbindable.c @ 19186:eef82b050c21

merge of 'bbeac90ad01d5059327da9e2504716614a191cab' and 'f30bfc6fc7aee19d096dd838aad5a784a7371d6c'
author Kevin Stange <kevin@simguy.net>
date Sat, 11 Aug 2007 21:08:27 +0000
parents c8f9584e3221
children 44b4e8bd759b
line wrap: on
line diff
--- a/finch/libgnt/gntbindable.c	Sat Aug 11 21:08:06 2007 +0000
+++ b/finch/libgnt/gntbindable.c	Sat Aug 11 21:08:27 2007 +0000
@@ -20,13 +20,182 @@
  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
  */
 
+#include <string.h>
+
 #include "gntbindable.h"
 #include "gntstyle.h"
 #include "gnt.h"
 #include "gntutils.h"
+#include "gnttextview.h"
+#include "gnttree.h"
+#include "gntbox.h"
+#include "gntbutton.h"
+#include "gntwindow.h"
+#include "gntlabel.h"
 
 static GObjectClass *parent_class = NULL;
 
+static struct
+{
+	char * okeys;         /* Old keystrokes */
+	char * keys;          /* New Keystrokes being bound to the action */
+	GntBindableClass * klass; /* Class of the object that's getting keys rebound */
+	char * name;          /* The name of the action */
+	GList * params;       /* The list of paramaters */
+} rebind_info;
+
+static void 
+gnt_bindable_free_rebind_info()
+{
+	g_free(rebind_info.name);
+	g_free(rebind_info.keys);
+	g_free(rebind_info.okeys);
+}
+
+static void
+gnt_bindable_rebinding_cancel(GntWidget *button, gpointer data)
+{
+	gnt_bindable_free_rebind_info();
+	gnt_widget_destroy(GNT_WIDGET(data));
+}
+
+static void
+gnt_bindable_rebinding_rebind(GntWidget *button, gpointer data)
+{
+	if (rebind_info.keys) {
+		gnt_bindable_register_binding(rebind_info.klass,
+				NULL,
+				rebind_info.okeys,
+				rebind_info.params);
+		gnt_bindable_register_binding(rebind_info.klass,
+				rebind_info.name,
+				rebind_info.keys,
+				rebind_info.params);
+	}
+	gnt_bindable_free_rebind_info();
+	gnt_widget_destroy(GNT_WIDGET(data));
+}
+
+static gboolean
+gnt_bindable_rebinding_grab_key(GntBindable *bindable, const char *text, gpointer data)
+{
+	GntTextView *textview = GNT_TEXT_VIEW(data);
+	char *new_text;
+	const char *tmp;
+
+	if (text && *text) {
+		/* Rebinding tab or enter for something is probably not that great an idea */
+		if (!strcmp(text, GNT_KEY_CTRL_I) || !strcmp(text, GNT_KEY_ENTER)) {
+			return FALSE;
+		}
+		
+		tmp = gnt_key_lookup(text);
+		new_text = g_strdup_printf("KEY: \"%s\"", tmp);
+		gnt_text_view_clear(textview);
+		gnt_text_view_append_text_with_flags(textview, new_text, GNT_TEXT_FLAG_NORMAL);
+		g_free(new_text);
+
+		g_free(rebind_info.keys);
+		rebind_info.keys = g_strdup(text);
+
+		return TRUE;
+	}
+	return FALSE;
+} 
+static void
+gnt_bindable_rebinding_activate(GntBindable *data, gpointer bindable)
+{
+	const char *widget_name = g_type_name(G_OBJECT_TYPE(bindable));
+	char *keys;
+	GntWidget *key_textview;
+	GntWidget *label;
+	GntWidget *bind_button, *cancel_button;
+	GntWidget *button_box;
+	GList *current_row_data;
+	char *tmp;
+	GntWidget *win = gnt_window_new();
+	GntTree *tree = GNT_TREE(data);
+	GntWidget *vbox = gnt_box_new(FALSE, TRUE);
+
+	rebind_info.klass = GNT_BINDABLE_GET_CLASS(bindable);
+
+	current_row_data = gnt_tree_get_selection_text_list(tree);
+	rebind_info.name = g_strdup(g_list_nth_data(current_row_data, 1));
+
+	keys = gnt_tree_get_selection_data(tree);
+	rebind_info.okeys = g_strdup(gnt_key_translate(keys));
+
+	rebind_info.params = NULL;
+
+	g_list_foreach(current_row_data, (GFunc)g_free, NULL);
+	g_list_free(current_row_data);
+
+	gnt_box_set_alignment(GNT_BOX(vbox), GNT_ALIGN_MID);
+
+	gnt_box_set_title(GNT_BOX(win), "Key Capture");
+
+	tmp = g_strdup_printf("Type the new bindings for %s in a %s.", rebind_info.name, widget_name);
+	label = gnt_label_new(tmp);
+	g_free(tmp);
+	gnt_box_add_widget(GNT_BOX(vbox), label);
+
+	tmp = g_strdup_printf("KEY: \"%s\"", keys);
+	key_textview = gnt_text_view_new();
+	gnt_widget_set_size(key_textview, key_textview->priv.x, 2);
+	gnt_text_view_append_text_with_flags(GNT_TEXT_VIEW(key_textview), tmp, GNT_TEXT_FLAG_NORMAL);
+	g_free(tmp);
+	gnt_widget_set_name(key_textview, "keystroke");
+	gnt_box_add_widget(GNT_BOX(vbox), key_textview);
+
+	g_signal_connect(G_OBJECT(win), "key_pressed", G_CALLBACK(gnt_bindable_rebinding_grab_key), key_textview);
+
+	button_box = gnt_box_new(FALSE, FALSE);
+	
+	bind_button = gnt_button_new("BIND");
+	gnt_widget_set_name(bind_button, "bind");
+	gnt_box_add_widget(GNT_BOX(button_box), bind_button);
+	
+	cancel_button = gnt_button_new("Cancel");
+	gnt_widget_set_name(cancel_button, "cancel");
+	gnt_box_add_widget(GNT_BOX(button_box), cancel_button);
+	
+	g_signal_connect(G_OBJECT(bind_button), "activate", G_CALLBACK(gnt_bindable_rebinding_rebind), win);
+	g_signal_connect(G_OBJECT(cancel_button), "activate", G_CALLBACK(gnt_bindable_rebinding_cancel), win);
+	
+	gnt_box_add_widget(GNT_BOX(vbox), button_box);
+
+	gnt_box_add_widget(GNT_BOX(win), vbox);
+	gnt_widget_show(win);
+}
+
+typedef struct
+{
+	GHashTable *hash;
+	GntTree *tree;
+} BindingView;
+
+static void
+add_binding(gpointer key, gpointer value, gpointer data)
+{
+	BindingView *bv = data;
+	GntBindableActionParam *act = value;
+	const char *name = g_hash_table_lookup(bv->hash, act->action);
+	if (name && *name) {
+		const char *k = gnt_key_lookup(key);
+		if (!k)
+			k = key;
+		gnt_tree_add_row_after(bv->tree, (gpointer)k,
+				gnt_tree_create_row(bv->tree, k, name), NULL, NULL);
+	}
+}
+
+static void
+add_action(gpointer key, gpointer value, gpointer data)
+{
+	BindingView *bv = data;
+	g_hash_table_insert(bv->hash, value, key);
+}
+
 static void
 gnt_bindable_class_init(GntBindableClass *klass)
 {
@@ -88,7 +257,7 @@
 {
 	static GType type = 0;
 
-	if(type == 0) {
+	if (type == 0) {
 		static const GTypeInfo info = {
 			sizeof(GntBindableClass),
 			(GBaseInitFunc)duplicate_hashes,	/* base_init		*/
@@ -251,4 +420,55 @@
 	g_free(param);
 }
 
+GntBindable * gnt_bindable_bindings_view(GntBindable *bind)
+{
+	GntBindable *tree = GNT_BINDABLE(gnt_tree_new_with_columns(2));
+	GntBindableClass *klass = GNT_BINDABLE_CLASS(GNT_BINDABLE_GET_CLASS(bind));
+	GHashTable *hash = g_hash_table_new(g_direct_hash, g_direct_equal);
+	BindingView bv = {hash, GNT_TREE(tree)};
 
+	gnt_tree_set_compare_func(bv.tree, (GCompareFunc)g_utf8_collate);
+	g_hash_table_foreach(klass->actions, add_action, &bv);
+	g_hash_table_foreach(klass->bindings, add_binding, &bv);
+	if (GNT_TREE(tree)->list == NULL) {
+		gnt_widget_destroy(GNT_WIDGET(tree));
+		tree = NULL;
+	} else
+		gnt_tree_adjust_columns(bv.tree);
+	g_hash_table_destroy(hash);
+
+	return tree;
+}
+
+static void
+reset_binding_window(GntBindableClass *window, gpointer k)
+{
+	GntBindableClass *klass = GNT_BINDABLE_CLASS(k);
+	klass->help_window = NULL;
+}
+
+gboolean
+gnt_bindable_build_help_window(GntBindable *bindable)
+{
+	GntWidget *tree;
+	GntBindableClass *klass = GNT_BINDABLE_GET_CLASS(bindable);
+	char *title;
+
+	tree = GNT_WIDGET(gnt_bindable_bindings_view(bindable));
+
+	klass->help_window = GNT_BINDABLE(gnt_window_new());
+	title = g_strdup_printf("Bindings for %s", g_type_name(G_OBJECT_TYPE(bindable)));
+	gnt_box_set_title(GNT_BOX(klass->help_window), title);
+	if (tree) {
+		g_signal_connect(G_OBJECT(tree), "activate", G_CALLBACK(gnt_bindable_rebinding_activate), bindable);
+		gnt_box_add_widget(GNT_BOX(klass->help_window), tree);
+	} else
+		gnt_box_add_widget(GNT_BOX(klass->help_window), gnt_label_new("This widget has no customizable bindings."));
+
+	g_signal_connect(G_OBJECT(klass->help_window), "destroy", G_CALLBACK(reset_binding_window), klass);
+	gnt_widget_show(GNT_WIDGET(klass->help_window));
+	g_free(title);
+
+	return TRUE;
+}
+