Issue #9228: make GEGL Operation tool's operations their own actions too.
Though the GEGL Operation tool is still useful as a generic dialog, let's generate also per-operation (the ones not ignored and not already special-cased in the rest of the GUI) tools and actions. These "tools" are mostly hidden (e.g. not selectable in toolbox where it would be a bit useless as they would show with the generic GEGL icon or none), but they can be searched with the action search, shortcuts can be assigned and they can be added to menus.
This commit is contained in:
parent
60354a0e59
commit
d51c64ec06
4 changed files with 169 additions and 39 deletions
|
|
@ -147,7 +147,13 @@ gimp_tool_dialog_new (GimpToolInfo *tool_info,
|
|||
gimp_dialog_add_buttons_valist (GIMP_DIALOG (dialog), args);
|
||||
va_end (args);
|
||||
|
||||
identifier = g_strconcat (gimp_object_get_name (tool_info), "-dialog", NULL);
|
||||
/* We don't register a foreign dialog for every generated GEGL op tool. Simply
|
||||
* use the base GimpGeglTool dialog for them all.
|
||||
*/
|
||||
if (g_str_has_prefix (gimp_object_get_name (tool_info), "gimp-gegl-op-"))
|
||||
identifier = g_strdup ("gimp-gegl-tool-dialog");
|
||||
else
|
||||
identifier = g_strconcat (gimp_object_get_name (tool_info), "-dialog", NULL);
|
||||
|
||||
gimp_dialog_factory_add_foreign (gimp_dialog_factory_get_singleton (),
|
||||
identifier,
|
||||
|
|
|
|||
|
|
@ -748,7 +748,10 @@ gimp_tools_register (GType tool_type,
|
|||
gimp_tool_item_set_visible (GIMP_TOOL_ITEM (tool_info), visible);
|
||||
|
||||
/* hack to hide the operation tool entirely */
|
||||
if (tool_type == GIMP_TYPE_OPERATION_TOOL)
|
||||
if (tool_type == GIMP_TYPE_OPERATION_TOOL ||
|
||||
/* Don't show the generated GEGL tools either. */
|
||||
(tool_type == GIMP_TYPE_GEGL_TOOL &&
|
||||
g_strcmp0 (identifier, "gimp-gegl-tool") != 0))
|
||||
tool_info->hidden = TRUE;
|
||||
|
||||
/* hack to not require experimental tools to be present in toolrc */
|
||||
|
|
|
|||
|
|
@ -29,8 +29,12 @@
|
|||
|
||||
#include "tools-types.h"
|
||||
|
||||
#include "core/gimp.h"
|
||||
#include "core/gimptoolinfo.h"
|
||||
|
||||
#include "widgets/gimphelp-ids.h"
|
||||
#include "widgets/gimppropwidgets.h"
|
||||
#include "widgets/gimpwidgets-utils.h"
|
||||
|
||||
#include "gimpfilteroptions.h"
|
||||
#include "gimpgegltool.h"
|
||||
|
|
@ -49,16 +53,18 @@ enum
|
|||
|
||||
/* local function prototypes */
|
||||
|
||||
static void gimp_gegl_tool_control (GimpTool *tool,
|
||||
GimpToolAction action,
|
||||
GimpDisplay *display);
|
||||
static void gimp_gegl_tool_control (GimpTool *tool,
|
||||
GimpToolAction action,
|
||||
GimpDisplay *display);
|
||||
|
||||
static void gimp_gegl_tool_dialog (GimpFilterTool *filter_tool);
|
||||
static GList * gimp_get_geglopclasses (void);
|
||||
|
||||
static void gimp_gegl_tool_halt (GimpGeglTool *gegl_tool);
|
||||
static void gimp_gegl_tool_dialog (GimpFilterTool *filter_tool);
|
||||
|
||||
static void gimp_gegl_tool_operation_changed (GtkWidget *widget,
|
||||
GimpGeglTool *gegl_tool);
|
||||
static void gimp_gegl_tool_halt (GimpGeglTool *gegl_tool);
|
||||
|
||||
static void gimp_gegl_tool_operation_changed (GtkWidget *widget,
|
||||
GimpGeglTool *gegl_tool);
|
||||
|
||||
|
||||
G_DEFINE_TYPE (GimpGeglTool, gimp_gegl_tool, GIMP_TYPE_OPERATION_TOOL)
|
||||
|
|
@ -70,6 +76,13 @@ void
|
|||
gimp_gegl_tool_register (GimpToolRegisterCallback callback,
|
||||
gpointer data)
|
||||
{
|
||||
GimpGeglToolClass *klass;
|
||||
Gimp *gimp = GIMP (data);
|
||||
GList *opclasses;
|
||||
GList *iter;
|
||||
|
||||
klass = g_type_class_ref (GIMP_TYPE_GEGL_TOOL);
|
||||
|
||||
(* callback) (GIMP_TYPE_GEGL_TOOL,
|
||||
GIMP_TYPE_FILTER_OPTIONS,
|
||||
gimp_color_options_gui,
|
||||
|
|
@ -81,6 +94,76 @@ gimp_gegl_tool_register (GimpToolRegisterCallback callback,
|
|||
NULL, GIMP_HELP_TOOL_GEGL,
|
||||
GIMP_ICON_GEGL,
|
||||
data);
|
||||
|
||||
/* We generate hidden tools for every non-ignored GEGL operation, allowing
|
||||
* people to easily access their custom GEGL operations.
|
||||
*/
|
||||
opclasses = gimp_get_geglopclasses ();
|
||||
|
||||
for (iter = opclasses; iter; iter = iter->next)
|
||||
{
|
||||
GeglOperationClass *opclass = GEGL_OPERATION_CLASS (iter->data);
|
||||
const gchar *icon_name = NULL;
|
||||
const gchar *op_name = opclass->name;
|
||||
const gchar *title;
|
||||
const gchar *desc;
|
||||
gchar *formatted_op_name;
|
||||
gchar *action_name;
|
||||
gchar *identifier;
|
||||
gchar *label;
|
||||
gint i = 2;
|
||||
|
||||
formatted_op_name = g_strdup (opclass->name);
|
||||
gimp_make_valid_action_name (formatted_op_name);
|
||||
action_name = g_strdup_printf ("tools-gegl-op-%s", formatted_op_name);
|
||||
|
||||
while (g_action_group_has_action (G_ACTION_GROUP (gimp->app), action_name))
|
||||
{
|
||||
/* In the off-chance that after formatting to a valid action name, 2
|
||||
* operations end up generating the same action name.
|
||||
*/
|
||||
g_free (action_name);
|
||||
action_name = g_strdup_printf ("tools-gegl-op-%s-%d", formatted_op_name, i++);
|
||||
}
|
||||
g_free (formatted_op_name);
|
||||
|
||||
/* gimp_tool_info_get_action_name() expects a name starting with "gimp-"
|
||||
* and ending with "-tool".
|
||||
*/
|
||||
identifier = g_strdup_printf ("gimp-%s-tool", action_name + strlen ("tools-"));
|
||||
g_hash_table_replace (klass->generated_ops, action_name, g_strdup (op_name));
|
||||
|
||||
if (g_str_has_prefix (op_name, "gegl:"))
|
||||
icon_name = GIMP_ICON_GEGL;
|
||||
|
||||
if (g_str_has_prefix (op_name, "gegl:"))
|
||||
op_name += strlen ("gegl:");
|
||||
|
||||
title = gegl_operation_class_get_key (opclass, "title");
|
||||
desc = gegl_operation_class_get_key (opclass, "description");
|
||||
|
||||
if (title)
|
||||
label = g_strdup_printf ("%s (%s)", title, op_name);
|
||||
else
|
||||
label = g_strdup (op_name);
|
||||
|
||||
(* callback) (GIMP_TYPE_GEGL_TOOL,
|
||||
GIMP_TYPE_FILTER_OPTIONS,
|
||||
gimp_color_options_gui,
|
||||
0,
|
||||
identifier,
|
||||
label, desc ? desc : label,
|
||||
label, NULL,
|
||||
NULL, GIMP_HELP_TOOL_GEGL,
|
||||
icon_name,
|
||||
data);
|
||||
|
||||
g_free (label);
|
||||
g_free (identifier);
|
||||
}
|
||||
|
||||
g_list_free (opclasses);
|
||||
g_type_class_unref (klass);
|
||||
}
|
||||
|
||||
static void
|
||||
|
|
@ -92,6 +175,12 @@ gimp_gegl_tool_class_init (GimpGeglToolClass *klass)
|
|||
tool_class->control = gimp_gegl_tool_control;
|
||||
|
||||
filter_tool_class->dialog = gimp_gegl_tool_dialog;
|
||||
|
||||
/* Store the mapping from tool identifier to operation name.
|
||||
* This data is leaking, otherwise we'd have to register a dynamic type with a
|
||||
* class_finalize() class method.
|
||||
**/
|
||||
klass->generated_ops = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, g_free);
|
||||
}
|
||||
|
||||
static void
|
||||
|
|
@ -400,9 +489,10 @@ gimp_get_geglopclasses (void)
|
|||
static void
|
||||
gimp_gegl_tool_dialog (GimpFilterTool *filter_tool)
|
||||
{
|
||||
GimpGeglTool *tool = GIMP_GEGL_TOOL (filter_tool);
|
||||
GimpOperationTool *o_tool = GIMP_OPERATION_TOOL (filter_tool);
|
||||
GtkListStore *store;
|
||||
GimpGeglTool *tool = GIMP_GEGL_TOOL (filter_tool);
|
||||
GimpOperationTool *o_tool = GIMP_OPERATION_TOOL (filter_tool);
|
||||
GimpToolInfo *tool_info = GIMP_TOOL (tool)->tool_info;
|
||||
GtkListStore *store = NULL;
|
||||
GtkCellRenderer *cell;
|
||||
GtkWidget *main_vbox;
|
||||
GtkWidget *hbox;
|
||||
|
|
@ -411,6 +501,14 @@ gimp_gegl_tool_dialog (GimpFilterTool *filter_tool)
|
|||
GtkWidget *options_box;
|
||||
GList *opclasses;
|
||||
GList *iter;
|
||||
gchar *action_name;
|
||||
gchar *show_op_name = NULL;
|
||||
GimpGeglToolClass *klass;
|
||||
|
||||
klass = GIMP_GEGL_TOOL_GET_CLASS (tool);
|
||||
action_name = gimp_tool_info_get_action_name (tool_info);
|
||||
show_op_name = g_hash_table_lookup (klass->generated_ops, action_name);
|
||||
g_free (action_name);
|
||||
|
||||
GIMP_FILTER_TOOL_CLASS (parent_class)->dialog (filter_tool);
|
||||
|
||||
|
|
@ -425,8 +523,9 @@ gimp_gegl_tool_dialog (GimpFilterTool *filter_tool)
|
|||
gtk_box_reorder_child (GTK_BOX (main_vbox), hbox, 0);
|
||||
gtk_widget_show (hbox);
|
||||
|
||||
store = gtk_list_store_new (N_COLUMNS,
|
||||
G_TYPE_STRING, G_TYPE_STRING, G_TYPE_STRING);
|
||||
if (show_op_name == NULL)
|
||||
store = gtk_list_store_new (N_COLUMNS,
|
||||
G_TYPE_STRING, G_TYPE_STRING, G_TYPE_STRING);
|
||||
|
||||
opclasses = gimp_get_geglopclasses ();
|
||||
|
||||
|
|
@ -438,6 +537,9 @@ gimp_gegl_tool_dialog (GimpFilterTool *filter_tool)
|
|||
const gchar *title;
|
||||
gchar *label;
|
||||
|
||||
if (show_op_name != NULL && g_strcmp0 (show_op_name, op_name) != 0)
|
||||
continue;
|
||||
|
||||
if (g_str_has_prefix (opclass->name, "gegl:"))
|
||||
icon_name = GIMP_ICON_GEGL;
|
||||
|
||||
|
|
@ -451,40 +553,57 @@ gimp_gegl_tool_dialog (GimpFilterTool *filter_tool)
|
|||
else
|
||||
label = g_strdup (op_name);
|
||||
|
||||
gtk_list_store_insert_with_values (store, NULL, -1,
|
||||
COLUMN_NAME, opclass->name,
|
||||
COLUMN_LABEL, label,
|
||||
COLUMN_ICON_NAME, icon_name,
|
||||
-1);
|
||||
if (store != NULL)
|
||||
gtk_list_store_insert_with_values (store, NULL, -1,
|
||||
COLUMN_NAME, opclass->name,
|
||||
COLUMN_LABEL, label,
|
||||
COLUMN_ICON_NAME, icon_name,
|
||||
-1);
|
||||
else
|
||||
gimp_operation_tool_set_operation (GIMP_OPERATION_TOOL (tool),
|
||||
opclass->name,
|
||||
label,
|
||||
gegl_operation_class_get_key (opclass, "description"),
|
||||
NULL,
|
||||
icon_name,
|
||||
GIMP_HELP_TOOL_GEGL);
|
||||
|
||||
g_free (label);
|
||||
}
|
||||
|
||||
if (show_op_name != NULL)
|
||||
break;
|
||||
}
|
||||
g_list_free (opclasses);
|
||||
|
||||
combo = gtk_combo_box_new_with_model (GTK_TREE_MODEL (store));
|
||||
g_object_unref (store);
|
||||
gtk_box_pack_start (GTK_BOX (hbox), combo, TRUE, TRUE, 0);
|
||||
gtk_widget_show (combo);
|
||||
/* We either show the full combo or we found a specific operation. */
|
||||
g_return_if_fail (store != NULL || iter != NULL);
|
||||
|
||||
cell = gtk_cell_renderer_pixbuf_new ();
|
||||
gtk_cell_layout_pack_start (GTK_CELL_LAYOUT (combo), cell, FALSE);
|
||||
gtk_cell_layout_add_attribute (GTK_CELL_LAYOUT (combo), cell,
|
||||
"icon-name", COLUMN_ICON_NAME);
|
||||
if (store != NULL)
|
||||
{
|
||||
combo = gtk_combo_box_new_with_model (GTK_TREE_MODEL (store));
|
||||
g_object_unref (store);
|
||||
gtk_box_pack_start (GTK_BOX (hbox), combo, TRUE, TRUE, 0);
|
||||
gtk_widget_show (combo);
|
||||
|
||||
cell = gtk_cell_renderer_text_new ();
|
||||
g_object_set (cell,
|
||||
"ellipsize", PANGO_ELLIPSIZE_MIDDLE,
|
||||
NULL);
|
||||
gtk_cell_layout_pack_start (GTK_CELL_LAYOUT (combo), cell, TRUE);
|
||||
gtk_cell_layout_add_attribute (GTK_CELL_LAYOUT (combo), cell,
|
||||
"text", COLUMN_LABEL);
|
||||
cell = gtk_cell_renderer_pixbuf_new ();
|
||||
gtk_cell_layout_pack_start (GTK_CELL_LAYOUT (combo), cell, FALSE);
|
||||
gtk_cell_layout_add_attribute (GTK_CELL_LAYOUT (combo), cell,
|
||||
"icon-name", COLUMN_ICON_NAME);
|
||||
|
||||
g_signal_connect (combo, "changed",
|
||||
G_CALLBACK (gimp_gegl_tool_operation_changed),
|
||||
tool);
|
||||
cell = gtk_cell_renderer_text_new ();
|
||||
g_object_set (cell,
|
||||
"ellipsize", PANGO_ELLIPSIZE_MIDDLE,
|
||||
NULL);
|
||||
gtk_cell_layout_pack_start (GTK_CELL_LAYOUT (combo), cell, TRUE);
|
||||
gtk_cell_layout_add_attribute (GTK_CELL_LAYOUT (combo), cell,
|
||||
"text", COLUMN_LABEL);
|
||||
|
||||
tool->operation_combo = combo;
|
||||
g_signal_connect (combo, "changed",
|
||||
G_CALLBACK (gimp_gegl_tool_operation_changed),
|
||||
tool);
|
||||
|
||||
tool->operation_combo = combo;
|
||||
}
|
||||
|
||||
tool->description_label = gtk_label_new ("");
|
||||
gtk_label_set_line_wrap (GTK_LABEL (tool->description_label), TRUE);
|
||||
|
|
|
|||
|
|
@ -45,6 +45,8 @@ struct _GimpGeglTool
|
|||
struct _GimpGeglToolClass
|
||||
{
|
||||
GimpOperationToolClass parent_class;
|
||||
|
||||
GHashTable *generated_ops;
|
||||
};
|
||||
|
||||
|
||||
|
|
|
|||
Loading…
Reference in a new issue