1 /* GIMP - The GNU Image Manipulation Program
2 * Copyright (C) 1995-1999 Spencer Kimball and Peter Mattis
3 *
4 * This program is free software: you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License as published by
6 * the Free Software Foundation; either version 3 of the License, or
7 * (at your option) any later version.
8 *
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
13 *
14 * You should have received a copy of the GNU General Public License
15 * along with this program. If not, see <https://www.gnu.org/licenses/>.
16 */
17
18 #include "config.h"
19
20 #include <gdk-pixbuf/gdk-pixbuf.h>
21 #include <gegl.h>
22
23 #include "libgimpmath/gimpmath.h"
24 #include "libgimpconfig/gimpconfig.h"
25
26 #include "core-types.h"
27
28 #include "gimpcurve.h"
29 #include "gimpdynamics.h"
30 #include "gimpdynamics-load.h"
31 #include "gimpdynamics-save.h"
32 #include "gimpdynamicsoutput.h"
33
34 #include "gimp-intl.h"
35
36
37 #define DEFAULT_NAME "Nameless dynamics"
38
39 enum
40 {
41 PROP_0,
42
43 PROP_NAME,
44
45 PROP_OPACITY_OUTPUT,
46 PROP_SIZE_OUTPUT,
47 PROP_ANGLE_OUTPUT,
48 PROP_COLOR_OUTPUT,
49 PROP_FORCE_OUTPUT,
50 PROP_HARDNESS_OUTPUT,
51 PROP_ASPECT_RATIO_OUTPUT,
52 PROP_SPACING_OUTPUT,
53 PROP_RATE_OUTPUT,
54 PROP_FLOW_OUTPUT,
55 PROP_JITTER_OUTPUT
56 };
57
58
59 typedef struct _GimpDynamicsPrivate GimpDynamicsPrivate;
60
61 struct _GimpDynamicsPrivate
62 {
63 GimpDynamicsOutput *opacity_output;
64 GimpDynamicsOutput *hardness_output;
65 GimpDynamicsOutput *force_output;
66 GimpDynamicsOutput *rate_output;
67 GimpDynamicsOutput *flow_output;
68 GimpDynamicsOutput *size_output;
69 GimpDynamicsOutput *aspect_ratio_output;
70 GimpDynamicsOutput *color_output;
71 GimpDynamicsOutput *angle_output;
72 GimpDynamicsOutput *jitter_output;
73 GimpDynamicsOutput *spacing_output;
74 };
75
76 #define GET_PRIVATE(output) \
77 ((GimpDynamicsPrivate *) gimp_dynamics_get_instance_private ((GimpDynamics *) (output)))
78
79
80 static void gimp_dynamics_finalize (GObject *object);
81 static void gimp_dynamics_set_property (GObject *object,
82 guint property_id,
83 const GValue *value,
84 GParamSpec *pspec);
85 static void gimp_dynamics_get_property (GObject *object,
86 guint property_id,
87 GValue *value,
88 GParamSpec *pspec);
89 static void
90 gimp_dynamics_dispatch_properties_changed (GObject *object,
91 guint n_pspecs,
92 GParamSpec **pspecs);
93
94 static const gchar * gimp_dynamics_get_extension (GimpData *data);
95 static void gimp_dynamics_copy (GimpData *data,
96 GimpData *src_data);
97
98 static GimpDynamicsOutput *
99 gimp_dynamics_create_output (GimpDynamics *dynamics,
100 const gchar *name,
101 GimpDynamicsOutputType type);
102 static void gimp_dynamics_output_notify (GObject *output,
103 const GParamSpec *pspec,
104 GimpDynamics *dynamics);
105
106
G_DEFINE_TYPE_WITH_PRIVATE(GimpDynamics,gimp_dynamics,GIMP_TYPE_DATA)107 G_DEFINE_TYPE_WITH_PRIVATE (GimpDynamics, gimp_dynamics, GIMP_TYPE_DATA)
108
109 #define parent_class gimp_dynamics_parent_class
110
111
112 static void
113 gimp_dynamics_class_init (GimpDynamicsClass *klass)
114 {
115 GObjectClass *object_class = G_OBJECT_CLASS (klass);
116 GimpDataClass *data_class = GIMP_DATA_CLASS (klass);
117 GimpViewableClass *viewable_class = GIMP_VIEWABLE_CLASS (klass);
118
119 object_class->finalize = gimp_dynamics_finalize;
120 object_class->set_property = gimp_dynamics_set_property;
121 object_class->get_property = gimp_dynamics_get_property;
122 object_class->dispatch_properties_changed = gimp_dynamics_dispatch_properties_changed;
123
124 viewable_class->default_icon_name = "gimp-dynamics";
125
126 data_class->save = gimp_dynamics_save;
127 data_class->get_extension = gimp_dynamics_get_extension;
128 data_class->copy = gimp_dynamics_copy;
129
130 GIMP_CONFIG_PROP_STRING (object_class, PROP_NAME,
131 "name",
132 NULL, NULL,
133 DEFAULT_NAME,
134 GIMP_PARAM_STATIC_STRINGS);
135
136 GIMP_CONFIG_PROP_OBJECT (object_class, PROP_OPACITY_OUTPUT,
137 "opacity-output",
138 NULL, NULL,
139 GIMP_TYPE_DYNAMICS_OUTPUT,
140 GIMP_CONFIG_PARAM_AGGREGATE);
141
142 GIMP_CONFIG_PROP_OBJECT (object_class, PROP_FORCE_OUTPUT,
143 "force-output",
144 NULL, NULL,
145 GIMP_TYPE_DYNAMICS_OUTPUT,
146 GIMP_CONFIG_PARAM_AGGREGATE);
147
148 GIMP_CONFIG_PROP_OBJECT (object_class, PROP_HARDNESS_OUTPUT,
149 "hardness-output",
150 NULL, NULL,
151 GIMP_TYPE_DYNAMICS_OUTPUT,
152 GIMP_CONFIG_PARAM_AGGREGATE);
153
154 GIMP_CONFIG_PROP_OBJECT (object_class, PROP_RATE_OUTPUT,
155 "rate-output",
156 NULL, NULL,
157 GIMP_TYPE_DYNAMICS_OUTPUT,
158 GIMP_CONFIG_PARAM_AGGREGATE);
159
160 GIMP_CONFIG_PROP_OBJECT (object_class, PROP_FLOW_OUTPUT,
161 "flow-output",
162 NULL, NULL,
163 GIMP_TYPE_DYNAMICS_OUTPUT,
164 GIMP_CONFIG_PARAM_AGGREGATE);
165
166 GIMP_CONFIG_PROP_OBJECT (object_class, PROP_SIZE_OUTPUT,
167 "size-output",
168 NULL, NULL,
169 GIMP_TYPE_DYNAMICS_OUTPUT,
170 GIMP_CONFIG_PARAM_AGGREGATE);
171
172 GIMP_CONFIG_PROP_OBJECT (object_class, PROP_ASPECT_RATIO_OUTPUT,
173 "aspect-ratio-output",
174 NULL, NULL,
175 GIMP_TYPE_DYNAMICS_OUTPUT,
176 GIMP_CONFIG_PARAM_AGGREGATE);
177
178 GIMP_CONFIG_PROP_OBJECT (object_class, PROP_COLOR_OUTPUT,
179 "color-output",
180 NULL, NULL,
181 GIMP_TYPE_DYNAMICS_OUTPUT,
182 GIMP_CONFIG_PARAM_AGGREGATE);
183
184 GIMP_CONFIG_PROP_OBJECT (object_class, PROP_ANGLE_OUTPUT,
185 "angle-output",
186 NULL, NULL,
187 GIMP_TYPE_DYNAMICS_OUTPUT,
188 GIMP_CONFIG_PARAM_AGGREGATE);
189
190 GIMP_CONFIG_PROP_OBJECT (object_class, PROP_JITTER_OUTPUT,
191 "jitter-output",
192 NULL, NULL,
193 GIMP_TYPE_DYNAMICS_OUTPUT,
194 GIMP_CONFIG_PARAM_AGGREGATE);
195
196 GIMP_CONFIG_PROP_OBJECT (object_class, PROP_SPACING_OUTPUT,
197 "spacing-output",
198 NULL, NULL,
199 GIMP_TYPE_DYNAMICS_OUTPUT,
200 GIMP_CONFIG_PARAM_AGGREGATE);
201 }
202
203 static void
gimp_dynamics_init(GimpDynamics * dynamics)204 gimp_dynamics_init (GimpDynamics *dynamics)
205 {
206 GimpDynamicsPrivate *private = GET_PRIVATE (dynamics);
207
208 private->opacity_output =
209 gimp_dynamics_create_output (dynamics,
210 "opacity-output",
211 GIMP_DYNAMICS_OUTPUT_OPACITY);
212
213 private->force_output =
214 gimp_dynamics_create_output (dynamics,
215 "force-output",
216 GIMP_DYNAMICS_OUTPUT_FORCE);
217
218 private->hardness_output =
219 gimp_dynamics_create_output (dynamics,
220 "hardness-output",
221 GIMP_DYNAMICS_OUTPUT_HARDNESS);
222
223 private->rate_output =
224 gimp_dynamics_create_output (dynamics,
225 "rate-output",
226 GIMP_DYNAMICS_OUTPUT_RATE);
227
228 private->flow_output =
229 gimp_dynamics_create_output (dynamics,
230 "flow-output",
231 GIMP_DYNAMICS_OUTPUT_FLOW);
232
233 private->size_output =
234 gimp_dynamics_create_output (dynamics,
235 "size-output",
236 GIMP_DYNAMICS_OUTPUT_SIZE);
237
238 private->aspect_ratio_output =
239 gimp_dynamics_create_output (dynamics,
240 "aspect-ratio-output",
241 GIMP_DYNAMICS_OUTPUT_ASPECT_RATIO);
242
243 private->color_output =
244 gimp_dynamics_create_output (dynamics,
245 "color-output",
246 GIMP_DYNAMICS_OUTPUT_COLOR);
247
248 private->angle_output =
249 gimp_dynamics_create_output (dynamics,
250 "angle-output",
251 GIMP_DYNAMICS_OUTPUT_ANGLE);
252
253 private->jitter_output =
254 gimp_dynamics_create_output (dynamics,
255 "jitter-output",
256 GIMP_DYNAMICS_OUTPUT_JITTER);
257
258 private->spacing_output =
259 gimp_dynamics_create_output (dynamics,
260 "spacing-output",
261 GIMP_DYNAMICS_OUTPUT_SPACING);
262 }
263
264 static void
gimp_dynamics_finalize(GObject * object)265 gimp_dynamics_finalize (GObject *object)
266 {
267 GimpDynamicsPrivate *private = GET_PRIVATE (object);
268
269 g_clear_object (&private->opacity_output);
270 g_clear_object (&private->force_output);
271 g_clear_object (&private->hardness_output);
272 g_clear_object (&private->rate_output);
273 g_clear_object (&private->flow_output);
274 g_clear_object (&private->size_output);
275 g_clear_object (&private->aspect_ratio_output);
276 g_clear_object (&private->color_output);
277 g_clear_object (&private->angle_output);
278 g_clear_object (&private->jitter_output);
279 g_clear_object (&private->spacing_output);
280
281 G_OBJECT_CLASS (parent_class)->finalize (object);
282 }
283
284 static void
gimp_dynamics_set_property(GObject * object,guint property_id,const GValue * value,GParamSpec * pspec)285 gimp_dynamics_set_property (GObject *object,
286 guint property_id,
287 const GValue *value,
288 GParamSpec *pspec)
289 {
290 GimpDynamicsPrivate *private = GET_PRIVATE (object);
291 GimpDynamicsOutput *src_output = NULL;
292 GimpDynamicsOutput *dest_output = NULL;
293
294 switch (property_id)
295 {
296 case PROP_NAME:
297 gimp_object_set_name (GIMP_OBJECT (object), g_value_get_string (value));
298 break;
299
300 case PROP_OPACITY_OUTPUT:
301 src_output = g_value_get_object (value);
302 dest_output = private->opacity_output;
303 break;
304
305 case PROP_FORCE_OUTPUT:
306 src_output = g_value_get_object (value);
307 dest_output = private->force_output;
308 break;
309
310 case PROP_HARDNESS_OUTPUT:
311 src_output = g_value_get_object (value);
312 dest_output = private->hardness_output;
313 break;
314
315 case PROP_RATE_OUTPUT:
316 src_output = g_value_get_object (value);
317 dest_output = private->rate_output;
318 break;
319
320 case PROP_FLOW_OUTPUT:
321 src_output = g_value_get_object (value);
322 dest_output = private->flow_output;
323 break;
324
325 case PROP_SIZE_OUTPUT:
326 src_output = g_value_get_object (value);
327 dest_output = private->size_output;
328 break;
329
330 case PROP_ASPECT_RATIO_OUTPUT:
331 src_output = g_value_get_object (value);
332 dest_output = private->aspect_ratio_output;
333 break;
334
335 case PROP_COLOR_OUTPUT:
336 src_output = g_value_get_object (value);
337 dest_output = private->color_output;
338 break;
339
340 case PROP_ANGLE_OUTPUT:
341 src_output = g_value_get_object (value);
342 dest_output = private->angle_output;
343 break;
344
345 case PROP_JITTER_OUTPUT:
346 src_output = g_value_get_object (value);
347 dest_output = private->jitter_output;
348 break;
349
350 case PROP_SPACING_OUTPUT:
351 src_output = g_value_get_object (value);
352 dest_output = private->spacing_output;
353 break;
354
355 default:
356 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
357 break;
358 }
359
360 if (src_output && dest_output)
361 {
362 gimp_config_copy (GIMP_CONFIG (src_output),
363 GIMP_CONFIG (dest_output),
364 GIMP_CONFIG_PARAM_SERIALIZE);
365 }
366 }
367
368 static void
gimp_dynamics_get_property(GObject * object,guint property_id,GValue * value,GParamSpec * pspec)369 gimp_dynamics_get_property (GObject *object,
370 guint property_id,
371 GValue *value,
372 GParamSpec *pspec)
373 {
374 GimpDynamicsPrivate *private = GET_PRIVATE (object);
375
376 switch (property_id)
377 {
378 case PROP_NAME:
379 g_value_set_string (value, gimp_object_get_name (object));
380 break;
381
382 case PROP_OPACITY_OUTPUT:
383 g_value_set_object (value, private->opacity_output);
384 break;
385
386 case PROP_FORCE_OUTPUT:
387 g_value_set_object (value, private->force_output);
388 break;
389
390 case PROP_HARDNESS_OUTPUT:
391 g_value_set_object (value, private->hardness_output);
392 break;
393
394 case PROP_RATE_OUTPUT:
395 g_value_set_object (value, private->rate_output);
396 break;
397
398 case PROP_FLOW_OUTPUT:
399 g_value_set_object (value, private->flow_output);
400 break;
401
402 case PROP_SIZE_OUTPUT:
403 g_value_set_object (value, private->size_output);
404 break;
405
406 case PROP_ASPECT_RATIO_OUTPUT:
407 g_value_set_object (value, private->aspect_ratio_output);
408 break;
409
410 case PROP_COLOR_OUTPUT:
411 g_value_set_object (value, private->color_output);
412 break;
413
414 case PROP_ANGLE_OUTPUT:
415 g_value_set_object (value, private->angle_output);
416 break;
417
418 case PROP_JITTER_OUTPUT:
419 g_value_set_object (value, private->jitter_output);
420 break;
421
422 case PROP_SPACING_OUTPUT:
423 g_value_set_object (value, private->spacing_output);
424 break;
425
426 default:
427 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
428 break;
429 }
430 }
431
432 static void
gimp_dynamics_dispatch_properties_changed(GObject * object,guint n_pspecs,GParamSpec ** pspecs)433 gimp_dynamics_dispatch_properties_changed (GObject *object,
434 guint n_pspecs,
435 GParamSpec **pspecs)
436 {
437 gint i;
438
439 G_OBJECT_CLASS (parent_class)->dispatch_properties_changed (object,
440 n_pspecs, pspecs);
441
442 for (i = 0; i < n_pspecs; i++)
443 {
444 if (pspecs[i]->flags & GIMP_CONFIG_PARAM_SERIALIZE)
445 {
446 gimp_data_dirty (GIMP_DATA (object));
447 break;
448 }
449 }
450 }
451
452 static const gchar *
gimp_dynamics_get_extension(GimpData * data)453 gimp_dynamics_get_extension (GimpData *data)
454 {
455 return GIMP_DYNAMICS_FILE_EXTENSION;
456 }
457
458 static void
gimp_dynamics_copy(GimpData * data,GimpData * src_data)459 gimp_dynamics_copy (GimpData *data,
460 GimpData *src_data)
461 {
462 gimp_data_freeze (data);
463
464 gimp_config_copy (GIMP_CONFIG (src_data),
465 GIMP_CONFIG (data), 0);
466
467 gimp_data_thaw (data);
468 }
469
470
471 /* public functions */
472
473 GimpData *
gimp_dynamics_new(GimpContext * context,const gchar * name)474 gimp_dynamics_new (GimpContext *context,
475 const gchar *name)
476 {
477 g_return_val_if_fail (name != NULL, NULL);
478 g_return_val_if_fail (name[0] != '\0', NULL);
479
480 return g_object_new (GIMP_TYPE_DYNAMICS,
481 "name", name,
482 NULL);
483 }
484
485 GimpData *
gimp_dynamics_get_standard(GimpContext * context)486 gimp_dynamics_get_standard (GimpContext *context)
487 {
488 static GimpData *standard_dynamics = NULL;
489
490 if (! standard_dynamics)
491 {
492 standard_dynamics = gimp_dynamics_new (context, "Standard dynamics");
493
494 gimp_data_clean (standard_dynamics);
495 gimp_data_make_internal (standard_dynamics, "gimp-dynamics-standard");
496
497 g_object_add_weak_pointer (G_OBJECT (standard_dynamics),
498 (gpointer *) &standard_dynamics);
499 }
500
501 return standard_dynamics;
502 }
503
504 GimpDynamicsOutput *
gimp_dynamics_get_output(GimpDynamics * dynamics,GimpDynamicsOutputType type_id)505 gimp_dynamics_get_output (GimpDynamics *dynamics,
506 GimpDynamicsOutputType type_id)
507 {
508 GimpDynamicsPrivate *private;
509
510 g_return_val_if_fail (GIMP_IS_DYNAMICS (dynamics), NULL);
511
512 private = GET_PRIVATE (dynamics);
513
514 switch (type_id)
515 {
516 case GIMP_DYNAMICS_OUTPUT_OPACITY:
517 return private->opacity_output;
518 break;
519
520 case GIMP_DYNAMICS_OUTPUT_FORCE:
521 return private->force_output;
522 break;
523
524 case GIMP_DYNAMICS_OUTPUT_HARDNESS:
525 return private->hardness_output;
526 break;
527
528 case GIMP_DYNAMICS_OUTPUT_RATE:
529 return private->rate_output;
530 break;
531
532 case GIMP_DYNAMICS_OUTPUT_FLOW:
533 return private->flow_output;
534 break;
535
536 case GIMP_DYNAMICS_OUTPUT_SIZE:
537 return private->size_output;
538 break;
539
540 case GIMP_DYNAMICS_OUTPUT_ASPECT_RATIO:
541 return private->aspect_ratio_output;
542 break;
543
544 case GIMP_DYNAMICS_OUTPUT_COLOR:
545 return private->color_output;
546 break;
547
548 case GIMP_DYNAMICS_OUTPUT_ANGLE:
549 return private->angle_output;
550 break;
551
552 case GIMP_DYNAMICS_OUTPUT_JITTER:
553 return private->jitter_output;
554 break;
555
556 case GIMP_DYNAMICS_OUTPUT_SPACING:
557 return private->spacing_output;
558 break;
559
560 default:
561 g_return_val_if_reached (NULL);
562 break;
563 }
564 }
565
566 gboolean
gimp_dynamics_is_output_enabled(GimpDynamics * dynamics,GimpDynamicsOutputType type)567 gimp_dynamics_is_output_enabled (GimpDynamics *dynamics,
568 GimpDynamicsOutputType type)
569 {
570 GimpDynamicsOutput *output;
571
572 g_return_val_if_fail (GIMP_IS_DYNAMICS (dynamics), FALSE);
573
574 output = gimp_dynamics_get_output (dynamics, type);
575
576 return gimp_dynamics_output_is_enabled (output);
577 }
578
579 gdouble
gimp_dynamics_get_linear_value(GimpDynamics * dynamics,GimpDynamicsOutputType type,const GimpCoords * coords,GimpPaintOptions * options,gdouble fade_point)580 gimp_dynamics_get_linear_value (GimpDynamics *dynamics,
581 GimpDynamicsOutputType type,
582 const GimpCoords *coords,
583 GimpPaintOptions *options,
584 gdouble fade_point)
585 {
586 GimpDynamicsOutput *output;
587
588 g_return_val_if_fail (GIMP_IS_DYNAMICS (dynamics), 0.0);
589
590 output = gimp_dynamics_get_output (dynamics, type);
591
592 return gimp_dynamics_output_get_linear_value (output, coords,
593 options, fade_point);
594 }
595
596 gdouble
gimp_dynamics_get_angular_value(GimpDynamics * dynamics,GimpDynamicsOutputType type,const GimpCoords * coords,GimpPaintOptions * options,gdouble fade_point)597 gimp_dynamics_get_angular_value (GimpDynamics *dynamics,
598 GimpDynamicsOutputType type,
599 const GimpCoords *coords,
600 GimpPaintOptions *options,
601 gdouble fade_point)
602 {
603 GimpDynamicsOutput *output;
604
605 g_return_val_if_fail (GIMP_IS_DYNAMICS (dynamics), 0.0);
606
607 output = gimp_dynamics_get_output (dynamics, type);
608
609 return gimp_dynamics_output_get_angular_value (output, coords,
610 options, fade_point);
611 }
612
613 gdouble
gimp_dynamics_get_aspect_value(GimpDynamics * dynamics,GimpDynamicsOutputType type,const GimpCoords * coords,GimpPaintOptions * options,gdouble fade_point)614 gimp_dynamics_get_aspect_value (GimpDynamics *dynamics,
615 GimpDynamicsOutputType type,
616 const GimpCoords *coords,
617 GimpPaintOptions *options,
618 gdouble fade_point)
619 {
620 GimpDynamicsOutput *output;
621
622 g_return_val_if_fail (GIMP_IS_DYNAMICS (dynamics), 0.0);
623
624 output = gimp_dynamics_get_output (dynamics, type);
625
626 return gimp_dynamics_output_get_aspect_value (output, coords,
627 options, fade_point);
628 }
629
630
631 /* private functions */
632
633 static GimpDynamicsOutput *
gimp_dynamics_create_output(GimpDynamics * dynamics,const gchar * name,GimpDynamicsOutputType type)634 gimp_dynamics_create_output (GimpDynamics *dynamics,
635 const gchar *name,
636 GimpDynamicsOutputType type)
637 {
638 GimpDynamicsOutput *output = gimp_dynamics_output_new (name, type);
639
640 g_signal_connect (output, "notify",
641 G_CALLBACK (gimp_dynamics_output_notify),
642 dynamics);
643
644 return output;
645 }
646
647 static void
gimp_dynamics_output_notify(GObject * output,const GParamSpec * pspec,GimpDynamics * dynamics)648 gimp_dynamics_output_notify (GObject *output,
649 const GParamSpec *pspec,
650 GimpDynamics *dynamics)
651 {
652 g_object_notify (G_OBJECT (dynamics), gimp_object_get_name (output));
653 }
654