1 /* GIMP - The GNU Image Manipulation Program
2  * Copyright (C) 1995 Spencer Kimball and Peter Mattis
3  *
4  * gimpviewabledialog.c
5  * Copyright (C) 2000 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 "libgimpwidgets/gimpwidgets.h"
27 
28 #include "widgets-types.h"
29 
30 #include "core/gimpcontext.h"
31 #include "core/gimpimage.h"
32 #include "core/gimpitem.h"
33 
34 #include "gimpview.h"
35 #include "gimpviewabledialog.h"
36 #include "gimpviewrenderer.h"
37 
38 
39 enum
40 {
41   PROP_0,
42   PROP_VIEWABLE,
43   PROP_CONTEXT,
44   PROP_ICON_NAME,
45   PROP_DESC
46 };
47 
48 
49 static void   gimp_viewable_dialog_dispose      (GObject            *object);
50 static void   gimp_viewable_dialog_set_property (GObject            *object,
51                                                  guint               property_id,
52                                                  const GValue       *value,
53                                                  GParamSpec         *pspec);
54 static void   gimp_viewable_dialog_get_property (GObject            *object,
55                                                  guint               property_id,
56                                                  GValue             *value,
57                                                  GParamSpec         *pspec);
58 
59 static void   gimp_viewable_dialog_name_changed (GimpObject         *object,
60                                                  GimpViewableDialog *dialog);
61 static void   gimp_viewable_dialog_close        (GimpViewableDialog *dialog);
62 
63 
G_DEFINE_TYPE(GimpViewableDialog,gimp_viewable_dialog,GIMP_TYPE_DIALOG)64 G_DEFINE_TYPE (GimpViewableDialog, gimp_viewable_dialog, GIMP_TYPE_DIALOG)
65 
66 #define parent_class gimp_viewable_dialog_parent_class
67 
68 
69 static void
70 gimp_viewable_dialog_class_init (GimpViewableDialogClass *klass)
71 {
72   GObjectClass *object_class = G_OBJECT_CLASS (klass);
73 
74   object_class->dispose      = gimp_viewable_dialog_dispose;
75   object_class->get_property = gimp_viewable_dialog_get_property;
76   object_class->set_property = gimp_viewable_dialog_set_property;
77 
78   g_object_class_install_property (object_class, PROP_VIEWABLE,
79                                    g_param_spec_object ("viewable", NULL, NULL,
80                                                         GIMP_TYPE_VIEWABLE,
81                                                         GIMP_PARAM_READWRITE));
82 
83   g_object_class_install_property (object_class, PROP_CONTEXT,
84                                    g_param_spec_object ("context", NULL, NULL,
85                                                         GIMP_TYPE_CONTEXT,
86                                                         GIMP_PARAM_READWRITE |
87                                                         G_PARAM_CONSTRUCT));
88 
89   g_object_class_install_property (object_class, PROP_ICON_NAME,
90                                    g_param_spec_string ("icon-name", NULL, NULL,
91                                                         NULL,
92                                                         GIMP_PARAM_WRITABLE |
93                                                         G_PARAM_CONSTRUCT));
94 
95   g_object_class_install_property (object_class, PROP_DESC,
96                                    g_param_spec_string ("description", NULL, NULL,
97                                                         NULL,
98                                                         GIMP_PARAM_WRITABLE |
99                                                         G_PARAM_CONSTRUCT));
100 }
101 
102 static void
gimp_viewable_dialog_init(GimpViewableDialog * dialog)103 gimp_viewable_dialog_init (GimpViewableDialog *dialog)
104 {
105   GtkWidget *content_area = gtk_dialog_get_content_area (GTK_DIALOG (dialog));
106   GtkWidget *frame;
107   GtkWidget *hbox;
108   GtkWidget *vbox;
109 
110   frame = gtk_frame_new (NULL);
111   gtk_frame_set_shadow_type (GTK_FRAME (frame), GTK_SHADOW_OUT);
112   gtk_box_pack_start (GTK_BOX (content_area), frame, FALSE, FALSE, 0);
113   gtk_widget_show (frame);
114 
115   hbox = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 6);
116   gtk_container_set_border_width (GTK_CONTAINER (hbox), 2);
117   gtk_container_add (GTK_CONTAINER (frame), hbox);
118   gtk_widget_show (hbox);
119 
120   dialog->icon = gtk_image_new ();
121   gtk_misc_set_alignment (GTK_MISC (dialog->icon), 0.5, 0.0);
122   gtk_box_pack_start (GTK_BOX (hbox), dialog->icon, FALSE, FALSE, 0);
123   gtk_widget_show (dialog->icon);
124 
125   vbox = gtk_box_new (GTK_ORIENTATION_VERTICAL, 0);
126   gtk_box_pack_start (GTK_BOX (hbox), vbox, TRUE, TRUE, 0);
127   gtk_widget_show (vbox);
128 
129   dialog->desc_label = gtk_label_new (NULL);
130   gtk_label_set_xalign (GTK_LABEL (dialog->desc_label), 0.0);
131   gimp_label_set_attributes (GTK_LABEL (dialog->desc_label),
132                              PANGO_ATTR_SCALE,  PANGO_SCALE_LARGE,
133                              PANGO_ATTR_WEIGHT, PANGO_WEIGHT_BOLD,
134                              -1);
135   gtk_box_pack_start (GTK_BOX (vbox), dialog->desc_label, FALSE, FALSE, 0);
136   gtk_widget_show (dialog->desc_label);
137 
138   dialog->viewable_label = g_object_new (GTK_TYPE_LABEL,
139                                          "xalign",    0.0,
140                                          "yalign",    0.5,
141                                          "ellipsize", PANGO_ELLIPSIZE_END,
142                                          NULL);
143   gimp_label_set_attributes (GTK_LABEL (dialog->viewable_label),
144                              PANGO_ATTR_SCALE,  PANGO_SCALE_SMALL,
145                              -1);
146   gtk_box_pack_start (GTK_BOX (vbox), dialog->viewable_label, FALSE, FALSE, 0);
147   gtk_widget_show (dialog->viewable_label);
148 }
149 
150 static void
gimp_viewable_dialog_dispose(GObject * object)151 gimp_viewable_dialog_dispose (GObject *object)
152 {
153   GimpViewableDialog *dialog = GIMP_VIEWABLE_DIALOG (object);
154 
155   if (dialog->view)
156     gimp_viewable_dialog_set_viewable (dialog, NULL, NULL);
157 
158   G_OBJECT_CLASS (parent_class)->dispose (object);
159 }
160 
161 static void
gimp_viewable_dialog_set_property(GObject * object,guint property_id,const GValue * value,GParamSpec * pspec)162 gimp_viewable_dialog_set_property (GObject      *object,
163                                    guint         property_id,
164                                    const GValue *value,
165                                    GParamSpec   *pspec)
166 {
167   GimpViewableDialog *dialog = GIMP_VIEWABLE_DIALOG (object);
168 
169   switch (property_id)
170     {
171     case PROP_VIEWABLE:
172       gimp_viewable_dialog_set_viewable (dialog,
173                                          g_value_get_object (value),
174                                          dialog->context);
175       break;
176 
177     case PROP_CONTEXT:
178       gimp_viewable_dialog_set_viewable (dialog,
179                                          dialog->view ?
180                                          GIMP_VIEW (dialog->view)->viewable :
181                                          NULL,
182                                          g_value_get_object (value));
183       break;
184 
185     case PROP_ICON_NAME:
186       gtk_image_set_from_icon_name (GTK_IMAGE (dialog->icon),
187                                     g_value_get_string (value),
188                                     GTK_ICON_SIZE_LARGE_TOOLBAR);
189       break;
190 
191     case PROP_DESC:
192       gtk_label_set_text (GTK_LABEL (dialog->desc_label),
193                           g_value_get_string (value));
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_viewable_dialog_get_property(GObject * object,guint property_id,GValue * value,GParamSpec * pspec)203 gimp_viewable_dialog_get_property (GObject    *object,
204                                    guint       property_id,
205                                    GValue     *value,
206                                    GParamSpec *pspec)
207 {
208   GimpViewableDialog *dialog = GIMP_VIEWABLE_DIALOG (object);
209 
210   switch (property_id)
211     {
212     case PROP_VIEWABLE:
213       g_value_set_object (value,
214                           dialog->view ?
215                           GIMP_VIEW (dialog->view)->viewable : NULL);
216       break;
217 
218     case PROP_CONTEXT:
219       g_value_set_object (value, dialog->context);
220       break;
221 
222     default:
223       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
224       break;
225     }
226 }
227 
228 GtkWidget *
gimp_viewable_dialog_new(GimpViewable * viewable,GimpContext * context,const gchar * title,const gchar * role,const gchar * icon_name,const gchar * desc,GtkWidget * parent,GimpHelpFunc help_func,const gchar * help_id,...)229 gimp_viewable_dialog_new (GimpViewable *viewable,
230                           GimpContext  *context,
231                           const gchar  *title,
232                           const gchar  *role,
233                           const gchar  *icon_name,
234                           const gchar  *desc,
235                           GtkWidget    *parent,
236                           GimpHelpFunc  help_func,
237                           const gchar  *help_id,
238                           ...)
239 {
240   GimpViewableDialog *dialog;
241   va_list             args;
242 
243   g_return_val_if_fail (viewable == NULL || GIMP_IS_VIEWABLE (viewable), NULL);
244   g_return_val_if_fail (context == NULL || GIMP_IS_CONTEXT (context), NULL);
245   g_return_val_if_fail (title != NULL, NULL);
246   g_return_val_if_fail (role != NULL, NULL);
247   g_return_val_if_fail (parent == NULL || GTK_IS_WIDGET (parent), NULL);
248 
249   if (! viewable)
250     g_warning ("Use of GimpViewableDialog with a NULL viewable is deprecated!");
251 
252   dialog = g_object_new (GIMP_TYPE_VIEWABLE_DIALOG,
253                          "viewable",    viewable,
254                          "context",     context,
255                          "title",       title,
256                          "role",        role,
257                          "help-func",   help_func,
258                          "help-id",     help_id,
259                          "icon-name",   icon_name,
260                          "description", desc,
261                          "parent",      parent,
262                          NULL);
263 
264   va_start (args, help_id);
265   gimp_dialog_add_buttons_valist (GIMP_DIALOG (dialog), args);
266   va_end (args);
267 
268   return GTK_WIDGET (dialog);
269 }
270 
271 void
gimp_viewable_dialog_set_viewable(GimpViewableDialog * dialog,GimpViewable * viewable,GimpContext * context)272 gimp_viewable_dialog_set_viewable (GimpViewableDialog *dialog,
273                                    GimpViewable       *viewable,
274                                    GimpContext        *context)
275 {
276   g_return_if_fail (GIMP_IS_VIEWABLE_DIALOG (dialog));
277   g_return_if_fail (viewable == NULL || GIMP_IS_VIEWABLE (viewable));
278   g_return_if_fail (context == NULL || GIMP_IS_CONTEXT (context));
279 
280   dialog->context = context;
281 
282   if (dialog->view)
283     {
284       GimpViewable *old_viewable = GIMP_VIEW (dialog->view)->viewable;
285 
286       if (viewable == old_viewable)
287         {
288           gimp_view_renderer_set_context (GIMP_VIEW (dialog->view)->renderer,
289                                           context);
290           return;
291         }
292 
293       gtk_widget_destroy (dialog->view);
294 
295       if (old_viewable)
296         {
297           g_signal_handlers_disconnect_by_func (old_viewable,
298                                                 gimp_viewable_dialog_name_changed,
299                                                 dialog);
300 
301           g_signal_handlers_disconnect_by_func (old_viewable,
302                                                 gimp_viewable_dialog_close,
303                                                 dialog);
304         }
305     }
306 
307   if (viewable)
308     {
309       GtkWidget *box;
310 
311       g_signal_connect_object (viewable,
312                                GIMP_VIEWABLE_GET_CLASS (viewable)->name_changed_signal,
313                                G_CALLBACK (gimp_viewable_dialog_name_changed),
314                                dialog,
315                                0);
316 
317       box = gtk_widget_get_parent (dialog->icon);
318 
319       dialog->view = gimp_view_new (context, viewable, 32, 1, TRUE);
320       gtk_box_pack_end (GTK_BOX (box), dialog->view, FALSE, FALSE, 2);
321       gtk_widget_show (dialog->view);
322 
323       g_object_add_weak_pointer (G_OBJECT (dialog->view),
324                                  (gpointer) &dialog->view);
325 
326       gimp_viewable_dialog_name_changed (GIMP_OBJECT (viewable), dialog);
327 
328       if (GIMP_IS_ITEM (viewable))
329         {
330           g_signal_connect_object (viewable, "removed",
331                                    G_CALLBACK (gimp_viewable_dialog_close),
332                                    dialog,
333                                    G_CONNECT_SWAPPED);
334         }
335       else
336         {
337           g_signal_connect_object (viewable, "disconnect",
338                                    G_CALLBACK (gimp_viewable_dialog_close),
339                                    dialog,
340                                    G_CONNECT_SWAPPED);
341         }
342     }
343 }
344 
345 
346 /*  private functions  */
347 
348 static void
gimp_viewable_dialog_name_changed(GimpObject * object,GimpViewableDialog * dialog)349 gimp_viewable_dialog_name_changed (GimpObject         *object,
350                                    GimpViewableDialog *dialog)
351 {
352   gchar *name;
353 
354   name = gimp_viewable_get_description (GIMP_VIEWABLE (object), NULL);
355 
356   if (GIMP_IS_ITEM (object))
357     {
358       GimpImage *image = gimp_item_get_image (GIMP_ITEM (object));
359       gchar     *tmp;
360 
361       tmp = name;
362       name = g_strdup_printf ("%s-%d (%s)",
363                               tmp,
364                               gimp_item_get_ID (GIMP_ITEM (object)),
365                               gimp_image_get_display_name (image));
366       g_free (tmp);
367     }
368 
369   gtk_label_set_text (GTK_LABEL (dialog->viewable_label), name);
370   g_free (name);
371 }
372 
373 static void
gimp_viewable_dialog_close(GimpViewableDialog * dialog)374 gimp_viewable_dialog_close (GimpViewableDialog *dialog)
375 {
376   g_signal_emit_by_name (dialog, "close");
377 }
378