gimpdynamics.c 19.9 KB
Newer Older
1 2 3 4 5 6 7 8 9 10 11 12 13 14
/* GIMP - The GNU Image Manipulation Program
 * Copyright (C) 1995-1999 Spencer Kimball and Peter Mattis
 *
 * 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
15
 * along with this program.  If not, see <https://www.gnu.org/licenses/>.
16 17 18 19
 */

#include "config.h"

20
#include <gdk-pixbuf/gdk-pixbuf.h>
21 22 23 24 25
#include <gegl.h>

#include "libgimpmath/gimpmath.h"
#include "libgimpconfig/gimpconfig.h"

26
#include "core-types.h"
27

28
#include "gimpcurve.h"
29
#include "gimpdynamics.h"
30
#include "gimpdynamics-load.h"
Alexia Death's avatar
Alexia Death committed
31
#include "gimpdynamics-save.h"
32
#include "gimpdynamicsoutput.h"
33 34 35 36

#include "gimp-intl.h"


37
#define DEFAULT_NAME "Nameless dynamics"
38 39 40 41 42

enum
{
  PROP_0,

43 44
  PROP_NAME,

45 46 47
  PROP_OPACITY_OUTPUT,
  PROP_SIZE_OUTPUT,
  PROP_ANGLE_OUTPUT,
48
  PROP_COLOR_OUTPUT,
49
  PROP_FORCE_OUTPUT,
50 51 52 53
  PROP_HARDNESS_OUTPUT,
  PROP_ASPECT_RATIO_OUTPUT,
  PROP_SPACING_OUTPUT,
  PROP_RATE_OUTPUT,
54
  PROP_FLOW_OUTPUT,
55
  PROP_JITTER_OUTPUT
56 57
};

zhenfeng zhao's avatar
zhenfeng zhao committed
58

59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76
typedef struct _GimpDynamicsPrivate GimpDynamicsPrivate;

struct _GimpDynamicsPrivate
{
  GimpDynamicsOutput *opacity_output;
  GimpDynamicsOutput *hardness_output;
  GimpDynamicsOutput *force_output;
  GimpDynamicsOutput *rate_output;
  GimpDynamicsOutput *flow_output;
  GimpDynamicsOutput *size_output;
  GimpDynamicsOutput *aspect_ratio_output;
  GimpDynamicsOutput *color_output;
  GimpDynamicsOutput *angle_output;
  GimpDynamicsOutput *jitter_output;
  GimpDynamicsOutput *spacing_output;
};

#define GET_PRIVATE(output) \
77
        ((GimpDynamicsPrivate *) gimp_dynamics_get_instance_private ((GimpDynamics *) (output)))
78 79


80 81 82 83 84 85 86 87 88
static void          gimp_dynamics_finalize      (GObject      *object);
static void          gimp_dynamics_set_property  (GObject      *object,
                                                  guint         property_id,
                                                  const GValue *value,
                                                  GParamSpec   *pspec);
static void          gimp_dynamics_get_property  (GObject      *object,
                                                  guint         property_id,
                                                  GValue       *value,
                                                  GParamSpec   *pspec);
89 90 91 92
static void
       gimp_dynamics_dispatch_properties_changed (GObject      *object,
                                                  guint         n_pspecs,
                                                  GParamSpec  **pspecs);
93

94
static const gchar * gimp_dynamics_get_extension (GimpData     *data);
95 96
static void          gimp_dynamics_copy          (GimpData     *data,
                                                  GimpData     *src_data);
97

98
static GimpDynamicsOutput *
99 100 101
                     gimp_dynamics_create_output (GimpDynamics           *dynamics,
                                                  const gchar            *name,
                                                  GimpDynamicsOutputType  type);
102 103 104 105
static void          gimp_dynamics_output_notify (GObject          *output,
                                                  const GParamSpec *pspec,
                                                  GimpDynamics     *dynamics);

106

