1 /* GIMP - The GNU Image Manipulation Program
2 * Copyright (C) 1995 Spencer Kimball and Peter Mattis
3 *
4 * gimptoolgroup.c
5 * Copyright (C) 2020 Ell
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 <gdk-pixbuf/gdk-pixbuf.h>
26 #include <gegl.h>
27
28 #include "libgimpbase/gimpbase.h"
29 #include "libgimpconfig/gimpconfig.h"
30
31 #include "core-types.h"
32
33 #include "gimplist.h"
34 #include "gimpmarshal.h"
35 #include "gimptoolgroup.h"
36 #include "gimptoolinfo.h"
37
38 #include "gimp-intl.h"
39
40
41 enum
42 {
43 ACTIVE_TOOL_CHANGED,
44 LAST_SIGNAL
45 };
46
47 enum
48 {
49 PROP_0,
50 PROP_ACTIVE_TOOL,
51 PROP_CHILDREN
52 };
53
54
55 struct _GimpToolGroupPrivate
56 {
57 gchar *active_tool;
58 GimpContainer *children;
59 };
60
61
62 /* local function prototypes */
63
64
65 static void gimp_tool_group_finalize (GObject *object);
66 static void gimp_tool_group_get_property (GObject *object,
67 guint property_id,
68 GValue *value,
69 GParamSpec *pspec);
70 static void gimp_tool_group_set_property (GObject *object,
71 guint property_id,
72 const GValue *value,
73 GParamSpec *pspec);
74
75 static gint64 gimp_tool_group_get_memsize (GimpObject *object,
76 gint64 *gui_size);
77
78 static gchar * gimp_tool_group_get_description (GimpViewable *viewable,
79 gchar **tooltip);
80 static GimpContainer * gimp_tool_group_get_children (GimpViewable *viewable);
81 static void gimp_tool_group_set_expanded (GimpViewable *viewable,
82 gboolean expand);
83 static gboolean gimp_tool_group_get_expanded (GimpViewable *viewable);
84
85 static void gimp_tool_group_child_add (GimpContainer *container,
86 GimpToolInfo *tool_info,
87 GimpToolGroup *tool_group);
88 static void gimp_tool_group_child_remove (GimpContainer *container,
89 GimpToolInfo *tool_info,
90 GimpToolGroup *tool_group);
91
92 static void gimp_tool_group_shown_changed (GimpToolItem *tool_item);
93
94
95 G_DEFINE_TYPE_WITH_PRIVATE (GimpToolGroup, gimp_tool_group, GIMP_TYPE_TOOL_ITEM)
96
97 #define parent_class gimp_tool_group_parent_class
98
99 static guint gimp_tool_group_signals[LAST_SIGNAL] = { 0 };
100
101
102 /* private functions */
103
104 static void
gimp_tool_group_class_init(GimpToolGroupClass * klass)105 gimp_tool_group_class_init (GimpToolGroupClass *klass)
106 {
107 GObjectClass *object_class = G_OBJECT_CLASS (klass);
108 GimpObjectClass *gimp_object_class = GIMP_OBJECT_CLASS (klass);
109 GimpViewableClass *viewable_class = GIMP_VIEWABLE_CLASS (klass);
110 GimpToolItemClass *tool_item_class = GIMP_TOOL_ITEM_CLASS (klass);
111
112 gimp_tool_group_signals[ACTIVE_TOOL_CHANGED] =
113 g_signal_new ("active-tool-changed",
114 G_TYPE_FROM_CLASS (klass),
115 G_SIGNAL_RUN_FIRST,
116 G_STRUCT_OFFSET (GimpToolGroupClass, active_tool_changed),
117 NULL, NULL,
118 gimp_marshal_VOID__VOID,
119 G_TYPE_NONE, 0);
120
121 object_class->finalize = gimp_tool_group_finalize;
122 object_class->get_property = gimp_tool_group_get_property;
123 object_class->set_property = gimp_tool_group_set_property;
124
125 gimp_object_class->get_memsize = gimp_tool_group_get_memsize;
126
127 viewable_class->default_icon_name = "folder";
128 viewable_class->get_description = gimp_tool_group_get_description;
129 viewable_class->get_children = gimp_tool_group_get_children;
130 viewable_class->get_expanded = gimp_tool_group_get_expanded;
131 viewable_class->set_expanded = gimp_tool_group_set_expanded;
132
133 tool_item_class->shown_changed = gimp_tool_group_shown_changed;
134
135 GIMP_CONFIG_PROP_STRING (object_class, PROP_ACTIVE_TOOL,
136 "active-tool", NULL, NULL,
137 NULL,
138 GIMP_PARAM_STATIC_STRINGS);
139
140 GIMP_CONFIG_PROP_OBJECT (object_class, PROP_CHILDREN,
141 "children", NULL, NULL,
142 GIMP_TYPE_CONTAINER,
143 GIMP_PARAM_STATIC_STRINGS |
144 GIMP_CONFIG_PARAM_AGGREGATE);
145 }
146
147 static void
gimp_tool_group_init(GimpToolGroup * tool_group)148 gimp_tool_group_init (GimpToolGroup *tool_group)
149 {
150 tool_group->priv = gimp_tool_group_get_instance_private (tool_group);
151
152 tool_group->priv->children = g_object_new (
153 GIMP_TYPE_LIST,
154 "children-type", GIMP_TYPE_TOOL_INFO,
155 "append", TRUE,
156 NULL);
157
158 g_signal_connect (tool_group->priv->children, "add",
159 G_CALLBACK (gimp_tool_group_child_add),
160 tool_group);
161 g_signal_connect (tool_group->priv->children, "remove",
162 G_CALLBACK (gimp_tool_group_child_remove),
163 tool_group);
164 }
165
166 static void
gimp_tool_group_finalize(GObject * object)167 gimp_tool_group_finalize (GObject *object)
168 {
169 GimpToolGroup *tool_group = GIMP_TOOL_GROUP (object);
170
171 g_clear_pointer (&tool_group->priv->active_tool, g_free);
172
173 g_clear_object (&tool_group->priv->children);
174
175 G_OBJECT_CLASS (parent_class)->finalize (object);
176 }
177
178 static void
gimp_tool_group_get_property(GObject * object,guint property_id,GValue * value,GParamSpec * pspec)179 gimp_tool_group_get_property (GObject *object,
180 guint property_id,
181 GValue *value,
182 GParamSpec *pspec)
183 {
184 GimpToolGroup *tool_group = GIMP_TOOL_GROUP (object);
185
186 switch (property_id)
187 {
188 case PROP_ACTIVE_TOOL:
189 g_value_set_string (value, tool_group->priv->active_tool);
190 break;
191
192 case PROP_CHILDREN:
193 g_value_set_object (value, tool_group->priv->children);
194 break;
195
196 default:
197 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
198 break;
199 }
200 }
201
202 static void
gimp_tool_group_set_property_add_tool(GimpToolInfo * tool_info,GimpToolGroup * tool_group)203 gimp_tool_group_set_property_add_tool (GimpToolInfo *tool_info,
204 GimpToolGroup *tool_group)
205 {
206 gimp_container_add (tool_group->priv->children, GIMP_OBJECT (tool_info));
207 }
208
209 static void
gimp_tool_group_set_property(GObject * object,guint property_id,const GValue * value,GParamSpec * pspec)210 gimp_tool_group_set_property (GObject *object,
211 guint property_id,
212 const GValue *value,
213 GParamSpec *pspec)
214 {
215 GimpToolGroup *tool_group = GIMP_TOOL_GROUP (object);
216
217 switch (property_id)
218 {
219 case PROP_ACTIVE_TOOL:
220 g_free (tool_group->priv->active_tool);
221
222 tool_group->priv->active_tool = g_value_dup_string (value);
223 break;
224
225 case PROP_CHILDREN:
226 {
227 GimpContainer *container = g_value_get_object (value);
228
229 gimp_container_clear (tool_group->priv->children);
230
231 if (! container)
232 break;
233
234 gimp_container_foreach (container,
235 (GFunc) gimp_tool_group_set_property_add_tool,
236 tool_group);
237 }
238 break;
239
240 default:
241 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
242 break;
243 }
244 }
245
246 static gint64
gimp_tool_group_get_memsize(GimpObject * object,gint64 * gui_size)247 gimp_tool_group_get_memsize (GimpObject *object,
248 gint64 *gui_size)
249 {
250 GimpToolGroup *tool_group = GIMP_TOOL_GROUP (object);
251 gint64 memsize = 0;
252
253 memsize += gimp_object_get_memsize (GIMP_OBJECT (tool_group->priv->children),
254 gui_size);
255
256 return memsize + GIMP_OBJECT_CLASS (parent_class)->get_memsize (object,
257 gui_size);
258 }
259
260 static gchar *
gimp_tool_group_get_description(GimpViewable * viewable,gchar ** tooltip)261 gimp_tool_group_get_description (GimpViewable *viewable,
262 gchar **tooltip)
263 {
264 /* Translators: this is a noun */
265 return g_strdup (C_("tool-item", "Group"));
266 }
267
268 static GimpContainer *
gimp_tool_group_get_children(GimpViewable * viewable)269 gimp_tool_group_get_children (GimpViewable *viewable)
270 {
271 GimpToolGroup *tool_group = GIMP_TOOL_GROUP (viewable);
272
273 return tool_group->priv->children;
274 }
275
276 static void
gimp_tool_group_set_expanded(GimpViewable * viewable,gboolean expand)277 gimp_tool_group_set_expanded (GimpViewable *viewable,
278 gboolean expand)
279 {
280 if (! expand)
281 gimp_viewable_expanded_changed (viewable);
282 }
283
284 static gboolean
gimp_tool_group_get_expanded(GimpViewable * viewable)285 gimp_tool_group_get_expanded (GimpViewable *viewable)
286 {
287 return TRUE;
288 }
289
290 static void
gimp_tool_group_child_add(GimpContainer * container,GimpToolInfo * tool_info,GimpToolGroup * tool_group)291 gimp_tool_group_child_add (GimpContainer *container,
292 GimpToolInfo *tool_info,
293 GimpToolGroup *tool_group)
294 {
295 g_return_if_fail (
296 gimp_viewable_get_parent (GIMP_VIEWABLE (tool_info)) == NULL);
297
298 gimp_viewable_set_parent (GIMP_VIEWABLE (tool_info),
299 GIMP_VIEWABLE (tool_group));
300
301 if (! tool_group->priv->active_tool)
302 gimp_tool_group_set_active_tool_info (tool_group, tool_info);
303 }
304
305 static void
gimp_tool_group_child_remove(GimpContainer * container,GimpToolInfo * tool_info,GimpToolGroup * tool_group)306 gimp_tool_group_child_remove (GimpContainer *container,
307 GimpToolInfo *tool_info,
308 GimpToolGroup *tool_group)
309 {
310 gimp_viewable_set_parent (GIMP_VIEWABLE (tool_info), NULL);
311
312 if (! g_strcmp0 (tool_group->priv->active_tool,
313 gimp_object_get_name (GIMP_OBJECT (tool_info))))
314 {
315 GimpToolInfo *active_tool_info = NULL;
316
317 if (! gimp_container_is_empty (tool_group->priv->children))
318 {
319 active_tool_info = GIMP_TOOL_INFO (
320 gimp_container_get_first_child (tool_group->priv->children));
321 }
322
323 gimp_tool_group_set_active_tool_info (tool_group, active_tool_info);
324 }
325 }
326
327 static void
gimp_tool_group_shown_changed(GimpToolItem * tool_item)328 gimp_tool_group_shown_changed (GimpToolItem *tool_item)
329 {
330 GimpToolGroup *tool_group = GIMP_TOOL_GROUP (tool_item);
331 GList *iter;
332
333 if (GIMP_TOOL_ITEM_CLASS (parent_class)->shown_changed)
334 GIMP_TOOL_ITEM_CLASS (parent_class)->shown_changed (tool_item);
335
336 for (iter = GIMP_LIST (tool_group->priv->children)->queue->head;
337 iter;
338 iter = g_list_next (iter))
339 {
340 GimpToolItem *tool_item = iter->data;
341
342 if (gimp_tool_item_get_visible (tool_item))
343 gimp_tool_item_shown_changed (tool_item);
344 }
345 }
346
347
348 /* public functions */
349
350 GimpToolGroup *
gimp_tool_group_new(void)351 gimp_tool_group_new (void)
352 {
353 GimpToolGroup *tool_group;
354
355 tool_group = g_object_new (GIMP_TYPE_TOOL_GROUP, NULL);
356
357 gimp_object_set_static_name (GIMP_OBJECT (tool_group), "tool group");
358
359 return tool_group;
360 }
361
362 void
gimp_tool_group_set_active_tool(GimpToolGroup * tool_group,const gchar * tool_name)363 gimp_tool_group_set_active_tool (GimpToolGroup *tool_group,
364 const gchar *tool_name)
365 {
366 g_return_if_fail (GIMP_IS_TOOL_GROUP (tool_group));
367
368 if (g_strcmp0 (tool_group->priv->active_tool, tool_name))
369 {
370 g_return_if_fail (tool_name == NULL ||
371 gimp_container_get_child_by_name (
372 tool_group->priv->children, tool_name) != NULL);
373
374 g_free (tool_group->priv->active_tool);
375
376 tool_group->priv->active_tool = g_strdup (tool_name);;
377
378 g_signal_emit (tool_group,
379 gimp_tool_group_signals[ACTIVE_TOOL_CHANGED], 0);
380
381 g_object_notify (G_OBJECT (tool_group), "active-tool");
382 }
383 }
384
385 const gchar *
gimp_tool_group_get_active_tool(GimpToolGroup * tool_group)386 gimp_tool_group_get_active_tool (GimpToolGroup *tool_group)
387 {
388 g_return_val_if_fail (GIMP_IS_TOOL_GROUP (tool_group), NULL);
389
390 return tool_group->priv->active_tool;
391 }
392
393 void
gimp_tool_group_set_active_tool_info(GimpToolGroup * tool_group,GimpToolInfo * tool_info)394 gimp_tool_group_set_active_tool_info (GimpToolGroup *tool_group,
395 GimpToolInfo *tool_info)
396 {
397 g_return_if_fail (GIMP_IS_TOOL_GROUP (tool_group));
398 g_return_if_fail (tool_info == NULL || GIMP_IS_TOOL_INFO (tool_info));
399
400 gimp_tool_group_set_active_tool (
401 tool_group,
402 tool_info ? gimp_object_get_name (GIMP_OBJECT (tool_info)) : NULL);
403 }
404
405 GimpToolInfo *
gimp_tool_group_get_active_tool_info(GimpToolGroup * tool_group)406 gimp_tool_group_get_active_tool_info (GimpToolGroup *tool_group)
407 {
408 g_return_val_if_fail (GIMP_IS_TOOL_GROUP (tool_group), NULL);
409
410 return GIMP_TOOL_INFO (
411 gimp_container_get_child_by_name (tool_group->priv->children,
412 tool_group->priv->active_tool));
413 }
414