[gimp/gimp-2-10] app: streamline GimpCurve
- From: Ell <ell src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [gimp/gimp-2-10] app: streamline GimpCurve
- Date: Fri, 19 Apr 2019 14:37:15 +0000 (UTC)
commit b5da9918f1d7b90ebb230602cbfd9c4569449a61
Author: Ell <ell_se yahoo com>
Date: Fri Apr 19 04:24:24 2019 -0400
app: streamline GimpCurve
In GimpCurve, replace the use of a fixed-length control-point array
with a dynamically-sized array. Adapt GimpCurve's interface, and
the rest of the code.
In addition to simplifying the code, this fixes a bug where the
curve object could be broken by moving the mouse too fast (yep...),
and allows more accurate point placement, both in the GUI editor,
and through canvas interaction in the Curves tool (see issue #814).
(cherry picked from commit b6d829a1b2f71d03185f0f7ed7c6b80fc0c2dfe6)
app/core/gimpcurve.c | 372 +++++++++++++++++++++++---------------
app/core/gimpcurve.h | 16 +-
app/operations/gimpcurvesconfig.c | 81 ++++-----
app/operations/gimplevelsconfig.c | 17 +-
app/tools/gimpcurvestool.c | 39 ++--
app/widgets/gimpcurveview.c | 218 ++++++++++++----------
6 files changed, 415 insertions(+), 328 deletions(-)
---
diff --git a/app/core/gimpcurve.c b/app/core/gimpcurve.c
index 247158c7ed..2a8e1f4302 100644
--- a/app/core/gimpcurve.c
+++ b/app/core/gimpcurve.c
@@ -37,6 +37,9 @@
#include "gimp-intl.h"
+#define EPSILON 1e-6
+
+
enum
{
PROP_0,
@@ -155,7 +158,9 @@ gimp_curve_class_init (GimpCurveClass *klass)
"n-points",
"Number of Points",
"The number of points",
- 17, 17, 17, 0);
+ 0, G_MAXINT, 0,
+ /* for backward compatibility */
+ GIMP_CONFIG_PARAM_IGNORE);
array_spec = g_param_spec_double ("point", NULL, NULL,
-1.0, 1.0, 0.0, GIMP_PARAM_READWRITE);
@@ -237,7 +242,7 @@ gimp_curve_set_property (GObject *object,
break;
case PROP_N_POINTS:
- gimp_curve_set_n_points (curve, g_value_get_int (value));
+ /* ignored */
break;
case PROP_POINTS:
@@ -246,19 +251,41 @@ gimp_curve_set_property (GObject *object,
gint length;
gint i;
+ curve->n_points = 0;
+ g_clear_pointer (&curve->points, g_free);
+
if (! array)
break;
- length = gimp_value_array_length (array);
+ length = gimp_value_array_length (array) / 2;
+
+ curve->points = g_new (GimpVector2, length);
- for (i = 0; i < curve->n_points && i * 2 < length; i++)
+ for (i = 0; i < length; i++)
{
GValue *x = gimp_value_array_index (array, i * 2);
GValue *y = gimp_value_array_index (array, i * 2 + 1);
- curve->points[i].x = g_value_get_double (x);
- curve->points[i].y = g_value_get_double (y);
+ /* for backward compatibility */
+ if (g_value_get_double (x) < 0.0)
+ continue;
+
+ curve->points[curve->n_points].x = CLAMP (g_value_get_double (x),
+ 0.0, 1.0);
+ curve->points[curve->n_points].y = CLAMP (g_value_get_double (y),
+ 0.0, 1.0);
+
+ if (curve->n_points > 0)
+ {
+ curve->points[curve->n_points].x = MAX (
+ curve->points[curve->n_points].x,
+ curve->points[curve->n_points - 1].x);
+ }
+
+ curve->n_points++;
}
+
+ g_object_notify (object, "n-points");
}
break;
@@ -281,7 +308,7 @@ gimp_curve_set_property (GObject *object,
{
GValue *v = gimp_value_array_index (array, i);
- curve->samples[i] = g_value_get_double (v);
+ curve->samples[i] = CLAMP (g_value_get_double (v), 0.0, 1.0);
}
}
break;
@@ -484,11 +511,19 @@ gimp_curve_equal (GimpConfig *a,
if (a_curve->curve_type != b_curve->curve_type)
return FALSE;
- if (memcmp (a_curve->points, b_curve->points,
- sizeof (GimpVector2) * b_curve->n_points) ||
+ if (a_curve->n_points != b_curve->n_points ||
+ memcmp (a_curve->points, b_curve->points,
+ sizeof (GimpVector2) * a_curve->n_points))
+ {
+ return FALSE;
+ }
+
+ if (a_curve->n_samples != b_curve->n_samples ||
memcmp (a_curve->samples, b_curve->samples,
- sizeof (gdouble) * b_curve->n_samples))
- return FALSE;
+ sizeof (gdouble) * a_curve->n_samples))
+ {
+ return FALSE;
+ }
return TRUE;
}
@@ -564,18 +599,18 @@ gimp_curve_reset (GimpCurve *curve,
g_object_notify (G_OBJECT (curve), "samples");
+ g_free (curve->points);
+
+ curve->n_points = 2;
+ curve->points = g_new (GimpVector2, 2);
+
curve->points[0].x = 0.0;
curve->points[0].y = 0.0;
- for (i = 1; i < curve->n_points - 1; i++)
- {
- curve->points[i].x = -1.0;
- curve->points[i].y = -1.0;
- }
-
- curve->points[curve->n_points - 1].x = 1.0;
- curve->points[curve->n_points - 1].y = 1.0;
+ curve->points[1].x = 1.0;
+ curve->points[1].y = 1.0;
+ g_object_notify (G_OBJECT (curve), "n-points");
g_object_notify (G_OBJECT (curve), "points");
if (reset_type)
@@ -599,44 +634,46 @@ gimp_curve_set_curve_type (GimpCurve *curve,
if (curve->curve_type != curve_type)
{
+ gimp_data_freeze (GIMP_DATA (curve));
+
g_object_freeze_notify (G_OBJECT (curve));
curve->curve_type = curve_type;
if (curve_type == GIMP_CURVE_SMOOTH)
{
- gint n_points;
gint i;
- for (i = 0; i < curve->n_points; i++)
- {
- curve->points[i].x = -1;
- curve->points[i].y = -1;
- }
+ g_free (curve->points);
/* pick some points from the curve and make them control
* points
*/
- n_points = CLAMP (9, curve->n_points / 2, curve->n_points);
+ curve->n_points = 9;
+ curve->points = g_new (GimpVector2, 9);
- for (i = 0; i < n_points; i++)
+ for (i = 0; i < curve->n_points; i++)
{
- gint sample = i * (curve->n_samples - 1) / (n_points - 1);
- gint point = i * (curve->n_points - 1) / (n_points - 1);
+ gint sample = i * (curve->n_samples - 1) / (curve->n_points - 1);
- curve->points[point].x = ((gdouble) sample /
- (gdouble) (curve->n_samples - 1));
- curve->points[point].y = curve->samples[sample];
+ curve->points[i].x = (gdouble) sample /
+ (gdouble) (curve->n_samples - 1);
+ curve->points[i].y = curve->samples[sample];
}
+ g_object_notify (G_OBJECT (curve), "n-points");
g_object_notify (G_OBJECT (curve), "points");
}
+ else
+ {
+ gimp_curve_clear_points (curve);
+ }
g_object_notify (G_OBJECT (curve), "curve-type");
g_object_thaw_notify (G_OBJECT (curve));
- gimp_data_dirty (GIMP_DATA (curve));
+ gimp_data_thaw (GIMP_DATA (curve));
}
}
@@ -648,46 +685,6 @@ gimp_curve_get_curve_type (GimpCurve *curve)
return curve->curve_type;
}
-void
-gimp_curve_set_n_points (GimpCurve *curve,
- gint n_points)
-{
- g_return_if_fail (GIMP_IS_CURVE (curve));
- g_return_if_fail (n_points >= 2);
- g_return_if_fail (n_points <= 1024);
-
- if (n_points != curve->n_points)
- {
- gint i;
-
- g_object_freeze_notify (G_OBJECT (curve));
-
- curve->n_points = n_points;
- g_object_notify (G_OBJECT (curve), "n-points");
-
- curve->points = g_renew (GimpVector2, curve->points, curve->n_points);
-
- curve->points[0].x = 0.0;
- curve->points[0].y = 0.0;
-
- for (i = 1; i < curve->n_points - 1; i++)
- {
- curve->points[i].x = -1.0;
- curve->points[i].y = -1.0;
- }
-
- curve->points[curve->n_points - 1].x = 1.0;
- curve->points[curve->n_points - 1].y = 1.0;
-
- g_object_notify (G_OBJECT (curve), "points");
-
- if (curve->curve_type == GIMP_CURVE_SMOOTH)
- curve->identity = TRUE;
-
- g_object_thaw_notify (G_OBJECT (curve));
- }
-}
-
gint
gimp_curve_get_n_points (GimpCurve *curve)
{
@@ -736,66 +733,152 @@ gimp_curve_get_n_samples (GimpCurve *curve)
}
gint
-gimp_curve_get_closest_point (GimpCurve *curve,
- gdouble x)
+gimp_curve_get_point_at (GimpCurve *curve,
+ gdouble x)
{
- gint closest_point = 0;
- gdouble distance = G_MAXDOUBLE;
+ gint closest_point = -1;
+ gdouble distance = EPSILON;
gint i;
- g_return_val_if_fail (GIMP_IS_CURVE (curve), 0);
+ g_return_val_if_fail (GIMP_IS_CURVE (curve), -1);
for (i = 0; i < curve->n_points; i++)
{
- if (curve->points[i].x >= 0.0 &&
- fabs (x - curve->points[i].x) < distance)
+ gdouble point_distance;
+
+ point_distance = fabs (x - curve->points[i].x);
+
+ if (point_distance <= distance)
{
- distance = fabs (x - curve->points[i].x);
closest_point = i;
+ distance = point_distance;
}
}
- if (distance > (1.0 / (curve->n_points * 2.0)))
- closest_point = ROUND (x * (gdouble) (curve->n_points - 1));
+ return closest_point;
+}
+
+gint
+gimp_curve_get_closest_point (GimpCurve *curve,
+ gdouble x,
+ gdouble y,
+ gdouble max_distance)
+{
+ gint closest_point = -1;
+ gdouble distance2 = G_MAXDOUBLE;
+ gint i;
+
+ g_return_val_if_fail (GIMP_IS_CURVE (curve), -1);
+
+ if (max_distance >= 0.0)
+ distance2 = SQR (max_distance);
+
+ for (i = curve->n_points - 1; i >= 0; i--)
+ {
+ gdouble point_distance2;
+
+ point_distance2 = SQR (x - curve->points[i].x) +
+ SQR (y - curve->points[i].y);
+
+ if (point_distance2 <= distance2)
+ {
+ closest_point = i;
+ distance2 = point_distance2;
+ }
+ }
return closest_point;
}
-void
-gimp_curve_set_point (GimpCurve *curve,
- gint point,
+gint
+gimp_curve_add_point (GimpCurve *curve,
gdouble x,
gdouble y)
{
+ GimpVector2 *points;
+ gint point;
+
+ g_return_val_if_fail (GIMP_IS_CURVE (curve), -1);
+
+ if (curve->curve_type == GIMP_CURVE_FREE)
+ return -1;
+
+ x = CLAMP (x, 0.0, 1.0);
+ y = CLAMP (y, 0.0, 1.0);
+
+ for (point = 0; point < curve->n_points; point++)
+ {
+ if (curve->points[point].x > x)
+ break;
+ }
+
+ points = g_new (GimpVector2, curve->n_points + 1);
+
+ memcpy (points, curve->points,
+ point * sizeof (GimpVector2));
+ memcpy (points + point + 1, curve->points + point,
+ (curve->n_points - point) * sizeof (GimpVector2));
+
+ points[point].x = x;
+ points[point].y = y;
+
+ g_free (curve->points);
+
+ curve->n_points++;
+ curve->points = points;
+
+ g_object_notify (G_OBJECT (curve), "n-points");
+ g_object_notify (G_OBJECT (curve), "points");
+
+ gimp_data_dirty (GIMP_DATA (curve));
+
+ return point;
+}
+
+void
+gimp_curve_delete_point (GimpCurve *curve,
+ gint point)
+{
+ GimpVector2 *points;
+
g_return_if_fail (GIMP_IS_CURVE (curve));
g_return_if_fail (point >= 0 && point < curve->n_points);
- g_return_if_fail (x == -1.0 || (x >= 0 && x <= 1.0));
- g_return_if_fail (y == -1.0 || (y >= 0 && y <= 1.0));
- if (curve->curve_type == GIMP_CURVE_FREE)
- return;
+ points = g_new (GimpVector2, curve->n_points - 1);
- curve->points[point].x = x;
- curve->points[point].y = y;
+ memcpy (points, curve->points,
+ point * sizeof (GimpVector2));
+ memcpy (points + point, curve->points + point + 1,
+ (curve->n_points - point - 1) * sizeof (GimpVector2));
+ g_free (curve->points);
+
+ curve->n_points--;
+ curve->points = points;
+
+ g_object_notify (G_OBJECT (curve), "n-points");
g_object_notify (G_OBJECT (curve), "points");
gimp_data_dirty (GIMP_DATA (curve));
}
void
-gimp_curve_move_point (GimpCurve *curve,
- gint point,
- gdouble y)
+gimp_curve_set_point (GimpCurve *curve,
+ gint point,
+ gdouble x,
+ gdouble y)
{
g_return_if_fail (GIMP_IS_CURVE (curve));
g_return_if_fail (point >= 0 && point < curve->n_points);
- g_return_if_fail (y >= 0 && y <= 1.0);
- if (curve->curve_type == GIMP_CURVE_FREE)
- return;
+ curve->points[point].x = CLAMP (x, 0.0, 1.0);
+ curve->points[point].y = CLAMP (y, 0.0, 1.0);
- curve->points[point].y = y;
+ if (point > 0)
+ curve->points[point].x = MAX (x, curve->points[point - 1].x);
+
+ if (point < curve->n_points - 1)
+ curve->points[point].x = MIN (x, curve->points[point + 1].x);
g_object_notify (G_OBJECT (curve), "points");
@@ -803,27 +886,14 @@ gimp_curve_move_point (GimpCurve *curve,
}
void
-gimp_curve_delete_point (GimpCurve *curve,
- gint point)
+gimp_curve_move_point (GimpCurve *curve,
+ gint point,
+ gdouble y)
{
g_return_if_fail (GIMP_IS_CURVE (curve));
g_return_if_fail (point >= 0 && point < curve->n_points);
- if (point == 0)
- {
- curve->points[0].x = 0.0;
- curve->points[0].y = 0.0;
- }
- else if (point == curve->n_points - 1)
- {
- curve->points[curve->n_points - 1].x = 1.0;
- curve->points[curve->n_points - 1].y = 1.0;
- }
- else
- {
- curve->points[point].x = -1.0;
- curve->points[point].y = -1.0;
- }
+ curve->points[point].y = CLAMP (y, 0.0, 1.0);
g_object_notify (G_OBJECT (curve), "points");
@@ -839,16 +909,25 @@ gimp_curve_get_point (GimpCurve *curve,
g_return_if_fail (GIMP_IS_CURVE (curve));
g_return_if_fail (point >= 0 && point < curve->n_points);
- if (curve->curve_type == GIMP_CURVE_FREE)
+ if (x) *x = curve->points[point].x;
+ if (y) *y = curve->points[point].y;
+}
+
+void
+gimp_curve_clear_points (GimpCurve *curve)
+{
+ g_return_if_fail (GIMP_IS_CURVE (curve));
+
+ if (curve->points)
{
- if (x) *x = -1.0;
- if (y) *y = -1.0;
+ curve->n_points = 0;
+ g_clear_pointer (&curve->points, g_free);
- return;
- }
+ g_object_notify (G_OBJECT (curve), "n-points");
+ g_object_notify (G_OBJECT (curve), "points");
- if (x) *x = curve->points[point].x;
- if (y) *y = curve->points[point].y;
+ gimp_data_dirty (GIMP_DATA (curve));
+ }
}
void
@@ -909,59 +988,49 @@ gimp_curve_get_uchar (GimpCurve *curve,
static void
gimp_curve_calculate (GimpCurve *curve)
{
- gint *points;
- gint i;
- gint num_pts;
- gint p1, p2, p3, p4;
+ gint i;
+ gint p1, p2, p3, p4;
if (gimp_data_is_frozen (GIMP_DATA (curve)))
return;
- points = g_newa (gint, curve->n_points);
-
switch (curve->curve_type)
{
case GIMP_CURVE_SMOOTH:
- /* cycle through the curves */
- num_pts = 0;
- for (i = 0; i < curve->n_points; i++)
- if (curve->points[i].x >= 0.0)
- points[num_pts++] = i;
-
/* Initialize boundary curve points */
- if (num_pts != 0)
+ if (curve->n_points > 0)
{
GimpVector2 point;
gint boundary;
- point = curve->points[points[0]];
+ point = curve->points[0];
boundary = ROUND (point.x * (gdouble) (curve->n_samples - 1));
for (i = 0; i < boundary; i++)
curve->samples[i] = point.y;
- point = curve->points[points[num_pts - 1]];
+ point = curve->points[curve->n_points - 1];
boundary = ROUND (point.x * (gdouble) (curve->n_samples - 1));
for (i = boundary; i < curve->n_samples; i++)
curve->samples[i] = point.y;
}
- for (i = 0; i < num_pts - 1; i++)
+ for (i = 0; i < curve->n_points - 1; i++)
{
- p1 = points[MAX (i - 1, 0)];
- p2 = points[i];
- p3 = points[i + 1];
- p4 = points[MIN (i + 2, num_pts - 1)];
+ p1 = MAX (i - 1, 0);
+ p2 = i;
+ p3 = i + 1;
+ p4 = MIN (i + 2, curve->n_points - 1);
gimp_curve_plot (curve, p1, p2, p3, p4);
}
/* ensure that the control points are used exactly */
- for (i = 0; i < num_pts; i++)
+ for (i = 0; i < curve->n_points; i++)
{
- gdouble x = curve->points[points[i]].x;
- gdouble y = curve->points[points[i]].y;
+ gdouble x = curve->points[i].x;
+ gdouble y = curve->points[i].y;
curve->samples[ROUND (x * (gdouble) (curve->n_samples - 1))] = y;
}
@@ -1013,7 +1082,16 @@ gimp_curve_plot (GimpCurve *curve,
dx = x3 - x0;
dy = y3 - y0;
- g_return_if_fail (dx > 0);
+ if (dx <= EPSILON)
+ {
+ gint index;
+
+ index = ROUND (x0 * (gdouble) (curve->n_samples - 1));
+
+ curve->samples[index] = y3;
+
+ return;
+ }
if (p1 == p2 && p3 == p4)
{
diff --git a/app/core/gimpcurve.h b/app/core/gimpcurve.h
index 77f553a074..b41794c168 100644
--- a/app/core/gimpcurve.h
+++ b/app/core/gimpcurve.h
@@ -65,17 +65,24 @@ void gimp_curve_set_curve_type (GimpCurve *curve,
GimpCurveType curve_type);
GimpCurveType gimp_curve_get_curve_type (GimpCurve *curve);
-void gimp_curve_set_n_points (GimpCurve *curve,
- gint n_points);
gint gimp_curve_get_n_points (GimpCurve *curve);
void gimp_curve_set_n_samples (GimpCurve *curve,
gint n_samples);
gint gimp_curve_get_n_samples (GimpCurve *curve);
-gint gimp_curve_get_closest_point (GimpCurve *curve,
+gint gimp_curve_get_point_at (GimpCurve *curve,
gdouble x);
+gint gimp_curve_get_closest_point (GimpCurve *curve,
+ gdouble x,
+ gdouble y,
+ gdouble max_distance);
+gint gimp_curve_add_point (GimpCurve *curve,
+ gdouble x,
+ gdouble y);
+void gimp_curve_delete_point (GimpCurve *curve,
+ gint point);
void gimp_curve_set_point (GimpCurve *curve,
gint point,
gdouble x,
@@ -83,12 +90,11 @@ void gimp_curve_set_point (GimpCurve *curve,
void gimp_curve_move_point (GimpCurve *curve,
gint point,
gdouble y);
-void gimp_curve_delete_point (GimpCurve *curve,
- gint point);
void gimp_curve_get_point (GimpCurve *curve,
gint point,
gdouble *x,
gdouble *y);
+void gimp_curve_clear_points (GimpCurve *curve);
void gimp_curve_set_curve (GimpCurve *curve,
gdouble x,
diff --git a/app/operations/gimpcurvesconfig.c b/app/operations/gimpcurvesconfig.c
index 4855ac8135..6f5a2ef8b5 100644
--- a/app/operations/gimpcurvesconfig.c
+++ b/app/operations/gimpcurvesconfig.c
@@ -402,13 +402,10 @@ gimp_curves_config_new_spline (gint32 channel,
gimp_data_freeze (GIMP_DATA (curve));
gimp_curve_set_curve_type (curve, GIMP_CURVE_SMOOTH);
- gimp_curve_set_n_points (curve, n_points);
-
- /* unset the last point */
- gimp_curve_set_point (curve, curve->n_points - 1, -1.0, -1.0);
+ gimp_curve_clear_points (curve);
for (i = 0; i < n_points; i++)
- gimp_curve_set_point (curve, i,
+ gimp_curve_add_point (curve,
(gdouble) points[i * 2],
(gdouble) points[i * 2 + 1]);
@@ -598,18 +595,18 @@ gimp_curves_config_load_cruft (GimpCurvesConfig *config,
gimp_data_freeze (GIMP_DATA (curve));
gimp_curve_set_curve_type (curve, GIMP_CURVE_SMOOTH);
- gimp_curve_set_n_points (curve, GIMP_CURVE_N_CRUFT_POINTS);
-
- gimp_curve_reset (curve, FALSE);
+ gimp_curve_clear_points (curve);
for (j = 0; j < GIMP_CURVE_N_CRUFT_POINTS; j++)
{
- if (index[i][j] < 0 || value[i][j] < 0)
- gimp_curve_set_point (curve, j, -1.0, -1.0);
- else
- gimp_curve_set_point (curve, j,
- (gdouble) index[i][j] / 255.0,
- (gdouble) value[i][j] / 255.0);
+ gdouble x;
+ gdouble y;
+
+ x = (gdouble) index[i][j] / 255.0;
+ y = (gdouble) value[i][j] / 255.0;
+
+ if (x >= 0.0)
+ gimp_curve_add_point (curve, x, y);
}
gimp_data_thaw (GIMP_DATA (curve));
@@ -643,50 +640,34 @@ gimp_curves_config_save_cruft (GimpCurvesConfig *config,
GimpCurve *curve = config->curve[i];
gint j;
- if (curve->curve_type == GIMP_CURVE_FREE)
+ if (curve->curve_type == GIMP_CURVE_SMOOTH)
{
- gint n_points;
-
- for (j = 0; j < curve->n_points; j++)
- {
- curve->points[j].x = -1;
- curve->points[j].y = -1;
- }
-
- /* pick some points from the curve and make them control
- * points
- */
- n_points = CLAMP (9, curve->n_points / 2, curve->n_points);
-
- for (j = 0; j < n_points; j++)
- {
- gint sample = j * (curve->n_samples - 1) / (n_points - 1);
- gint point = j * (curve->n_points - 1) / (n_points - 1);
+ g_object_ref (curve);
+ }
+ else
+ {
+ curve = GIMP_CURVE (gimp_data_duplicate (GIMP_DATA (curve)));
- curve->points[point].x = ((gdouble) sample /
- (gdouble) (curve->n_samples - 1));
- curve->points[point].y = curve->samples[sample];
- }
+ gimp_curve_set_curve_type (curve, GIMP_CURVE_SMOOTH);
}
- for (j = 0; j < curve->n_points; j++)
+ for (j = 0; j < GIMP_CURVE_N_CRUFT_POINTS; j++)
{
- /* don't use gimp_curve_get_point() because that doesn't
- * work when the curve type is GIMP_CURVE_FREE
- */
- gdouble x = curve->points[j].x;
- gdouble y = curve->points[j].y;
+ gint x = -1;
+ gint y = -1;
- if (x < 0.0 || y < 0.0)
+ if (j < gimp_curve_get_n_points (curve))
{
- g_string_append_printf (string, "%d %d ", -1, -1);
- }
- else
- {
- g_string_append_printf (string, "%d %d ",
- (gint) (x * 255.999),
- (gint) (y * 255.999));
+ gdouble point_x;
+ gdouble point_y;
+
+ gimp_curve_get_point (curve, j, &point_x, &point_y);
+
+ x = floor (point_x * 255.999);
+ y = floor (point_y * 255.999);
}
+
+ g_string_append_printf (string, "%d %d ", x, y);
}
g_string_append_printf (string, "\n");
diff --git a/app/operations/gimplevelsconfig.c b/app/operations/gimplevelsconfig.c
index 27325a3083..5ea17e9f51 100644
--- a/app/operations/gimplevelsconfig.c
+++ b/app/operations/gimplevelsconfig.c
@@ -696,17 +696,14 @@ gimp_levels_config_to_curves_config (GimpLevelsConfig *config)
channel++)
{
GimpCurve *curve = curves->curve[channel];
- const gint n_points = gimp_curve_get_n_points (curve);
static const gint n = 8;
- gint point = -1;
gdouble gamma = config->gamma[channel];
gdouble delta_in;
gdouble delta_out;
gdouble x, y;
/* clear the points set by default */
- gimp_curve_set_point (curve, 0, -1, -1);
- gimp_curve_set_point (curve, n_points - 1, -1, -1);
+ gimp_curve_clear_points (curve);
delta_in = config->high_input[channel] - config->low_input[channel];
delta_out = config->high_output[channel] - config->low_output[channel];
@@ -714,8 +711,7 @@ gimp_levels_config_to_curves_config (GimpLevelsConfig *config)
x = config->low_input[channel];
y = config->low_output[channel];
- point = CLAMP (n_points * x, point + 1, n_points - 1 - n);
- gimp_curve_set_point (curve, point, x, y);
+ gimp_curve_add_point (curve, x, y);
if (delta_out != 0 && gamma != 1.0)
{
@@ -755,8 +751,7 @@ gimp_levels_config_to_curves_config (GimpLevelsConfig *config)
x = config->low_input[channel] + dx;
y = config->low_output[channel] + delta_out *
gimp_operation_levels_map_input (config, channel, x);
- point = CLAMP (n_points * x, point + 1, n_points - 1 - n + i);
- gimp_curve_set_point (curve, point, x, y);
+ gimp_curve_add_point (curve, x, y);
}
}
else
@@ -792,8 +787,7 @@ gimp_levels_config_to_curves_config (GimpLevelsConfig *config)
y = config->low_output[channel] + dy;
x = config->low_input[channel] + delta_in *
gimp_operation_levels_map_input (config_inv, channel, y);
- point = CLAMP (n_points * x, point + 1, n_points - 1 - n + i);
- gimp_curve_set_point (curve, point, x, y);
+ gimp_curve_add_point (curve, x, y);
}
g_object_unref (config_inv);
@@ -803,8 +797,7 @@ gimp_levels_config_to_curves_config (GimpLevelsConfig *config)
x = config->high_input[channel];
y = config->high_output[channel];
- point = CLAMP (n_points * x, point + 1, n_points - 1);
- gimp_curve_set_point (curve, point, x, y);
+ gimp_curve_add_point (curve, x, y);
}
return curves;
diff --git a/app/tools/gimpcurvestool.c b/app/tools/gimpcurvestool.c
index 6e8b9b2961..d4c7ac4fb7 100644
--- a/app/tools/gimpcurvestool.c
+++ b/app/tools/gimpcurvestool.c
@@ -242,15 +242,18 @@ gimp_curves_tool_button_release (GimpTool *tool,
{
GimpCurve *curve = config->curve[config->channel];
gdouble value = c_tool->picked_color[config->channel];
- gint closest;
+ gint point;
- closest = gimp_curve_get_closest_point (curve, value);
+ point = gimp_curve_get_point_at (curve, value);
- gimp_curve_view_set_selected (GIMP_CURVE_VIEW (c_tool->graph),
- closest);
+ if (point < 0)
+ {
+ point = gimp_curve_add_point (
+ curve,
+ value, gimp_curve_map_value (curve, value));
+ }
- gimp_curve_set_point (curve, closest,
- value, gimp_curve_map_value (curve, value));
+ gimp_curve_view_set_selected (GIMP_CURVE_VIEW (c_tool->graph), point);
}
else if (state & gimp_get_toggle_behavior_mask ())
{
@@ -262,17 +265,25 @@ gimp_curves_tool_button_release (GimpTool *tool,
{
GimpCurve *curve = config->curve[channel];
gdouble value = c_tool->picked_color[channel];
- gint closest;
if (value != -1)
{
- closest = gimp_curve_get_closest_point (curve, value);
-
- gimp_curve_view_set_selected (GIMP_CURVE_VIEW (c_tool->graph),
- closest);
-
- gimp_curve_set_point (curve, closest,
- value, gimp_curve_map_value (curve, value));
+ gint point;
+
+ point = gimp_curve_get_point_at (curve, value);
+
+ if (point < 0)
+ {
+ point = gimp_curve_add_point (
+ curve,
+ value, gimp_curve_map_value (curve, value));
+ }
+
+ if (channel == config->channel)
+ {
+ gimp_curve_view_set_selected (GIMP_CURVE_VIEW (c_tool->graph),
+ point);
+ }
}
}
}
diff --git a/app/widgets/gimpcurveview.c b/app/widgets/gimpcurveview.c
index 2ba38e876c..5bfeb1e1c8 100644
--- a/app/widgets/gimpcurveview.c
+++ b/app/widgets/gimpcurveview.c
@@ -37,6 +37,10 @@
#include "gimpclipboard.h"
#include "gimpcurveview.h"
+#include "gimpwidgets-utils.h"
+
+
+#define POINT_MAX_DISTANCE 16.0
enum
@@ -67,40 +71,46 @@ typedef struct
} BGCurve;
-static void gimp_curve_view_finalize (GObject *object);
-static void gimp_curve_view_dispose (GObject *object);
-static void gimp_curve_view_set_property (GObject *object,
- guint property_id,
- const GValue *value,
- GParamSpec *pspec);
-static void gimp_curve_view_get_property (GObject *object,
- guint property_id,
- GValue *value,
- GParamSpec *pspec);
-
-static void gimp_curve_view_style_set (GtkWidget *widget,
- GtkStyle *prev_style);
-static gboolean gimp_curve_view_expose (GtkWidget *widget,
- GdkEventExpose *event);
-static gboolean gimp_curve_view_button_press (GtkWidget *widget,
- GdkEventButton *bevent);
-static gboolean gimp_curve_view_button_release (GtkWidget *widget,
- GdkEventButton *bevent);
-static gboolean gimp_curve_view_motion_notify (GtkWidget *widget,
- GdkEventMotion *bevent);
-static gboolean gimp_curve_view_leave_notify (GtkWidget *widget,
- GdkEventCrossing *cevent);
-static gboolean gimp_curve_view_key_press (GtkWidget *widget,
- GdkEventKey *kevent);
-
-static void gimp_curve_view_cut_clipboard (GimpCurveView *view);
-static void gimp_curve_view_copy_clipboard (GimpCurveView *view);
-static void gimp_curve_view_paste_clipboard (GimpCurveView *view);
-
-static void gimp_curve_view_set_cursor (GimpCurveView *view,
- gdouble x,
- gdouble y);
-static void gimp_curve_view_unset_cursor (GimpCurveView *view);
+static void gimp_curve_view_finalize (GObject *object);
+static void gimp_curve_view_dispose (GObject *object);
+static void gimp_curve_view_set_property (GObject *object,
+ guint property_id,
+ const GValue *value,
+ GParamSpec *pspec);
+static void gimp_curve_view_get_property (GObject *object,
+ guint property_id,
+ GValue *value,
+ GParamSpec *pspec);
+
+static void gimp_curve_view_style_set (GtkWidget *widget,
+ GtkStyle *prev_style);
+static gboolean gimp_curve_view_expose (GtkWidget *widget,
+ GdkEventExpose *event);
+static gboolean gimp_curve_view_button_press (GtkWidget *widget,
+ GdkEventButton *bevent);
+static gboolean gimp_curve_view_button_release (GtkWidget *widget,
+ GdkEventButton *bevent);
+static gboolean gimp_curve_view_motion_notify (GtkWidget *widget,
+ GdkEventMotion *bevent);
+static gboolean gimp_curve_view_leave_notify (GtkWidget *widget,
+ GdkEventCrossing *cevent);
+static gboolean gimp_curve_view_key_press (GtkWidget *widget,
+ GdkEventKey *kevent);
+
+static void gimp_curve_view_cut_clipboard (GimpCurveView *view);
+static void gimp_curve_view_copy_clipboard (GimpCurveView *view);
+static void gimp_curve_view_paste_clipboard (GimpCurveView *view);
+
+static void gimp_curve_view_curve_dirty (GimpCurve *curve,
+ GimpCurveView *view);
+static void gimp_curve_view_curve_notify_n_points (GimpCurve *curve,
+ GParamSpec *pspec,
+ GimpCurveView *view);
+
+static void gimp_curve_view_set_cursor (GimpCurveView *view,
+ gdouble x,
+ gdouble y);
+static void gimp_curve_view_unset_cursor (GimpCurveView *view);
G_DEFINE_TYPE (GimpCurveView, gimp_curve_view,
@@ -211,7 +221,7 @@ static void
gimp_curve_view_init (GimpCurveView *view)
{
view->curve = NULL;
- view->selected = 0;
+ view->selected = -1;
view->offset_x = 0.0;
view->offset_y = 0.0;
view->last_x = 0.0;
@@ -419,9 +429,6 @@ gimp_curve_view_draw_point (GimpCurveView *view,
gimp_curve_get_point (view->curve, i, &x, &y);
- if (x < 0.0)
- return;
-
y = 1.0 - y;
#define RADIUS 3
@@ -785,10 +792,9 @@ gimp_curve_view_button_press (GtkWidget *widget,
gint width, height;
gdouble x;
gdouble y;
+ gint point;
gdouble point_x;
gdouble point_y;
- gint closest_point;
- gint i;
if (! curve || bevent->button != 1)
return TRUE;
@@ -805,8 +811,6 @@ gimp_curve_view_button_press (GtkWidget *widget,
x = CLAMP (x, 0.0, 1.0);
y = CLAMP (y, 0.0, 1.0);
- closest_point = gimp_curve_get_closest_point (curve, x);
-
view->grabbed = TRUE;
view->orig_curve = GIMP_CURVE (gimp_data_duplicate (GIMP_DATA (curve)));
@@ -816,47 +820,34 @@ gimp_curve_view_button_press (GtkWidget *widget,
switch (gimp_curve_get_curve_type (curve))
{
case GIMP_CURVE_SMOOTH:
- /* determine the leftmost and rightmost points */
- view->leftmost = -1.0;
- for (i = closest_point - 1; i >= 0; i--)
- {
- gimp_curve_get_point (curve, i, &point_x, NULL);
-
- if (point_x >= 0.0)
- {
- view->leftmost = point_x;
- break;
- }
- }
+ point = gimp_curve_get_closest_point (curve, x, 1.0 - y,
+ POINT_MAX_DISTANCE /
+ MAX (width, height));
- view->rightmost = 2.0;
- for (i = closest_point + 1; i < curve->n_points; i++)
+ if (point < 0)
{
- gimp_curve_get_point (curve, i, &point_x, NULL);
+ if (bevent->state & gimp_get_constrain_behavior_mask ())
+ y = 1.0 - gimp_curve_map_value (view->orig_curve, x);
- if (point_x >= 0.0)
- {
- view->rightmost = point_x;
- break;
- }
+ point = gimp_curve_add_point (curve, x, 1.0 - y);
}
- gimp_curve_view_set_selected (view, closest_point);
-
- gimp_curve_get_point (curve, view->selected, &point_x, &point_y);
+ if (point > 0)
+ gimp_curve_get_point (curve, point - 1, &view->leftmost, NULL);
+ else
+ view->leftmost = -1.0;
- if (point_x >= 0.0)
- {
- view->offset_x = point_x - x;
- view->offset_y = (1.0 - point_y) - y;
- }
+ if (point < gimp_curve_get_n_points (curve) - 1)
+ gimp_curve_get_point (curve, point + 1, &view->rightmost, NULL);
else
- {
- if (bevent->state & gimp_get_constrain_behavior_mask ())
- y = 1.0 - gimp_curve_map_value (view->orig_curve, x);
+ view->rightmost = 2.0;
- gimp_curve_set_point (curve, view->selected, x, 1.0 - y);
- }
+ gimp_curve_view_set_selected (view, point);
+
+ gimp_curve_get_point (curve, point, &point_x, &point_y);
+
+ view->offset_x = point_x - x;
+ view->offset_y = (1.0 - point_y) - y;
break;
case GIMP_CURVE_FREE:
@@ -908,7 +899,7 @@ gimp_curve_view_motion_notify (GtkWidget *widget,
gdouble y;
gdouble point_x;
gdouble point_y;
- gint closest_point;
+ gint point;
if (! curve)
return TRUE;
@@ -928,17 +919,19 @@ gimp_curve_view_motion_notify (GtkWidget *widget,
x = CLAMP (x, 0.0, 1.0);
y = CLAMP (y, 0.0, 1.0);
- closest_point = gimp_curve_get_closest_point (curve, x);
-
switch (gimp_curve_get_curve_type (curve))
{
case GIMP_CURVE_SMOOTH:
if (! view->grabbed) /* If no point is grabbed... */
{
- gimp_curve_get_point (curve, closest_point, &point_x, &point_y);
+ point = gimp_curve_get_closest_point (curve, x, 1.0 - y,
+ POINT_MAX_DISTANCE /
+ MAX (width, height));
- if (point_x >= 0.0)
+ if (point >= 0)
{
+ gimp_curve_get_point (curve, point, &point_x, &point_y);
+
new_cursor = GDK_FLEUR;
x = point_x;
@@ -961,20 +954,27 @@ gimp_curve_view_motion_notify (GtkWidget *widget,
gimp_data_freeze (GIMP_DATA (curve));
- gimp_curve_set_point (curve, view->selected, -1.0, -1.0);
-
if (x > view->leftmost && x < view->rightmost)
{
- gint n_points = gimp_curve_get_n_points (curve);
-
- closest_point = ROUND (x * (gdouble) (n_points - 1));
-
- gimp_curve_get_point (curve, closest_point, &point_x, NULL);
-
- if (point_x < 0.0)
- gimp_curve_view_set_selected (view, closest_point);
+ if (view->selected < 0)
+ {
+ gimp_curve_view_set_selected (
+ view,
+ gimp_curve_add_point (curve, x, 1.0 - y));
+ }
+ else
+ {
+ gimp_curve_set_point (curve, view->selected, x, 1.0 - y);
+ }
+ }
+ else
+ {
+ if (view->selected >= 0)
+ {
+ gimp_curve_delete_point (curve, view->selected);
- gimp_curve_set_point (curve, view->selected, x, 1.0 - y);
+ gimp_curve_view_set_selected (view, -1);
+ }
}
gimp_data_thaw (GIMP_DATA (curve));
@@ -1067,8 +1067,10 @@ gimp_curve_view_key_press (GtkWidget *widget,
GimpCurve *curve = view->curve;
gboolean handled = FALSE;
- if (! view->grabbed && curve &&
- gimp_curve_get_curve_type (curve) == GIMP_CURVE_SMOOTH)
+ if (! view->grabbed &&
+ curve &&
+ gimp_curve_get_curve_type (curve) == GIMP_CURVE_SMOOTH &&
+ view->selected >= 0)
{
gint i = view->selected;
gdouble x, y;
@@ -1205,6 +1207,21 @@ gimp_curve_view_paste_clipboard (GimpCurveView *view)
}
}
+static void
+gimp_curve_view_curve_dirty (GimpCurve *curve,
+ GimpCurveView *view)
+{
+ gtk_widget_queue_draw (GTK_WIDGET (view));
+}
+
+static void
+gimp_curve_view_curve_notify_n_points (GimpCurve *curve,
+ GParamSpec *pspec,
+ GimpCurveView *view)
+{
+ gimp_curve_view_set_selected (view, -1);
+}
+
/* public functions */
@@ -1214,13 +1231,6 @@ gimp_curve_view_new (void)
return g_object_new (GIMP_TYPE_CURVE_VIEW, NULL);
}
-static void
-gimp_curve_view_curve_dirty (GimpCurve *curve,
- GimpCurveView *view)
-{
- gtk_widget_queue_draw (GTK_WIDGET (view));
-}
-
void
gimp_curve_view_set_curve (GimpCurveView *view,
GimpCurve *curve,
@@ -1237,6 +1247,9 @@ gimp_curve_view_set_curve (GimpCurveView *view,
g_signal_handlers_disconnect_by_func (view->curve,
gimp_curve_view_curve_dirty,
view);
+ g_signal_handlers_disconnect_by_func (view->curve,
+ gimp_curve_view_curve_notify_n_points,
+ view);
g_object_unref (view->curve);
}
@@ -1248,6 +1261,9 @@ gimp_curve_view_set_curve (GimpCurveView *view,
g_signal_connect (view->curve, "dirty",
G_CALLBACK (gimp_curve_view_curve_dirty),
view);
+ g_signal_connect (view->curve, "notify::n-points",
+ G_CALLBACK (gimp_curve_view_curve_notify_n_points),
+ view);
}
if (view->curve_color)
@@ -1258,6 +1274,8 @@ gimp_curve_view_set_curve (GimpCurveView *view,
else
view->curve_color = NULL;
+ gimp_curve_view_set_selected (view, -1);
+
gtk_widget_queue_draw (GTK_WIDGET (view));
}
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]