107
G_DEFINE_TYPE_WITH_PRIVATE (GimpDynamics, gimp_dynamics, GIMP_TYPE_DATA)
zhenfeng zhao's avatar
zhenfeng zhao committed
108

109
#define parent_class gimp_dynamics_parent_class
110 111 112


static void
113
gimp_dynamics_class_init (GimpDynamicsClass *klass)
114
{
115 116 117
  GObjectClass      *object_class   = G_OBJECT_CLASS (klass);
  GimpDataClass     *data_class     = GIMP_DATA_CLASS (klass);
  GimpViewableClass *viewable_class = GIMP_VIEWABLE_CLASS (klass);
118

119 120 121 122
  object_class->finalize                    = gimp_dynamics_finalize;
  object_class->set_property                = gimp_dynamics_set_property;
  object_class->get_property                = gimp_dynamics_get_property;
  object_class->dispatch_properties_changed = gimp_dynamics_dispatch_properties_changed;
123

124
  viewable_class->default_icon_name         = "gimp-dynamics";
125

126 127
  data_class->save                          = gimp_dynamics_save;
  data_class->get_extension                 = gimp_dynamics_get_extension;
128
  data_class->copy                          = gimp_dynamics_copy;
Alexia Death's avatar
Alexia Death committed
129

130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200
  GIMP_CONFIG_PROP_STRING (object_class, PROP_NAME,
                           "name",
                           NULL, NULL,
                           DEFAULT_NAME,
                           GIMP_PARAM_STATIC_STRINGS);

  GIMP_CONFIG_PROP_OBJECT (object_class, PROP_OPACITY_OUTPUT,
                           "opacity-output",
                           NULL, NULL,
                           GIMP_TYPE_DYNAMICS_OUTPUT,
                           GIMP_CONFIG_PARAM_AGGREGATE);

  GIMP_CONFIG_PROP_OBJECT (object_class, PROP_FORCE_OUTPUT,
                           "force-output",
                           NULL, NULL,
                           GIMP_TYPE_DYNAMICS_OUTPUT,
                           GIMP_CONFIG_PARAM_AGGREGATE);

  GIMP_CONFIG_PROP_OBJECT (object_class, PROP_HARDNESS_OUTPUT,
                           "hardness-output",
                           NULL, NULL,
                           GIMP_TYPE_DYNAMICS_OUTPUT,
                           GIMP_CONFIG_PARAM_AGGREGATE);

  GIMP_CONFIG_PROP_OBJECT (object_class, PROP_RATE_OUTPUT,
                           "rate-output",
                           NULL, NULL,
                           GIMP_TYPE_DYNAMICS_OUTPUT,
                           GIMP_CONFIG_PARAM_AGGREGATE);

  GIMP_CONFIG_PROP_OBJECT (object_class, PROP_FLOW_OUTPUT,
                           "flow-output",
                           NULL, NULL,
                           GIMP_TYPE_DYNAMICS_OUTPUT,
                           GIMP_CONFIG_PARAM_AGGREGATE);

  GIMP_CONFIG_PROP_OBJECT (object_class, PROP_SIZE_OUTPUT,
                           "size-output",
                           NULL, NULL,
                           GIMP_TYPE_DYNAMICS_OUTPUT,
                           GIMP_CONFIG_PARAM_AGGREGATE);

  GIMP_CONFIG_PROP_OBJECT (object_class, PROP_ASPECT_RATIO_OUTPUT,
                           "aspect-ratio-output",
                           NULL, NULL,
                           GIMP_TYPE_DYNAMICS_OUTPUT,
                           GIMP_CONFIG_PARAM_AGGREGATE);

  GIMP_CONFIG_PROP_OBJECT (object_class, PROP_COLOR_OUTPUT,
                           "color-output",
                           NULL, NULL,
                           GIMP_TYPE_DYNAMICS_OUTPUT,
                           GIMP_CONFIG_PARAM_AGGREGATE);

  GIMP_CONFIG_PROP_OBJECT (object_class, PROP_ANGLE_OUTPUT,
                           "angle-output",
                           NULL, NULL,
                           GIMP_TYPE_DYNAMICS_OUTPUT,
                           GIMP_CONFIG_PARAM_AGGREGATE);

  GIMP_CONFIG_PROP_OBJECT (object_class, PROP_JITTER_OUTPUT,
                           "jitter-output",
                           NULL, NULL,
                           GIMP_TYPE_DYNAMICS_OUTPUT,
                           GIMP_CONFIG_PARAM_AGGREGATE);

  GIMP_CONFIG_PROP_OBJECT (object_class, PROP_SPACING_OUTPUT,
                           "spacing-output",
                           NULL, NULL,
                           GIMP_TYPE_DYNAMICS_OUTPUT,
                           GIMP_CONFIG_PARAM_AGGREGATE);
201 202 203
}

