1 /* GIMP - The GNU Image Manipulation Program
2 * Copyright (C) 1995 Spencer Kimball and Peter Mattis
3 *
4 * gimpviewrenderergradient.c
5 * Copyright (C) 2003 Michael Natterer <mitch@gimp.org>
6 *
7 * This program is free software: you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation; either version 3 of the License, or
10 * (at your option) any later version.
11 *
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
16 *
17 * You should have received a copy of the GNU General Public License
18 * along with this program. If not, see <https://www.gnu.org/licenses/>.
19 */
20
21 #include "config.h"
22
23 #include <string.h>
24
25 #include <gegl.h>
26 #include <gtk/gtk.h>
27
28 #include "libgimpbase/gimpbase.h"
29 #include "libgimpcolor/gimpcolor.h"
30 #include "libgimpmath/gimpmath.h"
31 #include "libgimpwidgets/gimpwidgets.h"
32
33 #include "widgets-types.h"
34
35 #include "core/gimpgradient.h"
36
37 #include "gimpviewrenderergradient.h"
38
39
40 static void gimp_view_renderer_gradient_set_context (GimpViewRenderer *renderer,
41 GimpContext *context);
42 static void gimp_view_renderer_gradient_invalidate (GimpViewRenderer *renderer);
43 static void gimp_view_renderer_gradient_render (GimpViewRenderer *renderer,
44 GtkWidget *widget);
45
46
47 G_DEFINE_TYPE (GimpViewRendererGradient, gimp_view_renderer_gradient,
48 GIMP_TYPE_VIEW_RENDERER);
49
50 #define parent_class gimp_view_renderer_gradient_parent_class
51
52
53 static void
gimp_view_renderer_gradient_class_init(GimpViewRendererGradientClass * klass)54 gimp_view_renderer_gradient_class_init (GimpViewRendererGradientClass *klass)
55 {
56 GimpViewRendererClass *renderer_class = GIMP_VIEW_RENDERER_CLASS (klass);
57
58 renderer_class->set_context = gimp_view_renderer_gradient_set_context;
59 renderer_class->invalidate = gimp_view_renderer_gradient_invalidate;
60 renderer_class->render = gimp_view_renderer_gradient_render;
61 }
62
63 static void
gimp_view_renderer_gradient_init(GimpViewRendererGradient * renderer)64 gimp_view_renderer_gradient_init (GimpViewRendererGradient *renderer)
65 {
66 renderer->left = 0.0;
67 renderer->right = 1.0;
68 }
69
70 static void
gimp_view_renderer_gradient_fg_bg_changed(GimpContext * context,const GimpRGB * color,GimpViewRenderer * renderer)71 gimp_view_renderer_gradient_fg_bg_changed (GimpContext *context,
72 const GimpRGB *color,
73 GimpViewRenderer *renderer)
74 {
75 #if 0
76 g_printerr ("%s: invalidating %s\n", G_STRFUNC,
77 gimp_object_get_name (renderer->viewable));
78 #endif
79
80 gimp_view_renderer_invalidate (renderer);
81 }
82
83 static void
gimp_view_renderer_gradient_set_context(GimpViewRenderer * renderer,GimpContext * context)84 gimp_view_renderer_gradient_set_context (GimpViewRenderer *renderer,
85 GimpContext *context)
86 {
87 GimpViewRendererGradient *rendergrad;
88
89 rendergrad = GIMP_VIEW_RENDERER_GRADIENT (renderer);
90
91 if (renderer->context && rendergrad->has_fg_bg_segments)
92 {
93 g_signal_handlers_disconnect_by_func (renderer->context,
94 gimp_view_renderer_gradient_fg_bg_changed,
95 renderer);
96 }
97
98 GIMP_VIEW_RENDERER_CLASS (parent_class)->set_context (renderer, context);
99
100 if (renderer->context && rendergrad->has_fg_bg_segments)
101 {
102 g_signal_connect (renderer->context, "foreground-changed",
103 G_CALLBACK (gimp_view_renderer_gradient_fg_bg_changed),
104 renderer);
105 g_signal_connect (renderer->context, "background-changed",
106 G_CALLBACK (gimp_view_renderer_gradient_fg_bg_changed),
107 renderer);
108
109 gimp_view_renderer_gradient_fg_bg_changed (renderer->context,
110 NULL,
111 renderer);
112 }
113 }
114
115 static void
gimp_view_renderer_gradient_invalidate(GimpViewRenderer * renderer)116 gimp_view_renderer_gradient_invalidate (GimpViewRenderer *renderer)
117 {
118 GimpViewRendererGradient *rendergrad;
119 gboolean has_fg_bg_segments = FALSE;
120
121 rendergrad = GIMP_VIEW_RENDERER_GRADIENT (renderer);
122
123 if (renderer->viewable)
124 has_fg_bg_segments =
125 gimp_gradient_has_fg_bg_segments (GIMP_GRADIENT (renderer->viewable));
126
127 if (rendergrad->has_fg_bg_segments != has_fg_bg_segments)
128 {
129 if (renderer->context)
130 {
131 if (rendergrad->has_fg_bg_segments)
132 {
133 g_signal_handlers_disconnect_by_func (renderer->context,
134 gimp_view_renderer_gradient_fg_bg_changed,
135 renderer);
136 }
137 else
138 {
139 g_signal_connect (renderer->context, "foreground-changed",
140 G_CALLBACK (gimp_view_renderer_gradient_fg_bg_changed),
141 renderer);
142 g_signal_connect (renderer->context, "background-changed",
143 G_CALLBACK (gimp_view_renderer_gradient_fg_bg_changed),
144 renderer);
145 }
146 }
147
148 rendergrad->has_fg_bg_segments = has_fg_bg_segments;
149 }
150
151 GIMP_VIEW_RENDERER_CLASS (parent_class)->invalidate (renderer);
152 }
153
154 static void
gimp_view_renderer_gradient_render(GimpViewRenderer * renderer,GtkWidget * widget)155 gimp_view_renderer_gradient_render (GimpViewRenderer *renderer,
156 GtkWidget *widget)
157 {
158 GimpViewRendererGradient *rendergrad = GIMP_VIEW_RENDERER_GRADIENT (renderer);
159 GimpGradient *gradient = GIMP_GRADIENT (renderer->viewable);
160 GimpGradientSegment *seg = NULL;
161 GimpColorTransform *transform;
162 guchar *buf;
163 guchar *dest;
164 gint dest_stride;
165 gint x;
166 gint y;
167 gdouble dx, cur_x;
168 GimpRGB color;
169
170 buf = g_alloca (4 * renderer->width);
171 dx = (rendergrad->right - rendergrad->left) / (renderer->width - 1);
172 cur_x = rendergrad->left;
173
174 for (x = 0, dest = buf; x < renderer->width; x++, dest += 4)
175 {
176 guchar r, g, b, a;
177
178 seg = gimp_gradient_get_color_at (gradient, renderer->context, seg,
179 cur_x,
180 rendergrad->reverse,
181 rendergrad->blend_color_space,
182 &color);
183 cur_x += dx;
184
185 gimp_rgba_get_uchar (&color, &r, &g, &b, &a);
186
187 GIMP_CAIRO_ARGB32_SET_PIXEL (dest, r, g, b, a);
188 }
189
190 if (! renderer->surface)
191 renderer->surface = cairo_image_surface_create (CAIRO_FORMAT_ARGB32,
192 renderer->width,
193 renderer->height);
194
195 cairo_surface_flush (renderer->surface);
196
197 dest = cairo_image_surface_get_data (renderer->surface);
198 dest_stride = cairo_image_surface_get_stride (renderer->surface);
199
200 transform = gimp_view_renderer_get_color_transform (renderer, widget,
201 babl_format ("cairo-ARGB32"),
202 babl_format ("cairo-ARGB32"));
203
204 if (transform)
205 gimp_color_transform_process_pixels (transform,
206 babl_format ("cairo-ARGB32"), buf,
207 babl_format ("cairo-ARGB32"), buf,
208 renderer->width);
209
210 for (y = 0; y < renderer->height; y++, dest += dest_stride)
211 {
212 memcpy (dest, buf, renderer->width * 4);
213 }
214
215 cairo_surface_mark_dirty (renderer->surface);
216 }
217
218 void
gimp_view_renderer_gradient_set_offsets(GimpViewRendererGradient * renderer,gdouble left,gdouble right)219 gimp_view_renderer_gradient_set_offsets (GimpViewRendererGradient *renderer,
220 gdouble left,
221 gdouble right)
222 {
223 g_return_if_fail (GIMP_IS_VIEW_RENDERER_GRADIENT (renderer));
224
225 left = CLAMP (left, 0.0, 1.0);
226 right = CLAMP (right, left, 1.0);
227
228 if (left != renderer->left || right != renderer->right)
229 {
230 renderer->left = left;
231 renderer->right = right;
232
233 gimp_view_renderer_invalidate (GIMP_VIEW_RENDERER (renderer));
234 }
235 }
236
237 void
gimp_view_renderer_gradient_set_reverse(GimpViewRendererGradient * renderer,gboolean reverse)238 gimp_view_renderer_gradient_set_reverse (GimpViewRendererGradient *renderer,
239 gboolean reverse)
240 {
241 g_return_if_fail (GIMP_IS_VIEW_RENDERER_GRADIENT (renderer));
242
243 if (reverse != renderer->reverse)
244 {
245 renderer->reverse = reverse ? TRUE : FALSE;
246
247 gimp_view_renderer_invalidate (GIMP_VIEW_RENDERER (renderer));
248 gimp_view_renderer_update (GIMP_VIEW_RENDERER (renderer));
249 }
250 }
251
252 void
gimp_view_renderer_gradient_set_blend_color_space(GimpViewRendererGradient * renderer,GimpGradientBlendColorSpace blend_color_space)253 gimp_view_renderer_gradient_set_blend_color_space (GimpViewRendererGradient *renderer,
254 GimpGradientBlendColorSpace blend_color_space)
255 {
256 g_return_if_fail (GIMP_IS_VIEW_RENDERER_GRADIENT (renderer));
257
258 if (blend_color_space != renderer->blend_color_space)
259 {
260 renderer->blend_color_space = blend_color_space;
261
262 gimp_view_renderer_invalidate (GIMP_VIEW_RENDERER (renderer));
263 gimp_view_renderer_update (GIMP_VIEW_RENDERER (renderer));
264 }
265 }
266