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