static void
204
gimp_dynamics_init (GimpDynamics *dynamics)
205
{
206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230
  GimpDynamicsPrivate *private = GET_PRIVATE (dynamics);

  private->opacity_output =
    gimp_dynamics_create_output (dynamics,
                                 "opacity-output",
                                 GIMP_DYNAMICS_OUTPUT_OPACITY);

  private->force_output =
    gimp_dynamics_create_output (dynamics,
                                 "force-output",
                                 GIMP_DYNAMICS_OUTPUT_FORCE);

  private->hardness_output =
    gimp_dynamics_create_output (dynamics,
                                 "hardness-output",
                                 GIMP_DYNAMICS_OUTPUT_HARDNESS);

  private->rate_output =
    gimp_dynamics_create_output (dynamics,
                                 "rate-output",
                                 GIMP_DYNAMICS_OUTPUT_RATE);

  private->flow_output =
    gimp_dynamics_create_output (dynamics,
                                 "flow-output",
231
                                 GIMP_DYNAMICS_OUTPUT_FLOW);
232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261

  private->size_output =
    gimp_dynamics_create_output (dynamics,
                                 "size-output",
                                 GIMP_DYNAMICS_OUTPUT_SIZE);

  private->aspect_ratio_output =
    gimp_dynamics_create_output (dynamics,
                                 "aspect-ratio-output",
                                 GIMP_DYNAMICS_OUTPUT_ASPECT_RATIO);

  private->color_output =
    gimp_dynamics_create_output (dynamics,
                                 "color-output",
                                 GIMP_DYNAMICS_OUTPUT_COLOR);

  private->angle_output =
    gimp_dynamics_create_output (dynamics,
                                 "angle-output",
                                 GIMP_DYNAMICS_OUTPUT_ANGLE);

  private->jitter_output =
    gimp_dynamics_create_output (dynamics,
                                 "jitter-output",
                                 GIMP_DYNAMICS_OUTPUT_JITTER);

  private->spacing_output =
    gimp_dynamics_create_output (dynamics,
                                 "spacing-output",
                                 GIMP_DYNAMICS_OUTPUT_SPACING);
262 263 264
}

static void
265
gimp_dynamics_finalize (GObject *object)
266
{
267 268
  GimpDynamicsPrivate *private = GET_PRIVATE (object);

269 270 271 272 273 274 275 276 277 278 279
  g_clear_object (&private->opacity_output);
  g_clear_object (&private->force_output);
  g_clear_object (&private->hardness_output);
  g_clear_object (&private->rate_output);
  g_clear_object (&private->flow_output);
  g_clear_object (&private->size_output);
  g_clear_object (&private->aspect_ratio_output);
  g_clear_object (&private->color_output);
  g_clear_object (&private->angle_output);
  g_clear_object (&private->jitter_output);
  g_clear_object (&private->spacing_output);
Alexia Death's avatar
Alexia Death committed
280

281 282 283 284
  G_OBJECT_CLASS (parent_class)->finalize (object);
}

