1 /* GIMP - The GNU Image Manipulation Program
2  * Copyright (C) 1995 Spencer Kimball and Peter Mattis
3  *
4  * gimpcontainerpopup.c
5  * Copyright (C) 2003-2014 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 #include <gdk/gdkkeysyms.h>
26 
27 #include "libgimpwidgets/gimpwidgets.h"
28 
29 #include "widgets-types.h"
30 
31 #include "core/gimp.h"
32 #include "core/gimpcontext.h"
33 #include "core/gimpcontainer.h"
34 #include "core/gimpviewable.h"
35 
36 #include "gimpcontainerbox.h"
37 #include "gimpcontainereditor.h"
38 #include "gimpcontainerpopup.h"
39 #include "gimpcontainertreeview.h"
40 #include "gimpcontainerview.h"
41 #include "gimpdialogfactory.h"
42 #include "gimpviewrenderer.h"
43 #include "gimpwidgets-utils.h"
44 #include "gimpwindowstrategy.h"
45 
46 #include "gimp-intl.h"
47 
48 
49 static void   gimp_container_popup_finalize         (GObject            *object);
50 
51 static void   gimp_container_popup_confirm          (GimpPopup          *popup);
52 
53 static void   gimp_container_popup_create_view      (GimpContainerPopup *popup);
54 
55 static void   gimp_container_popup_smaller_clicked  (GtkWidget          *button,
56                                                      GimpContainerPopup *popup);
57 static void   gimp_container_popup_larger_clicked   (GtkWidget          *button,
58                                                      GimpContainerPopup *popup);
59 static void   gimp_container_popup_view_type_toggled(GtkWidget          *button,
60                                                      GimpContainerPopup *popup);
61 static void   gimp_container_popup_dialog_clicked   (GtkWidget          *button,
62                                                      GimpContainerPopup *popup);
63 
64 
G_DEFINE_TYPE(GimpContainerPopup,gimp_container_popup,GIMP_TYPE_POPUP)65 G_DEFINE_TYPE (GimpContainerPopup, gimp_container_popup, GIMP_TYPE_POPUP)
66 
67 #define parent_class gimp_container_popup_parent_class
68 
69 
70 static void
71 gimp_container_popup_class_init (GimpContainerPopupClass *klass)
72 {
73   GObjectClass   *object_class = G_OBJECT_CLASS (klass);
74   GimpPopupClass *popup_class  = GIMP_POPUP_CLASS (klass);
75 
76   object_class->finalize = gimp_container_popup_finalize;
77 
78   popup_class->confirm   = gimp_container_popup_confirm;
79 }
80 
81 static void
gimp_container_popup_init(GimpContainerPopup * popup)82 gimp_container_popup_init (GimpContainerPopup *popup)
83 {
84   popup->view_type         = GIMP_VIEW_TYPE_LIST;
85   popup->default_view_size = GIMP_VIEW_SIZE_SMALL;
86   popup->view_size         = GIMP_VIEW_SIZE_SMALL;
87   popup->view_border_width = 1;
88 
89   popup->frame = gtk_frame_new (NULL);
90   gtk_frame_set_shadow_type (GTK_FRAME (popup->frame), GTK_SHADOW_OUT);
91   gtk_container_add (GTK_CONTAINER (popup), popup->frame);
92   gtk_widget_show (popup->frame);
93 }
94 
95 static void
gimp_container_popup_finalize(GObject * object)96 gimp_container_popup_finalize (GObject *object)
97 {
98   GimpContainerPopup *popup = GIMP_CONTAINER_POPUP (object);
99 
100   g_clear_object (&popup->context);
101 
102   g_clear_pointer (&popup->dialog_identifier, g_free);
103   g_clear_pointer (&popup->dialog_icon_name,  g_free);
104   g_clear_pointer (&popup->dialog_tooltip,    g_free);
105 
106   G_OBJECT_CLASS (parent_class)->finalize (object);
107 }
108 
109 static void
gimp_container_popup_confirm(GimpPopup * popup)110 gimp_container_popup_confirm (GimpPopup *popup)
111 {
112   GimpContainerPopup *c_popup = GIMP_CONTAINER_POPUP (popup);
113   GimpObject         *object;
114 
115   object = gimp_context_get_by_type (c_popup->context,
116                                      gimp_container_get_children_type (c_popup->container));
117   gimp_context_set_by_type (c_popup->orig_context,
118                             gimp_container_get_children_type (c_popup->container),
119                             object);
120 
121   GIMP_POPUP_CLASS (parent_class)->confirm (popup);
122 }
123 
124 static void
gimp_container_popup_context_changed(GimpContext * context,GimpViewable * viewable,GimpContainerPopup * popup)125 gimp_container_popup_context_changed (GimpContext        *context,
126                                       GimpViewable       *viewable,
127                                       GimpContainerPopup *popup)
128 {
129   GdkEvent *current_event;
130   gboolean  confirm = FALSE;
131 
132   current_event = gtk_get_current_event ();
133 
134   if (current_event)
135     {
136       if (((GdkEventAny *) current_event)->type == GDK_BUTTON_PRESS ||
137           ((GdkEventAny *) current_event)->type == GDK_BUTTON_RELEASE)
138         confirm = TRUE;
139 
140       gdk_event_free (current_event);
141     }
142 
143   if (confirm)
144     g_signal_emit_by_name (popup, "confirm");
145 }
146 
147 GtkWidget *
gimp_container_popup_new(GimpContainer * container,GimpContext * context,GimpViewType view_type,gint default_view_size,gint view_size,gint view_border_width,GimpDialogFactory * dialog_factory,const gchar * dialog_identifier,const gchar * dialog_icon_name,const gchar * dialog_tooltip)148 gimp_container_popup_new (GimpContainer     *container,
149                           GimpContext       *context,
150                           GimpViewType       view_type,
151                           gint               default_view_size,
152                           gint               view_size,
153                           gint               view_border_width,
154                           GimpDialogFactory *dialog_factory,
155                           const gchar       *dialog_identifier,
156                           const gchar       *dialog_icon_name,
157                           const gchar       *dialog_tooltip)
158 {
159   GimpContainerPopup *popup;
160 
161   g_return_val_if_fail (GIMP_IS_CONTAINER (container), NULL);
162   g_return_val_if_fail (GIMP_IS_CONTEXT (context), NULL);
163   g_return_val_if_fail (default_view_size >  0 &&
164                         default_view_size <= GIMP_VIEWABLE_MAX_POPUP_SIZE,
165                         NULL);
166   g_return_val_if_fail (view_size >  0 &&
167                         view_size <= GIMP_VIEWABLE_MAX_POPUP_SIZE, NULL);
168   g_return_val_if_fail (view_border_width >= 0 &&
169                         view_border_width <= GIMP_VIEW_MAX_BORDER_WIDTH,
170                         NULL);
171   g_return_val_if_fail (dialog_factory == NULL ||
172                         GIMP_IS_DIALOG_FACTORY (dialog_factory), NULL);
173   if (dialog_factory)
174     {
175       g_return_val_if_fail (dialog_identifier != NULL, NULL);
176       g_return_val_if_fail (dialog_icon_name != NULL, NULL);
177       g_return_val_if_fail (dialog_tooltip != NULL, NULL);
178     }
179 
180   popup = g_object_new (GIMP_TYPE_CONTAINER_POPUP,
181                         "type", GTK_WINDOW_POPUP,
182                         NULL);
183   gtk_window_set_resizable (GTK_WINDOW (popup), FALSE);
184 
185   popup->container    = container;
186   popup->orig_context = context;
187   popup->context      = gimp_context_new (context->gimp, "popup", context);
188 
189   popup->view_type         = view_type;
190   popup->default_view_size = default_view_size;
191   popup->view_size         = view_size;
192   popup->view_border_width = view_border_width;
193 
194   g_signal_connect (popup->context,
195                     gimp_context_type_to_signal_name (gimp_container_get_children_type (container)),
196                     G_CALLBACK (gimp_container_popup_context_changed),
197                     popup);
198 
199   if (dialog_factory)
200     {
201       popup->dialog_factory    = dialog_factory;
202       popup->dialog_identifier = g_strdup (dialog_identifier);
203       popup->dialog_icon_name  = g_strdup (dialog_icon_name);
204       popup->dialog_tooltip    = g_strdup (dialog_tooltip);
205     }
206 
207   gimp_container_popup_create_view (popup);
208 
209   return GTK_WIDGET (popup);
210 }
211 
212 GimpViewType
gimp_container_popup_get_view_type(GimpContainerPopup * popup)213 gimp_container_popup_get_view_type (GimpContainerPopup *popup)
214 {
215   g_return_val_if_fail (GIMP_IS_CONTAINER_POPUP (popup), GIMP_VIEW_TYPE_LIST);
216 
217   return popup->view_type;
218 }
219 
220 void
gimp_container_popup_set_view_type(GimpContainerPopup * popup,GimpViewType view_type)221 gimp_container_popup_set_view_type (GimpContainerPopup *popup,
222                                     GimpViewType        view_type)
223 {
224   g_return_if_fail (GIMP_IS_CONTAINER_POPUP (popup));
225 
226   if (view_type != popup->view_type)
227     {
228       popup->view_type = view_type;
229 
230       gtk_widget_destroy (GTK_WIDGET (popup->editor));
231       gimp_container_popup_create_view (popup);
232     }
233 }
234 
235 gint
gimp_container_popup_get_view_size(GimpContainerPopup * popup)236 gimp_container_popup_get_view_size (GimpContainerPopup *popup)
237 {
238   g_return_val_if_fail (GIMP_IS_CONTAINER_POPUP (popup), GIMP_VIEW_SIZE_SMALL);
239 
240   return popup->view_size;
241 }
242 
243 void
gimp_container_popup_set_view_size(GimpContainerPopup * popup,gint view_size)244 gimp_container_popup_set_view_size (GimpContainerPopup *popup,
245                                     gint                view_size)
246 {
247   GtkWidget     *scrolled_win;
248   GtkWidget     *viewport;
249   GtkAllocation  allocation;
250 
251   g_return_if_fail (GIMP_IS_CONTAINER_POPUP (popup));
252 
253   scrolled_win = GIMP_CONTAINER_BOX (popup->editor->view)->scrolled_win;
254   viewport     = gtk_bin_get_child (GTK_BIN (scrolled_win));
255 
256   gtk_widget_get_allocation (viewport, &allocation);
257 
258   view_size = CLAMP (view_size, GIMP_VIEW_SIZE_TINY,
259                      MIN (GIMP_VIEW_SIZE_GIGANTIC,
260                           allocation.width - 2 * popup->view_border_width));
261 
262   if (view_size != popup->view_size)
263     {
264       popup->view_size = view_size;
265 
266       gimp_container_view_set_view_size (popup->editor->view,
267                                          popup->view_size,
268                                          popup->view_border_width);
269     }
270 }
271 
272 
273 /*  private functions  */
274 
275 static void
gimp_container_popup_create_view(GimpContainerPopup * popup)276 gimp_container_popup_create_view (GimpContainerPopup *popup)
277 {
278   GimpEditor *editor;
279   GtkWidget  *button;
280   gint        rows;
281   gint        columns;
282 
283   popup->editor = g_object_new (GIMP_TYPE_CONTAINER_EDITOR,
284                                 "view-type",         popup->view_type,
285                                 "container",         popup->container,
286                                 "context",           popup->context,
287                                 "view-size",         popup->view_size,
288                                 "view-border-width", popup->view_border_width,
289                                 NULL);
290 
291   gimp_container_view_set_reorderable (GIMP_CONTAINER_VIEW (popup->editor->view),
292                                        FALSE);
293 
294   if (popup->view_type == GIMP_VIEW_TYPE_LIST)
295     {
296       GtkWidget *search_entry;
297 
298       search_entry = gtk_entry_new ();
299       gtk_box_pack_end (GTK_BOX (popup->editor->view), search_entry,
300                         FALSE, FALSE, 0);
301       gtk_tree_view_set_search_entry (GTK_TREE_VIEW (GIMP_CONTAINER_TREE_VIEW (GIMP_CONTAINER_VIEW (popup->editor->view))->view),
302                                       GTK_ENTRY (search_entry));
303       gtk_widget_show (search_entry);
304     }
305 
306   /* lame workaround for bug #761998 */
307   if (popup->default_view_size >= GIMP_VIEW_SIZE_LARGE)
308     {
309       rows    = 6;
310       columns = 6;
311     }
312   else
313     {
314       rows    = 10;
315       columns = 6;
316     }
317 
318   gimp_container_box_set_size_request (GIMP_CONTAINER_BOX (popup->editor->view),
319                                        columns * (popup->default_view_size +
320                                                   2 * popup->view_border_width),
321                                        rows    * (popup->default_view_size +
322                                                   2 * popup->view_border_width));
323 
324   if (GIMP_IS_EDITOR (popup->editor->view))
325     gimp_editor_set_show_name (GIMP_EDITOR (popup->editor->view), FALSE);
326 
327   gtk_container_add (GTK_CONTAINER (popup->frame), GTK_WIDGET (popup->editor));
328   gtk_widget_show (GTK_WIDGET (popup->editor));
329 
330   editor = GIMP_EDITOR (popup->editor->view);
331 
332   gimp_editor_add_button (editor, "zoom-out",
333                           _("Smaller Previews"), NULL,
334                           G_CALLBACK (gimp_container_popup_smaller_clicked),
335                           NULL,
336                           popup);
337   gimp_editor_add_button (editor, "zoom-in",
338                           _("Larger Previews"), NULL,
339                           G_CALLBACK (gimp_container_popup_larger_clicked),
340                           NULL,
341                           popup);
342 
343   button = gimp_editor_add_icon_box (editor, GIMP_TYPE_VIEW_TYPE, "gimp",
344                                      G_CALLBACK (gimp_container_popup_view_type_toggled),
345                                      popup);
346   gimp_int_radio_group_set_active (GTK_RADIO_BUTTON (button), popup->view_type);
347 
348   if (popup->dialog_factory)
349     gimp_editor_add_button (editor, popup->dialog_icon_name,
350                             popup->dialog_tooltip, NULL,
351                             G_CALLBACK (gimp_container_popup_dialog_clicked),
352                             NULL,
353                             popup);
354 
355   gtk_widget_grab_focus (GTK_WIDGET (popup->editor));
356 }
357 
358 static void
gimp_container_popup_smaller_clicked(GtkWidget * button,GimpContainerPopup * popup)359 gimp_container_popup_smaller_clicked (GtkWidget          *button,
360                                       GimpContainerPopup *popup)
361 {
362   gint view_size;
363 
364   view_size = gimp_container_view_get_view_size (popup->editor->view, NULL);
365 
366   gimp_container_popup_set_view_size (popup, view_size * 0.8);
367 }
368 
369 static void
gimp_container_popup_larger_clicked(GtkWidget * button,GimpContainerPopup * popup)370 gimp_container_popup_larger_clicked (GtkWidget          *button,
371                                      GimpContainerPopup *popup)
372 {
373   gint view_size;
374 
375   view_size = gimp_container_view_get_view_size (popup->editor->view, NULL);
376 
377   gimp_container_popup_set_view_size (popup, view_size * 1.2);
378 }
379 
380 static void
gimp_container_popup_view_type_toggled(GtkWidget * button,GimpContainerPopup * popup)381 gimp_container_popup_view_type_toggled (GtkWidget          *button,
382                                         GimpContainerPopup *popup)
383 {
384   if (gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (button)))
385     {
386       GimpViewType view_type;
387 
388       view_type = GPOINTER_TO_INT (g_object_get_data (G_OBJECT (button),
389                                                       "gimp-item-data"));
390 
391       gimp_container_popup_set_view_type (popup, view_type);
392     }
393 }
394 
395 static void
gimp_container_popup_dialog_clicked(GtkWidget * button,GimpContainerPopup * popup)396 gimp_container_popup_dialog_clicked (GtkWidget          *button,
397                                      GimpContainerPopup *popup)
398 {
399   gimp_window_strategy_show_dockable_dialog (GIMP_WINDOW_STRATEGY (gimp_get_window_strategy (popup->context->gimp)),
400                                              popup->context->gimp,
401                                              popup->dialog_factory,
402                                              gtk_widget_get_screen (button),
403                                              gimp_widget_get_monitor (button),
404                                              popup->dialog_identifier);
405   g_signal_emit_by_name (popup, "confirm");
406 }
407