Mercurial > pidgin
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; +} +