1 /* GIMP - The GNU Image Manipulation Program
2 * Copyright (C) 1995 Spencer Kimball and Peter Mattis
3 *
4 * gimpaction.c
5 * Copyright (C) 2004-2019 Michael Natterer <mitch@gimp.org>
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 <gegl.h>
24 #include <gtk/gtk.h>
25
26 #include "libgimpbase/gimpbase.h"
27 #include "libgimpcolor/gimpcolor.h"
28 #include "libgimpwidgets/gimpwidgets.h"
29
30 #include "widgets-types.h"
31
32 #include "config/gimpcoreconfig.h"
33
34 #include "core/gimp.h"
35 #include "core/gimpcontext.h"
36 #include "core/gimpmarshal.h"
37 #include "core/gimpimagefile.h" /* eek */
38
39 #include "gimpaction.h"
40 #include "gimpactionimpl.h"
41 #include "gimpaction-history.h"
42 #include "gimpview.h"
43 #include "gimpviewrenderer.h"
44 #include "gimpwidgets-utils.h"
45
46
47 enum
48 {
49 PROP_0,
50 PROP_CONTEXT,
51 PROP_COLOR,
52 PROP_VIEWABLE,
53 PROP_ELLIPSIZE,
54 PROP_MAX_WIDTH_CHARS
55 };
56
57
58 static void gimp_action_impl_finalize (GObject *object);
59 static void gimp_action_impl_set_property (GObject *object,
60 guint prop_id,
61 const GValue *value,
62 GParamSpec *pspec);
63 static void gimp_action_impl_get_property (GObject *object,
64 guint prop_id,
65 GValue *value,
66 GParamSpec *pspec);
67
68 static void gimp_action_impl_activate (GtkAction *action);
69 static void gimp_action_impl_connect_proxy (GtkAction *action,
70 GtkWidget *proxy);
71
72 static void gimp_action_impl_set_proxy (GimpActionImpl *impl,
73 GtkWidget *proxy);
74
75
G_DEFINE_TYPE_WITH_CODE(GimpActionImpl,gimp_action_impl,GTK_TYPE_ACTION,G_IMPLEMENT_INTERFACE (GIMP_TYPE_ACTION,NULL))76 G_DEFINE_TYPE_WITH_CODE (GimpActionImpl, gimp_action_impl, GTK_TYPE_ACTION,
77 G_IMPLEMENT_INTERFACE (GIMP_TYPE_ACTION, NULL))
78
79 #define parent_class gimp_action_impl_parent_class
80
81
82 static void
83 gimp_action_impl_class_init (GimpActionImplClass *klass)
84 {
85 GObjectClass *object_class = G_OBJECT_CLASS (klass);
86 GtkActionClass *action_class = GTK_ACTION_CLASS (klass);
87 GimpRGB black;
88
89 object_class->finalize = gimp_action_impl_finalize;
90 object_class->set_property = gimp_action_impl_set_property;
91 object_class->get_property = gimp_action_impl_get_property;
92
93 action_class->activate = gimp_action_impl_activate;
94 action_class->connect_proxy = gimp_action_impl_connect_proxy;
95
96 gimp_rgba_set (&black, 0.0, 0.0, 0.0, GIMP_OPACITY_OPAQUE);
97
98 g_object_class_install_property (object_class, PROP_CONTEXT,
99 g_param_spec_object ("context",
100 NULL, NULL,
101 GIMP_TYPE_CONTEXT,
102 GIMP_PARAM_READWRITE));
103
104 g_object_class_install_property (object_class, PROP_COLOR,
105 gimp_param_spec_rgb ("color",
106 NULL, NULL,
107 TRUE, &black,
108 GIMP_PARAM_READWRITE));
109
110 g_object_class_install_property (object_class, PROP_VIEWABLE,
111 g_param_spec_object ("viewable",
112 NULL, NULL,
113 GIMP_TYPE_VIEWABLE,
114 GIMP_PARAM_READWRITE));
115
116 g_object_class_install_property (object_class, PROP_ELLIPSIZE,
117 g_param_spec_enum ("ellipsize",
118 NULL, NULL,
119 PANGO_TYPE_ELLIPSIZE_MODE,
120 PANGO_ELLIPSIZE_NONE,
121 GIMP_PARAM_READWRITE));
122
123 g_object_class_install_property (object_class, PROP_MAX_WIDTH_CHARS,
124 g_param_spec_int ("max-width-chars",
125 NULL, NULL,
126 -1, G_MAXINT, -1,
127 GIMP_PARAM_READWRITE));
128 }
129
130 static void
gimp_action_impl_init(GimpActionImpl * impl)131 gimp_action_impl_init (GimpActionImpl *impl)
132 {
133 impl->ellipsize = PANGO_ELLIPSIZE_NONE;
134 impl->max_width_chars = -1;
135
136 gimp_action_init (GIMP_ACTION (impl));
137 }
138
139 static void
gimp_action_impl_finalize(GObject * object)140 gimp_action_impl_finalize (GObject *object)
141 {
142 GimpActionImpl *impl = GIMP_ACTION_IMPL (object);
143
144 g_clear_object (&impl->context);
145 g_clear_pointer (&impl->color, g_free);
146 g_clear_object (&impl->viewable);
147
148 G_OBJECT_CLASS (parent_class)->finalize (object);
149 }
150
151 static void
gimp_action_impl_get_property(GObject * object,guint prop_id,GValue * value,GParamSpec * pspec)152 gimp_action_impl_get_property (GObject *object,
153 guint prop_id,
154 GValue *value,
155 GParamSpec *pspec)
156 {
157 GimpActionImpl *impl = GIMP_ACTION_IMPL (object);
158
159 switch (prop_id)
160 {
161 case PROP_CONTEXT:
162 g_value_set_object (value, impl->context);
163 break;
164
165 case PROP_COLOR:
166 g_value_set_boxed (value, impl->color);
167 break;
168
169 case PROP_VIEWABLE:
170 g_value_set_object (value, impl->viewable);
171 break;
172
173 case PROP_ELLIPSIZE:
174 g_value_set_enum (value, impl->ellipsize);
175 break;
176
177 case PROP_MAX_WIDTH_CHARS:
178 g_value_set_int (value, impl->max_width_chars);
179 break;
180
181 default:
182 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
183 break;
184 }
185 }
186
187 static void
gimp_action_impl_set_property(GObject * object,guint prop_id,const GValue * value,GParamSpec * pspec)188 gimp_action_impl_set_property (GObject *object,
189 guint prop_id,
190 const GValue *value,
191 GParamSpec *pspec)
192 {
193 GimpActionImpl *impl = GIMP_ACTION_IMPL (object);
194 gboolean set_proxy = FALSE;
195
196 switch (prop_id)
197 {
198 case PROP_CONTEXT:
199 g_set_object (&impl->context, g_value_get_object (value));
200 break;
201
202 case PROP_COLOR:
203 g_clear_pointer (&impl->color, g_free);
204 impl->color = g_value_dup_boxed (value);
205 set_proxy = TRUE;
206 break;
207
208 case PROP_VIEWABLE:
209 g_set_object (&impl->viewable, g_value_get_object (value));
210 set_proxy = TRUE;
211 break;
212
213 case PROP_ELLIPSIZE:
214 impl->ellipsize = g_value_get_enum (value);
215 set_proxy = TRUE;
216 break;
217
218 case PROP_MAX_WIDTH_CHARS:
219 impl->max_width_chars = g_value_get_int (value);
220 set_proxy = TRUE;
221 break;
222
223 default:
224 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
225 break;
226 }
227
228 if (set_proxy)
229 {
230 GSList *list;
231
232 for (list = gimp_action_get_proxies (GIMP_ACTION (impl));
233 list;
234 list = g_slist_next (list))
235 {
236 gimp_action_impl_set_proxy (impl, list->data);
237 }
238 }
239 }
240
241 static void
gimp_action_impl_activate(GtkAction * action)242 gimp_action_impl_activate (GtkAction *action)
243 {
244 if (GTK_ACTION_CLASS (parent_class)->activate)
245 GTK_ACTION_CLASS (parent_class)->activate (action);
246
247 gimp_action_emit_activate (GIMP_ACTION (action), NULL);
248
249 gimp_action_history_action_activated (GIMP_ACTION (action));
250 }
251
252 static void
gimp_action_impl_connect_proxy(GtkAction * action,GtkWidget * proxy)253 gimp_action_impl_connect_proxy (GtkAction *action,
254 GtkWidget *proxy)
255 {
256 GTK_ACTION_CLASS (parent_class)->connect_proxy (action, proxy);
257
258 gimp_action_impl_set_proxy (GIMP_ACTION_IMPL (action), proxy);
259
260 gimp_action_set_proxy (GIMP_ACTION (action), proxy);
261 }
262
263
264 /* public functions */
265
266 GimpAction *
gimp_action_impl_new(const gchar * name,const gchar * label,const gchar * tooltip,const gchar * icon_name,const gchar * help_id)267 gimp_action_impl_new (const gchar *name,
268 const gchar *label,
269 const gchar *tooltip,
270 const gchar *icon_name,
271 const gchar *help_id)
272 {
273 GimpAction *action;
274
275 action = g_object_new (GIMP_TYPE_ACTION_IMPL,
276 "name", name,
277 "label", label,
278 "tooltip", tooltip,
279 "icon-name", icon_name,
280 NULL);
281
282 gimp_action_set_help_id (action, help_id);
283
284 return action;
285 }
286
287
288 /* private functions */
289
290 static void
gimp_action_impl_set_proxy(GimpActionImpl * impl,GtkWidget * proxy)291 gimp_action_impl_set_proxy (GimpActionImpl *impl,
292 GtkWidget *proxy)
293 {
294 if (! GTK_IS_IMAGE_MENU_ITEM (proxy))
295 return;
296
297 if (impl->color)
298 {
299 GtkWidget *area;
300
301 area = gtk_image_menu_item_get_image (GTK_IMAGE_MENU_ITEM (proxy));
302
303 if (GIMP_IS_COLOR_AREA (area))
304 {
305 gimp_color_area_set_color (GIMP_COLOR_AREA (area), impl->color);
306 }
307 else
308 {
309 gint width, height;
310
311 area = gimp_color_area_new (impl->color,
312 GIMP_COLOR_AREA_SMALL_CHECKS, 0);
313 gimp_color_area_set_draw_border (GIMP_COLOR_AREA (area), TRUE);
314
315 if (impl->context)
316 gimp_color_area_set_color_config (GIMP_COLOR_AREA (area),
317 impl->context->gimp->config->color_management);
318
319 gtk_icon_size_lookup_for_settings (gtk_widget_get_settings (proxy),
320 GTK_ICON_SIZE_MENU,
321 &width, &height);
322
323 gtk_widget_set_size_request (area, width, height);
324 gtk_image_menu_item_set_image (GTK_IMAGE_MENU_ITEM (proxy), area);
325 gtk_image_menu_item_set_always_show_image (GTK_IMAGE_MENU_ITEM (proxy),
326 TRUE);
327 gtk_widget_show (area);
328 }
329 }
330 else if (impl->viewable)
331 {
332 GtkWidget *view;
333
334 view = gtk_image_menu_item_get_image (GTK_IMAGE_MENU_ITEM (proxy));
335
336 if (GIMP_IS_VIEW (view) &&
337 g_type_is_a (G_TYPE_FROM_INSTANCE (impl->viewable),
338 GIMP_VIEW (view)->renderer->viewable_type))
339 {
340 gimp_view_set_viewable (GIMP_VIEW (view), impl->viewable);
341 }
342 else
343 {
344 GtkIconSize size;
345 gint width, height;
346 gint border_width;
347
348 if (GIMP_IS_IMAGEFILE (impl->viewable))
349 {
350 size = GTK_ICON_SIZE_LARGE_TOOLBAR;
351 border_width = 0;
352 }
353 else
354 {
355 size = GTK_ICON_SIZE_MENU;
356 border_width = 1;
357 }
358
359 gtk_icon_size_lookup_for_settings (gtk_widget_get_settings (proxy),
360 size, &width, &height);
361
362 view = gimp_view_new_full (impl->context, impl->viewable,
363 width, height, border_width,
364 FALSE, FALSE, FALSE);
365 gtk_image_menu_item_set_image (GTK_IMAGE_MENU_ITEM (proxy), view);
366 gtk_image_menu_item_set_always_show_image (GTK_IMAGE_MENU_ITEM (proxy),
367 TRUE);
368 gtk_widget_show (view);
369 }
370 }
371 else
372 {
373 GtkWidget *image;
374
375 image = gtk_image_menu_item_get_image (GTK_IMAGE_MENU_ITEM (proxy));
376
377 if (GIMP_IS_VIEW (image) || GIMP_IS_COLOR_AREA (image))
378 {
379 gtk_image_menu_item_set_image (GTK_IMAGE_MENU_ITEM (proxy), NULL);
380 gtk_image_menu_item_set_always_show_image (GTK_IMAGE_MENU_ITEM (proxy),
381 FALSE);
382 g_object_notify (G_OBJECT (impl), "icon-name");
383 }
384 }
385
386 {
387 GtkWidget *child = gtk_bin_get_child (GTK_BIN (proxy));
388
389 if (GTK_IS_BOX (child))
390 child = g_object_get_data (G_OBJECT (proxy), "gimp-menu-item-label");
391
392 if (GTK_IS_LABEL (child))
393 {
394 GtkLabel *label = GTK_LABEL (child);
395
396 gtk_label_set_ellipsize (label, impl->ellipsize);
397 gtk_label_set_max_width_chars (label, impl->max_width_chars);
398 }
399 }
400 }
401