Commit f4f2de1b authored by Michael Natterer's avatar Michael Natterer 😴

app: start an infrastructure for on-canvas controllers for operations

Pass a "GimpCreateControllerFunc" to all gimppropgui-*.[ch]
constructors which takes a callback (to update the config object when
the on-canvas GUI) and a controller type that determines the
callback's signature, and returns another callback (to update the
on-canvas GUI when the config object changes).

In GimpOperationTool, pass such a GimpCreateControllerFunc that
handles creating and adding on-canvas controller via the new
gimpfiltertool-widgets.[ch]. So far, a simple line like in the
blend tool is supported.

Add a custom GUI for gegl:spiral, and have its origin, radius and
angle controlled by such a line.
parent a2c33101
......@@ -80,6 +80,8 @@ libapptools_a_sources = \
gimpfiltertool.h \
gimpfiltertool-settings.c \
gimpfiltertool-settings.h \
gimpfiltertool-widgets.c \
gimpfiltertool-widgets.h \
gimpflipoptions.c \
gimpflipoptions.h \
gimpfliptool.c \
......
/* GIMP - The GNU Image Manipulation Program
* Copyright (C) 1995 Spencer Kimball and Peter Mattis
*
* gimpfiltertool-widgets.c
*
* 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 3 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, see <http://www.gnu.org/licenses/>.
*/
#include "config.h"
#include <gegl.h>
#include <gtk/gtk.h>
#include "tools-types.h"
#include "core/gimpitem.h"
#include "display/gimpdisplay.h"
#include "display/gimptoolline.h"
#include "gimpfilteroptions.h"
#include "gimpfiltertool.h"
#include "gimpfiltertool-widgets.h"
typedef struct _Controller Controller;
struct _Controller
{
GimpFilterTool *filter_tool;
GimpControllerType controller_type;
GimpToolWidget *widget;
GCallback creator_callback;
gpointer creator_data;
};
/* local function prototypes */
static void gimp_filter_tool_set_line (Controller *controller,
GeglRectangle *area,
gdouble x1,
gdouble y1,
gdouble x2,
gdouble y2);
static void gimp_filter_tool_line_changed (GimpToolWidget *widget,
Controller *controller);
/* public functions */
GimpToolWidget *
gimp_filter_tool_create_widget (GimpFilterTool *filter_tool,
GimpControllerType controller_type,
GCallback callback,
gpointer callback_data,
GCallback *set_func,
gpointer *set_func_data)
{
GimpTool *tool;
GimpDisplayShell *shell;
Controller *controller;
g_return_val_if_fail (GIMP_IS_FILTER_TOOL (filter_tool), NULL);
tool = GIMP_TOOL (filter_tool);
g_return_val_if_fail (tool->display != NULL, NULL);
shell = gimp_display_get_shell (tool->display);
controller = g_new0 (Controller, 1);
controller->filter_tool = filter_tool;
controller->controller_type = controller_type;
controller->creator_callback = callback;
controller->creator_data = callback_data;
switch (controller_type)
{
case GIMP_CONTROLLER_TYPE_LINE:
controller->widget = gimp_tool_line_new (shell, 100, 100, 500, 500);
g_signal_connect (controller->widget, "changed",
G_CALLBACK (gimp_filter_tool_line_changed),
controller);
*set_func = (GCallback) gimp_filter_tool_set_line;
*set_func_data = controller;
break;
}
g_object_set_data_full (G_OBJECT (controller->widget),
"controller", controller,
(GDestroyNotify) g_free);
return controller->widget;
}
/* private functions */
static void
gimp_filter_tool_set_line (Controller *controller,
GeglRectangle *area,
gdouble x1,
gdouble y1,
gdouble x2,
gdouble y2)
{
GimpDrawable *drawable = controller->filter_tool->drawable;
if (drawable)
{
gint off_x, off_y;
gimp_item_get_offset (GIMP_ITEM (drawable), &off_x, &off_y);
x1 += off_x + area->x;
y1 += off_y + area->y;
x2 += off_x + area->x;
y2 += off_y + area->y;
}
g_signal_handlers_block_by_func (controller->widget,
gimp_filter_tool_line_changed,
controller);
g_object_set (controller->widget,
"x1", x1,
"y1", y1,
"x2", x2,
"y2", y2,
NULL);
g_signal_handlers_unblock_by_func (controller->widget,
gimp_filter_tool_line_changed,
controller);
}
static void
gimp_filter_tool_line_changed (GimpToolWidget *widget,
Controller *controller)
{
GimpFilterTool *filter_tool = controller->filter_tool;
GimpControllerLineCallback line_callback;
gdouble x1, y1, x2, y2;
gint off_x, off_y;
GeglRectangle area;
line_callback = (GimpControllerLineCallback) controller->creator_callback;
g_object_get (widget,
"x1", &x1,
"y1", &y1,
"x2", &x2,
"y2", &y2,
NULL);
gimp_filter_tool_get_drawable_area (filter_tool, &off_x, &off_y, &area);
x1 -= off_x + area.x;
y1 -= off_y + area.y;
x2 -= off_x + area.x;
y2 -= off_y + area.y;
line_callback (controller->creator_data,
&area, x1, y1, x2, y2);
}
/* GIMP - The GNU Image Manipulation Program
* Copyright (C) 1995 Spencer Kimball and Peter Mattis
*
* gimpfiltertool-widgets.h
*
* 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 3 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, see <http://www.gnu.org/licenses/>.
*/
#ifndef __GIMP_FILTER_TOOL_WIDGETS_H__
#define __GIMP_FILTER_TOOL_WIDGETS_H__
#include "widgets/gimppropgui.h" /* FIXME remove */
GimpToolWidget * gimp_filter_tool_create_widget (GimpFilterTool *filter_tool,
GimpControllerType controller_type,
GCallback callback,
gpointer callback_data,
GCallback *set_func,
gpointer *set_func_data);
#endif /* __GIMP_FILTER_TOOL_WIDGETS_H__ */
......@@ -51,6 +51,7 @@
#include "display/gimptoolgui.h"
#include "gimpfilteroptions.h"
#include "gimpfiltertool-widgets.h"
#include "gimpoperationtool.h"
#include "gimp-intl.h"
......@@ -98,9 +99,12 @@ static void gimp_operation_tool_color_picked (GimpFilterTool *filte
const Babl *sample_format,
const GimpRGB *color);
static void gimp_operation_tool_halt (GimpOperationTool *op_tool);
static void gimp_operation_tool_sync_op (GimpOperationTool *op_tool,
GimpDrawable *drawable,
gboolean sync_colors);
static void gimp_operation_tool_create_gui (GimpOperationTool *tool);
static AuxInput * gimp_operation_tool_aux_input_new (GimpOperationTool *tool,
GeglNode *operation,
......@@ -219,7 +223,12 @@ gimp_operation_tool_initialize (GimpTool *tool,
GimpDrawable *drawable = gimp_image_get_active_drawable (image);
if (filter_tool->config)
gimp_operation_tool_sync_op (op_tool, drawable, TRUE);
{
gimp_operation_tool_sync_op (op_tool, drawable, TRUE);
if (! op_tool->options_gui)
gimp_operation_tool_create_gui (op_tool);
}
return TRUE;
}
......@@ -241,8 +250,7 @@ gimp_operation_tool_control (GimpTool *tool,
break;
case GIMP_TOOL_ACTION_HALT:
g_list_foreach (op_tool->aux_inputs,
(GFunc) gimp_operation_tool_aux_input_clear, NULL);
gimp_operation_tool_halt (op_tool);
break;
case GIMP_TOOL_ACTION_COMMIT:
......@@ -294,6 +302,9 @@ gimp_operation_tool_dialog (GimpFilterTool *filter_tool)
TRUE, TRUE, 0);
gtk_widget_show (tool->options_box);
g_object_add_weak_pointer (G_OBJECT (tool->options_box),
(gpointer) &tool->options_box);
for (list = tool->aux_inputs; list; list = g_list_next (list))
{
AuxInput *input = list->data;
......@@ -342,47 +353,20 @@ gimp_operation_tool_color_picked (GimpFilterTool *filter_tool,
const Babl *sample_format,
const GimpRGB *color)
{
GimpOperationTool *tool = GIMP_OPERATION_TOOL (filter_tool);
gchar **pspecs;
pspecs = g_strsplit (identifier, ":", 2);
gchar **pspecs = g_strsplit (identifier, ":", 2);
if (pspecs[1])
{
GimpFilterOptions *options = GIMP_FILTER_TOOL_GET_OPTIONS (tool);
GimpDrawable *drawable = GIMP_TOOL (filter_tool)->drawable;
GObjectClass *object_class = G_OBJECT_GET_CLASS (filter_tool->config);
GParamSpec *pspec_x;
GParamSpec *pspec_y;
gint width = 1;
gint height = 1;
if (drawable)
{
gint off_x, off_y;
GObjectClass *object_class = G_OBJECT_GET_CLASS (filter_tool->config);
GParamSpec *pspec_x;
GParamSpec *pspec_y;
gint off_x, off_y;
GeglRectangle area;
gimp_item_get_offset (GIMP_ITEM (drawable), &off_x, &off_y);
gimp_filter_tool_get_drawable_area (filter_tool, &off_x, &off_y, &area);
x -= off_x;
y -= off_y;
switch (options->region)
{
case GIMP_FILTER_REGION_SELECTION:
if (gimp_item_mask_intersect (GIMP_ITEM (drawable),
&off_x, &off_y, &width, &height))
{
x -= off_x;
y -= off_y;
}
break;
case GIMP_FILTER_REGION_DRAWABLE:
width = gimp_item_get_width (GIMP_ITEM (drawable));
height = gimp_item_get_height (GIMP_ITEM (drawable));
break;
}
}
x -= off_x + area.x;
y -= off_y + area.y;
pspec_x = g_object_class_find_property (object_class, pspecs[0]);
pspec_y = g_object_class_find_property (object_class, pspecs[1]);
......@@ -401,8 +385,8 @@ gimp_operation_tool_color_picked (GimpFilterTool *filter_tool,
if (HAS_KEY (pspec_x, "unit", "relative-coordinate") &&
HAS_KEY (pspec_y, "unit", "relative-coordinate"))
{
x /= (gdouble) width;
y /= (gdouble) height;
x /= (gdouble) area.width;
y /= (gdouble) area.height;
}
if (G_IS_PARAM_SPEC_INT (pspec_x))
......@@ -451,6 +435,50 @@ gimp_operation_tool_color_picked (GimpFilterTool *filter_tool,
g_strfreev (pspecs);
}
static void
gimp_operation_tool_halt (GimpOperationTool *op_tool)
{
if (op_tool->operation)
{
g_free (op_tool->operation);
op_tool->operation = NULL;
}
if (op_tool->title)
{
g_free (op_tool->title);
op_tool->title = NULL;
}
if (op_tool->description)
{
g_free (op_tool->description);
op_tool->description = NULL;
}
if (op_tool->undo_desc)
{
g_free (op_tool->undo_desc);
op_tool->undo_desc = NULL;
}
if (op_tool->icon_name)
{
g_free (op_tool->icon_name);
op_tool->icon_name = NULL;
}
if (op_tool->help_id)
{
g_free (op_tool->help_id);
op_tool->help_id = NULL;
}
g_list_foreach (op_tool->aux_inputs,
(GFunc) gimp_operation_tool_aux_input_free, NULL);
op_tool->aux_inputs = NULL;
}
static void
gimp_operation_tool_sync_op (GimpOperationTool *op_tool,
GimpDrawable *drawable,
......@@ -524,6 +552,62 @@ gimp_operation_tool_sync_op (GimpOperationTool *op_tool,
g_free (pspecs);
}
static GCallback
gimp_operation_tool_add_controller (GimpOperationTool *op_tool,
GimpControllerType controller_type,
GCallback callback,
gpointer callback_data,
gpointer *set_func_data)
{
GimpFilterTool *filter_tool = GIMP_FILTER_TOOL (op_tool);
GimpToolWidget *widget;
GCallback set_func;
widget = gimp_filter_tool_create_widget (filter_tool,
controller_type,
callback,
callback_data,
&set_func,
set_func_data);
gimp_filter_tool_set_widget (filter_tool, widget);
g_object_unref (widget);
return set_func;
}
static void
gimp_operation_tool_create_gui (GimpOperationTool *tool)
{
GimpFilterTool *filter_tool = GIMP_FILTER_TOOL (tool);
gint off_x, off_y;
GeglRectangle area;
gimp_filter_tool_get_drawable_area (filter_tool, &off_x, &off_y, &area);
tool->options_gui =
gimp_prop_gui_new (G_OBJECT (filter_tool->config),
G_TYPE_FROM_INSTANCE (filter_tool->config), 0,
&area,
GIMP_CONTEXT (GIMP_TOOL_GET_OPTIONS (tool)),
(GimpCreatePickerFunc) gimp_filter_tool_add_color_picker,
(GimpCreateControllerFunc) gimp_operation_tool_add_controller,
tool);
g_object_add_weak_pointer (G_OBJECT (tool->options_gui),
(gpointer) &tool->options_gui);
/* ugly, see comment in the function */
gimp_filter_tool_set_has_settings (filter_tool,
! GTK_IS_LABEL (tool->options_gui));
if (tool->options_box)
{
gtk_box_pack_start (GTK_BOX (tool->options_box), tool->options_gui,
TRUE, TRUE, 0);
gtk_widget_show (tool->options_gui);
}
}
/* aux input utility functions */
......@@ -584,6 +668,8 @@ gimp_operation_tool_aux_input_clear (AuxInput *input)
static void
gimp_operation_tool_aux_input_free (AuxInput *input)
{
gimp_operation_tool_aux_input_clear (input);
g_free (input->pad);
g_object_unref (input->node);
gtk_widget_destroy (input->box);
......@@ -641,6 +727,8 @@ gimp_operation_tool_set_operation (GimpOperationTool *tool,
(GDestroyNotify) gimp_operation_tool_aux_input_free);
tool->aux_inputs = NULL;
gimp_filter_tool_set_widget (filter_tool, NULL);
gimp_filter_tool_get_operation (filter_tool);
if (tool->options_gui)
......@@ -706,41 +794,9 @@ gimp_operation_tool_set_operation (GimpOperationTool *tool,
if (size_group)
g_object_unref (size_group);
if (filter_tool->config)
{
GeglRectangle *area = NULL;
GeglRectangle tmp = { 0, };
if (GIMP_TOOL (tool)->drawable)
{
GimpDrawable *drawable = GIMP_TOOL (tool)->drawable;
tmp.width = gimp_item_get_width (GIMP_ITEM (drawable));
tmp.height = gimp_item_get_height (GIMP_ITEM (drawable));
area = &tmp;
}
tool->options_gui =
gimp_prop_gui_new (G_OBJECT (filter_tool->config),
G_TYPE_FROM_INSTANCE (filter_tool->config), 0,
area,
GIMP_CONTEXT (GIMP_TOOL_GET_OPTIONS (tool)),
(GimpCreatePickerFunc) gimp_filter_tool_add_color_picker,
tool);
/* ugly, see comment in the function */
gimp_filter_tool_set_has_settings (filter_tool,
! GTK_IS_LABEL (tool->options_gui));
if (tool->options_box)
{
gtk_box_pack_start (GTK_BOX (tool->options_box), tool->options_gui,
TRUE, TRUE, 0);
gtk_widget_show (tool->options_gui);
}
}
if (GIMP_TOOL (tool)->drawable)
gimp_operation_tool_sync_op (tool, GIMP_TOOL (tool)->drawable, TRUE);
if (filter_tool->config && GIMP_TOOL (tool)->display)
gimp_operation_tool_create_gui (tool);
}
......@@ -317,6 +317,8 @@ libappwidgets_a_sources = \
gimppropgui-generic.h \
gimppropgui-hue-saturation.c \
gimppropgui-hue-saturation.h \
gimppropgui-spiral.c \
gimppropgui-spiral.h \
gimppropwidgets.c \
gimppropwidgets.h \
gimpradioaction.c \
......
......@@ -37,13 +37,14 @@
GtkWidget *
_gimp_prop_gui_new_channel_mixer (GObject *config,
GParamSpec **param_specs,
guint n_param_specs,
GeglRectangle *area,
GimpContext *context,
GimpCreatePickerFunc create_picker_func,
gpointer picker_creator)
_gimp_prop_gui_new_channel_mixer (GObject *config,
GParamSpec **param_specs,
guint n_param_specs,
GeglRectangle *area,
GimpContext *context,
GimpCreatePickerFunc create_picker_func,
GimpCreateControllerFunc create_controller_func,
gpointer creator)
{
GtkWidget *main_vbox;
GtkWidget *frame;
......@@ -68,17 +69,17 @@ _gimp_prop_gui_new_channel_mixer (GObject *config,
gtk_widget_show (vbox);
scale = gimp_prop_widget_new (config, "rr-gain",
area, context, NULL, NULL, &label);
area, context, NULL, NULL, NULL, &label);
gtk_box_pack_start (GTK_BOX (vbox), scale, FALSE, FALSE, 0);
gtk_widget_show (scale);
scale = gimp_prop_widget_new (config, "rg-gain",
area, context, NULL, NULL, &label);
area, context, NULL, NULL, NULL, &label);
gtk_box_pack_start (GTK_BOX (vbox), scale, FALSE, FALSE, 0);
gtk_widget_show (scale);
scale = gimp_prop_widget_new (config, "rb-gain",
area, context, NULL, NULL, &label);
area, context, NULL, NULL, NULL, &label);
gtk_box_pack_start (GTK_BOX (vbox), scale, FALSE, FALSE, 0);
gtk_widget_show (scale);
......@@ -92,17 +93,17 @@ _gimp_prop_gui_new_channel_mixer (GObject *config,
gtk_widget_show (vbox);
scale = gimp_prop_widget_new (config, "gr-gain",
area, context, NULL, NULL, &label);
area, context, NULL, NULL, NULL, &label);
gtk_box_pack_start (GTK_BOX (vbox), scale, FALSE, FALSE, 0);
gtk_widget_show (scale);
scale = gimp_prop_widget_new (config, "gg-gain",
area, context, NULL, NULL, &label);
area, context, NULL, NULL, NULL, &label);
gtk_box_pack_start (GTK_BOX (vbox), scale, FALSE, FALSE, 0);
gtk_widget_show (scale);
scale = gimp_prop_widget_new (config, "gb-gain",
area, context, NULL, NULL, &label);
area, context, NULL, NULL, NULL, &label);
gtk_box_pack_start (GTK_BOX (vbox), scale, FALSE, FALSE, 0);
gtk_widget_show (scale);
......@@ -116,23 +117,23 @@ _gimp_prop_gui_new_channel_mixer (GObject *config,
gtk_widget_show (vbox);
scale = gimp_prop_widget_new (config, "br-gain",
area, context, NULL, NULL, &label);
area, context, NULL, NULL, NULL, &label);
gtk_box_pack_start (GTK_BOX (vbox), scale, FALSE, FALSE, 0);
gtk_widget_show (scale);
scale = gimp_prop_widget_new (config, "bg-gain",
area, context, NULL, NULL, &label);
area, context, NULL, NULL, NULL, &label);
gtk_box_pack_start (GTK_BOX (vbox), scale, FALSE, FALSE, 0);
gtk_widget_show (scale);
scale = gimp_prop_widget_new (config, "bb-gain",
area, context, NULL, NULL, &label);
area, context, NULL, NULL, NULL, &label);
gtk_box_pack_start (GTK_BOX (vbox), scale, FALSE, FALSE, 0);
gtk_widget_show (scale);
checkbox = gimp_prop_widget_new (config, "preserve-luminosity",
area, context, NULL, NULL, &label);
area, context, NULL, NULL, NULL, &label);
gtk_box_pack_start (GTK_BOX (main_vbox), checkbox, FALSE, FALSE, 0);
gtk_widget_show (checkbox);
......
......@@ -22,13 +22,14 @@
GtkWidget *
_gimp_prop_gui_new_channel_mixer (GObject *config,
GParamSpec **param_specs,
guint n_param_specs,
GeglRectangle *area,
GimpContext *context,
GimpCreatePickerFunc create_picker_func,
gpointer picker_creator);
_gimp_prop_gui_new_channel_mixer (GObject *config,
GParamSpec **param_specs,
guint n_param_specs,
GeglRectangle *area,
GimpContext *context,
GimpCreatePickerFunc create_picker_func,
GimpCreateControllerFunc create_controller_func,
gpointer creator);
#endif /* __GIMP_PROP_GUI_CHANNEL_MIXER_H__ */
......@@ -70,13 +70,14 @@ create_levels_scale (GObject *config,
}
GtkWidget *
_gimp_prop_gui_new_color_balance (GObject *config,
GParamSpec **param_specs,
guint n_param_specs,
GeglRectangle *area,
GimpContext *context,
GimpCreatePickerFunc create_picker_func,
gpointer picker_creator)
_gimp_prop_gui_new_color_balance (GObject *config,
GParamSpec **param_specs,
guint n_param_specs,
GeglRectangle *area,
GimpContext *context,
GimpCreatePickerFunc create_picker_func,
GimpCreateControllerFunc create_controller_func,
gpointer creator)
{
GtkWidget *main_vbox;
GtkWidget *vbox;
......
......@@ -22,13 +22,14 @@
GtkWidget *
_gimp_prop_gui_new_color_balance (GObject *config,
GParamSpec **param_specs,
guint n_param_specs,
GeglRectangle *area,
GimpContext *context,
GimpCreatePickerFunc create_picker_func,
gpointer picker_creator);
_gimp_prop_gui_new_color_balance (GObject *config,
GParamSpec **param_specs,
guint n_param_specs,
GeglRectangle *area,
GimpContext *context,
GimpCreatePickerFunc create_picker_func,
GimpCreateControllerFunc create_controller_func,
gpointer creator);
#endif /* __GIMP_PROP_GUI_COLOR_BALANCE_H__ */
......@@ -189,13 +189,14 @@ gimp_prop_polar_box_new (GObject *config,
}
GtkWidget *
_gimp_prop_gui_new_color_rotate (GObject *config,
GParamSpec **param_specs,
guint n_param_specs,
GeglRectangle *area,
GimpContext *context,
GimpCreatePickerFunc create_picker_func,
gpointer picker_creator)
_gimp_prop_gui_new_color_rotate (GObject *config,
GParamSpec **param_specs,
guint n_param_specs,
GeglRectangle *area,
GimpContext *context,
GimpCreatePickerFunc create_picker_func,
GimpCreateControllerFunc create_controller_func,
gpointer creator)
{
GtkWidget *main_vbox;
GtkWidget *frame;
......@@ -242,7 +243,9 @@ _gimp_prop_gui_new_color_rotate (GObject *config,
box = _gimp_prop_gui_new_generic (config,
param_specs + 6, 2,
area, context,
create_picker_func, picker_creator);
create_picker_func,
create_controller_func,
creator);
gtk_box_pack_start (GTK_BOX (vbox), box, FALSE, FALSE, 0);
gtk_widget_show (box);
......