1 /* The GIMP -- an image manipulation program
2  * Copyright (C) 1995-1999 Spencer Kimball and Peter Mattis
3  *
4  * gimpfilloptions.c
5  * Copyright (C) 2003 Simon Budig
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 <cairo.h>
24 #include <gdk-pixbuf/gdk-pixbuf.h>
25 #include <gegl.h>
26 
27 #include "libgimpcolor/gimpcolor.h"
28 #include "libgimpconfig/gimpconfig.h"
29 
30 #include "core-types.h"
31 
32 #include "operations/layer-modes/gimp-layer-modes.h"
33 
34 #include "gimp.h"
35 #include "gimp-palettes.h"
36 #include "gimpdrawable.h"
37 #include "gimpdrawable-fill.h"
38 #include "gimperror.h"
39 #include "gimpfilloptions.h"
40 #include "gimppattern.h"
41 
42 #include "gimp-intl.h"
43 
44 
45 enum
46 {
47   PROP_0,
48   PROP_STYLE,
49   PROP_ANTIALIAS,
50   PROP_FEATHER,
51   PROP_FEATHER_RADIUS,
52   PROP_PATTERN_VIEW_TYPE,
53   PROP_PATTERN_VIEW_SIZE
54 };
55 
56 
57 typedef struct _GimpFillOptionsPrivate GimpFillOptionsPrivate;
58 
59 struct _GimpFillOptionsPrivate
60 {
61   GimpFillStyle style;
62   gboolean      antialias;
63   gboolean      feather;
64   gdouble       feather_radius;
65 
66   GimpViewType  pattern_view_type;
67   GimpViewSize  pattern_view_size;
68 
69   const gchar  *undo_desc;
70 };
71 
72 #define GET_PRIVATE(options) \
73         ((GimpFillOptionsPrivate *) gimp_fill_options_get_instance_private ((GimpFillOptions *) (options)))
74 
75 
76 static void     gimp_fill_options_config_init  (GimpConfigInterface *iface);
77 
78 static void     gimp_fill_options_set_property (GObject             *object,
79                                                 guint                property_id,
80                                                 const GValue        *value,
81                                                 GParamSpec          *pspec);
82 static void     gimp_fill_options_get_property (GObject             *object,
83                                                 guint                property_id,
84                                                 GValue              *value,
85                                                 GParamSpec          *pspec);
86 
87 static gboolean gimp_fill_options_serialize    (GimpConfig          *config,
88                                                 GimpConfigWriter    *writer,
89                                                 gpointer             data);
90 
91 
G_DEFINE_TYPE_WITH_CODE(GimpFillOptions,gimp_fill_options,GIMP_TYPE_CONTEXT,G_ADD_PRIVATE (GimpFillOptions)G_IMPLEMENT_INTERFACE (GIMP_TYPE_CONFIG,gimp_fill_options_config_init))92 G_DEFINE_TYPE_WITH_CODE (GimpFillOptions, gimp_fill_options, GIMP_TYPE_CONTEXT,
93                          G_ADD_PRIVATE (GimpFillOptions)
94                          G_IMPLEMENT_INTERFACE (GIMP_TYPE_CONFIG,
95                                                 gimp_fill_options_config_init))
96 
97 
98 static void
99 gimp_fill_options_class_init (GimpFillOptionsClass *klass)
100 {
101   GObjectClass *object_class = G_OBJECT_CLASS (klass);
102 
103   object_class->set_property = gimp_fill_options_set_property;
104   object_class->get_property = gimp_fill_options_get_property;
105 
106   GIMP_CONFIG_PROP_ENUM (object_class, PROP_STYLE,
107                          "style",
108                          _("Style"),
109                          NULL,
110                          GIMP_TYPE_FILL_STYLE,
111                          GIMP_FILL_STYLE_SOLID,
112                          GIMP_PARAM_STATIC_STRINGS);
113 
114   GIMP_CONFIG_PROP_BOOLEAN (object_class, PROP_ANTIALIAS,
115                             "antialias",
116                             _("Antialiasing"),
117                             NULL,
118                             TRUE,
119                             GIMP_PARAM_STATIC_STRINGS);
120 
121   GIMP_CONFIG_PROP_BOOLEAN (object_class, PROP_FEATHER,
122                             "feather",
123                             _("Feather edges"),
124                             _("Enable feathering of fill edges"),
125                             FALSE,
126                             GIMP_PARAM_STATIC_STRINGS);
127 
128   GIMP_CONFIG_PROP_DOUBLE (object_class, PROP_FEATHER_RADIUS,
129                            "feather-radius",
130                            _("Radius"),
131                            _("Radius of feathering"),
132                            0.0, 100.0, 10.0,
133                            GIMP_PARAM_STATIC_STRINGS);
134 
135   g_object_class_install_property (object_class, PROP_PATTERN_VIEW_TYPE,
136                                    g_param_spec_enum ("pattern-view-type",
137                                                       NULL, NULL,
138                                                       GIMP_TYPE_VIEW_TYPE,
139                                                       GIMP_VIEW_TYPE_GRID,
140                                                       G_PARAM_CONSTRUCT |
141                                                       GIMP_PARAM_READWRITE));
142 
143   g_object_class_install_property (object_class, PROP_PATTERN_VIEW_SIZE,
144                                    g_param_spec_int ("pattern-view-size",
145                                                      NULL, NULL,
146                                                      GIMP_VIEW_SIZE_TINY,
147                                                      GIMP_VIEWABLE_MAX_BUTTON_SIZE,
148                                                      GIMP_VIEW_SIZE_SMALL,
149                                                      G_PARAM_CONSTRUCT |
150                                                      GIMP_PARAM_READWRITE));
151 }
152 
153 static void
gimp_fill_options_config_init(GimpConfigInterface * iface)154 gimp_fill_options_config_init (GimpConfigInterface *iface)
155 {
156   iface->serialize = gimp_fill_options_serialize;
157 }
158 
159 static void
gimp_fill_options_init(GimpFillOptions * options)160 gimp_fill_options_init (GimpFillOptions *options)
161 {
162 }
163 
164 static void
gimp_fill_options_set_property(GObject * object,guint property_id,const GValue * value,GParamSpec * pspec)165 gimp_fill_options_set_property (GObject      *object,
166                                 guint         property_id,
167                                 const GValue *value,
168                                 GParamSpec   *pspec)
169 {
170   GimpFillOptionsPrivate *private = GET_PRIVATE (object);
171 
172   switch (property_id)
173     {
174     case PROP_STYLE:
175       private->style = g_value_get_enum (value);
176       private->undo_desc = NULL;
177       break;
178     case PROP_ANTIALIAS:
179       private->antialias = g_value_get_boolean (value);
180       break;
181     case PROP_FEATHER:
182       private->feather = g_value_get_boolean (value);
183       break;
184     case PROP_FEATHER_RADIUS:
185       private->feather_radius = g_value_get_double (value);
186       break;
187 
188     case PROP_PATTERN_VIEW_TYPE:
189       private->pattern_view_type = g_value_get_enum (value);
190       break;
191     case PROP_PATTERN_VIEW_SIZE:
192       private->pattern_view_size = g_value_get_int (value);
193       break;
194 
195     default:
196       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
197       break;
198     }
199 }
200 
201 static void
gimp_fill_options_get_property(GObject * object,guint property_id,GValue * value,GParamSpec * pspec)202 gimp_fill_options_get_property (GObject    *object,
203                                 guint       property_id,
204                                 GValue     *value,
205                                 GParamSpec *pspec)
206 {
207   GimpFillOptionsPrivate *private = GET_PRIVATE (object);
208 
209   switch (property_id)
210     {
211     case PROP_STYLE:
212       g_value_set_enum (value, private->style);
213       break;
214     case PROP_ANTIALIAS:
215       g_value_set_boolean (value, private->antialias);
216       break;
217     case PROP_FEATHER:
218       g_value_set_boolean (value, private->feather);
219       break;
220     case PROP_FEATHER_RADIUS:
221       g_value_set_double (value, private->feather_radius);
222       break;
223 
224     case PROP_PATTERN_VIEW_TYPE:
225       g_value_set_enum (value, private->pattern_view_type);
226       break;
227     case PROP_PATTERN_VIEW_SIZE:
228       g_value_set_int (value, private->pattern_view_size);
229       break;
230 
231     default:
232       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
233       break;
234     }
235 }
236 
237 static gboolean
gimp_fill_options_serialize(GimpConfig * config,GimpConfigWriter * writer,gpointer data)238 gimp_fill_options_serialize (GimpConfig       *config,
239                              GimpConfigWriter *writer,
240                              gpointer          data)
241 {
242   return gimp_config_serialize_properties (config, writer);
243 }
244 
245 
246 /*  public functions  */
247 
248 GimpFillOptions *
gimp_fill_options_new(Gimp * gimp,GimpContext * context,gboolean use_context_color)249 gimp_fill_options_new (Gimp        *gimp,
250                        GimpContext *context,
251                        gboolean     use_context_color)
252 {
253   GimpFillOptions *options;
254 
255   g_return_val_if_fail (GIMP_IS_GIMP (gimp), NULL);
256   g_return_val_if_fail (context == NULL || GIMP_IS_CONTEXT (context), NULL);
257   g_return_val_if_fail (use_context_color == FALSE || context != NULL, NULL);
258 
259   options = g_object_new (GIMP_TYPE_FILL_OPTIONS,
260                           "gimp", gimp,
261                           NULL);
262 
263   if (use_context_color)
264     {
265       gimp_context_define_properties (GIMP_CONTEXT (options),
266                                       GIMP_CONTEXT_PROP_MASK_FOREGROUND |
267                                       GIMP_CONTEXT_PROP_MASK_PATTERN,
268                                       FALSE);
269 
270       gimp_context_set_parent (GIMP_CONTEXT (options), context);
271     }
272 
273   return options;
274 }
275 
276 GimpFillStyle
gimp_fill_options_get_style(GimpFillOptions * options)277 gimp_fill_options_get_style (GimpFillOptions *options)
278 {
279   g_return_val_if_fail (GIMP_IS_FILL_OPTIONS (options), GIMP_FILL_STYLE_SOLID);
280 
281   return GET_PRIVATE (options)->style;
282 }
283 
284 void
gimp_fill_options_set_style(GimpFillOptions * options,GimpFillStyle style)285 gimp_fill_options_set_style (GimpFillOptions *options,
286                              GimpFillStyle    style)
287 {
288   g_return_if_fail (GIMP_IS_FILL_OPTIONS (options));
289 
290   g_object_set (options, "style", style, NULL);
291 }
292 
293 gboolean
gimp_fill_options_get_antialias(GimpFillOptions * options)294 gimp_fill_options_get_antialias (GimpFillOptions *options)
295 {
296   g_return_val_if_fail (GIMP_IS_FILL_OPTIONS (options), FALSE);
297 
298   return GET_PRIVATE (options)->antialias;
299 }
300 
301 void
gimp_fill_options_set_antialias(GimpFillOptions * options,gboolean antialias)302 gimp_fill_options_set_antialias (GimpFillOptions *options,
303                                  gboolean         antialias)
304 {
305   g_return_if_fail (GIMP_IS_FILL_OPTIONS (options));
306 
307   g_object_set (options, "antialias", antialias, NULL);
308 }
309 
310 gboolean
gimp_fill_options_get_feather(GimpFillOptions * options,gdouble * radius)311 gimp_fill_options_get_feather (GimpFillOptions *options,
312                                gdouble         *radius)
313 {
314   g_return_val_if_fail (GIMP_IS_FILL_OPTIONS (options), FALSE);
315 
316   if (radius)
317     *radius = GET_PRIVATE (options)->feather_radius;
318 
319   return GET_PRIVATE (options)->feather;
320 }
321 
322 void
gimp_fill_options_set_feather(GimpFillOptions * options,gboolean feather,gdouble radius)323 gimp_fill_options_set_feather (GimpFillOptions *options,
324                                gboolean         feather,
325                                gdouble          radius)
326 {
327   g_return_if_fail (GIMP_IS_FILL_OPTIONS (options));
328 
329   g_object_set (options, "feather", feather, NULL);
330   g_object_set (options, "feather-radius", radius, NULL);
331 }
332 
333 gboolean
gimp_fill_options_set_by_fill_type(GimpFillOptions * options,GimpContext * context,GimpFillType fill_type,GError ** error)334 gimp_fill_options_set_by_fill_type (GimpFillOptions  *options,
335                                     GimpContext      *context,
336                                     GimpFillType      fill_type,
337                                     GError          **error)
338 {
339   GimpFillOptionsPrivate *private;
340   GimpRGB                 color;
341   const gchar            *undo_desc;
342 
343   g_return_val_if_fail (GIMP_IS_FILL_OPTIONS (options), FALSE);
344   g_return_val_if_fail (GIMP_IS_CONTEXT (context), FALSE);
345   g_return_val_if_fail (error == NULL || *error == NULL, FALSE);
346 
347   private = GET_PRIVATE (options);
348 
349   private->undo_desc = NULL;
350 
351   switch (fill_type)
352     {
353     case GIMP_FILL_FOREGROUND:
354       gimp_context_get_foreground (context, &color);
355       undo_desc = C_("undo-type", "Fill with Foreground Color");
356       break;
357 
358     case GIMP_FILL_BACKGROUND:
359       gimp_context_get_background (context, &color);
360       undo_desc = C_("undo-type", "Fill with Background Color");
361       break;
362 
363     case GIMP_FILL_WHITE:
364       gimp_rgba_set (&color, 1.0, 1.0, 1.0, GIMP_OPACITY_OPAQUE);
365       undo_desc = C_("undo-type", "Fill with White");
366       break;
367 
368     case GIMP_FILL_TRANSPARENT:
369       gimp_context_get_background (context, &color);
370       gimp_context_set_paint_mode (GIMP_CONTEXT (options),
371                                    GIMP_LAYER_MODE_ERASE);
372       undo_desc = C_("undo-type", "Fill with Transparency");
373       break;
374 
375     case GIMP_FILL_PATTERN:
376       {
377         GimpPattern *pattern = gimp_context_get_pattern (context);
378 
379         if (! pattern)
380           {
381             g_set_error_literal (error, GIMP_ERROR, GIMP_FAILED,
382                                  _("No patterns available for this operation."));
383             return FALSE;
384           }
385 
386         gimp_fill_options_set_style (options, GIMP_FILL_STYLE_PATTERN);
387         gimp_context_set_pattern (GIMP_CONTEXT (options), pattern);
388         private->undo_desc = C_("undo-type", "Fill with Pattern");
389 
390         return TRUE;
391       }
392       break;
393 
394     default:
395       g_warning ("%s: invalid fill_type %d", G_STRFUNC, fill_type);
396       return FALSE;
397     }
398 
399   gimp_fill_options_set_style (options, GIMP_FILL_STYLE_SOLID);
400   gimp_context_set_foreground (GIMP_CONTEXT (options), &color);
401   private->undo_desc = undo_desc;
402 
403   return TRUE;
404 }
405 
406 gboolean
gimp_fill_options_set_by_fill_mode(GimpFillOptions * options,GimpContext * context,GimpBucketFillMode fill_mode,GError ** error)407 gimp_fill_options_set_by_fill_mode (GimpFillOptions     *options,
408                                     GimpContext         *context,
409                                     GimpBucketFillMode   fill_mode,
410                                     GError             **error)
411 {
412   GimpFillType fill_type;
413 
414   g_return_val_if_fail (GIMP_IS_FILL_OPTIONS (options), FALSE);
415   g_return_val_if_fail (GIMP_IS_CONTEXT (context), FALSE);
416   g_return_val_if_fail (error == NULL || *error == NULL, FALSE);
417 
418   switch (fill_mode)
419     {
420     default:
421     case GIMP_BUCKET_FILL_FG:
422       fill_type = GIMP_FILL_FOREGROUND;
423       break;
424 
425     case GIMP_BUCKET_FILL_BG:
426       fill_type = GIMP_FILL_BACKGROUND;
427       break;
428 
429     case GIMP_BUCKET_FILL_PATTERN:
430       fill_type = GIMP_FILL_PATTERN;
431       break;
432     }
433 
434   return gimp_fill_options_set_by_fill_type (options, context,
435                                              fill_type, error);
436 }
437 
438 const gchar *
gimp_fill_options_get_undo_desc(GimpFillOptions * options)439 gimp_fill_options_get_undo_desc (GimpFillOptions *options)
440 {
441   GimpFillOptionsPrivate *private;
442 
443   g_return_val_if_fail (GIMP_IS_FILL_OPTIONS (options), NULL);
444 
445   private = GET_PRIVATE (options);
446 
447   if (private->undo_desc)
448     return private->undo_desc;
449 
450   switch (private->style)
451     {
452     case GIMP_FILL_STYLE_SOLID:
453       return C_("undo-type", "Fill with Solid Color");
454 
455     case GIMP_FILL_STYLE_PATTERN:
456       return C_("undo-type", "Fill with Pattern");
457     }
458 
459   g_return_val_if_reached (NULL);
460 }
461 
462 const Babl *
gimp_fill_options_get_format(GimpFillOptions * options,GimpDrawable * drawable)463 gimp_fill_options_get_format (GimpFillOptions *options,
464                               GimpDrawable    *drawable)
465 {
466   GimpContext *context;
467 
468   g_return_val_if_fail (GIMP_IS_FILL_OPTIONS (options), NULL);
469   g_return_val_if_fail (GIMP_IS_DRAWABLE (drawable), NULL);
470 
471   context = GIMP_CONTEXT (options);
472 
473   return gimp_layer_mode_get_format (gimp_context_get_paint_mode (context),
474                                      GIMP_LAYER_COLOR_SPACE_AUTO,
475                                      GIMP_LAYER_COLOR_SPACE_AUTO,
476                                      gimp_layer_mode_get_paint_composite_mode (
477                                        gimp_context_get_paint_mode (context)),
478                                      gimp_drawable_get_format (drawable));
479 }
480 
481 GeglBuffer *
gimp_fill_options_create_buffer(GimpFillOptions * options,GimpDrawable * drawable,const GeglRectangle * rect,gint pattern_offset_x,gint pattern_offset_y)482 gimp_fill_options_create_buffer (GimpFillOptions     *options,
483                                  GimpDrawable        *drawable,
484                                  const GeglRectangle *rect,
485                                  gint                 pattern_offset_x,
486                                  gint                 pattern_offset_y)
487 {
488   GeglBuffer *buffer;
489 
490   g_return_val_if_fail (GIMP_IS_FILL_OPTIONS (options), NULL);
491   g_return_val_if_fail (gimp_fill_options_get_style (options) !=
492                         GIMP_FILL_STYLE_PATTERN ||
493                         gimp_context_get_pattern (GIMP_CONTEXT (options)) != NULL,
494                         NULL);
495   g_return_val_if_fail (GIMP_IS_DRAWABLE (drawable), NULL);
496   g_return_val_if_fail (rect != NULL, NULL);
497 
498   buffer = gegl_buffer_new (rect,
499                             gimp_fill_options_get_format (options, drawable));
500 
501   gimp_fill_options_fill_buffer (options, drawable, buffer,
502                                  pattern_offset_x, pattern_offset_y);
503 
504   return buffer;
505 }
506 
507 void
gimp_fill_options_fill_buffer(GimpFillOptions * options,GimpDrawable * drawable,GeglBuffer * buffer,gint pattern_offset_x,gint pattern_offset_y)508 gimp_fill_options_fill_buffer (GimpFillOptions *options,
509                                GimpDrawable    *drawable,
510                                GeglBuffer      *buffer,
511                                gint             pattern_offset_x,
512                                gint             pattern_offset_y)
513 {
514   g_return_if_fail (GIMP_IS_FILL_OPTIONS (options));
515   g_return_if_fail (gimp_fill_options_get_style (options) !=
516                     GIMP_FILL_STYLE_PATTERN ||
517                     gimp_context_get_pattern (GIMP_CONTEXT (options)) != NULL);
518   g_return_if_fail (GIMP_IS_DRAWABLE (drawable));
519   g_return_if_fail (GEGL_IS_BUFFER (buffer));
520 
521   switch (gimp_fill_options_get_style (options))
522     {
523     case GIMP_FILL_STYLE_SOLID:
524       {
525         GimpRGB color;
526 
527         gimp_context_get_foreground (GIMP_CONTEXT (options), &color);
528         gimp_palettes_add_color_history (GIMP_CONTEXT (options)->gimp, &color);
529 
530         gimp_drawable_fill_buffer (drawable, buffer,
531                                    &color, NULL, 0, 0);
532       }
533       break;
534 
535     case GIMP_FILL_STYLE_PATTERN:
536       {
537         GimpPattern *pattern;
538 
539         pattern = gimp_context_get_pattern (GIMP_CONTEXT (options));
540 
541         gimp_drawable_fill_buffer (drawable, buffer,
542                                    NULL, pattern,
543                                    pattern_offset_x,
544                                    pattern_offset_y);
545       }
546       break;
547     }
548 }
549