static void
285
gimp_dynamics_set_property (GObject      *object,
286
                            guint         property_id,
287 288
                            const GValue *value,
                            GParamSpec   *pspec)
289
{
290 291 292
  GimpDynamicsPrivate *private     = GET_PRIVATE (object);
  GimpDynamicsOutput  *src_output  = NULL;
  GimpDynamicsOutput  *dest_output = NULL;
293 294 295

  switch (property_id)
    {
296
    case PROP_NAME:
297
      gimp_object_set_name (GIMP_OBJECT (object), g_value_get_string (value));
298 299
      break;

300 301
    case PROP_OPACITY_OUTPUT:
      src_output  = g_value_get_object (value);
302
      dest_output = private->opacity_output;
303 304
      break;

305 306
    case PROP_FORCE_OUTPUT:
      src_output  = g_value_get_object (value);
307
      dest_output = private->force_output;
308 309
      break;

310 311
    case PROP_HARDNESS_OUTPUT:
      src_output  = g_value_get_object (value);
312
      dest_output = private->hardness_output;
313 314
      break;

315 316
    case PROP_RATE_OUTPUT:
      src_output  = g_value_get_object (value);
317
      dest_output = private->rate_output;
318 319
      break;

320 321
    case PROP_FLOW_OUTPUT:
      src_output  = g_value_get_object (value);
322
      dest_output = private->flow_output;
323 324
      break;

325 326
    case PROP_SIZE_OUTPUT:
      src_output  = g_value_get_object (value);
327
      dest_output = private->size_output;
328 329
      break;

330 331
    case PROP_ASPECT_RATIO_OUTPUT:
      src_output  = g_value_get_object (value);
332
      dest_output = private->aspect_ratio_output;
333 334
      break;

335 336
    case PROP_COLOR_OUTPUT:
      src_output  = g_value_get_object (value);
337
      dest_output = private->color_output;
Alexia Death's avatar
Alexia Death committed
338
      break;
339

340 341
    case PROP_ANGLE_OUTPUT:
      src_output  = g_value_get_object (value);
342
      dest_output = private->angle_output;
343 344
      break;

345 346
    case PROP_JITTER_OUTPUT:
      src_output  = g_value_get_object (value);
347
      dest_output = private->jitter_output;
348 349
      break;

350 351
    case PROP_SPACING_OUTPUT:
      src_output  = g_value_get_object (value);
352
      dest_output = private->spacing_output;
353 354
      break;

355 356 357 358
    default:
      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
      break;
    }
359 360 361 362 363 364 365

  if (src_output && dest_output)
    {
      gimp_config_copy (GIMP_CONFIG (src_output),
                        GIMP_CONFIG (dest_output),
                        GIMP_CONFIG_PARAM_SERIALIZE);
    }
366 367 368
}

static void
369
gimp_dynamics_get_property (GObject    *object,
370 371 372
                            guint       property_id,
                            GValue     *value,
                            GParamSpec *pspec)
373
{
374
  GimpDynamicsPrivate *private = GET_PRIVATE (object);
375 376 377

  switch (property_id)
    {
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 385
      break;

386
    case PROP_FORCE_OUTPUT:
387
      g_value_set_object (value, private->force_output);
388 389
      break;

390
    case PROP_HARDNESS_OUTPUT:
391
      g_value_set_object (value, private->hardness_output);
Alexia Death's avatar
Alexia Death committed
392 393
      break;

394
    case PROP_RATE_OUTPUT:
395
      g_value_set_object (value, private->rate_output);
396 397
      break;

398
    case PROP_FLOW_OUTPUT:
399
      g_value_set_object (value, private->flow_output);
400 401
      break;

402
    case PROP_SIZE_OUTPUT:
403
      g_value_set_object (value, private->size_output);
404 405
      break;

406
    case PROP_ASPECT_RATIO_OUTPUT:
407
      g_value_set_object (value, private->aspect_ratio_output);
408 409
      break;

410
    case PROP_COLOR_OUTPUT:
411
      g_value_set_object (value, private->color_output);
412 413
      break;

414
    case PROP_ANGLE_OUTPUT:
415
      g_value_set_object (value, private->angle_output);
416 417
      break;

418
    case PROP_JITTER_OUTPUT:
419
      g_value_set_object (value, private->jitter_output);
Alexia Death's avatar
Alexia Death committed
420 421
      break;

422
    case PROP_SPACING_OUTPUT:
423
      g_value_set_object (value, private->spacing_output);
424 425
      break;

426 427 428 429 430 431
    default:
      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
      break;
    }
}

