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