mirror of
https://gitlab.gnome.org/GNOME/glade.git
synced 2025-12-15 00:05:35 -05:00
869 lines
27 KiB
C
869 lines
27 KiB
C
/*
|
|
* Copyright (C) 2008 Tristan Van Berkom
|
|
*
|
|
* This program is free software; you can redistribute it and/or modify
|
|
* it under the terms of the GNU General Public License as
|
|
* published by the Free Software Foundation; either version 2 of the
|
|
* License, or (at your option) any later version.
|
|
*
|
|
* This program is distributed in the hope that it will be useful,
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
* GNU General Public License for more details.
|
|
*
|
|
* You should have received a copy of the GNU General Public License
|
|
* along with this program; if not, write to the Free Software
|
|
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
|
*
|
|
* Authors:
|
|
* Tristan Van Berkom <tvb@gnome.org>
|
|
*/
|
|
|
|
#include <config.h>
|
|
|
|
#include <gladeui/glade.h>
|
|
#include <gtk/gtk.h>
|
|
#include <glib/gi18n-lib.h>
|
|
#include <string.h>
|
|
|
|
#include "glade-accels.h"
|
|
|
|
#define GLADE_RESPONSE_CLEAR 42
|
|
|
|
GList *
|
|
glade_accel_list_copy (GList * accels)
|
|
{
|
|
GList *ret = NULL, *list;
|
|
GladeAccelInfo *info, *dup_info;
|
|
|
|
for (list = accels; list; list = list->next)
|
|
{
|
|
info = list->data;
|
|
|
|
dup_info = g_new0 (GladeAccelInfo, 1);
|
|
dup_info->signal = g_strdup (info->signal);
|
|
dup_info->key = info->key;
|
|
dup_info->modifiers = info->modifiers;
|
|
|
|
ret = g_list_prepend (ret, dup_info);
|
|
}
|
|
|
|
return g_list_reverse (ret);
|
|
}
|
|
|
|
void
|
|
glade_accel_list_free (GList * accels)
|
|
{
|
|
GList *list;
|
|
GladeAccelInfo *info;
|
|
|
|
for (list = accels; list; list = list->next)
|
|
{
|
|
info = list->data;
|
|
|
|
g_free (info->signal);
|
|
g_free (info);
|
|
}
|
|
g_list_free (accels);
|
|
}
|
|
|
|
GType
|
|
glade_accel_glist_get_type (void)
|
|
{
|
|
static GType type_id = 0;
|
|
|
|
if (!type_id)
|
|
type_id = g_boxed_type_register_static
|
|
("GladeAccelGList",
|
|
(GBoxedCopyFunc) glade_accel_list_copy,
|
|
(GBoxedFreeFunc) glade_accel_list_free);
|
|
return type_id;
|
|
}
|
|
|
|
/* This is not used to save in the glade file... and its a one-way conversion.
|
|
* its only usefull to show the values in the UI.
|
|
*/
|
|
gchar *
|
|
glade_accels_make_string (GList * accels)
|
|
{
|
|
GladeAccelInfo *info;
|
|
GString *string;
|
|
GList *list;
|
|
gchar *accel_text;
|
|
|
|
string = g_string_new ("");
|
|
|
|
for (list = accels; list; list = list->next)
|
|
{
|
|
info = list->data;
|
|
|
|
accel_text = gtk_accelerator_name (info->key, info->modifiers);
|
|
g_string_append (string, accel_text);
|
|
g_free (accel_text);
|
|
|
|
if (list->next)
|
|
g_string_append (string, ", ");
|
|
}
|
|
|
|
return g_string_free (string, FALSE);
|
|
}
|
|
|
|
|
|
/**************************************************************
|
|
* GladeEditorProperty stuff here
|
|
**************************************************************/
|
|
|
|
enum
|
|
{
|
|
ACCEL_COLUMN_SIGNAL = 0,
|
|
ACCEL_COLUMN_REAL_SIGNAL,
|
|
ACCEL_COLUMN_TEXT,
|
|
ACCEL_COLUMN_WEIGHT,
|
|
ACCEL_COLUMN_STYLE,
|
|
ACCEL_COLUMN_FOREGROUND,
|
|
ACCEL_COLUMN_VISIBLE,
|
|
ACCEL_COLUMN_KEY_ENTERED,
|
|
ACCEL_COLUMN_KEYCODE,
|
|
ACCEL_COLUMN_MODIFIERS,
|
|
ACCEL_NUM_COLUMNS
|
|
};
|
|
|
|
typedef struct
|
|
{
|
|
GladeEditorProperty parent_instance;
|
|
|
|
GtkWidget *entry;
|
|
GList *parent_iters;
|
|
GtkTreeModel *model;
|
|
} GladeEPropAccel;
|
|
|
|
typedef struct
|
|
{
|
|
GtkTreeIter *iter;
|
|
const gchar *name; /* <-- dont free */
|
|
} GladeEpropIterTab;
|
|
|
|
GLADE_MAKE_EPROP (GladeEPropAccel, glade_eprop_accel)
|
|
#define GLADE_EPROP_ACCEL(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GLADE_TYPE_EPROP_ACCEL, GladeEPropAccel))
|
|
#define GLADE_EPROP_ACCEL_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), GLADE_TYPE_EPROP_ACCEL, GladeEPropAccelClass))
|
|
#define GLADE_IS_EPROP_ACCEL(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GLADE_TYPE_EPROP_ACCEL))
|
|
#define GLADE_IS_EPROP_ACCEL_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), GLADE_TYPE_EPROP_ACCEL))
|
|
#define GLADE_EPROP_ACCEL_GET_CLASS(o) (G_TYPE_INSTANCE_GET_CLASS ((o), GLADE_EPROP_ACCEL, GladeEPropAccelClass))
|
|
static void glade_eprop_accel_finalize (GObject * object)
|
|
{
|
|
/* Chain up */
|
|
GObjectClass *parent_class =
|
|
g_type_class_peek_parent (G_OBJECT_GET_CLASS (object));
|
|
|
|
G_OBJECT_CLASS (parent_class)->finalize (object);
|
|
}
|
|
|
|
static void
|
|
glade_eprop_accel_load (GladeEditorProperty * eprop, GladeProperty * property)
|
|
{
|
|
GladeEditorPropertyClass *parent_class =
|
|
g_type_class_peek_parent (GLADE_EDITOR_PROPERTY_GET_CLASS (eprop));
|
|
GladeEPropAccel *eprop_accel = GLADE_EPROP_ACCEL (eprop);
|
|
gchar *accels;
|
|
|
|
/* Chain up first */
|
|
parent_class->load (eprop, property);
|
|
|
|
if (property == NULL)
|
|
return;
|
|
|
|
if ((accels =
|
|
glade_accels_make_string (g_value_get_boxed (glade_property_inline_value (property)))) != NULL)
|
|
{
|
|
gtk_entry_set_text (GTK_ENTRY (eprop_accel->entry), accels);
|
|
g_free (accels);
|
|
}
|
|
else
|
|
gtk_entry_set_text (GTK_ENTRY (eprop_accel->entry), "");
|
|
|
|
}
|
|
|
|
static gint
|
|
eprop_find_iter (GladeEpropIterTab * iter_tab, gchar * name)
|
|
{
|
|
return strcmp (iter_tab->name, name);
|
|
}
|
|
|
|
static void
|
|
iter_tab_free (GladeEpropIterTab * iter_tab)
|
|
{
|
|
gtk_tree_iter_free (iter_tab->iter);
|
|
g_free (iter_tab);
|
|
}
|
|
|
|
static void
|
|
glade_eprop_accel_populate_view (GladeEditorProperty * eprop,
|
|
GtkTreeView * view)
|
|
{
|
|
GladeEPropAccel *eprop_accel = GLADE_EPROP_ACCEL (eprop);
|
|
GladeSignalClass *sclass;
|
|
GladePropertyClass *pclass = glade_editor_property_get_pclass (eprop);
|
|
GladeProperty *property = glade_editor_property_get_property (eprop);
|
|
GladeWidgetAdaptor *adaptor = glade_property_class_get_adaptor (pclass);
|
|
GtkTreeStore *model = (GtkTreeStore *) gtk_tree_view_get_model (view);
|
|
GtkTreeIter iter;
|
|
GladeEpropIterTab *parent_tab;
|
|
GladeAccelInfo *info;
|
|
GList *l, *found, *accelerators;
|
|
gchar *name, *accel_text;
|
|
const GList *list;
|
|
|
|
accelerators = g_value_get_boxed (glade_property_inline_value (property));
|
|
|
|
/* First make parent iters...
|
|
*/
|
|
for (list = glade_widget_adaptor_get_signals (adaptor); list; list = list->next)
|
|
{
|
|
sclass = list->data;
|
|
|
|
/* Special case for GtkAction accelerators */
|
|
if (glade_widget_adaptor_get_object_type (adaptor) == GTK_TYPE_ACTION ||
|
|
g_type_is_a (glade_widget_adaptor_get_object_type (adaptor), GTK_TYPE_ACTION))
|
|
{
|
|
if (g_strcmp0 (glade_signal_class_get_type (sclass), "GtkAction") != 0 ||
|
|
g_strcmp0 (glade_signal_class_get_name (sclass), "activate") != 0)
|
|
continue;
|
|
}
|
|
/* Only action signals have accelerators. */
|
|
else if ((glade_signal_class_get_flags (sclass) & G_SIGNAL_ACTION) == 0)
|
|
continue;
|
|
|
|
if (g_list_find_custom (eprop_accel->parent_iters,
|
|
glade_signal_class_get_type (sclass),
|
|
(GCompareFunc) eprop_find_iter) == NULL)
|
|
{
|
|
gtk_tree_store_append (model, &iter, NULL);
|
|
gtk_tree_store_set (model, &iter,
|
|
ACCEL_COLUMN_SIGNAL, glade_signal_class_get_type (sclass),
|
|
ACCEL_COLUMN_WEIGHT, PANGO_WEIGHT_BOLD,
|
|
ACCEL_COLUMN_VISIBLE, FALSE, -1);
|
|
|
|
parent_tab = g_new0 (GladeEpropIterTab, 1);
|
|
parent_tab->name = glade_signal_class_get_type (sclass);
|
|
parent_tab->iter = gtk_tree_iter_copy (&iter);
|
|
|
|
eprop_accel->parent_iters =
|
|
g_list_prepend (eprop_accel->parent_iters, parent_tab);
|
|
}
|
|
}
|
|
|
|
/* Now we populate...
|
|
*/
|
|
for (list = glade_widget_adaptor_get_signals (adaptor); list; list = list->next)
|
|
{
|
|
sclass = list->data;
|
|
|
|
/* Special case for GtkAction accelerators */
|
|
if (glade_widget_adaptor_get_object_type (adaptor) == GTK_TYPE_ACTION ||
|
|
g_type_is_a (glade_widget_adaptor_get_object_type (adaptor), GTK_TYPE_ACTION))
|
|
{
|
|
if (g_strcmp0 (glade_signal_class_get_type (sclass), "GtkAction") != 0 ||
|
|
g_strcmp0 (glade_signal_class_get_name (sclass), "activate") != 0)
|
|
continue;
|
|
}
|
|
/* Only action signals have accelerators. */
|
|
else if ((glade_signal_class_get_flags (sclass) & G_SIGNAL_ACTION) == 0)
|
|
continue;
|
|
|
|
if ((found = g_list_find_custom (eprop_accel->parent_iters,
|
|
glade_signal_class_get_type (sclass),
|
|
(GCompareFunc) eprop_find_iter)) != NULL)
|
|
{
|
|
parent_tab = found->data;
|
|
name = g_strdup_printf (" %s", glade_signal_class_get_name (sclass));
|
|
|
|
/* Populate from accelerator list
|
|
*/
|
|
for (l = accelerators; l; l = l->next)
|
|
{
|
|
info = l->data;
|
|
|
|
if (g_strcmp0 (info->signal, glade_signal_class_get_name (sclass)))
|
|
continue;
|
|
|
|
accel_text = gtk_accelerator_name (info->key, info->modifiers);
|
|
|
|
gtk_tree_store_append (model, &iter, parent_tab->iter);
|
|
gtk_tree_store_set
|
|
(model, &iter,
|
|
ACCEL_COLUMN_SIGNAL, name,
|
|
ACCEL_COLUMN_REAL_SIGNAL, glade_signal_class_get_name (sclass),
|
|
ACCEL_COLUMN_TEXT, accel_text,
|
|
ACCEL_COLUMN_WEIGHT, PANGO_WEIGHT_NORMAL,
|
|
ACCEL_COLUMN_STYLE, PANGO_STYLE_NORMAL,
|
|
ACCEL_COLUMN_FOREGROUND, "Black",
|
|
ACCEL_COLUMN_VISIBLE, TRUE,
|
|
ACCEL_COLUMN_KEYCODE, info->key,
|
|
ACCEL_COLUMN_MODIFIERS, info->modifiers,
|
|
ACCEL_COLUMN_KEY_ENTERED, TRUE, -1);
|
|
|
|
g_free (accel_text);
|
|
}
|
|
|
|
/* Special case for GtkAction accelerators */
|
|
if ((glade_widget_adaptor_get_object_type (adaptor) == GTK_TYPE_ACTION ||
|
|
g_type_is_a (glade_widget_adaptor_get_object_type (adaptor), GTK_TYPE_ACTION)) &&
|
|
g_list_length (accelerators) > 0)
|
|
continue;
|
|
|
|
/* Append a new empty slot at the end */
|
|
gtk_tree_store_append (model, &iter, parent_tab->iter);
|
|
gtk_tree_store_set
|
|
(model, &iter,
|
|
ACCEL_COLUMN_SIGNAL, name,
|
|
ACCEL_COLUMN_REAL_SIGNAL, glade_signal_class_get_name (sclass),
|
|
ACCEL_COLUMN_TEXT, _("<choose a key>"),
|
|
ACCEL_COLUMN_WEIGHT, PANGO_WEIGHT_NORMAL,
|
|
ACCEL_COLUMN_STYLE, PANGO_STYLE_ITALIC,
|
|
ACCEL_COLUMN_FOREGROUND, "Grey",
|
|
ACCEL_COLUMN_VISIBLE, TRUE,
|
|
ACCEL_COLUMN_KEYCODE, 0,
|
|
ACCEL_COLUMN_MODIFIERS, 0, ACCEL_COLUMN_KEY_ENTERED, FALSE, -1);
|
|
|
|
g_free (name);
|
|
}
|
|
}
|
|
}
|
|
|
|
void
|
|
accel_edited (GtkCellRendererAccel * accel,
|
|
gchar * path_string,
|
|
guint accel_key,
|
|
GdkModifierType accel_mods,
|
|
guint hardware_keycode, GladeEPropAccel * eprop_accel)
|
|
{
|
|
gboolean key_was_set;
|
|
GtkTreeIter iter, parent_iter, new_iter;
|
|
gchar *accel_text;
|
|
GladePropertyClass *pclass;
|
|
GladeWidgetAdaptor *adaptor;
|
|
gboolean is_action;
|
|
|
|
pclass = glade_editor_property_get_pclass (GLADE_EDITOR_PROPERTY (eprop_accel));
|
|
adaptor = glade_property_class_get_adaptor (pclass);
|
|
|
|
if (!gtk_tree_model_get_iter_from_string (eprop_accel->model,
|
|
&iter, path_string))
|
|
return;
|
|
|
|
is_action = (glade_widget_adaptor_get_object_type (adaptor) == GTK_TYPE_ACTION ||
|
|
g_type_is_a (glade_widget_adaptor_get_object_type (adaptor), GTK_TYPE_ACTION));
|
|
|
|
gtk_tree_model_get (eprop_accel->model, &iter,
|
|
ACCEL_COLUMN_KEY_ENTERED, &key_was_set, -1);
|
|
|
|
accel_text = gtk_accelerator_name (accel_key, accel_mods);
|
|
|
|
gtk_tree_store_set
|
|
(GTK_TREE_STORE (eprop_accel->model), &iter,
|
|
ACCEL_COLUMN_KEY_ENTERED, TRUE,
|
|
ACCEL_COLUMN_STYLE, PANGO_STYLE_NORMAL,
|
|
ACCEL_COLUMN_FOREGROUND, "Black",
|
|
ACCEL_COLUMN_TEXT, accel_text,
|
|
ACCEL_COLUMN_KEYCODE, accel_key, ACCEL_COLUMN_MODIFIERS, accel_mods, -1);
|
|
|
|
g_free (accel_text);
|
|
|
|
/* Append a new one if needed
|
|
*/
|
|
if (is_action == FALSE && key_was_set == FALSE &&
|
|
gtk_tree_model_iter_parent (eprop_accel->model, &parent_iter, &iter))
|
|
{
|
|
gchar *signal, *real_signal;
|
|
|
|
gtk_tree_model_get (eprop_accel->model, &iter,
|
|
ACCEL_COLUMN_SIGNAL, &signal,
|
|
ACCEL_COLUMN_REAL_SIGNAL, &real_signal, -1);
|
|
|
|
/* Append a new empty slot at the end */
|
|
gtk_tree_store_insert_after (GTK_TREE_STORE (eprop_accel->model),
|
|
&new_iter, &parent_iter, &iter);
|
|
gtk_tree_store_set (GTK_TREE_STORE (eprop_accel->model), &new_iter,
|
|
ACCEL_COLUMN_SIGNAL, signal,
|
|
ACCEL_COLUMN_REAL_SIGNAL, real_signal,
|
|
ACCEL_COLUMN_TEXT, _("<choose a key>"),
|
|
ACCEL_COLUMN_WEIGHT, PANGO_WEIGHT_NORMAL,
|
|
ACCEL_COLUMN_STYLE, PANGO_STYLE_ITALIC,
|
|
ACCEL_COLUMN_FOREGROUND, "Grey",
|
|
ACCEL_COLUMN_VISIBLE, TRUE,
|
|
ACCEL_COLUMN_KEYCODE, 0,
|
|
ACCEL_COLUMN_MODIFIERS, 0,
|
|
ACCEL_COLUMN_KEY_ENTERED, FALSE, -1);
|
|
g_free (signal);
|
|
g_free (real_signal);
|
|
}
|
|
}
|
|
|
|
void
|
|
accel_cleared (GtkCellRendererAccel * accel,
|
|
gchar * path_string, GladeEPropAccel * eprop_accel)
|
|
{
|
|
GtkTreeIter iter;
|
|
|
|
if (!gtk_tree_model_get_iter_from_string (eprop_accel->model,
|
|
&iter, path_string))
|
|
return;
|
|
|
|
gtk_tree_store_remove (GTK_TREE_STORE (eprop_accel->model), &iter);
|
|
}
|
|
|
|
|
|
static GtkWidget *
|
|
glade_eprop_accel_view (GladeEditorProperty * eprop)
|
|
{
|
|
GladeEPropAccel *eprop_accel = GLADE_EPROP_ACCEL (eprop);
|
|
GtkWidget *view_widget;
|
|
GtkCellRenderer *renderer;
|
|
GtkTreeViewColumn *column;
|
|
|
|
eprop_accel->model = (GtkTreeModel *)
|
|
gtk_tree_store_new (ACCEL_NUM_COLUMNS, G_TYPE_STRING, /* The GSignal name formatted for display */
|
|
G_TYPE_STRING, /* The GSignal name */
|
|
G_TYPE_STRING, /* The text to show in the accelerator cell */
|
|
G_TYPE_INT, /* PangoWeight attribute for bold headers */
|
|
G_TYPE_INT, /* PangoStyle attribute for italic grey unset items */
|
|
G_TYPE_STRING, /* Foreground colour for italic grey unset items */
|
|
G_TYPE_BOOLEAN, /* Visible attribute to hide items for header entries */
|
|
G_TYPE_BOOLEAN, /* Whether the key has been entered for this row */
|
|
G_TYPE_UINT, /* Hardware keycode */
|
|
G_TYPE_INT); /* GdkModifierType */
|
|
|
|
view_widget = gtk_tree_view_new_with_model (eprop_accel->model);
|
|
gtk_tree_view_set_show_expanders (GTK_TREE_VIEW (view_widget), FALSE);
|
|
gtk_tree_view_set_enable_search (GTK_TREE_VIEW (view_widget), FALSE);
|
|
|
|
/********************* signal name column *********************/
|
|
renderer = gtk_cell_renderer_text_new ();
|
|
g_object_set (G_OBJECT (renderer), "editable", FALSE, NULL);
|
|
|
|
column = gtk_tree_view_column_new_with_attributes
|
|
(_("Signal"), renderer,
|
|
"text", ACCEL_COLUMN_SIGNAL, "weight", ACCEL_COLUMN_WEIGHT, NULL);
|
|
|
|
|
|
gtk_tree_view_column_set_expand (GTK_TREE_VIEW_COLUMN (column), TRUE);
|
|
gtk_tree_view_append_column (GTK_TREE_VIEW (view_widget), column);
|
|
|
|
/********************* accel editor column *********************/
|
|
renderer = gtk_cell_renderer_accel_new ();
|
|
g_object_set (G_OBJECT (renderer), "editable", TRUE, NULL);
|
|
|
|
g_signal_connect (renderer, "accel-edited", G_CALLBACK (accel_edited), eprop);
|
|
g_signal_connect (renderer, "accel-cleared",
|
|
G_CALLBACK (accel_cleared), eprop);
|
|
|
|
column = gtk_tree_view_column_new_with_attributes
|
|
(_("Accelerator Key"), renderer,
|
|
"text", ACCEL_COLUMN_TEXT,
|
|
"foreground", ACCEL_COLUMN_FOREGROUND,
|
|
"style", ACCEL_COLUMN_STYLE, "visible", ACCEL_COLUMN_VISIBLE, NULL);
|
|
|
|
gtk_tree_view_column_set_expand (GTK_TREE_VIEW_COLUMN (column), TRUE);
|
|
gtk_tree_view_append_column (GTK_TREE_VIEW (view_widget), column);
|
|
|
|
return view_widget;
|
|
}
|
|
|
|
static gboolean
|
|
glade_eprop_accel_accum_accelerators (GtkTreeModel * model,
|
|
GtkTreePath * path,
|
|
GtkTreeIter * iter, GList ** ret)
|
|
{
|
|
GladeAccelInfo *info;
|
|
gchar *signal;
|
|
GdkModifierType accel_mods;
|
|
guint accel_key;
|
|
gboolean entered = FALSE;
|
|
|
|
gtk_tree_model_get (model, iter, ACCEL_COLUMN_KEY_ENTERED, &entered, -1);
|
|
if (!entered)
|
|
return FALSE;
|
|
|
|
gtk_tree_model_get (model, iter,
|
|
ACCEL_COLUMN_REAL_SIGNAL, &signal,
|
|
ACCEL_COLUMN_KEYCODE, &accel_key,
|
|
ACCEL_COLUMN_MODIFIERS, &accel_mods, -1);
|
|
|
|
info = g_new0 (GladeAccelInfo, 1);
|
|
info->signal = signal;
|
|
info->key = accel_key;
|
|
info->modifiers = accel_mods;
|
|
|
|
*ret = g_list_prepend (*ret, info);
|
|
|
|
return FALSE;
|
|
}
|
|
|
|
|
|
static void
|
|
glade_eprop_accel_show_dialog (GtkWidget * dialog_button,
|
|
GladeEditorProperty * eprop)
|
|
{
|
|
GladeEPropAccel *eprop_accel = GLADE_EPROP_ACCEL (eprop);
|
|
GtkWidget *dialog, *parent, *vbox, *sw, *tree_view;
|
|
GValue value = { 0, };
|
|
GList *accelerators = NULL;
|
|
gint res;
|
|
|
|
parent = gtk_widget_get_toplevel (GTK_WIDGET (eprop));
|
|
|
|
dialog = gtk_dialog_new_with_buttons (_("Choose accelerator keys..."),
|
|
GTK_WINDOW (parent),
|
|
GTK_DIALOG_MODAL |
|
|
GTK_DIALOG_DESTROY_WITH_PARENT,
|
|
GTK_STOCK_CLEAR, GLADE_RESPONSE_CLEAR,
|
|
GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL,
|
|
GTK_STOCK_OK, GTK_RESPONSE_OK, NULL);
|
|
|
|
vbox = gtk_box_new (GTK_ORIENTATION_VERTICAL, 6);
|
|
gtk_widget_show (vbox);
|
|
|
|
gtk_container_set_border_width (GTK_CONTAINER (vbox), 6);
|
|
|
|
gtk_box_pack_start (GTK_BOX
|
|
(gtk_dialog_get_content_area (GTK_DIALOG (dialog))), vbox,
|
|
TRUE, TRUE, 0);
|
|
|
|
sw = gtk_scrolled_window_new (NULL, NULL);
|
|
gtk_widget_show (sw);
|
|
gtk_box_pack_start (GTK_BOX (vbox), sw, TRUE, TRUE, 0);
|
|
gtk_widget_set_size_request (sw, 400, 200);
|
|
gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (sw),
|
|
GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC);
|
|
gtk_scrolled_window_set_shadow_type (GTK_SCROLLED_WINDOW (sw), GTK_SHADOW_IN);
|
|
|
|
tree_view = glade_eprop_accel_view (eprop);
|
|
glade_eprop_accel_populate_view (eprop, GTK_TREE_VIEW (tree_view));
|
|
|
|
gtk_tree_view_expand_all (GTK_TREE_VIEW (tree_view));
|
|
|
|
gtk_widget_show (tree_view);
|
|
gtk_container_add (GTK_CONTAINER (sw), tree_view);
|
|
|
|
/* Run the dialog */
|
|
res = gtk_dialog_run (GTK_DIALOG (dialog));
|
|
if (res == GTK_RESPONSE_OK)
|
|
{
|
|
gtk_tree_model_foreach
|
|
(gtk_tree_view_get_model (GTK_TREE_VIEW (tree_view)),
|
|
(GtkTreeModelForeachFunc)
|
|
glade_eprop_accel_accum_accelerators, &accelerators);
|
|
|
|
g_value_init (&value, GLADE_TYPE_ACCEL_GLIST);
|
|
g_value_take_boxed (&value, accelerators);
|
|
|
|
glade_editor_property_commit (eprop, &value);
|
|
g_value_unset (&value);
|
|
}
|
|
else if (res == GLADE_RESPONSE_CLEAR)
|
|
{
|
|
g_value_init (&value, GLADE_TYPE_ACCEL_GLIST);
|
|
g_value_set_boxed (&value, NULL);
|
|
|
|
glade_editor_property_commit (eprop, &value);
|
|
|
|
g_value_unset (&value);
|
|
}
|
|
|
|
/* Clean up ...
|
|
*/
|
|
gtk_widget_destroy (dialog);
|
|
|
|
g_object_unref (G_OBJECT (eprop_accel->model));
|
|
eprop_accel->model = NULL;
|
|
|
|
if (eprop_accel->parent_iters)
|
|
{
|
|
g_list_foreach (eprop_accel->parent_iters, (GFunc) iter_tab_free, NULL);
|
|
g_list_free (eprop_accel->parent_iters);
|
|
eprop_accel->parent_iters = NULL;
|
|
}
|
|
|
|
}
|
|
|
|
static GtkWidget *
|
|
glade_eprop_accel_create_input (GladeEditorProperty * eprop)
|
|
{
|
|
GladeEPropAccel *eprop_accel = GLADE_EPROP_ACCEL (eprop);
|
|
GtkWidget *hbox;
|
|
GtkWidget *button;
|
|
|
|
hbox = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 0);
|
|
eprop_accel->entry = gtk_entry_new ();
|
|
gtk_editable_set_editable (GTK_EDITABLE (eprop_accel->entry), FALSE);
|
|
gtk_widget_show (eprop_accel->entry);
|
|
gtk_box_pack_start (GTK_BOX (hbox), eprop_accel->entry, TRUE, TRUE, 0);
|
|
|
|
button = gtk_button_new_with_label ("...");
|
|
gtk_widget_show (button);
|
|
gtk_box_pack_start (GTK_BOX (hbox), button, FALSE, FALSE, 0);
|
|
|
|
g_signal_connect (G_OBJECT (button), "clicked",
|
|
G_CALLBACK (glade_eprop_accel_show_dialog), eprop);
|
|
|
|
return hbox;
|
|
}
|
|
|
|
|
|
static GdkModifierType
|
|
glade_gtk_parse_modifiers (const gchar * string)
|
|
{
|
|
const gchar *pos = string;
|
|
GdkModifierType modifiers = 0;
|
|
|
|
while (pos && pos[0])
|
|
{
|
|
if (!strncmp (pos, "GDK_", 4))
|
|
{
|
|
pos += 4;
|
|
if (!strncmp (pos, "SHIFT_MASK", 10))
|
|
{
|
|
modifiers |= GDK_SHIFT_MASK;
|
|
pos += 10;
|
|
}
|
|
else if (!strncmp (pos, "LOCK_MASK", 9))
|
|
{
|
|
modifiers |= GDK_LOCK_MASK;
|
|
pos += 9;
|
|
}
|
|
else if (!strncmp (pos, "CONTROL_MASK", 12))
|
|
{
|
|
modifiers |= GDK_CONTROL_MASK;
|
|
pos += 12;
|
|
}
|
|
else if (!strncmp (pos, "MOD", 3) && !strncmp (pos + 4, "_MASK", 5))
|
|
{
|
|
switch (pos[3])
|
|
{
|
|
case '1':
|
|
modifiers |= GDK_MOD1_MASK;
|
|
break;
|
|
case '2':
|
|
modifiers |= GDK_MOD2_MASK;
|
|
break;
|
|
case '3':
|
|
modifiers |= GDK_MOD3_MASK;
|
|
break;
|
|
case '4':
|
|
modifiers |= GDK_MOD4_MASK;
|
|
break;
|
|
case '5':
|
|
modifiers |= GDK_MOD5_MASK;
|
|
break;
|
|
}
|
|
pos += 9;
|
|
}
|
|
else if (!strncmp (pos, "BUTTON", 6) &&
|
|
!strncmp (pos + 7, "_MASK", 5))
|
|
{
|
|
switch (pos[6])
|
|
{
|
|
case '1':
|
|
modifiers |= GDK_BUTTON1_MASK;
|
|
break;
|
|
case '2':
|
|
modifiers |= GDK_BUTTON2_MASK;
|
|
break;
|
|
case '3':
|
|
modifiers |= GDK_BUTTON3_MASK;
|
|
break;
|
|
case '4':
|
|
modifiers |= GDK_BUTTON4_MASK;
|
|
break;
|
|
case '5':
|
|
modifiers |= GDK_BUTTON5_MASK;
|
|
break;
|
|
}
|
|
pos += 12;
|
|
}
|
|
else if (!strncmp (pos, "RELEASE_MASK", 12))
|
|
{
|
|
modifiers |= GDK_RELEASE_MASK;
|
|
pos += 12;
|
|
}
|
|
else
|
|
pos++;
|
|
}
|
|
else
|
|
pos++;
|
|
}
|
|
return modifiers;
|
|
}
|
|
|
|
|
|
static gchar *
|
|
glade_gtk_modifier_string_from_bits (GdkModifierType modifiers)
|
|
{
|
|
GString *string = g_string_new ("");
|
|
|
|
if (modifiers & GDK_SHIFT_MASK)
|
|
{
|
|
if (string->len > 0)
|
|
g_string_append (string, " | ");
|
|
g_string_append (string, "GDK_SHIFT_MASK");
|
|
}
|
|
|
|
if (modifiers & GDK_LOCK_MASK)
|
|
{
|
|
if (string->len > 0)
|
|
g_string_append (string, " | ");
|
|
g_string_append (string, "GDK_LOCK_MASK");
|
|
}
|
|
|
|
if (modifiers & GDK_CONTROL_MASK)
|
|
{
|
|
if (string->len > 0)
|
|
g_string_append (string, " | ");
|
|
g_string_append (string, "GDK_CONTROL_MASK");
|
|
}
|
|
|
|
if (modifiers & GDK_MOD1_MASK)
|
|
{
|
|
if (string->len > 0)
|
|
g_string_append (string, " | ");
|
|
g_string_append (string, "GDK_MOD1_MASK");
|
|
}
|
|
|
|
if (modifiers & GDK_MOD2_MASK)
|
|
{
|
|
if (string->len > 0)
|
|
g_string_append (string, " | ");
|
|
g_string_append (string, "GDK_MOD2_MASK");
|
|
}
|
|
|
|
if (modifiers & GDK_MOD3_MASK)
|
|
{
|
|
if (string->len > 0)
|
|
g_string_append (string, " | ");
|
|
g_string_append (string, "GDK_MOD3_MASK");
|
|
}
|
|
|
|
if (modifiers & GDK_MOD4_MASK)
|
|
{
|
|
if (string->len > 0)
|
|
g_string_append (string, " | ");
|
|
g_string_append (string, "GDK_MOD4_MASK");
|
|
}
|
|
|
|
if (modifiers & GDK_MOD5_MASK)
|
|
{
|
|
if (string->len > 0)
|
|
g_string_append (string, " | ");
|
|
g_string_append (string, "GDK_MOD5_MASK");
|
|
}
|
|
|
|
if (modifiers & GDK_BUTTON1_MASK)
|
|
{
|
|
if (string->len > 0)
|
|
g_string_append (string, " | ");
|
|
g_string_append (string, "GDK_BUTTON1_MASK");
|
|
}
|
|
|
|
if (modifiers & GDK_BUTTON2_MASK)
|
|
{
|
|
if (string->len > 0)
|
|
g_string_append (string, " | ");
|
|
g_string_append (string, "GDK_BUTTON2_MASK");
|
|
}
|
|
|
|
if (modifiers & GDK_BUTTON3_MASK)
|
|
{
|
|
if (string->len > 0)
|
|
g_string_append (string, " | ");
|
|
g_string_append (string, "GDK_BUTTON3_MASK");
|
|
}
|
|
|
|
if (modifiers & GDK_BUTTON4_MASK)
|
|
{
|
|
if (string->len > 0)
|
|
g_string_append (string, " | ");
|
|
g_string_append (string, "GDK_BUTTON4_MASK");
|
|
}
|
|
|
|
if (modifiers & GDK_BUTTON5_MASK)
|
|
{
|
|
if (string->len > 0)
|
|
g_string_append (string, " | ");
|
|
g_string_append (string, "GDK_BUTTON5_MASK");
|
|
}
|
|
|
|
if (modifiers & GDK_RELEASE_MASK)
|
|
{
|
|
if (string->len > 0)
|
|
g_string_append (string, " | ");
|
|
g_string_append (string, "GDK_RELEASE_MASK");
|
|
}
|
|
|
|
if (string->len > 0)
|
|
return g_string_free (string, FALSE);
|
|
|
|
g_string_free (string, TRUE);
|
|
return NULL;
|
|
}
|
|
|
|
GladeAccelInfo *
|
|
glade_accel_read (GladeXmlNode * node, gboolean require_signal)
|
|
{
|
|
GladeAccelInfo *ainfo;
|
|
gchar *key, *modifiers, *signal;
|
|
|
|
g_return_val_if_fail (node != NULL, NULL);
|
|
|
|
if (!glade_xml_node_verify (node, GLADE_TAG_ACCEL))
|
|
return NULL;
|
|
|
|
/* Get from xml... */
|
|
key = glade_xml_get_property_string_required
|
|
(node, GLADE_TAG_ACCEL_KEY, NULL);
|
|
if (require_signal)
|
|
signal =
|
|
glade_xml_get_property_string_required (node, GLADE_TAG_ACCEL_SIGNAL,
|
|
NULL);
|
|
else
|
|
signal = glade_xml_get_property_string (node, GLADE_TAG_ACCEL_SIGNAL);
|
|
|
|
modifiers = glade_xml_get_property_string (node, GLADE_TAG_ACCEL_MODIFIERS);
|
|
|
|
/* translate to GladeAccelInfo... */
|
|
ainfo = g_new0 (GladeAccelInfo, 1);
|
|
ainfo->key = gdk_keyval_from_name (key);
|
|
ainfo->signal = signal; /* take string ownership... */
|
|
ainfo->modifiers = glade_gtk_parse_modifiers (modifiers);
|
|
|
|
g_free (modifiers);
|
|
|
|
return ainfo;
|
|
}
|
|
|
|
GladeXmlNode *
|
|
glade_accel_write (GladeAccelInfo * accel,
|
|
GladeXmlContext * context, gboolean write_signal)
|
|
{
|
|
GladeXmlNode *accel_node;
|
|
gchar *modifiers;
|
|
|
|
g_return_val_if_fail (accel != NULL, NULL);
|
|
g_return_val_if_fail (context != NULL, NULL);
|
|
|
|
accel_node = glade_xml_node_new (context, GLADE_TAG_ACCEL);
|
|
modifiers = glade_gtk_modifier_string_from_bits (accel->modifiers);
|
|
|
|
glade_xml_node_set_property_string (accel_node, GLADE_TAG_ACCEL_KEY,
|
|
gdk_keyval_name (accel->key));
|
|
|
|
if (write_signal)
|
|
glade_xml_node_set_property_string (accel_node, GLADE_TAG_ACCEL_SIGNAL,
|
|
accel->signal);
|
|
glade_xml_node_set_property_string (accel_node, GLADE_TAG_ACCEL_MODIFIERS,
|
|
modifiers);
|
|
|
|
g_free (modifiers);
|
|
|
|
return accel_node;
|
|
}
|