diff --git a/ChangeLog b/ChangeLog index aa5ebeb911..b30a719965 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,32 @@ +2004-07-20 Michael Natterer + + * app/widgets/gimpactionfactory.[ch] + * app/widgets/gimpactiongroup.[ch]: added "label" and "stock-id" + properties to GtkActionGroup and allow to register them in the + GimpActionFactory. + + * app/actions/actions.c: register user visible labels and icons + with all action groups. + + * app/widgets/Makefile.am + * app/widgets/widgets-types.h + * app/widgets/gimpactionview.[ch]: new widget which shows a + treeview of action groups and their actions & shortcuts. + + * app/widgets/gimpaction.[ch]: added gimp_action_name_compare() + utility function. + + * app/widgets/gimpwidgets-utils.[ch]: added + gimp_get_accel_string() utility function. + + * app/widgets/gimpcontrollers.[ch]: added + gimp_controllers_get_ui_manager() which will be used for setting + up the controller mapping dialog. + + * app/gui/preferences-dialog.c: added a "Configure Keyboard + Shortcuts" button which pops up a GimpControllerView. Work in + progress... + 2004-07-20 Michael Natterer * app/actions/image-actions.c: make sure that the "image-new" and diff --git a/app/actions/actions.c b/app/actions/actions.c index 2252e64304..c24199a7dd 100644 --- a/app/actions/actions.c +++ b/app/actions/actions.c @@ -74,6 +74,8 @@ #include "vectors-actions.h" #include "view-actions.h" +#include "gimp-intl.h" + /* global variables */ @@ -84,97 +86,97 @@ GimpActionFactory *global_action_factory = NULL; static GimpActionFactoryEntry action_groups[] = { - { "brushes", + { "brushes", N_("Brushes"), GIMP_STOCK_BRUSH, brushes_actions_setup, brushes_actions_update }, - { "buffers", + { "buffers", N_("Buffers"), GIMP_STOCK_BUFFER, buffers_actions_setup, buffers_actions_update }, - { "channels", + { "channels", N_("Channels"), GIMP_STOCK_CHANNEL, channels_actions_setup, channels_actions_update }, - { "colormap-editor", + { "colormap-editor", N_("Colormap Editor"), GIMP_STOCK_INDEXED_PALETTE, colormap_editor_actions_setup, colormap_editor_actions_update }, - { "context", + { "context", N_("Context"), NULL, context_actions_setup, context_actions_update }, - { "debug", + { "debug", N_("Debug"), NULL, debug_actions_setup, debug_actions_update }, - { "dialogs", + { "dialogs", N_("Dialogs"), NULL, dialogs_actions_setup, dialogs_actions_update }, - { "dockable", + { "dockable", N_("Dockable"), NULL, dockable_actions_setup, dockable_actions_update }, - { "documents", + { "documents", N_("Document History"), NULL, documents_actions_setup, documents_actions_update }, - { "drawable", + { "drawable", N_("Drawable"), GIMP_STOCK_LAYER, drawable_actions_setup, drawable_actions_update }, - { "edit", + { "edit", N_("Edit"), GIMP_STOCK_EDIT, edit_actions_setup, edit_actions_update }, - { "error-console", + { "error-console", N_("Error Console"), GIMP_STOCK_WARNING, error_console_actions_setup, error_console_actions_update }, - { "file", + { "file", N_("File"), GTK_STOCK_OPEN, file_actions_setup, file_actions_update }, - { "fonts", + { "fonts", N_("Fonts"), GIMP_STOCK_FONT, fonts_actions_setup, fonts_actions_update }, - { "gradient-editor", + { "gradient-editor", N_("Gradient Editor"), GIMP_STOCK_GRADIENT, gradient_editor_actions_setup, gradient_editor_actions_update }, - { "gradients", + { "gradients", N_("Gradients"), GIMP_STOCK_GRADIENT, gradients_actions_setup, gradients_actions_update }, - { "help", + { "help", N_("Help"), GTK_STOCK_HELP, help_actions_setup, help_actions_update }, - { "image", + { "image", N_("Image"), GIMP_STOCK_IMAGE, image_actions_setup, image_actions_update }, - { "images", + { "images", N_("Images"), GIMP_STOCK_IMAGE, images_actions_setup, images_actions_update }, - { "layers", + { "layers", N_("Layers"), GIMP_STOCK_LAYER, layers_actions_setup, layers_actions_update }, - { "palette-editor", + { "palette-editor", N_("Palette Editor"), GIMP_STOCK_PALETTE, palette_editor_actions_setup, palette_editor_actions_update }, - { "palettes", + { "palettes", N_("Palettes"), GIMP_STOCK_PALETTE, palettes_actions_setup, palettes_actions_update }, - { "patterns", + { "patterns", N_("Patterns"), GIMP_STOCK_PATTERN, patterns_actions_setup, patterns_actions_update }, - { "plug-in", + { "plug-in", N_("Plug-Ins"), GIMP_STOCK_PLUGIN, plug_in_actions_setup, plug_in_actions_update }, - { "qmask", + { "qmask", N_("QuickMask"), GIMP_STOCK_QMASK_ON, qmask_actions_setup, qmask_actions_update }, - { "select", + { "select", N_("Select"), GIMP_STOCK_SELECTION, select_actions_setup, select_actions_update }, - { "templates", + { "templates", N_("Templates"), GIMP_STOCK_TEMPLATE, templates_actions_setup, templates_actions_update }, - { "tool-options", + { "tool-options", N_("Tool Options"), GIMP_STOCK_TOOL_OPTIONS, tool_options_actions_setup, tool_options_actions_update }, - { "tools", + { "tools", N_("Tools"), GIMP_STOCK_TOOLS, tools_actions_setup, tools_actions_update }, - { "vectors", + { "vectors", N_("Paths"), GIMP_STOCK_PATH, vectors_actions_setup, vectors_actions_update }, - { "view", + { "view", N_("View"), NULL, view_actions_setup, view_actions_update } }; @@ -195,6 +197,8 @@ actions_init (Gimp *gimp) for (i = 0; i < G_N_ELEMENTS (action_groups); i++) gimp_action_factory_group_register (global_action_factory, action_groups[i].identifier, + gettext (action_groups[i].label), + action_groups[i].stock_id, action_groups[i].setup_func, action_groups[i].update_func); } diff --git a/app/dialogs/preferences-dialog.c b/app/dialogs/preferences-dialog.c index bf15acf9bc..8353362130 100644 --- a/app/dialogs/preferences-dialog.c +++ b/app/dialogs/preferences-dialog.c @@ -38,6 +38,7 @@ #include "core/gimplist.h" #include "core/gimptemplate.h" +#include "widgets/gimpactionview.h" #include "widgets/gimpcolorpanel.h" #include "widgets/gimpcontainercombobox.h" #include "widgets/gimpcontainerview.h" @@ -49,6 +50,7 @@ #include "widgets/gimpgrideditor.h" #include "widgets/gimphelp-ids.h" #include "widgets/gimppropwidgets.h" +#include "widgets/gimpuimanager.h" #include "widgets/gimptemplateeditor.h" #include "widgets/gimpwidgets-utils.h" @@ -80,10 +82,12 @@ static void prefs_resolution_source_callback (GtkWidget *widget, static void prefs_resolution_calibrate_callback (GtkWidget *widget, GtkWidget *sizeentry); static void prefs_input_devices_dialog (GtkWidget *widget, - gpointer user_data); + Gimp *gimp); static void prefs_input_dialog_able_callback (GtkWidget *widget, GdkDevice *device, gpointer data); +static void prefs_keyboard_shortcuts_dialog (GtkWidget *widget, + Gimp *gimp); /* private variables */ @@ -407,12 +411,10 @@ prefs_resolution_calibrate_callback (GtkWidget *widget, static void prefs_input_devices_dialog (GtkWidget *widget, - gpointer user_data) + Gimp *gimp) { static GtkWidget *input_dialog = NULL; - Gimp *gimp = GIMP (user_data); - if (input_dialog) { gtk_window_present (GTK_WINDOW (input_dialog)); @@ -456,6 +458,46 @@ prefs_input_dialog_able_callback (GtkWidget *widget, gimp_device_info_changed_by_device (device); } +static void +prefs_keyboard_shortcuts_dialog (GtkWidget *widget, + Gimp *gimp) +{ + GtkWidget *dialog; + GtkWidget *scrolled_window; + GtkWidget *view; + + dialog = gimp_dialog_new (_("Configure Keyboard Shortcuts"), + "gimp-keyboard-shortcuts-dialog", + gtk_widget_get_toplevel (widget), + GTK_DIALOG_DESTROY_WITH_PARENT, + gimp_standard_help_func, + GIMP_HELP_PREFS_INTERFACE, + + GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL, + GTK_STOCK_OK, GTK_RESPONSE_OK, + + NULL); + + g_signal_connect (dialog, "response", + G_CALLBACK (gtk_widget_destroy), + NULL); + + scrolled_window = gtk_scrolled_window_new (NULL, NULL); + gtk_scrolled_window_set_shadow_type (GTK_SCROLLED_WINDOW (scrolled_window), + GTK_SHADOW_IN); + gtk_container_set_border_width (GTK_CONTAINER (scrolled_window), 12); + gtk_container_add (GTK_CONTAINER (GTK_DIALOG (dialog)->vbox), scrolled_window); + gtk_widget_show (scrolled_window); + + view = gimp_action_view_new (gimp_ui_managers_from_name ("")->data, + TRUE); + gtk_widget_set_size_request (view, 300, 400); + gtk_container_add (GTK_CONTAINER (scrolled_window), view); + gtk_widget_show (view); + + gtk_widget_show (dialog); +} + static GtkWidget * prefs_notebook_append_page (Gimp *gimp, GtkNotebook *notebook, @@ -1166,6 +1208,13 @@ prefs_dialog_new (Gimp *gimp, vbox2 = prefs_frame_new (_("Keyboard Shortcuts"), GTK_CONTAINER (vbox), FALSE); + button = prefs_button_add (GTK_STOCK_PREFERENCES, + _("Configure Keyboard Shortcuts..."), + GTK_BOX (vbox2)); + g_signal_connect (button, "clicked", + G_CALLBACK (prefs_keyboard_shortcuts_dialog), + gimp); + prefs_check_button_add (object, "can-change-accels", _("Use dynamic _keyboard shortcuts"), GTK_BOX (vbox2)); diff --git a/app/gui/preferences-dialog.c b/app/gui/preferences-dialog.c index bf15acf9bc..8353362130 100644 --- a/app/gui/preferences-dialog.c +++ b/app/gui/preferences-dialog.c @@ -38,6 +38,7 @@ #include "core/gimplist.h" #include "core/gimptemplate.h" +#include "widgets/gimpactionview.h" #include "widgets/gimpcolorpanel.h" #include "widgets/gimpcontainercombobox.h" #include "widgets/gimpcontainerview.h" @@ -49,6 +50,7 @@ #include "widgets/gimpgrideditor.h" #include "widgets/gimphelp-ids.h" #include "widgets/gimppropwidgets.h" +#include "widgets/gimpuimanager.h" #include "widgets/gimptemplateeditor.h" #include "widgets/gimpwidgets-utils.h" @@ -80,10 +82,12 @@ static void prefs_resolution_source_callback (GtkWidget *widget, static void prefs_resolution_calibrate_callback (GtkWidget *widget, GtkWidget *sizeentry); static void prefs_input_devices_dialog (GtkWidget *widget, - gpointer user_data); + Gimp *gimp); static void prefs_input_dialog_able_callback (GtkWidget *widget, GdkDevice *device, gpointer data); +static void prefs_keyboard_shortcuts_dialog (GtkWidget *widget, + Gimp *gimp); /* private variables */ @@ -407,12 +411,10 @@ prefs_resolution_calibrate_callback (GtkWidget *widget, static void prefs_input_devices_dialog (GtkWidget *widget, - gpointer user_data) + Gimp *gimp) { static GtkWidget *input_dialog = NULL; - Gimp *gimp = GIMP (user_data); - if (input_dialog) { gtk_window_present (GTK_WINDOW (input_dialog)); @@ -456,6 +458,46 @@ prefs_input_dialog_able_callback (GtkWidget *widget, gimp_device_info_changed_by_device (device); } +static void +prefs_keyboard_shortcuts_dialog (GtkWidget *widget, + Gimp *gimp) +{ + GtkWidget *dialog; + GtkWidget *scrolled_window; + GtkWidget *view; + + dialog = gimp_dialog_new (_("Configure Keyboard Shortcuts"), + "gimp-keyboard-shortcuts-dialog", + gtk_widget_get_toplevel (widget), + GTK_DIALOG_DESTROY_WITH_PARENT, + gimp_standard_help_func, + GIMP_HELP_PREFS_INTERFACE, + + GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL, + GTK_STOCK_OK, GTK_RESPONSE_OK, + + NULL); + + g_signal_connect (dialog, "response", + G_CALLBACK (gtk_widget_destroy), + NULL); + + scrolled_window = gtk_scrolled_window_new (NULL, NULL); + gtk_scrolled_window_set_shadow_type (GTK_SCROLLED_WINDOW (scrolled_window), + GTK_SHADOW_IN); + gtk_container_set_border_width (GTK_CONTAINER (scrolled_window), 12); + gtk_container_add (GTK_CONTAINER (GTK_DIALOG (dialog)->vbox), scrolled_window); + gtk_widget_show (scrolled_window); + + view = gimp_action_view_new (gimp_ui_managers_from_name ("")->data, + TRUE); + gtk_widget_set_size_request (view, 300, 400); + gtk_container_add (GTK_CONTAINER (scrolled_window), view); + gtk_widget_show (view); + + gtk_widget_show (dialog); +} + static GtkWidget * prefs_notebook_append_page (Gimp *gimp, GtkNotebook *notebook, @@ -1166,6 +1208,13 @@ prefs_dialog_new (Gimp *gimp, vbox2 = prefs_frame_new (_("Keyboard Shortcuts"), GTK_CONTAINER (vbox), FALSE); + button = prefs_button_add (GTK_STOCK_PREFERENCES, + _("Configure Keyboard Shortcuts..."), + GTK_BOX (vbox2)); + g_signal_connect (button, "clicked", + G_CALLBACK (prefs_keyboard_shortcuts_dialog), + gimp); + prefs_check_button_add (object, "can-change-accels", _("Use dynamic _keyboard shortcuts"), GTK_BOX (vbox2)); diff --git a/app/widgets/Makefile.am b/app/widgets/Makefile.am index 3fae1c38b8..1fc3b5dced 100644 --- a/app/widgets/Makefile.am +++ b/app/widgets/Makefile.am @@ -25,6 +25,8 @@ libappwidgets_a_sources = \ gimpactionfactory.h \ gimpactiongroup.c \ gimpactiongroup.h \ + gimpactionview.c \ + gimpactionview.h \ gimpbrusheditor.c \ gimpbrusheditor.h \ gimpbrushfactoryview.c \ diff --git a/app/widgets/gimpaction.c b/app/widgets/gimpaction.c index 929b1c2a3a..fa1859b009 100644 --- a/app/widgets/gimpaction.c +++ b/app/widgets/gimpaction.c @@ -21,6 +21,8 @@ #include "config.h" +#include + #include #include "libgimpcolor/gimpcolor.h" @@ -241,6 +243,14 @@ gimp_action_new (const gchar *name, NULL); } +gint +gimp_action_name_compare (GimpAction *action1, + GimpAction *action2) +{ + return strcmp (gtk_action_get_name ((GtkAction *) action1), + gtk_action_get_name ((GtkAction *) action2)); +} + /* private functions */ diff --git a/app/widgets/gimpaction.h b/app/widgets/gimpaction.h index d18538b800..e21ec05a9f 100644 --- a/app/widgets/gimpaction.h +++ b/app/widgets/gimpaction.h @@ -50,11 +50,14 @@ struct _GimpActionClass }; -GType gimp_action_get_type (void); -GimpAction * gimp_action_new (const gchar *name, - const gchar *label, - const gchar *tooltip, - const gchar *stock_id); +GType gimp_action_get_type (void); +GimpAction * gimp_action_new (const gchar *name, + const gchar *label, + const gchar *tooltip, + const gchar *stock_id); + +gint gimp_action_name_compare (GimpAction *action1, + GimpAction *action2); #endif /* __GIMP_ACTION_H__ */ diff --git a/app/widgets/gimpactionfactory.c b/app/widgets/gimpactionfactory.c index ce0f0300f0..d5af1c5ee9 100644 --- a/app/widgets/gimpactionfactory.c +++ b/app/widgets/gimpactionfactory.c @@ -100,6 +100,8 @@ gimp_action_factory_finalize (GObject *object) GimpActionFactoryEntry *entry = list->data; g_free (entry->identifier); + g_free (entry->label); + g_free (entry->stock_id); g_free (entry); } @@ -126,6 +128,8 @@ gimp_action_factory_new (Gimp *gimp) void gimp_action_factory_group_register (GimpActionFactory *factory, const gchar *identifier, + const gchar *label, + const gchar *stock_id, GimpActionGroupSetupFunc setup_func, GimpActionGroupUpdateFunc update_func) { @@ -133,12 +137,15 @@ gimp_action_factory_group_register (GimpActionFactory *factory, g_return_if_fail (GIMP_IS_ACTION_FACTORY (factory)); g_return_if_fail (identifier != NULL); + g_return_if_fail (label != NULL); g_return_if_fail (setup_func != NULL); g_return_if_fail (update_func != NULL); entry = g_new0 (GimpActionFactoryEntry, 1); entry->identifier = g_strdup (identifier); + entry->label = g_strdup (label); + entry->stock_id = g_strdup (stock_id); entry->setup_func = setup_func; entry->update_func = update_func; @@ -166,6 +173,8 @@ gimp_action_factory_group_new (GimpActionFactory *factory, group = gimp_action_group_new (factory->gimp, entry->identifier, + entry->label, + entry->stock_id, user_data, entry->update_func); diff --git a/app/widgets/gimpactionfactory.h b/app/widgets/gimpactionfactory.h index f457ecdaf5..75e3139d6b 100644 --- a/app/widgets/gimpactionfactory.h +++ b/app/widgets/gimpactionfactory.h @@ -31,6 +31,8 @@ typedef struct _GimpActionFactoryEntry GimpActionFactoryEntry; struct _GimpActionFactoryEntry { gchar *identifier; + gchar *label; + gchar *stock_id; GimpActionGroupSetupFunc setup_func; GimpActionGroupUpdateFunc update_func; }; @@ -66,6 +68,8 @@ GimpActionFactory * gimp_action_factory_new (Gimp *gimp); void gimp_action_factory_group_register (GimpActionFactory *factory, const gchar *identifier, + const gchar *label, + const gchar *stock_id, GimpActionGroupSetupFunc setup_func, GimpActionGroupUpdateFunc update_func); diff --git a/app/widgets/gimpactiongroup.c b/app/widgets/gimpactiongroup.c index 7c37b696f1..fbf0228281 100644 --- a/app/widgets/gimpactiongroup.c +++ b/app/widgets/gimpactiongroup.c @@ -43,7 +43,9 @@ enum { PROP_0, - PROP_GIMP + PROP_GIMP, + PROP_LABEL, + PROP_STOCK_ID }; @@ -54,6 +56,7 @@ static GObject * gimp_action_group_constructor (GType type, guint n_params, GObjectConstructParam *params); static void gimp_action_group_dispose (GObject *object); +static void gimp_action_group_finalize (GObject *object); static void gimp_action_group_set_property (GObject *object, guint prop_id, const GValue *value, @@ -104,6 +107,7 @@ gimp_action_group_class_init (GimpActionGroupClass *klass) object_class->constructor = gimp_action_group_constructor; object_class->dispose = gimp_action_group_dispose; + object_class->finalize = gimp_action_group_finalize; object_class->set_property = gimp_action_group_set_property; object_class->get_property = gimp_action_group_get_property; @@ -114,6 +118,20 @@ gimp_action_group_class_init (GimpActionGroupClass *klass) G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY)); + g_object_class_install_property (object_class, PROP_LABEL, + g_param_spec_string ("label", + NULL, NULL, + NULL, + G_PARAM_READWRITE | + G_PARAM_CONSTRUCT_ONLY)); + + g_object_class_install_property (object_class, PROP_STOCK_ID, + g_param_spec_string ("stock-id", + NULL, NULL, + NULL, + G_PARAM_READWRITE | + G_PARAM_CONSTRUCT_ONLY)); + klass->groups = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, NULL); } @@ -185,6 +203,26 @@ gimp_action_group_dispose (GObject *object) G_OBJECT_CLASS (parent_class)->dispose (object); } +static void +gimp_action_group_finalize (GObject *object) +{ + GimpActionGroup *group = GIMP_ACTION_GROUP (object); + + if (group->label) + { + g_free (group->label); + group->label = NULL; + } + + if (group->stock_id) + { + g_free (group->stock_id); + group->stock_id = NULL; + } + + G_OBJECT_CLASS (parent_class)->finalize (object); +} + static void gimp_action_group_set_property (GObject *object, guint prop_id, @@ -198,6 +236,12 @@ gimp_action_group_set_property (GObject *object, case PROP_GIMP: group->gimp = g_value_get_object (value); break; + case PROP_LABEL: + group->label = g_value_dup_string (value); + break; + case PROP_STOCK_ID: + group->stock_id = g_value_dup_string (value); + break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); break; @@ -217,6 +261,12 @@ gimp_action_group_get_property (GObject *object, case PROP_GIMP: g_value_set_object (value, group->gimp); break; + case PROP_LABEL: + g_value_set_string (value, group->label); + break; + case PROP_STOCK_ID: + g_value_set_string (value, group->stock_id); + break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); break; @@ -227,6 +277,8 @@ gimp_action_group_get_property (GObject *object, * gimp_action_group_new: * @gimp: the @Gimp instance this action group belongs to * @name: the name of the action group. + * @label: the user visible label of the action group. + * @stock_id: the icon of the action group. * @user_data: the user_data for #GtkAction callbacks. * @update_func: the function that will be called on * gimp_action_group_update(). @@ -240,6 +292,8 @@ gimp_action_group_get_property (GObject *object, GimpActionGroup * gimp_action_group_new (Gimp *gimp, const gchar *name, + const gchar *label, + const gchar *stock_id, gpointer user_data, GimpActionGroupUpdateFunc update_func) { @@ -249,8 +303,10 @@ gimp_action_group_new (Gimp *gimp, g_return_val_if_fail (name != NULL, NULL); group = g_object_new (GIMP_TYPE_ACTION_GROUP, - "gimp", gimp, - "name", name, + "gimp", gimp, + "name", name, + "label", label, + "stock-id", stock_id, NULL); group->user_data = user_data; diff --git a/app/widgets/gimpactiongroup.h b/app/widgets/gimpactiongroup.h index 0a73600e8b..2ff03b46ae 100644 --- a/app/widgets/gimpactiongroup.h +++ b/app/widgets/gimpactiongroup.h @@ -37,10 +37,13 @@ typedef struct _GimpActionGroupClass GimpActionGroupClass; struct _GimpActionGroup { - GtkActionGroup parent_instance; + GtkActionGroup parent_instance; - Gimp *gimp; - gpointer user_data; + Gimp *gimp; + gchar *label; + gchar *stock_id; + + gpointer user_data; GimpActionGroupUpdateFunc update_func; }; @@ -129,6 +132,8 @@ struct _GimpPlugInActionEntry GType gimp_action_group_get_type (void); GimpActionGroup *gimp_action_group_new (Gimp *gimp, const gchar *name, + const gchar *label, + const gchar *stock_id, gpointer user_data, GimpActionGroupUpdateFunc update_func); diff --git a/app/widgets/gimpactionview.c b/app/widgets/gimpactionview.c new file mode 100644 index 0000000000..98165d8942 --- /dev/null +++ b/app/widgets/gimpactionview.c @@ -0,0 +1,382 @@ +/* The GIMP -- an image manipulation program + * Copyright (C) 1995 Spencer Kimball and Peter Mattis + * + * gimpactionview.c + * Copyright (C) 2004 Michael Natterer + * + * 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +#include "config.h" + +#include + +#include + +#include "libgimpbase/gimpbase.h" + +#include "widgets-types.h" + +#include "gimpaction.h" +#include "gimpactiongroup.h" +#include "gimpactionview.h" +#include "gimpuimanager.h" +#include "gimpwidgets-utils.h" + +#include "gimp-intl.h" + + +enum +{ + COLUMN_ACTION, + COLUMN_STOCK_ID, + COLUMN_LABEL, + COLUMN_NAME, + COLUMN_SHORTCUT, + COLUMN_MENU_ITEM, + NUM_COLUMNS +}; + + +/* local function prototypes */ + +static void gimp_action_view_class_init (GimpActionViewClass *klass); +static void gimp_action_view_init (GimpActionView *view); + +static gchar * gimp_action_view_get_shortcut (GtkAccelGroup *group, + GClosure *accel_closure); +static gboolean gimp_action_view_accel_find_func (GtkAccelKey *key, + GClosure *closure, + gpointer data); +static void gimp_action_view_accel_changed (GtkAccelGroup *accel_group, + guint unused1, + GdkModifierType unused2, + GClosure *accel_closure, + GimpActionView *view); + + +GType +gimp_action_view_get_type (void) +{ + static GType view_type = 0; + + if (! view_type) + { + static const GTypeInfo view_info = + { + sizeof (GimpActionViewClass), + NULL, /* base_init */ + NULL, /* base_finalize */ + (GClassInitFunc) gimp_action_view_class_init, + NULL, /* class_finalize */ + NULL, /* class_data */ + sizeof (GimpActionView), + 0, /* n_preallocs */ + (GInstanceInitFunc) gimp_action_view_init + }; + + view_type = g_type_register_static (GTK_TYPE_TREE_VIEW, + "GimpActionView", + &view_info, 0); + } + + return view_type; +} + +static void +gimp_action_view_class_init (GimpActionViewClass *klass) +{ +} + +static void +gimp_action_view_init (GimpActionView *view) +{ +} + +GtkWidget * +gimp_action_view_new (GimpUIManager *manager, + gboolean show_shortcuts) +{ + GtkTreeView *view; + GtkTreeViewColumn *column; + GtkCellRenderer *cell; + GtkTreeStore *store; + GtkAccelGroup *accel_group; + GList *list; + + g_return_val_if_fail (GIMP_IS_UI_MANAGER (manager), NULL); + + store = gtk_tree_store_new (NUM_COLUMNS, + GTK_TYPE_ACTION, /* COLUMN_ACTION */ + G_TYPE_STRING, /* COLUMN_STOCK_ID */ + G_TYPE_STRING, /* COLUMN_LABEL */ + G_TYPE_STRING, /* COLUMN_NAME */ + G_TYPE_STRING, /* COLUMN_SHORTCUT */ + GTK_TYPE_MENU_ITEM); /* COLUMN_MENU_ITEM */ + + accel_group = gtk_ui_manager_get_accel_group (GTK_UI_MANAGER (manager)); + + for (list = gtk_ui_manager_get_action_groups (GTK_UI_MANAGER (manager)); + list; + list = g_list_next (list)) + { + GimpActionGroup *group = list->data; + GList *actions; + GList *list2; + GtkTreeIter group_iter; + + gtk_tree_store_append (store, &group_iter, NULL); + + gtk_tree_store_set (store, &group_iter, + COLUMN_ACTION, NULL, + COLUMN_STOCK_ID, group->stock_id, + COLUMN_LABEL, group->label, + COLUMN_NAME, NULL, + COLUMN_SHORTCUT, NULL, + COLUMN_MENU_ITEM, NULL, + -1); + + actions = gtk_action_group_list_actions (GTK_ACTION_GROUP (group)); + + actions = g_list_sort (actions, (GCompareFunc) gimp_action_name_compare); + + for (list2 = actions; list2; list2 = g_list_next (list2)) + { + GtkAction *action = list2->data; + const gchar *name = gtk_action_get_name (action); + + if (! strstr (name, "-menu") && + ! strstr (name, "-popup")) + { + GtkTreeIter action_iter; + gchar *stock_id; + gchar *label; + gchar *stripped; + gchar *shortcut = NULL; + GtkWidget *menu_item = NULL; + + g_object_get (action, + "stock-id", &stock_id, + "label", &label, + NULL); + + stripped = gimp_strip_uline (label); + + if (show_shortcuts) + { + gtk_action_set_accel_group (action, accel_group); + + menu_item = gtk_action_create_menu_item (action); + + if (GTK_IS_MENU_ITEM (menu_item) && + GTK_IS_ACCEL_LABEL (GTK_BIN (menu_item)->child)) + { + GtkWidget *accel_label = GTK_BIN (menu_item)->child; + GClosure *accel_closure; + + g_object_get (accel_label, + "accel-closure", &accel_closure, + NULL); + + if (accel_closure) + shortcut = + gimp_action_view_get_shortcut (accel_group, + accel_closure); + + g_object_ref (menu_item); + gtk_object_sink (GTK_OBJECT (menu_item)); + } + else if (menu_item) + { + gtk_object_sink (GTK_OBJECT (menu_item)); + menu_item = NULL; + } + } + + gtk_tree_store_append (store, &action_iter, &group_iter); + + gtk_tree_store_set (store, &action_iter, + COLUMN_ACTION, action, + COLUMN_STOCK_ID, stock_id, + COLUMN_LABEL, stripped, + COLUMN_NAME, name, + COLUMN_SHORTCUT, shortcut, + COLUMN_MENU_ITEM, menu_item, + -1); + + g_free (stock_id); + g_free (label); + g_free (stripped); + g_free (shortcut); + + if (menu_item) + g_object_unref (menu_item); + } + } + + g_list_free (actions); + } + + view = g_object_new (GIMP_TYPE_ACTION_VIEW, + "model", store, + "rules-hint", TRUE, + NULL); + + g_object_unref (store); + + column = gtk_tree_view_column_new (); + gtk_tree_view_column_set_title (column, _("Action")); + + cell = gtk_cell_renderer_pixbuf_new (); + gtk_tree_view_column_pack_start (column, cell, FALSE); + gtk_tree_view_column_set_attributes (column, cell, + "stock-id", COLUMN_STOCK_ID, + NULL); + + cell = gtk_cell_renderer_text_new (); + gtk_tree_view_column_pack_start (column, cell, TRUE); + gtk_tree_view_column_set_attributes (column, cell, + "text", COLUMN_LABEL, + NULL); + + gtk_tree_view_append_column (view, column); + + if (show_shortcuts) + { + g_signal_connect_object (accel_group, "accel_changed", + G_CALLBACK (gimp_action_view_accel_changed), + view, 0); + + column = gtk_tree_view_column_new (); + gtk_tree_view_column_set_title (column, _("Shortcut")); + + cell = gtk_cell_renderer_text_new (); + gtk_tree_view_column_pack_start (column, cell, TRUE); + gtk_tree_view_column_set_attributes (column, cell, + "text", COLUMN_SHORTCUT, + NULL); + + gtk_tree_view_append_column (view, column); + } + else + { + column = gtk_tree_view_column_new (); + gtk_tree_view_column_set_title (column, _("Name")); + + cell = gtk_cell_renderer_text_new (); + gtk_tree_view_column_pack_start (column, cell, TRUE); + gtk_tree_view_column_set_attributes (column, cell, + "text", COLUMN_NAME, + NULL); + + gtk_tree_view_append_column (view, column); + } + + return GTK_WIDGET (view); +} + + +/* private functions */ + +static gchar * +gimp_action_view_get_shortcut (GtkAccelGroup *accel_group, + GClosure *accel_closure) +{ + GtkAccelKey *accel_key; + + accel_key = gtk_accel_group_find (accel_group, + gimp_action_view_accel_find_func, + accel_closure); + + if (accel_key && + accel_key->accel_key && + accel_key->accel_flags & GTK_ACCEL_VISIBLE) + { + return gimp_get_accel_string (accel_key->accel_key, + accel_key->accel_mods); + } + + return NULL; +} + +static gboolean +gimp_action_view_accel_find_func (GtkAccelKey *key, + GClosure *closure, + gpointer data) +{ + return (GClosure *) data == closure; +} + +static void +gimp_action_view_accel_changed (GtkAccelGroup *accel_group, + guint unused1, + GdkModifierType unused2, + GClosure *accel_closure, + GimpActionView *view) +{ + GtkTreeModel *model; + GtkTreeIter iter; + gboolean iter_valid; + + model = gtk_tree_view_get_model (GTK_TREE_VIEW (view)); + if (! model) + return; + + for (iter_valid = gtk_tree_model_get_iter_first (model, &iter); + iter_valid; + iter_valid = gtk_tree_model_iter_next (model, &iter)) + { + GtkTreeIter child_iter; + gboolean child_valid; + + for (child_valid = gtk_tree_model_iter_children (model, &child_iter, + &iter); + child_valid; + child_valid = gtk_tree_model_iter_next (model, &child_iter)) + { + GtkWidget *menu_item; + + gtk_tree_model_get (model, &child_iter, + COLUMN_MENU_ITEM, &menu_item, + -1); + + if (menu_item) + { + GClosure *item_closure; + + g_object_get (GTK_BIN (menu_item)->child, + "accel-closure", &item_closure, + NULL); + + g_object_unref (menu_item); + + if (accel_closure == item_closure) + { + gchar *shortcut; + + shortcut = gimp_action_view_get_shortcut (accel_group, + accel_closure); + + gtk_tree_store_set (GTK_TREE_STORE (model), &child_iter, + COLUMN_SHORTCUT, shortcut, + -1); + g_free (shortcut); + + return; + } + } + } + } +} diff --git a/app/widgets/gimpactionview.h b/app/widgets/gimpactionview.h new file mode 100644 index 0000000000..0337dbb35c --- /dev/null +++ b/app/widgets/gimpactionview.h @@ -0,0 +1,58 @@ +/* The GIMP -- an image manipulation program + * Copyright (C) 1995 Spencer Kimball and Peter Mattis + * + * gimpactionview.h + * Copyright (C) 2004 Michael Natterer + * + * 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +#ifndef __GIMP_ACTION_VIEW_H__ +#define __GIMP_ACTION_VIEW_H__ + + +#include + + +#define GIMP_TYPE_ACTION_VIEW (gimp_action_view_get_type ()) +#define GIMP_ACTION_VIEW(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GIMP_TYPE_ACTION_VIEW, GimpActionView)) +#define GIMP_ACTION_VIEW_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), GIMP_TYPE_ACTION_VIEW, GimpActionViewClass)) +#define GIMP_IS_ACTION_VIEW(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GIMP_TYPE_ACTION_VIEW)) +#define GIMP_IS_ACTION_VIEW_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), GIMP_TYPE_ACTION_VIEW)) +#define GIMP_ACTION_VIEW_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), GIMP_TYPE_ACTION_VIEW, GimpActionViewClass)) + + +typedef struct _GimpActionViewClass GimpActionViewClass; + +struct _GimpActionView +{ + GtkTreeView parent_instance; +}; + +struct _GimpActionViewClass +{ + GtkTreeViewClass parent_class; + + void (* changed) (GimpActionView *view); +}; + + +GType gimp_action_view_get_type (void) G_GNUC_CONST; + +GtkWidget * gimp_action_view_new (GimpUIManager *manager, + gboolean show_shortcuts); + + +#endif /* __GIMP_ACTION_VIEW_H__ */ diff --git a/app/widgets/gimpcontrollers.c b/app/widgets/gimpcontrollers.c index f8167219af..dbd0010105 100644 --- a/app/widgets/gimpcontrollers.c +++ b/app/widgets/gimpcontrollers.c @@ -237,6 +237,20 @@ gimp_controllers_get_list (Gimp *gimp) return manager->controllers; } +GimpUIManager * +gimp_controllers_get_ui_manager (Gimp *gimp) +{ + GimpControllerManager *manager; + + g_return_val_if_fail (GIMP_IS_GIMP (gimp), NULL); + + manager = gimp_controller_manager_get (gimp); + + g_return_val_if_fail (manager != NULL, NULL); + + return manager->ui_manager; +} + GimpController * gimp_controllers_get_wheel (Gimp *gimp) { diff --git a/app/widgets/gimpcontrollers.h b/app/widgets/gimpcontrollers.h index 9903412c61..ce5861188f 100644 --- a/app/widgets/gimpcontrollers.h +++ b/app/widgets/gimpcontrollers.h @@ -23,16 +23,17 @@ #define __GIMP_CONTROLLERS_H__ -void gimp_controllers_init (Gimp *gimp); -void gimp_controllers_exit (Gimp *gimp); +void gimp_controllers_init (Gimp *gimp); +void gimp_controllers_exit (Gimp *gimp); -void gimp_controllers_restore (Gimp *gimp, - GimpUIManager *ui_manager); -void gimp_controllers_save (Gimp *gimp); +void gimp_controllers_restore (Gimp *gimp, + GimpUIManager *ui_manager); +void gimp_controllers_save (Gimp *gimp); -GimpContainer * gimp_controllers_get_list (Gimp *gimp); -GimpController * gimp_controllers_get_wheel (Gimp *gimp); -GimpController * gimp_controllers_get_keyboard (Gimp *gimp); +GimpContainer * gimp_controllers_get_list (Gimp *gimp); +GimpUIManager * gimp_controllers_get_ui_manager (Gimp *gimp); +GimpController * gimp_controllers_get_wheel (Gimp *gimp); +GimpController * gimp_controllers_get_keyboard (Gimp *gimp); #endif /* __GIMP_CONTROLLERS_H__ */ diff --git a/app/widgets/gimpwidgets-utils.c b/app/widgets/gimpwidgets-utils.c index e442bfbb5f..110bad4525 100644 --- a/app/widgets/gimpwidgets-utils.c +++ b/app/widgets/gimpwidgets-utils.c @@ -663,7 +663,67 @@ gimp_get_mod_string (GdkModifierType modifiers) } } - return ""; + return NULL; +} + +static void +gimp_substitute_underscores (gchar *str) +{ + gchar *p; + + for (p = str; *p; p++) + if (*p == '_') + *p = ' '; +} + +gchar * +gimp_get_accel_string (guint key, + GdkModifierType modifiers) +{ + GtkAccelLabelClass *accel_label_class; + GString *gstring; + gunichar ch; + + accel_label_class = g_type_class_peek (GTK_TYPE_ACCEL_LABEL); + + gstring = g_string_new (gimp_get_mod_string (modifiers)); + + if (gstring->len > 0) + g_string_append (gstring, gimp_get_mod_separator ()); + + ch = gdk_keyval_to_unicode (key); + + if (ch && (g_unichar_isgraph (ch) || ch == ' ') && + (ch < 0x80 || accel_label_class->latin1_to_char)) + { + switch (ch) + { + case ' ': + g_string_append (gstring, "Space"); + break; + case '\\': + g_string_append (gstring, "Backslash"); + break; + default: + g_string_append_unichar (gstring, g_unichar_toupper (ch)); + break; + } + } + else + { + gchar *tmp; + + tmp = gtk_accelerator_name (key, 0); + + if (tmp[0] != 0 && tmp[1] == 0) + tmp[0] = g_ascii_toupper (tmp[0]); + + gimp_substitute_underscores (tmp); + g_string_append (gstring, tmp); + g_free (tmp); + } + + return g_string_free (gstring, FALSE); } diff --git a/app/widgets/gimpwidgets-utils.h b/app/widgets/gimpwidgets-utils.h index f72f393b06..280f290d13 100644 --- a/app/widgets/gimpwidgets-utils.h +++ b/app/widgets/gimpwidgets-utils.h @@ -57,6 +57,8 @@ const gchar * gimp_get_mod_name_control (void); const gchar * gimp_get_mod_name_alt (void); const gchar * gimp_get_mod_separator (void); const gchar * gimp_get_mod_string (GdkModifierType modifiers); +gchar * gimp_get_accel_string (guint key, + GdkModifierType modifiers); void gimp_get_screen_resolution (GdkScreen *screen, gdouble *xres, diff --git a/app/widgets/widgets-types.h b/app/widgets/widgets-types.h index e75712dce3..61fd18f086 100644 --- a/app/widgets/widgets-types.h +++ b/app/widgets/widgets-types.h @@ -141,6 +141,7 @@ typedef struct _GimpFontSelect GimpFontSelect; /* misc widgets */ +typedef struct _GimpActionView GimpActionView; typedef struct _GimpColorBar GimpColorBar; typedef struct _GimpColorDisplayEditor GimpColorDisplayEditor; typedef struct _GimpColorFrame GimpColorFrame;