432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451
static void
gimp_dynamics_dispatch_properties_changed (GObject     *object,
                                           guint        n_pspecs,
                                           GParamSpec **pspecs)
{
  gint i;

  G_OBJECT_CLASS (parent_class)->dispatch_properties_changed (object,
                                                              n_pspecs, pspecs);

  for (i = 0; i < n_pspecs; i++)
    {
      if (pspecs[i]->flags & GIMP_CONFIG_PARAM_SERIALIZE)
        {
          gimp_data_dirty (GIMP_DATA (object));
          break;
        }
    }
}

452 453 454 455 456 457
static const gchar *
gimp_dynamics_get_extension (GimpData *data)
{
  return GIMP_DYNAMICS_FILE_EXTENSION;
}

458 459 460
static void
gimp_dynamics_copy (GimpData *data,
                    GimpData *src_data)
461
{
462
  gimp_data_freeze (data);
463

464 465
  gimp_config_copy (GIMP_CONFIG (src_data),
                    GIMP_CONFIG (data), 0);
466

467
  gimp_data_thaw (data);
468 469
}

470 471 472

/*  public functions  */

473
GimpData *
474 475
gimp_dynamics_new (GimpContext *context,
                   const gchar *name)
476
{
477 478 479
  g_return_val_if_fail (name != NULL, NULL);
  g_return_val_if_fail (name[0] != '\0', NULL);

480 481 482
  return g_object_new (GIMP_TYPE_DYNAMICS,
                       "name", name,
                       NULL);
483 484
}

485
GimpData *
486
gimp_dynamics_get_standard (GimpContext *context)
487 488 489 490 491
{
  static GimpData *standard_dynamics = NULL;

  if (! standard_dynamics)
    {
492
      standard_dynamics = gimp_dynamics_new (context, "Standard dynamics");
493

494 495
      gimp_data_clean (standard_dynamics);
      gimp_data_make_internal (standard_dynamics, "gimp-dynamics-standard");
496

497 498
      g_object_add_weak_pointer (G_OBJECT (standard_dynamics),
                                 (gpointer *) &standard_dynamics);
499 500 501 502 503
    }

  return standard_dynamics;
}

504 505 506 507
GimpDynamicsOutput *
gimp_dynamics_get_output (GimpDynamics           *dynamics,
                          GimpDynamicsOutputType  type_id)
{
508 509 510 511 512
  GimpDynamicsPrivate *private;

  g_return_val_if_fail (GIMP_IS_DYNAMICS (dynamics), NULL);

  private = GET_PRIVATE (dynamics);
513 514 515 516

  switch (type_id)
    {
    case GIMP_DYNAMICS_OUTPUT_OPACITY:
517
      return private->opacity_output;
518 519
      break;

520
    case GIMP_DYNAMICS_OUTPUT_FORCE:
521
      return private->force_output;
522 523
      break;

524
    case GIMP_DYNAMICS_OUTPUT_HARDNESS:
525
      return private->hardness_output;
526 527 528
      break;

    case GIMP_DYNAMICS_OUTPUT_RATE:
529
      return private->rate_output;
530 531
      break;

532
    case GIMP_DYNAMICS_OUTPUT_FLOW:
533
      return private->flow_output;
534 535
      break;

536
    case GIMP_DYNAMICS_OUTPUT_SIZE:
537
      return private->size_output;
538 539 540
      break;

    case GIMP_DYNAMICS_OUTPUT_ASPECT_RATIO:
541
      return private->aspect_ratio_output;
542 543 544
      break;

    case GIMP_DYNAMICS_OUTPUT_COLOR:
545
      return private->color_output;
546 547 548
      break;

    case GIMP_DYNAMICS_OUTPUT_ANGLE:
549
      return private->angle_output;
550 551 552
      break;

    case GIMP_DYNAMICS_OUTPUT_JITTER:
553
      return private->jitter_output;
554 555 556
      break;

    case GIMP_DYNAMICS_OUTPUT_SPACING:
557
      return private->spacing_output;
558 559 560
      break;

    default:
561
      g_return_val_if_reached (NULL);
562 563 564 565
      break;
    }
}

