1 /* GIMP - The GNU Image Manipulation Program
2 * Copyright (C) 1995 Spencer Kimball and Peter Mattis
3 *
4 * gimpbrusheditor.c
5 * Copyright 1998 Jay Cox <jaycox@earthlink.net>
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 "libgimpmath/gimpmath.h"
29 #include "libgimpwidgets/gimpwidgets.h"
30
31 #include "widgets-types.h"
32
33 #include "core/gimp.h"
34 #include "core/gimpbrushgenerated.h"
35 #include "core/gimpcontext.h"
36
37 #include "gimpbrusheditor.h"
38 #include "gimpdocked.h"
39 #include "gimpspinscale.h"
40 #include "gimpview.h"
41 #include "gimpviewrenderer.h"
42
43 #include "gimp-intl.h"
44
45
46 #define BRUSH_VIEW_SIZE 96
47
48
49 /* local function prototypes */
50
51 static void gimp_brush_editor_docked_iface_init (GimpDockedInterface *face);
52
53 static void gimp_brush_editor_constructed (GObject *object);
54
55 static void gimp_brush_editor_set_data (GimpDataEditor *editor,
56 GimpData *data);
57
58 static void gimp_brush_editor_set_context (GimpDocked *docked,
59 GimpContext *context);
60
61 static void gimp_brush_editor_update_brush (GtkAdjustment *adjustment,
62 GimpBrushEditor *editor);
63 static void gimp_brush_editor_update_shape (GtkWidget *widget,
64 GimpBrushEditor *editor);
65 static void gimp_brush_editor_notify_brush (GimpBrushGenerated *brush,
66 GParamSpec *pspec,
67 GimpBrushEditor *editor);
68
69
70 G_DEFINE_TYPE_WITH_CODE (GimpBrushEditor, gimp_brush_editor,
71 GIMP_TYPE_DATA_EDITOR,
72 G_IMPLEMENT_INTERFACE (GIMP_TYPE_DOCKED,
73 gimp_brush_editor_docked_iface_init))
74
75 #define parent_class gimp_brush_editor_parent_class
76
77 static GimpDockedInterface *parent_docked_iface = NULL;
78
79
80 static void
gimp_brush_editor_class_init(GimpBrushEditorClass * klass)81 gimp_brush_editor_class_init (GimpBrushEditorClass *klass)
82 {
83 GObjectClass *object_class = G_OBJECT_CLASS (klass);
84 GimpDataEditorClass *editor_class = GIMP_DATA_EDITOR_CLASS (klass);
85
86 object_class->constructed = gimp_brush_editor_constructed;
87
88 editor_class->set_data = gimp_brush_editor_set_data;
89 editor_class->title = _("Brush Editor");
90 }
91
92 static void
gimp_brush_editor_docked_iface_init(GimpDockedInterface * iface)93 gimp_brush_editor_docked_iface_init (GimpDockedInterface *iface)
94 {
95 parent_docked_iface = g_type_interface_peek_parent (iface);
96
97 if (! parent_docked_iface)
98 parent_docked_iface = g_type_default_interface_peek (GIMP_TYPE_DOCKED);
99
100 iface->set_context = gimp_brush_editor_set_context;
101 }
102
103 static void
gimp_brush_editor_init(GimpBrushEditor * editor)104 gimp_brush_editor_init (GimpBrushEditor *editor)
105 {
106 GimpDataEditor *data_editor = GIMP_DATA_EDITOR (editor);
107 GtkWidget *frame;
108 GtkWidget *hbox;
109 GtkWidget *label;
110 GtkWidget *box;
111 GtkWidget *scale;
112
113 frame = gtk_frame_new (NULL);
114 gtk_frame_set_shadow_type (GTK_FRAME (frame), GTK_SHADOW_IN);
115 gtk_box_pack_start (GTK_BOX (editor), frame, TRUE, TRUE, 0);
116 gtk_widget_show (frame);
117
118 data_editor->view = gimp_view_new_full_by_types (NULL,
119 GIMP_TYPE_VIEW,
120 GIMP_TYPE_BRUSH,
121 BRUSH_VIEW_SIZE,
122 BRUSH_VIEW_SIZE, 0,
123 FALSE, FALSE, TRUE);
124 gtk_widget_set_size_request (data_editor->view, -1, BRUSH_VIEW_SIZE);
125 gimp_view_set_expand (GIMP_VIEW (data_editor->view), TRUE);
126 gtk_container_add (GTK_CONTAINER (frame), data_editor->view);
127 gtk_widget_show (data_editor->view);
128
129 editor->shape_group = NULL;
130
131 editor->options_box = gtk_box_new (GTK_ORIENTATION_VERTICAL, 2);
132 gtk_box_pack_start (GTK_BOX (editor), editor->options_box, FALSE, FALSE, 0);
133 gtk_widget_show (editor->options_box);
134
135 /* Stock Box for the brush shape */
136 hbox = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 2);
137 gtk_box_pack_start (GTK_BOX (editor->options_box), hbox, FALSE, FALSE, 0);
138 gtk_widget_show (hbox);
139
140 label = gtk_label_new (_("Shape:"));
141 gtk_box_pack_start (GTK_BOX (hbox), label, FALSE, FALSE, 0);
142 gtk_widget_show (label);
143
144 box = gimp_enum_icon_box_new (GIMP_TYPE_BRUSH_GENERATED_SHAPE,
145 "gimp-shape",
146 GTK_ICON_SIZE_MENU,
147 G_CALLBACK (gimp_brush_editor_update_shape),
148 editor,
149 &editor->shape_group);
150 gtk_box_pack_start (GTK_BOX (hbox), box, FALSE, FALSE, 0);
151 gtk_widget_show (box);
152
153 /* brush radius scale */
154 editor->radius_data =
155 GTK_ADJUSTMENT (gtk_adjustment_new (0.0, 0.1, 1000.0, 1.0, 10.0, 0.0));
156 scale = gimp_spin_scale_new (editor->radius_data, _("Radius"), 1);
157 gtk_box_pack_start (GTK_BOX (editor->options_box), scale, FALSE, FALSE, 0);
158 gtk_widget_show (scale);
159
160 g_signal_connect (editor->radius_data, "value-changed",
161 G_CALLBACK (gimp_brush_editor_update_brush),
162 editor);
163
164 /* number of spikes */
165 editor->spikes_data =
166 GTK_ADJUSTMENT (gtk_adjustment_new (2.0, 2.0, 20.0, 1.0, 1.0, 0.0));
167 scale = gimp_spin_scale_new (editor->spikes_data, _("Spikes"), 0);
168 gtk_box_pack_start (GTK_BOX (editor->options_box), scale, FALSE, FALSE, 0);
169 gtk_widget_show (scale);
170
171 g_signal_connect (editor->spikes_data, "value-changed",
172 G_CALLBACK (gimp_brush_editor_update_brush),
173 editor);
174
175 /* brush hardness scale */
176 editor->hardness_data =
177 GTK_ADJUSTMENT (gtk_adjustment_new (0.0, 0.0, 1.0, 0.01, 0.1, 0.0));
178 scale = gimp_spin_scale_new (editor->hardness_data, _("Hardness"), 2);
179 gtk_box_pack_start (GTK_BOX (editor->options_box), scale, FALSE, FALSE, 0);
180 gtk_widget_show (scale);
181
182 g_signal_connect (editor->hardness_data, "value-changed",
183 G_CALLBACK (gimp_brush_editor_update_brush),
184 editor);
185
186 /* brush aspect ratio scale */
187 editor->aspect_ratio_data =
188 GTK_ADJUSTMENT (gtk_adjustment_new (0.0, 1.0, 20.0, 0.1, 1.0, 0.0));
189 scale = gimp_spin_scale_new (editor->aspect_ratio_data, _("Aspect ratio"), 1);
190 gtk_box_pack_start (GTK_BOX (editor->options_box), scale, FALSE, FALSE, 0);
191 gtk_widget_show (scale);
192
193 g_signal_connect (editor->aspect_ratio_data,"value-changed",
194 G_CALLBACK (gimp_brush_editor_update_brush),
195 editor);
196
197 /* brush angle scale */
198 editor->angle_data =
199 GTK_ADJUSTMENT (gtk_adjustment_new (0.0, 0.0, 180.0, 0.1, 1.0, 0.0));
200 scale = gimp_spin_scale_new (editor->angle_data, _("Angle"), 1);
201 gtk_box_pack_start (GTK_BOX (editor->options_box), scale, FALSE, FALSE, 0);
202 gtk_widget_show (scale);
203
204 g_signal_connect (editor->angle_data, "value-changed",
205 G_CALLBACK (gimp_brush_editor_update_brush),
206 editor);
207
208 /* brush spacing */
209 editor->spacing_data =
210 GTK_ADJUSTMENT (gtk_adjustment_new (0.0, 1.0, 5000.0, 1.0, 10.0, 0.0));
211 scale = gimp_spin_scale_new (editor->spacing_data, _("Spacing"), 1);
212 gimp_spin_scale_set_scale_limits (GIMP_SPIN_SCALE (scale), 1.0, 200.0);
213 gtk_box_pack_start (GTK_BOX (editor->options_box), scale, FALSE, FALSE, 0);
214 gtk_widget_show (scale);
215
216 gimp_help_set_help_data (scale, _("Percentage of width of brush"), NULL);
217
218 g_signal_connect (editor->spacing_data, "value-changed",
219 G_CALLBACK (gimp_brush_editor_update_brush),
220 editor);
221 }
222
223 static void
gimp_brush_editor_constructed(GObject * object)224 gimp_brush_editor_constructed (GObject *object)
225 {
226 G_OBJECT_CLASS (parent_class)->constructed (object);
227
228 gimp_docked_set_show_button_bar (GIMP_DOCKED (object), FALSE);
229 }
230
231 static void
gimp_brush_editor_set_data(GimpDataEditor * editor,GimpData * data)232 gimp_brush_editor_set_data (GimpDataEditor *editor,
233 GimpData *data)
234 {
235 GimpBrushEditor *brush_editor = GIMP_BRUSH_EDITOR (editor);
236 GimpBrushGeneratedShape shape = GIMP_BRUSH_GENERATED_CIRCLE;
237 gdouble radius = 0.0;
238 gint spikes = 2;
239 gdouble hardness = 0.0;
240 gdouble ratio = 0.0;
241 gdouble angle = 0.0;
242 gdouble spacing = 0.0;
243
244 if (editor->data)
245 g_signal_handlers_disconnect_by_func (editor->data,
246 gimp_brush_editor_notify_brush,
247 editor);
248
249 GIMP_DATA_EDITOR_CLASS (parent_class)->set_data (editor, data);
250
251 if (editor->data)
252 g_signal_connect (editor->data, "notify",
253 G_CALLBACK (gimp_brush_editor_notify_brush),
254 editor);
255
256 gimp_view_set_viewable (GIMP_VIEW (editor->view), GIMP_VIEWABLE (data));
257
258 if (editor->data)
259 {
260 spacing = gimp_brush_get_spacing (GIMP_BRUSH (editor->data));
261
262 if (GIMP_IS_BRUSH_GENERATED (editor->data))
263 {
264 GimpBrushGenerated *brush = GIMP_BRUSH_GENERATED (editor->data);
265
266 shape = gimp_brush_generated_get_shape (brush);
267 radius = gimp_brush_generated_get_radius (brush);
268 spikes = gimp_brush_generated_get_spikes (brush);
269 hardness = gimp_brush_generated_get_hardness (brush);
270 ratio = gimp_brush_generated_get_aspect_ratio (brush);
271 angle = gimp_brush_generated_get_angle (brush);
272 }
273 }
274
275 gtk_widget_set_sensitive (brush_editor->options_box,
276 editor->data_editable);
277
278 gimp_int_radio_group_set_active (GTK_RADIO_BUTTON (brush_editor->shape_group),
279 shape);
280
281 gtk_adjustment_set_value (brush_editor->radius_data, radius);
282 gtk_adjustment_set_value (brush_editor->spikes_data, spikes);
283 gtk_adjustment_set_value (brush_editor->hardness_data, hardness);
284 gtk_adjustment_set_value (brush_editor->aspect_ratio_data, ratio);
285 gtk_adjustment_set_value (brush_editor->angle_data, angle);
286 gtk_adjustment_set_value (brush_editor->spacing_data, spacing);
287 }
288
289 static void
gimp_brush_editor_set_context(GimpDocked * docked,GimpContext * context)290 gimp_brush_editor_set_context (GimpDocked *docked,
291 GimpContext *context)
292 {
293 GimpDataEditor *data_editor = GIMP_DATA_EDITOR (docked);
294
295 parent_docked_iface->set_context (docked, context);
296
297 gimp_view_renderer_set_context (GIMP_VIEW (data_editor->view)->renderer,
298 context);
299 }
300
301
302 /* public functions */
303
304 GtkWidget *
gimp_brush_editor_new(GimpContext * context,GimpMenuFactory * menu_factory)305 gimp_brush_editor_new (GimpContext *context,
306 GimpMenuFactory *menu_factory)
307 {
308 g_return_val_if_fail (GIMP_IS_CONTEXT (context), NULL);
309
310 return g_object_new (GIMP_TYPE_BRUSH_EDITOR,
311 "menu-factory", menu_factory,
312 "menu-identifier", "<BrushEditor>",
313 "ui-path", "/brush-editor-popup",
314 "data-factory", context->gimp->brush_factory,
315 "context", context,
316 "data", gimp_context_get_brush (context),
317 NULL);
318 }
319
320
321 /* private functions */
322
323 static void
gimp_brush_editor_update_brush(GtkAdjustment * adjustment,GimpBrushEditor * editor)324 gimp_brush_editor_update_brush (GtkAdjustment *adjustment,
325 GimpBrushEditor *editor)
326 {
327 GimpBrushGenerated *brush;
328 gdouble value;
329
330 if (! GIMP_IS_BRUSH_GENERATED (GIMP_DATA_EDITOR (editor)->data))
331 return;
332
333 brush = GIMP_BRUSH_GENERATED (GIMP_DATA_EDITOR (editor)->data);
334
335 g_signal_handlers_block_by_func (brush,
336 gimp_brush_editor_notify_brush,
337 editor);
338
339 value = gtk_adjustment_get_value (adjustment);
340
341 if (adjustment == editor->radius_data)
342 {
343 if (value != gimp_brush_generated_get_radius (brush))
344 gimp_brush_generated_set_radius (brush, value);
345 }
346 else if (adjustment == editor->spikes_data)
347 {
348 if (ROUND (value) != gimp_brush_generated_get_spikes (brush))
349 gimp_brush_generated_set_spikes (brush, ROUND (value));
350 }
351 else if (adjustment == editor->hardness_data)
352 {
353 if (value != gimp_brush_generated_get_hardness (brush))
354 gimp_brush_generated_set_hardness (brush, value);
355 }
356 else if (adjustment == editor->aspect_ratio_data)
357 {
358 if (value != gimp_brush_generated_get_aspect_ratio (brush))
359 gimp_brush_generated_set_aspect_ratio (brush, value);
360 }
361 else if (adjustment == editor->angle_data)
362 {
363 if (value != gimp_brush_generated_get_angle (brush))
364 gimp_brush_generated_set_angle (brush, value);
365 }
366 else if (adjustment == editor->spacing_data)
367 {
368 if (value != gimp_brush_get_spacing (GIMP_BRUSH (brush)))
369 gimp_brush_set_spacing (GIMP_BRUSH (brush), value);
370 }
371
372 g_signal_handlers_unblock_by_func (brush,
373 gimp_brush_editor_notify_brush,
374 editor);
375 }
376
377 static void
gimp_brush_editor_update_shape(GtkWidget * widget,GimpBrushEditor * editor)378 gimp_brush_editor_update_shape (GtkWidget *widget,
379 GimpBrushEditor *editor)
380 {
381 GimpBrushGenerated *brush;
382
383 if (! GIMP_IS_BRUSH_GENERATED (GIMP_DATA_EDITOR (editor)->data))
384 return;
385
386 brush = GIMP_BRUSH_GENERATED (GIMP_DATA_EDITOR (editor)->data);
387
388 if (gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (widget)))
389 {
390 GimpBrushGeneratedShape shape;
391
392 shape = GPOINTER_TO_INT (g_object_get_data (G_OBJECT (widget),
393 "gimp-item-data"));
394
395 if (gimp_brush_generated_get_shape (brush) != shape)
396 gimp_brush_generated_set_shape (brush, shape);
397 }
398 }
399
400 static void
gimp_brush_editor_notify_brush(GimpBrushGenerated * brush,GParamSpec * pspec,GimpBrushEditor * editor)401 gimp_brush_editor_notify_brush (GimpBrushGenerated *brush,
402 GParamSpec *pspec,
403 GimpBrushEditor *editor)
404 {
405 GtkAdjustment *adj = NULL;
406 gdouble value = 0.0;
407
408 if (! strcmp (pspec->name, "shape"))
409 {
410 g_signal_handlers_block_by_func (editor->shape_group,
411 gimp_brush_editor_update_shape,
412 editor);
413
414 gimp_int_radio_group_set_active (GTK_RADIO_BUTTON (editor->shape_group),
415 brush->shape);
416
417 g_signal_handlers_unblock_by_func (editor->shape_group,
418 gimp_brush_editor_update_shape,
419 editor);
420 }
421 else if (! strcmp (pspec->name, "radius"))
422 {
423 adj = editor->radius_data;
424 value = gimp_brush_generated_get_radius (brush);
425 }
426 else if (! strcmp (pspec->name, "spikes"))
427 {
428 adj = editor->spikes_data;
429 value = gimp_brush_generated_get_spikes (brush);
430 }
431 else if (! strcmp (pspec->name, "hardness"))
432 {
433 adj = editor->hardness_data;
434 value = gimp_brush_generated_get_hardness (brush);
435 }
436 else if (! strcmp (pspec->name, "angle"))
437 {
438 adj = editor->angle_data;
439 value = gimp_brush_generated_get_angle (brush);
440 }
441 else if (! strcmp (pspec->name, "aspect-ratio"))
442 {
443 adj = editor->aspect_ratio_data;
444 value = gimp_brush_generated_get_aspect_ratio (brush);
445 }
446 else if (! strcmp (pspec->name, "spacing"))
447 {
448 adj = editor->spacing_data;
449 value = gimp_brush_get_spacing (GIMP_BRUSH (brush));
450 }
451
452 if (adj)
453 {
454 g_signal_handlers_block_by_func (adj,
455 gimp_brush_editor_update_brush,
456 editor);
457
458 gtk_adjustment_set_value (adj, value);
459
460 g_signal_handlers_unblock_by_func (adj,
461 gimp_brush_editor_update_brush,
462 editor);
463 }
464 }
465