[gimp/multi-stroke: 2/2] app: add a tiling multi-stroke.
- From: Jehan Pagès <jehanp src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [gimp/multi-stroke: 2/2] app: add a tiling multi-stroke.
- Date: Sun, 15 Mar 2015 21:32:52 +0000 (UTC)
commit b2b7739ac502c489d3847895f3b6219fee0c01ea
Author: Jehan <jehan girinstud io>
Date: Sun Mar 15 17:21:02 2015 +0100
app: add a tiling multi-stroke.
app/paint/Makefile.am | 4 +-
app/paint/gimpmultistroke-info.c | 2 +
app/paint/gimptiling.c | 409 ++++++++++++++++++++++++++++++++++++++
app/paint/gimptiling.h | 57 ++++++
app/paint/paint-types.h | 1 +
5 files changed, 472 insertions(+), 1 deletions(-)
---
diff --git a/app/paint/Makefile.am b/app/paint/Makefile.am
index 0d6a154..7c502c7 100644
--- a/app/paint/Makefile.am
+++ b/app/paint/Makefile.am
@@ -84,7 +84,9 @@ libapppaint_a_sources = \
gimpsourcecore.c \
gimpsourcecore.h \
gimpsourceoptions.c \
- gimpsourceoptions.h
+ gimpsourceoptions.h \
+ gimptiling.c \
+ gimptiling.h
libapppaint_a_built_sources = paint-enums.c
diff --git a/app/paint/gimpmultistroke-info.c b/app/paint/gimpmultistroke-info.c
index 6ca4876..5d7b56e 100644
--- a/app/paint/gimpmultistroke-info.c
+++ b/app/paint/gimpmultistroke-info.c
@@ -28,6 +28,7 @@
#include "gimpmirror.h"
#include "gimpmultistroke.h"
#include "gimpmultistroke-info.h"
+#include "gimptiling.h"
GList *
gimp_multi_stroke_list (void)
@@ -35,6 +36,7 @@ gimp_multi_stroke_list (void)
GList *list = NULL;
list = g_list_prepend (list, GINT_TO_POINTER (GIMP_TYPE_MIRROR));
+ list = g_list_prepend (list, GINT_TO_POINTER (GIMP_TYPE_TILING));
return list;
}
diff --git a/app/paint/gimptiling.c b/app/paint/gimptiling.c
new file mode 100644
index 0000000..f71aa93
--- /dev/null
+++ b/app/paint/gimptiling.c
@@ -0,0 +1,409 @@
+/* GIMP - The GNU Image Manipulation Program
+ * Copyright (C) 1995 Spencer Kimball and Peter Mattis
+ *
+ * gimptiling.c
+ * Copyright (C) 2015 Jehan <jehan gimp org>
+ *
+ * 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 <string.h>
+
+#include <gegl.h>
+#include <gdk-pixbuf/gdk-pixbuf.h>
+
+#include "libgimpconfig/gimpconfig.h"
+
+#include "paint-types.h"
+
+#include "core/gimp.h"
+#include "core/gimpdrawable.h"
+#include "core/gimpimage.h"
+#include "core/gimpitem.h"
+
+#include "gimptiling.h"
+
+#include "gimp-intl.h"
+
+/* Using same epsilon as in GLIB. */
+#define G_DOUBLE_EPSILON (1e-90)
+
+enum
+{
+ PROP_0,
+
+ PROP_X_INTERVAL,
+ PROP_Y_INTERVAL,
+ PROP_SHIFT,
+ PROP_X_MAX,
+ PROP_Y_MAX
+};
+
+/* Local function prototypes */
+
+static void gimp_tiling_constructed (GObject *object);
+static void gimp_tiling_finalize (GObject *object);
+static void gimp_tiling_set_property (GObject *object,
+ guint property_id,
+ const GValue *value,
+ GParamSpec *pspec);
+static void gimp_tiling_get_property (GObject *object,
+ guint property_id,
+ GValue *value,
+ GParamSpec *pspec);
+
+static void gimp_tiling_update_strokes (GimpMultiStroke *tiling,
+ GimpDrawable *drawable,
+ GimpCoords *origin);
+static GeglNode * gimp_tiling_get_operation (GimpMultiStroke *tiling,
+ GimpPaintCore *core,
+ GeglBuffer *paint_buffer,
+ gint stroke);
+static GParamSpec ** gimp_tiling_get_settings (GimpMultiStroke *mstroke,
+ guint *nsettings);
+static void
+ gimp_tiling_image_size_changed_cb (GimpImage *image ,
+ gint previous_origin_x,
+ gint previous_origin_y,
+ gint previous_width,
+ gint previous_height,
+ GimpMultiStroke *mstroke);
+
+G_DEFINE_TYPE (GimpTiling, gimp_tiling, GIMP_TYPE_MULTI_STROKE)
+
+#define parent_class gimp_tiling_parent_class
+
+static void
+gimp_tiling_class_init (GimpTilingClass *klass)
+{
+ GObjectClass *object_class = G_OBJECT_CLASS (klass);
+ GimpMultiStrokeClass *multi_stroke_class = GIMP_MULTI_STROKE_CLASS (klass);
+
+ object_class->constructed = gimp_tiling_constructed;
+ object_class->finalize = gimp_tiling_finalize;
+ object_class->set_property = gimp_tiling_set_property;
+ object_class->get_property = gimp_tiling_get_property;
+
+ multi_stroke_class->label = "Tiling";
+ multi_stroke_class->update_strokes = gimp_tiling_update_strokes;
+ multi_stroke_class->get_operation = gimp_tiling_get_operation;
+ multi_stroke_class->get_settings = gimp_tiling_get_settings;
+ multi_stroke_class->get_xcf_settings = gimp_tiling_get_settings;
+
+ GIMP_CONFIG_INSTALL_PROP_DOUBLE (object_class, PROP_X_INTERVAL,
+ "x-interval", _("Intervals on x-axis (pixels)"),
+ 0.0, 10000.0, 0.0,
+ GIMP_PARAM_STATIC_STRINGS);
+ GIMP_CONFIG_INSTALL_PROP_DOUBLE (object_class, PROP_Y_INTERVAL,
+ "y-interval", _("Intervals on y-axis (pixels)"),
+ 0.0, 10000.0, 0.0,
+ GIMP_PARAM_STATIC_STRINGS);
+ GIMP_CONFIG_INSTALL_PROP_DOUBLE (object_class, PROP_SHIFT,
+ "shift", _("X-shift between lines (pixels)"),
+ 0.0, 10000.0, 0.0,
+ GIMP_PARAM_STATIC_STRINGS);
+ GIMP_CONFIG_INSTALL_PROP_UINT (object_class, PROP_X_MAX,
+ "x-max", _("Max strokes on x-axis"),
+ 0, 100, 0,
+ GIMP_PARAM_STATIC_STRINGS);
+ GIMP_CONFIG_INSTALL_PROP_UINT (object_class, PROP_Y_MAX,
+ "y-max", _("Max strokes on y-axis"),
+ 0, 100, 0,
+ GIMP_PARAM_STATIC_STRINGS);
+}
+
+static void
+gimp_tiling_init (GimpTiling *tiling)
+{
+ tiling->interval_x = 0.0;
+ tiling->interval_y = 0.0;
+ tiling->shift = 0.0;
+}
+
+static void
+gimp_tiling_constructed (GObject *object)
+{
+ GimpMultiStroke *mstroke;
+ GParamSpecDouble *dspec;
+
+ mstroke = GIMP_MULTI_STROKE (object);
+
+ // TODO: can I have it in property and still save it in parent? Test.
+ // Also connect on image changing size.
+ // Connect to either GimpImage::size-changed-detailed
+ // or GimpViewable::size-changed
+ // see gimp_image_real_size_changed_detailed
+ /* Update property values to actual image size. */
+ dspec = G_PARAM_SPEC_DOUBLE (g_object_class_find_property (G_OBJECT_GET_CLASS (object),
+ "x-interval"));
+ dspec->maximum = gimp_image_get_width (mstroke->image);
+
+ dspec = G_PARAM_SPEC_DOUBLE (g_object_class_find_property (G_OBJECT_GET_CLASS (object),
+ "shift"));
+ dspec->maximum = gimp_image_get_width (mstroke->image);
+
+ dspec = G_PARAM_SPEC_DOUBLE (g_object_class_find_property (G_OBJECT_GET_CLASS (object),
+ "y-interval"));
+ dspec->maximum = gimp_image_get_height (mstroke->image);
+
+ g_signal_connect (mstroke->image, "size-changed-detailed",
+ G_CALLBACK (gimp_tiling_image_size_changed_cb),
+ mstroke);
+}
+
+static void
+gimp_tiling_finalize (GObject *object)
+{
+ G_OBJECT_CLASS (parent_class)->finalize (object);
+}
+
+static void
+gimp_tiling_set_property (GObject *object,
+ guint property_id,
+ const GValue *value,
+ GParamSpec *pspec)
+{
+ GimpTiling *tiling = GIMP_TILING (object);
+ GimpMultiStroke *mstroke = GIMP_MULTI_STROKE (tiling);
+
+ switch (property_id)
+ {
+ case PROP_X_INTERVAL:
+ if (mstroke->image)
+ {
+ gdouble new_x = g_value_get_double (value);
+
+ if (new_x < gimp_image_get_width (mstroke->image))
+ {
+ tiling->interval_x = new_x;
+
+ if (tiling->interval_x <= tiling->shift + G_DOUBLE_EPSILON)
+ {
+ GValue val = {0,};
+
+ g_value_init (&val, G_TYPE_DOUBLE);
+ g_value_set_double (&val, 0.0);
+ g_object_set_property (G_OBJECT (object), "shift", &val);
+ }
+ else if (mstroke->drawable)
+ gimp_tiling_update_strokes (mstroke, mstroke->drawable, mstroke->origin);
+ }
+ }
+ break;
+ case PROP_Y_INTERVAL:
+ {
+ gdouble new_y = g_value_get_double (value);
+
+ if (new_y < gimp_image_get_height (mstroke->image))
+ {
+ tiling->interval_y = new_y;
+
+ if (tiling->interval_y <= G_DOUBLE_EPSILON)
+ {
+ GValue val = {0,};
+
+ g_value_init (&val, G_TYPE_DOUBLE);
+ g_value_set_double (&val, 0.0);
+ g_object_set_property (G_OBJECT (object), "shift", &val);
+ }
+ else if (mstroke->drawable)
+ gimp_tiling_update_strokes (mstroke, mstroke->drawable, mstroke->origin);
+ }
+ }
+ break;
+ case PROP_SHIFT:
+ {
+ gdouble new_shift = g_value_get_double (value);
+
+ if (new_shift == 0.0 ||
+ (tiling->interval_y != 0.0 && new_shift < tiling->interval_x))
+ {
+ tiling->shift = new_shift;
+ if (mstroke->drawable)
+ gimp_tiling_update_strokes (mstroke, mstroke->drawable, mstroke->origin);
+ }
+ }
+ break;
+ case PROP_X_MAX:
+ tiling->max_x = g_value_get_uint (value);
+ if (mstroke->drawable)
+ gimp_tiling_update_strokes (mstroke, mstroke->drawable, mstroke->origin);
+ break;
+ case PROP_Y_MAX:
+ tiling->max_y = g_value_get_uint (value);
+ if (mstroke->drawable)
+ gimp_tiling_update_strokes (mstroke, mstroke->drawable, mstroke->origin);
+ break;
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
+ break;
+ }
+}
+
+static void
+gimp_tiling_get_property (GObject *object,
+ guint property_id,
+ GValue *value,
+ GParamSpec *pspec)
+{
+ GimpTiling *tiling = GIMP_TILING (object);
+
+ switch (property_id)
+ {
+ case PROP_X_INTERVAL:
+ g_value_set_double (value, tiling->interval_x);
+ break;
+ case PROP_Y_INTERVAL:
+ g_value_set_double (value, tiling->interval_y);
+ break;
+ case PROP_SHIFT:
+ g_value_set_double (value, tiling->shift);
+ break;
+ case PROP_X_MAX:
+ g_value_set_uint (value, tiling->max_x);
+ break;
+ case PROP_Y_MAX:
+ g_value_set_uint (value, tiling->max_y);
+ break;
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
+ break;
+ }
+}
+
+static void
+gimp_tiling_update_strokes (GimpMultiStroke *mstroke,
+ GimpDrawable *drawable,
+ GimpCoords *origin)
+{
+ GList *strokes = NULL;
+ GimpTiling *tiling = GIMP_TILING (mstroke);
+ GimpCoords *coords;
+ gint width;
+ gint height;
+ gint startx = origin->x;
+ gint starty = origin->y;
+ gint x;
+ gint y;
+ gint x_count;
+ gint y_count;
+
+ g_return_if_fail (GIMP_IS_DRAWABLE (drawable));
+ g_return_if_fail (GIMP_IS_MULTI_STROKE (mstroke));
+
+ g_list_free_full (mstroke->strokes, g_free);
+ mstroke->strokes = NULL;
+
+ width = gimp_item_get_width (GIMP_ITEM (drawable));
+ height = gimp_item_get_height (GIMP_ITEM (drawable));
+
+ if (origin->x > 0 && tiling->max_x == 0)
+ startx = origin->x - tiling->interval_x * (gint) (origin->x / tiling->interval_x + 1)
+ - tiling->shift * (gint) (origin->y / tiling->interval_y + 1);
+ if (origin->y > 0 && tiling->max_y == 0)
+ starty = origin->y - tiling->interval_y * (gint) (origin->y / tiling->interval_y + 1);
+ for (y_count = 0, y = starty; y < height + tiling->interval_y;
+ y_count++, y += tiling->interval_y)
+ {
+ for (x_count = 0, x = startx; x < width + tiling->interval_x;
+ x_count++, x += tiling->interval_x)
+ {
+ coords = g_memdup (origin, sizeof (GimpCoords));
+ coords->x = x;
+ coords->y = y;
+ strokes = g_list_prepend (strokes, coords);
+ if (tiling->interval_x < 1.0 ||
+ (tiling->max_x && x_count >= (gint) tiling->max_x))
+ break;
+ }
+ if (tiling->interval_y < 1.0 ||
+ (tiling->max_y && y_count >= (gint) tiling->max_y))
+ break;
+ if (tiling->max_x || startx + tiling->shift <= 0.0)
+ startx = startx + tiling->shift;
+ else
+ startx = startx - tiling->interval_x + tiling->shift;
+ }
+ mstroke->strokes = strokes;
+
+ g_signal_emit_by_name (mstroke, "strokes-updated", mstroke->image);
+}
+
+static GeglNode *
+gimp_tiling_get_operation (GimpMultiStroke *mstroke,
+ GimpPaintCore *core,
+ GeglBuffer *paint_buffer,
+ gint stroke)
+{
+ /* No buffer transformation happens for tiling. */
+ return NULL;
+}
+
+static GParamSpec **
+gimp_tiling_get_settings (GimpMultiStroke *mstroke,
+ guint *nsettings)
+{
+ GParamSpec **pspecs;
+
+ *nsettings = 6;
+ pspecs = g_new (GParamSpec*, 6);
+
+ pspecs[0] = g_object_class_find_property (G_OBJECT_GET_CLASS (mstroke),
+ "x-interval");
+ pspecs[1] = g_object_class_find_property (G_OBJECT_GET_CLASS (mstroke),
+ "y-interval");
+ pspecs[2] = g_object_class_find_property (G_OBJECT_GET_CLASS (mstroke),
+ "shift");
+ pspecs[3] = NULL;
+ pspecs[4] = g_object_class_find_property (G_OBJECT_GET_CLASS (mstroke),
+ "x-max");
+ pspecs[5] = g_object_class_find_property (G_OBJECT_GET_CLASS (mstroke),
+ "y-max");
+
+ return pspecs;
+}
+
+static void
+gimp_tiling_image_size_changed_cb (GimpImage *image,
+ gint previous_origin_x,
+ gint previous_origin_y,
+ gint previous_width,
+ gint previous_height,
+ GimpMultiStroke *mstroke)
+{
+ GParamSpecDouble *dspec;
+
+ if (previous_width != gimp_image_get_width (image))
+ {
+ dspec = G_PARAM_SPEC_DOUBLE (g_object_class_find_property (G_OBJECT_GET_CLASS (mstroke),
+ "x-interval"));
+ dspec->maximum = gimp_image_get_width (mstroke->image);
+
+ dspec = G_PARAM_SPEC_DOUBLE (g_object_class_find_property (G_OBJECT_GET_CLASS (mstroke),
+ "shift"));
+ dspec->maximum = gimp_image_get_width (mstroke->image);
+ }
+ if (previous_height != gimp_image_get_height (image))
+ {
+ dspec = G_PARAM_SPEC_DOUBLE (g_object_class_find_property (G_OBJECT_GET_CLASS (mstroke),
+ "y-interval"));
+ dspec->maximum = gimp_image_get_height (mstroke->image);
+ }
+
+ if (previous_width != gimp_image_get_width (image) ||
+ previous_height != gimp_image_get_height (image))
+ g_signal_emit_by_name (mstroke, "update-ui", mstroke->image);
+}
diff --git a/app/paint/gimptiling.h b/app/paint/gimptiling.h
new file mode 100644
index 0000000..7f60185
--- /dev/null
+++ b/app/paint/gimptiling.h
@@ -0,0 +1,57 @@
+/* GIMP - The GNU Image Manipulation Program
+ * Copyright (C) 1995 Spencer Kimball and Peter Mattis
+ *
+ * gimptiling.h
+ * Copyright (C) 2015 Jehan <jehan gimp org>
+ *
+ * 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_TILING_H__
+#define __GIMP_TILING_H__
+
+
+#include "gimpmultistroke.h"
+
+
+#define GIMP_TYPE_TILING (gimp_tiling_get_type ())
+#define GIMP_TILING(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GIMP_TYPE_TILING, GimpTiling))
+#define GIMP_TILING_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), GIMP_TYPE_TILING, GimpTilingClass))
+#define GIMP_IS_TILING(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GIMP_TYPE_TILING))
+#define GIMP_IS_TILING_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), GIMP_TYPE_TILING))
+#define GIMP_TILING_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), GIMP_TYPE_TILING, GimpTilingClass))
+
+typedef struct _GimpTilingClass GimpTilingClass;
+
+struct _GimpTiling
+{
+ GimpMultiStroke parent_instance;
+
+ gdouble interval_x;
+ gdouble interval_y;
+ gdouble shift;
+ guint max_x;
+ guint max_y;
+};
+
+struct _GimpTilingClass
+{
+ GimpMultiStrokeClass parent_class;
+};
+
+GType gimp_tiling_get_type (void) G_GNUC_CONST;
+
+#endif /* __GIMP_TILING_H__ */
+
+
diff --git a/app/paint/paint-types.h b/app/paint/paint-types.h
index 6a0b80b..2592b30 100644
--- a/app/paint/paint-types.h
+++ b/app/paint/paint-types.h
@@ -44,6 +44,7 @@ typedef struct _GimpSmudge GimpSmudge;
/* Multi-stroke transformations */
typedef struct _GimpMultiStroke GimpMultiStroke;
typedef struct _GimpMirror GimpMirror;
+typedef struct _GimpTiling GimpTiling;
/* paint options */
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]