566 567 568 569 570 571 572 573 574 575 576 577 578
gboolean
gimp_dynamics_is_output_enabled (GimpDynamics           *dynamics,
                                 GimpDynamicsOutputType  type)
{
  GimpDynamicsOutput *output;

  g_return_val_if_fail (GIMP_IS_DYNAMICS (dynamics), FALSE);

  output = gimp_dynamics_get_output (dynamics, type);

  return gimp_dynamics_output_is_enabled (output);
}

579 580 581 582 583 584 585 586 587 588 589 590 591 592 593 594 595 596 597 598 599 600 601 602 603 604 605 606 607 608 609 610 611 612 613 614 615 616 617 618 619 620 621 622 623 624 625 626 627 628 629
gdouble
gimp_dynamics_get_linear_value (GimpDynamics           *dynamics,
                                GimpDynamicsOutputType  type,
                                const GimpCoords       *coords,
                                GimpPaintOptions       *options,
                                gdouble                 fade_point)
{
  GimpDynamicsOutput *output;

  g_return_val_if_fail (GIMP_IS_DYNAMICS (dynamics), 0.0);

  output = gimp_dynamics_get_output (dynamics, type);

  return gimp_dynamics_output_get_linear_value (output, coords,
                                                options, fade_point);
}

gdouble
gimp_dynamics_get_angular_value (GimpDynamics           *dynamics,
                                 GimpDynamicsOutputType  type,
                                 const GimpCoords       *coords,
                                 GimpPaintOptions       *options,
                                 gdouble                 fade_point)
{
  GimpDynamicsOutput *output;

  g_return_val_if_fail (GIMP_IS_DYNAMICS (dynamics), 0.0);

  output = gimp_dynamics_get_output (dynamics, type);

  return gimp_dynamics_output_get_angular_value (output, coords,
                                                 options, fade_point);
}

gdouble
gimp_dynamics_get_aspect_value (GimpDynamics           *dynamics,
                                GimpDynamicsOutputType  type,
                                const GimpCoords       *coords,
                                GimpPaintOptions       *options,
                                gdouble                 fade_point)
{
  GimpDynamicsOutput *output;

  g_return_val_if_fail (GIMP_IS_DYNAMICS (dynamics), 0.0);

  output = gimp_dynamics_get_output (dynamics, type);

  return gimp_dynamics_output_get_aspect_value (output, coords,
                                                options, fade_point);
}

630 631 632 633

/*  private functions  */

static GimpDynamicsOutput *
634 635 636
gimp_dynamics_create_output (GimpDynamics           *dynamics,
                             const gchar            *name,
                             GimpDynamicsOutputType  type)
637
{
638
  GimpDynamicsOutput *output = gimp_dynamics_output_new (name, type);
639 640 641 642 643 644 645 646 647 648 649 650 651 652 653

  g_signal_connect (output, "notify",
                    G_CALLBACK (gimp_dynamics_output_notify),
                    dynamics);

  return output;
}

static void
gimp_dynamics_output_notify (GObject          *output,
                             const GParamSpec *pspec,
                             GimpDynamics     *dynamics)
{
  g_object_notify (G_OBJECT (dynamics), gimp_object_get_name (output));
}