[gimp] app: add option to stroke the warp tool during cursor motion ...
- From: N/A <ell src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [gimp] app: add option to stroke the warp tool during cursor motion ...
- Date: Fri, 19 May 2017 08:57:47 +0000 (UTC)
commit 40afffbebc87ef46abe66acb90b471ac013dd89c
Author: Ell <ell_se yahoo com>
Date: Fri May 19 03:32:59 2017 -0400
app: add option to stroke the warp tool during cursor motion ...
... and to disable/control the rate of the periodic stroke.
The warp tool is now fast enough to enable stroking directly in
the motion handler, which gives better-quality response to motion
than stroking periodically. It's not quite fast enough to enable
exact motion, though :/
Allow individually enabling/disabling stroking during motion and
periodically, and allow controlling the rate of the periodical
stroke.
app/tools/gimpwarpoptions.c | 93 +++++++++++++++++++----
app/tools/gimpwarpoptions.h | 4 +
app/tools/gimpwarptool.c | 178 ++++++++++++++++++++++++++++++-------------
app/tools/gimpwarptool.h | 1 -
4 files changed, 207 insertions(+), 69 deletions(-)
---
diff --git a/app/tools/gimpwarpoptions.c b/app/tools/gimpwarpoptions.c
index 913560d..40385a1 100644
--- a/app/tools/gimpwarpoptions.c
+++ b/app/tools/gimpwarpoptions.c
@@ -44,18 +44,21 @@ enum
PROP_EFFECT_SIZE,
PROP_EFFECT_HARDNESS,
PROP_STROKE_SPACING,
+ PROP_STROKE_DURING_MOTION,
+ PROP_STROKE_PERIODICALLY,
+ PROP_STROKE_PERIODICALLY_RATE,
PROP_N_ANIMATION_FRAMES
};
-static void gimp_warp_options_set_property (GObject *object,
- guint property_id,
- const GValue *value,
- GParamSpec *pspec);
-static void gimp_warp_options_get_property (GObject *object,
- guint property_id,
- GValue *value,
- GParamSpec *pspec);
+static void gimp_warp_options_set_property (GObject *object,
+ guint property_id,
+ const GValue *value,
+ GParamSpec *pspec);
+static void gimp_warp_options_get_property (GObject *object,
+ guint property_id,
+ GValue *value,
+ GParamSpec *pspec);
G_DEFINE_TYPE (GimpWarpOptions, gimp_warp_options,
@@ -108,6 +111,27 @@ gimp_warp_options_class_init (GimpWarpOptionsClass *klass)
1.0, 100.0, 20.0,
GIMP_PARAM_STATIC_STRINGS);
+ GIMP_CONFIG_PROP_BOOLEAN (object_class, PROP_STROKE_DURING_MOTION,
+ "stroke-during-motion",
+ _("During motion"),
+ _("Apply effect during motion"),
+ TRUE,
+ GIMP_PARAM_STATIC_STRINGS);
+
+ GIMP_CONFIG_PROP_BOOLEAN (object_class, PROP_STROKE_PERIODICALLY,
+ "stroke-periodically",
+ _("Periodically"),
+ _("Apply effect periodically"),
+ FALSE,
+ GIMP_PARAM_STATIC_STRINGS);
+
+ GIMP_CONFIG_PROP_DOUBLE (object_class, PROP_STROKE_PERIODICALLY_RATE,
+ "stroke-periodically-rate",
+ _("Rate"),
+ _("Periodical stroke rate"),
+ 0.0, 100.0, 50.0,
+ GIMP_PARAM_STATIC_STRINGS);
+
GIMP_CONFIG_PROP_INT (object_class, PROP_N_ANIMATION_FRAMES,
"n-animation-frames",
_("Frames"),
@@ -146,6 +170,15 @@ gimp_warp_options_set_property (GObject *object,
case PROP_STROKE_SPACING:
options->stroke_spacing = g_value_get_double (value);
break;
+ case PROP_STROKE_DURING_MOTION:
+ options->stroke_during_motion = g_value_get_boolean (value);
+ break;
+ case PROP_STROKE_PERIODICALLY:
+ options->stroke_periodically = g_value_get_boolean (value);
+ break;
+ case PROP_STROKE_PERIODICALLY_RATE:
+ options->stroke_periodically_rate = g_value_get_double (value);
+ break;
case PROP_N_ANIMATION_FRAMES:
options->n_animation_frames = g_value_get_int (value);
break;
@@ -181,6 +214,15 @@ gimp_warp_options_get_property (GObject *object,
case PROP_STROKE_SPACING:
g_value_set_double (value, options->stroke_spacing);
break;
+ case PROP_STROKE_DURING_MOTION:
+ g_value_set_boolean (value, options->stroke_during_motion);
+ break;
+ case PROP_STROKE_PERIODICALLY:
+ g_value_set_boolean (value, options->stroke_periodically);
+ break;
+ case PROP_STROKE_PERIODICALLY_RATE:
+ g_value_set_double (value, options->stroke_periodically_rate);
+ break;
case PROP_N_ANIMATION_FRAMES:
g_value_set_int (value, options->n_animation_frames);
break;
@@ -198,7 +240,8 @@ gimp_warp_options_gui (GimpToolOptions *tool_options)
GObject *config = G_OBJECT (tool_options);
GtkWidget *vbox = gimp_tool_options_gui (tool_options);
GtkWidget *frame;
- GtkWidget *anim_vbox;
+ GtkWidget *vbox2;
+ GtkWidget *button;
GtkWidget *combo;
GtkWidget *scale;
@@ -231,24 +274,46 @@ gimp_warp_options_gui (GimpToolOptions *tool_options)
gtk_box_pack_start (GTK_BOX (vbox), scale, FALSE, FALSE, 0);
gtk_widget_show (scale);
+ /* the stroke frame */
+ frame = gimp_frame_new (_("Stroke"));
+ gtk_box_pack_start (GTK_BOX (vbox), frame, FALSE, FALSE, 0);
+ gtk_widget_show (frame);
+
+ vbox2 = gtk_box_new (GTK_ORIENTATION_VERTICAL, 2);
+ gtk_container_add (GTK_CONTAINER (frame), vbox2);
+ gtk_widget_show (vbox2);
+
+ button = gimp_prop_check_button_new (config, "stroke-during-motion", NULL);
+ gtk_box_pack_start (GTK_BOX (vbox2), button, FALSE, FALSE, 0);
+ gtk_widget_show (button);
+
+ scale = gimp_prop_spin_scale_new (config, "stroke-periodically-rate", NULL,
+ 1, 10, 1);
+ gimp_spin_scale_set_scale_limits (GIMP_SPIN_SCALE (scale), 0.0, 100.0);
+
+ frame = gimp_prop_expanding_frame_new (config, "stroke-periodically", NULL,
+ scale, NULL);
+ gtk_box_pack_start (GTK_BOX (vbox2), frame, FALSE, FALSE, 0);
+ gtk_widget_show (frame);
+
/* the animation frame */
frame = gimp_frame_new (_("Animate"));
gtk_box_pack_start (GTK_BOX (vbox), frame, FALSE, FALSE, 0);
gtk_widget_show (frame);
- anim_vbox = gtk_box_new (GTK_ORIENTATION_VERTICAL, 2);
- gtk_container_add (GTK_CONTAINER (frame), anim_vbox);
- gtk_widget_show (anim_vbox);
+ vbox2 = gtk_box_new (GTK_ORIENTATION_VERTICAL, 2);
+ gtk_container_add (GTK_CONTAINER (frame), vbox2);
+ gtk_widget_show (vbox2);
scale = gimp_prop_spin_scale_new (config, "n-animation-frames", NULL,
1.0, 10.0, 0);
gimp_spin_scale_set_scale_limits (GIMP_SPIN_SCALE (scale), 3.0, 100.0);
- gtk_box_pack_start (GTK_BOX (anim_vbox), scale, FALSE, FALSE, 0);
+ gtk_box_pack_start (GTK_BOX (vbox2), scale, FALSE, FALSE, 0);
gtk_widget_show (scale);
options->animate_button = gtk_button_new_with_label (_("Create Animation"));
gtk_widget_set_sensitive (options->animate_button, FALSE);
- gtk_box_pack_start (GTK_BOX (anim_vbox), options->animate_button,
+ gtk_box_pack_start (GTK_BOX (vbox2), options->animate_button,
FALSE, FALSE, 0);
gtk_widget_show (options->animate_button);
diff --git a/app/tools/gimpwarpoptions.h b/app/tools/gimpwarpoptions.h
index 231c66f..f66beda 100644
--- a/app/tools/gimpwarpoptions.h
+++ b/app/tools/gimpwarpoptions.h
@@ -45,6 +45,10 @@ struct _GimpWarpOptions
gdouble effect_hardness;
gdouble stroke_spacing;
+ gboolean stroke_during_motion;
+ gboolean stroke_periodically;
+ gdouble stroke_periodically_rate;
+
gint n_animation_frames;
/* options gui */
diff --git a/app/tools/gimpwarptool.c b/app/tools/gimpwarptool.c
index b8a1744..bed1676 100644
--- a/app/tools/gimpwarptool.c
+++ b/app/tools/gimpwarptool.c
@@ -52,9 +52,9 @@
#include "gimp-intl.h"
-#define STROKE_PERIOD 100
-#define PREVIEW_SAMPLER GEGL_SAMPLER_NEAREST
-#define COMMIT_SAMPLER GEGL_SAMPLER_CUBIC
+#define STROKE_TIMER_MAX_FPS 20
+#define PREVIEW_SAMPLER GEGL_SAMPLER_NEAREST
+#define COMMIT_SAMPLER GEGL_SAMPLER_CUBIC
static void gimp_warp_tool_control (GimpTool *tool,
@@ -103,11 +103,17 @@ static void gimp_warp_tool_options_notify (GimpTool *tool
static void gimp_warp_tool_draw (GimpDrawTool *draw_tool);
+static gboolean gimp_warp_tool_can_stroke (GimpWarpTool *wt,
+ GimpDisplay *display,
+ gboolean show_message);
+
static gboolean gimp_warp_tool_start (GimpWarpTool *wt,
GimpDisplay *display);
static void gimp_warp_tool_halt (GimpWarpTool *wt);
static void gimp_warp_tool_commit (GimpWarpTool *wt);
+static void gimp_warp_tool_start_stroke_timer (GimpWarpTool *wt);
+static void gimp_warp_tool_stop_stroke_timer (GimpWarpTool *wt);
static gboolean gimp_warp_tool_stroke_timer (GimpWarpTool *wt);
static void gimp_warp_tool_create_graph (GimpWarpTool *wt);
@@ -243,6 +249,9 @@ gimp_warp_tool_button_press (GimpTool *tool,
return;
}
+ if (! gimp_warp_tool_can_stroke (wt, display, TRUE))
+ return;
+
wt->current_stroke = gegl_path_new ();
new_op = gegl_node_new_child (NULL,
@@ -267,11 +276,7 @@ gimp_warp_tool_button_press (GimpTool *tool,
gegl_path_append (wt->current_stroke,
'M', coords->x - off_x, coords->y - off_y);
- wt->cursor_moved = FALSE;
-
- wt->stroke_timer = g_timeout_add (STROKE_PERIOD,
- (GSourceFunc) gimp_warp_tool_stroke_timer,
- wt);
+ gimp_warp_tool_start_stroke_timer (wt);
gimp_tool_control_activate (tool->control);
}
@@ -290,8 +295,7 @@ gimp_warp_tool_button_release (GimpTool *tool,
gimp_tool_control_halt (tool->control);
- g_source_remove (wt->stroke_timer);
- wt->stroke_timer = 0;
+ gimp_warp_tool_stop_stroke_timer (wt);
g_signal_handlers_disconnect_by_func (wt->current_stroke,
gimp_warp_tool_stroke_changed,
@@ -339,13 +343,25 @@ gimp_warp_tool_motion (GimpTool *tool,
GdkModifierType state,
GimpDisplay *display)
{
- GimpWarpTool *wt = GIMP_WARP_TOOL (tool);
+ GimpWarpTool *wt = GIMP_WARP_TOOL (tool);
+ GimpWarpOptions *options = GIMP_WARP_TOOL_GET_OPTIONS (wt);
gimp_draw_tool_pause (GIMP_DRAW_TOOL (tool));
- wt->cursor_x = coords->x;
- wt->cursor_y = coords->y;
- wt->cursor_moved = TRUE;
+ wt->cursor_x = coords->x;
+ wt->cursor_y = coords->y;
+
+ if (options->stroke_during_motion)
+ {
+ gint off_x, off_y;
+
+ gimp_item_get_offset (GIMP_ITEM (tool->drawable), &off_x, &off_y);
+
+ gegl_path_append (wt->current_stroke,
+ 'L', wt->cursor_x - off_x, wt->cursor_y - off_y);
+
+ gimp_warp_tool_start_stroke_timer (wt);
+ }
gimp_draw_tool_resume (GIMP_DRAW_TOOL (tool));
}
@@ -414,10 +430,15 @@ gimp_warp_tool_cursor_update (GimpTool *tool,
GdkModifierType state,
GimpDisplay *display)
{
+ GimpWarpTool *wt = GIMP_WARP_TOOL (tool);
GimpWarpOptions *options = GIMP_WARP_TOOL_GET_OPTIONS (tool);
GimpCursorModifier modifier = GIMP_CURSOR_MODIFIER_PLUS;
- if (display == tool->display)
+ if (! gimp_warp_tool_can_stroke (wt, display, FALSE))
+ {
+ modifier = GIMP_CURSOR_MODIFIER_BAD;
+ }
+ else if (display == tool->display)
{
/* FIXME have better cursors */
@@ -434,18 +455,6 @@ gimp_warp_tool_cursor_update (GimpTool *tool,
break;
}
}
- else
- {
- GimpImage *image = gimp_display_get_image (display);
- GimpDrawable *drawable = gimp_image_get_active_drawable (image);
-
- if (gimp_viewable_get_children (GIMP_VIEWABLE (drawable)) ||
- gimp_item_is_content_locked (GIMP_ITEM (drawable)) ||
- ! gimp_item_is_visible (GIMP_ITEM (drawable)))
- {
- modifier = GIMP_CURSOR_MODIFIER_BAD;
- }
- }
gimp_tool_control_set_cursor_modifier (tool->control, modifier);
@@ -571,37 +580,77 @@ gimp_warp_tool_draw (GimpDrawTool *draw_tool)
}
static gboolean
-gimp_warp_tool_start (GimpWarpTool *wt,
- GimpDisplay *display)
+gimp_warp_tool_can_stroke (GimpWarpTool *wt,
+ GimpDisplay *display,
+ gboolean show_message)
{
GimpTool *tool = GIMP_TOOL (wt);
GimpWarpOptions *options = GIMP_WARP_TOOL_GET_OPTIONS (wt);
GimpImage *image = gimp_display_get_image (display);
GimpDrawable *drawable = gimp_image_get_active_drawable (image);
- const Babl *format;
- GeglRectangle bbox;
if (gimp_viewable_get_children (GIMP_VIEWABLE (drawable)))
{
- gimp_tool_message_literal (tool, display,
- _("Cannot warp layer groups."));
+ if (show_message)
+ {
+ gimp_tool_message_literal (tool, display,
+ _("Cannot warp layer groups."));
+ }
+
return FALSE;
}
if (gimp_item_is_content_locked (GIMP_ITEM (drawable)))
{
- gimp_tool_message_literal (tool, display,
- _("The active layer's pixels are locked."));
+ if (show_message)
+ {
+ gimp_tool_message_literal (tool, display,
+ _("The active layer's pixels are locked."));
+ }
+
return FALSE;
}
if (! gimp_item_is_visible (GIMP_ITEM (drawable)))
{
- gimp_tool_message_literal (tool, display,
- _("The active layer is not visible."));
+ if (show_message)
+ {
+ gimp_tool_message_literal (tool, display,
+ _("The active layer is not visible."));
+ }
+
+ return FALSE;
+ }
+
+ if (! options->stroke_during_motion &&
+ ! options->stroke_periodically)
+ {
+ if (show_message)
+ {
+ gimp_tool_message_literal (tool, display,
+ _("No stroke events selected."));
+ }
+
return FALSE;
}
+ return TRUE;
+}
+
+static gboolean
+gimp_warp_tool_start (GimpWarpTool *wt,
+ GimpDisplay *display)
+{
+ GimpTool *tool = GIMP_TOOL (wt);
+ GimpWarpOptions *options = GIMP_WARP_TOOL_GET_OPTIONS (wt);
+ GimpImage *image = gimp_display_get_image (display);
+ GimpDrawable *drawable = gimp_image_get_active_drawable (image);
+ const Babl *format;
+ GeglRectangle bbox;
+
+ if (! gimp_warp_tool_can_stroke (wt, display, TRUE))
+ return FALSE;
+
tool->display = display;
tool->drawable = drawable;
@@ -711,26 +760,47 @@ gimp_warp_tool_commit (GimpWarpTool *wt)
}
}
-static gboolean
-gimp_warp_tool_stroke_timer (GimpWarpTool *wt)
+static void
+gimp_warp_tool_start_stroke_timer (GimpWarpTool *wt)
{
- GimpTool *tool = GIMP_TOOL (wt);
GimpWarpOptions *options = GIMP_WARP_TOOL_GET_OPTIONS (wt);
- gint off_x, off_y;
- /* don't append the current point to the path if we're using the MOVE
- * behavior, and the cursor didn't move since last time; it's a nop, and
- * results in an unnecessary update.
- */
- if (options->behavior != GIMP_WARP_BEHAVIOR_MOVE || wt->cursor_moved)
+ gimp_warp_tool_stop_stroke_timer (wt);
+
+ if (options->stroke_periodically &&
+ options->stroke_periodically_rate > 0.0 &&
+ ! (options->behavior == GIMP_WARP_BEHAVIOR_MOVE &&
+ options->stroke_during_motion))
{
- gimp_item_get_offset (GIMP_ITEM (tool->drawable), &off_x, &off_y);
+ gdouble fps;
- gegl_path_append (wt->current_stroke,
- 'L', wt->cursor_x - off_x, wt->cursor_y - off_y);
+ fps = STROKE_TIMER_MAX_FPS * options->stroke_periodically_rate / 100.0;
- wt->cursor_moved = FALSE;
+ wt->stroke_timer = g_timeout_add (1000.0 / fps,
+ (GSourceFunc) gimp_warp_tool_stroke_timer,
+ wt);
}
+}
+
+static void
+gimp_warp_tool_stop_stroke_timer (GimpWarpTool *wt)
+{
+ if (wt->stroke_timer)
+ g_source_remove (wt->stroke_timer);
+
+ wt->stroke_timer = 0;
+}
+
+static gboolean
+gimp_warp_tool_stroke_timer (GimpWarpTool *wt)
+{
+ GimpTool *tool = GIMP_TOOL (wt);
+ gint off_x, off_y;
+
+ gimp_item_get_offset (GIMP_ITEM (tool->drawable), &off_x, &off_y);
+
+ gegl_path_append (wt->current_stroke,
+ 'L', wt->cursor_x - off_x, wt->cursor_y - off_y);
return TRUE;
}
@@ -826,10 +896,10 @@ gimp_warp_tool_update_stroke (GimpWarpTool *wt,
gegl_path_get_bounds (stroke, &min_x, &max_x, &min_y, &max_y);
g_object_unref (stroke);
- bbox.x = min_x - size * 0.5;
- bbox.y = min_y - size * 0.5;
- bbox.width = max_x - min_x + size;
- bbox.height = max_y - min_y + size;
+ bbox.x = floor (min_x - size * 0.5);
+ bbox.y = floor (min_y - size * 0.5);
+ bbox.width = ceil (max_x + size * 0.5) - bbox.x;
+ bbox.height = ceil (max_y + size * 0.5) - bbox.y;
#ifdef WARP_DEBUG
g_printerr ("update stroke: (%d,%d), %dx%d\n",
diff --git a/app/tools/gimpwarptool.h b/app/tools/gimpwarptool.h
index 627e022..932f43a 100644
--- a/app/tools/gimpwarptool.h
+++ b/app/tools/gimpwarptool.h
@@ -43,7 +43,6 @@ struct _GimpWarpTool
gdouble cursor_x; /* Hold the cursor x position */
gdouble cursor_y; /* Hold the cursor y position */
- gboolean cursor_moved; /* Did the cursor move since the last stroke? */
GeglBuffer *coords_buffer; /* Buffer where coordinates are stored */
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]