1 /* GIMP - The GNU Image Manipulation Program
2  * Copyright (C) 1995 Spencer Kimball and Peter Mattis
3  *
4  * gimptoolgui.c
5  * Copyright (C) 2013  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 "display-types.h"
29 
30 #include "core/gimpcontext.h"
31 #include "core/gimpmarshal.h"
32 #include "core/gimptoolinfo.h"
33 
34 #include "widgets/gimpdialogfactory.h"
35 #include "widgets/gimpoverlaybox.h"
36 #include "widgets/gimpoverlaydialog.h"
37 #include "widgets/gimpwidgets-utils.h"
38 
39 #include "gimpdisplayshell.h"
40 #include "gimptooldialog.h"
41 #include "gimptoolgui.h"
42 
43 
44 enum
45 {
46   RESPONSE,
47   LAST_SIGNAL
48 };
49 
50 
51 typedef struct _ResponseEntry ResponseEntry;
52 
53 struct _ResponseEntry
54 {
55   gint      response_id;
56   gchar    *button_text;
57   gint      alternative_position;
58   gboolean  sensitive;
59 };
60 
61 typedef struct _GimpToolGuiPrivate GimpToolGuiPrivate;
62 
63 struct _GimpToolGuiPrivate
64 {
65   GimpToolInfo     *tool_info;
66   gchar            *title;
67   gchar            *description;
68   gchar            *icon_name;
69   gchar            *help_id;
70   GList            *response_entries;
71   gint              default_response;
72   gboolean          focus_on_map;
73 
74   gboolean          overlay;
75   gboolean          auto_overlay;
76 
77   GimpDisplayShell *shell;
78   GimpViewable     *viewable;
79 
80   GtkWidget        *dialog;
81   GtkWidget        *vbox;
82 };
83 
84 #define GET_PRIVATE(gui) ((GimpToolGuiPrivate *) gimp_tool_gui_get_instance_private ((GimpToolGui *) (gui)))
85 
86 
87 static void            gimp_tool_gui_dispose           (GObject       *object);
88 static void            gimp_tool_gui_finalize          (GObject       *object);
89 
90 static void            gimp_tool_gui_create_dialog     (GimpToolGui   *gui,
91                                                         GdkScreen     *screen,
92                                                         gint           monitor);
93 static void            gimp_tool_gui_add_dialog_button (GimpToolGui   *gui,
94                                                         ResponseEntry *entry);
95 static void            gimp_tool_gui_update_buttons    (GimpToolGui   *gui);
96 static void            gimp_tool_gui_update_shell      (GimpToolGui   *gui);
97 static void            gimp_tool_gui_update_viewable   (GimpToolGui   *gui);
98 
99 static void            gimp_tool_gui_dialog_response   (GtkWidget     *dialog,
100                                                         gint           response_id,
101                                                         GimpToolGui   *gui);
102 static void            gimp_tool_gui_canvas_resized    (GtkWidget     *canvas,
103                                                         GtkAllocation *allocation,
104                                                         GimpToolGui   *gui);
105 
106 static ResponseEntry * response_entry_new              (gint           response_id,
107                                                         const gchar   *button_text);
108 static void            response_entry_free             (ResponseEntry *entry);
109 static ResponseEntry * response_entry_find             (GList         *entries,
110                                                         gint           response_id);
111 
112 
113 G_DEFINE_TYPE_WITH_PRIVATE (GimpToolGui, gimp_tool_gui, GIMP_TYPE_OBJECT)
114 
115 static guint signals[LAST_SIGNAL] = { 0, };
116 
117 #define parent_class gimp_tool_gui_parent_class
118 
119 
120 static void
gimp_tool_gui_class_init(GimpToolGuiClass * klass)121 gimp_tool_gui_class_init (GimpToolGuiClass *klass)
122 {
123   GObjectClass *object_class = G_OBJECT_CLASS (klass);
124 
125   object_class->dispose  = gimp_tool_gui_dispose;
126   object_class->finalize = gimp_tool_gui_finalize;
127 
128   signals[RESPONSE] =
129     g_signal_new ("response",
130                   G_OBJECT_CLASS_TYPE (klass),
131                   G_SIGNAL_RUN_LAST,
132                   G_STRUCT_OFFSET (GimpToolGuiClass, response),
133                   NULL, NULL,
134                   gimp_marshal_VOID__INT,
135                   G_TYPE_NONE, 1,
136                   G_TYPE_INT);
137 }
138 
139 static void
gimp_tool_gui_init(GimpToolGui * gui)140 gimp_tool_gui_init (GimpToolGui *gui)
141 {
142   GimpToolGuiPrivate *private = GET_PRIVATE (gui);
143 
144   private->default_response = -1;
145   private->focus_on_map     = TRUE;
146 
147   private->vbox = gtk_box_new (GTK_ORIENTATION_VERTICAL, 6);
148   g_object_ref_sink (private->vbox);
149 }
150 
151 static void
gimp_tool_gui_dispose(GObject * object)152 gimp_tool_gui_dispose (GObject *object)
153 {
154   GimpToolGuiPrivate *private = GET_PRIVATE (object);
155 
156   g_clear_object (&private->tool_info);
157 
158   if (private->shell)
159     gimp_tool_gui_set_shell (GIMP_TOOL_GUI (object), NULL);
160 
161   if (private->viewable)
162     gimp_tool_gui_set_viewable (GIMP_TOOL_GUI (object), NULL);
163 
164   g_clear_object (&private->vbox);
165 
166   if (private->dialog)
167     {
168       if (gtk_widget_get_visible (private->dialog))
169         gimp_tool_gui_hide (GIMP_TOOL_GUI (object));
170 
171       if (private->overlay)
172         g_object_unref (private->dialog);
173       else
174         gtk_widget_destroy (private->dialog);
175 
176       private->dialog = NULL;
177     }
178 
179   G_OBJECT_CLASS (parent_class)->dispose (object);
180 }
181 
182 static void
gimp_tool_gui_finalize(GObject * object)183 gimp_tool_gui_finalize (GObject *object)
184 {
185   GimpToolGuiPrivate *private = GET_PRIVATE (object);
186 
187   g_clear_pointer (&private->title,       g_free);
188   g_clear_pointer (&private->description, g_free);
189   g_clear_pointer (&private->icon_name,   g_free);
190   g_clear_pointer (&private->help_id,     g_free);
191 
192   if (private->response_entries)
193     {
194       g_list_free_full (private->response_entries,
195                         (GDestroyNotify) response_entry_free);
196       private->response_entries = NULL;
197     }
198 
199   G_OBJECT_CLASS (parent_class)->finalize (object);
200 }
201 
202 
203 /**
204  * gimp_tool_gui_new:
205  * @tool_info:   a #GimpToolInfo
206  * @description: a string to use in the gui header or %NULL to use the help
207  *               field from #GimpToolInfo
208  * @...:         a %NULL-terminated valist of button parameters as described in
209  *               gtk_gui_new_with_buttons().
210  *
211  * This function creates a #GimpToolGui using the information stored
212  * in @tool_info.
213  *
214  * Return value: a new #GimpToolGui
215  **/
216 GimpToolGui *
gimp_tool_gui_new(GimpToolInfo * tool_info,const gchar * title,const gchar * description,const gchar * icon_name,const gchar * help_id,GdkScreen * screen,gint monitor,gboolean overlay,...)217 gimp_tool_gui_new (GimpToolInfo *tool_info,
218                    const gchar  *title,
219                    const gchar  *description,
220                    const gchar  *icon_name,
221                    const gchar  *help_id,
222                    GdkScreen    *screen,
223                    gint          monitor,
224                    gboolean      overlay,
225                    ...)
226 {
227   GimpToolGui        *gui;
228   GimpToolGuiPrivate *private;
229   va_list             args;
230 
231   g_return_val_if_fail (GIMP_IS_TOOL_INFO (tool_info), NULL);
232 
233   gui = g_object_new (GIMP_TYPE_TOOL_GUI, NULL);
234 
235   private = GET_PRIVATE (gui);
236 
237   if (! title)
238     title = tool_info->label;
239 
240   if (! description)
241     description = tool_info->label;
242 
243   if (! icon_name)
244     icon_name = gimp_viewable_get_icon_name (GIMP_VIEWABLE (tool_info));
245 
246   if (! help_id)
247     help_id = tool_info->help_id;
248 
249   private->tool_info   = g_object_ref (tool_info);
250   private->title       = g_strdup (title);
251   private->description = g_strdup (description);
252   private->icon_name   = g_strdup (icon_name);
253   private->help_id     = g_strdup (help_id);
254   private->overlay     = overlay;
255 
256   va_start (args, overlay);
257 
258   gimp_tool_gui_add_buttons_valist (gui, args);
259 
260   va_end (args);
261 
262   gimp_tool_gui_create_dialog (gui, screen, monitor);
263 
264   return gui;
265 }
266 
267 void
gimp_tool_gui_set_title(GimpToolGui * gui,const gchar * title)268 gimp_tool_gui_set_title (GimpToolGui *gui,
269                          const gchar *title)
270 {
271   GimpToolGuiPrivate *private;
272 
273   g_return_if_fail (GIMP_IS_TOOL_GUI (gui));
274 
275   private = GET_PRIVATE (gui);
276 
277   if (title == private->title)
278     return;
279 
280   g_free (private->title);
281   private->title = g_strdup (title);
282 
283   if (! title)
284     title = private->tool_info->label;
285 
286   g_object_set (private->dialog, "title", title, NULL);
287 }
288 
289 void
gimp_tool_gui_set_description(GimpToolGui * gui,const gchar * description)290 gimp_tool_gui_set_description (GimpToolGui *gui,
291                                const gchar *description)
292 {
293   GimpToolGuiPrivate *private;
294 
295   g_return_if_fail (GIMP_IS_TOOL_GUI (gui));
296 
297   private = GET_PRIVATE (gui);
298 
299   if (description == private->description)
300     return;
301 
302   g_free (private->description);
303   private->description = g_strdup (description);
304 
305   if (! description)
306     description = private->tool_info->tooltip;
307 
308   if (private->overlay)
309     {
310       /* TODO */
311     }
312   else
313     {
314       g_object_set (private->dialog, "description", description, NULL);
315     }
316 }
317 
318 void
gimp_tool_gui_set_icon_name(GimpToolGui * gui,const gchar * icon_name)319 gimp_tool_gui_set_icon_name (GimpToolGui *gui,
320                              const gchar *icon_name)
321 {
322   GimpToolGuiPrivate *private;
323 
324   g_return_if_fail (GIMP_IS_TOOL_GUI (gui));
325 
326   private = GET_PRIVATE (gui);
327 
328   if (icon_name == private->icon_name)
329     return;
330 
331   g_free (private->icon_name);
332   private->icon_name = g_strdup (icon_name);
333 
334   if (! icon_name)
335     icon_name = gimp_viewable_get_icon_name (GIMP_VIEWABLE (private->tool_info));
336 
337   g_object_set (private->dialog, "icon-name", icon_name, NULL);
338 }
339 
340 void
gimp_tool_gui_set_help_id(GimpToolGui * gui,const gchar * help_id)341 gimp_tool_gui_set_help_id (GimpToolGui *gui,
342                            const gchar *help_id)
343 {
344   GimpToolGuiPrivate *private;
345 
346   g_return_if_fail (GIMP_IS_TOOL_GUI (gui));
347 
348   private = GET_PRIVATE (gui);
349 
350   if (help_id == private->help_id)
351     return;
352 
353   g_free (private->help_id);
354   private->help_id = g_strdup (help_id);
355 
356   if (! help_id)
357     help_id = private->tool_info->help_id;
358 
359   if (private->overlay)
360     {
361       /* TODO */
362     }
363   else
364     {
365       g_object_set (private->dialog, "help-id", help_id, NULL);
366     }
367 }
368 
369 void
gimp_tool_gui_set_shell(GimpToolGui * gui,GimpDisplayShell * shell)370 gimp_tool_gui_set_shell (GimpToolGui      *gui,
371                          GimpDisplayShell *shell)
372 {
373   GimpToolGuiPrivate *private;
374 
375   g_return_if_fail (GIMP_IS_TOOL_GUI (gui));
376   g_return_if_fail (shell == NULL || GIMP_IS_DISPLAY_SHELL (shell));
377 
378   private = GET_PRIVATE (gui);
379 
380   if (shell == private->shell)
381     return;
382 
383   if (private->shell)
384     {
385       g_object_remove_weak_pointer (G_OBJECT (private->shell),
386                                     (gpointer) &private->shell);
387       g_signal_handlers_disconnect_by_func (private->shell->canvas,
388                                             gimp_tool_gui_canvas_resized,
389                                             gui);
390     }
391 
392   private->shell = shell;
393 
394   if (private->shell)
395     {
396       g_signal_connect (private->shell->canvas, "size-allocate",
397                         G_CALLBACK (gimp_tool_gui_canvas_resized),
398                         gui);
399       g_object_add_weak_pointer (G_OBJECT (private->shell),
400                                  (gpointer) &private->shell);
401     }
402 
403   gimp_tool_gui_update_shell (gui);
404 }
405 
406 void
gimp_tool_gui_set_viewable(GimpToolGui * gui,GimpViewable * viewable)407 gimp_tool_gui_set_viewable (GimpToolGui  *gui,
408                             GimpViewable *viewable)
409 {
410   GimpToolGuiPrivate *private;
411 
412   g_return_if_fail (GIMP_IS_TOOL_GUI (gui));
413   g_return_if_fail (viewable == NULL || GIMP_IS_VIEWABLE (viewable));
414 
415   private = GET_PRIVATE (gui);
416 
417   if (private->viewable == viewable)
418     return;
419 
420   if (private->viewable)
421     g_object_remove_weak_pointer (G_OBJECT (private->viewable),
422                                   (gpointer) &private->viewable);
423 
424   private->viewable = viewable;
425 
426   if (private->viewable)
427     g_object_add_weak_pointer (G_OBJECT (private->viewable),
428                                (gpointer) &private->viewable);
429 
430   gimp_tool_gui_update_viewable (gui);
431 }
432 
433 GtkWidget *
gimp_tool_gui_get_dialog(GimpToolGui * gui)434 gimp_tool_gui_get_dialog (GimpToolGui *gui)
435 {
436   g_return_val_if_fail (GIMP_IS_TOOL_GUI (gui), NULL);
437 
438   return GET_PRIVATE (gui)->dialog;
439 }
440 
441 GtkWidget *
gimp_tool_gui_get_vbox(GimpToolGui * gui)442 gimp_tool_gui_get_vbox (GimpToolGui *gui)
443 {
444   g_return_val_if_fail (GIMP_IS_TOOL_GUI (gui), NULL);
445 
446   return GET_PRIVATE (gui)->vbox;
447 }
448 
449 gboolean
gimp_tool_gui_get_visible(GimpToolGui * gui)450 gimp_tool_gui_get_visible (GimpToolGui *gui)
451 {
452   GimpToolGuiPrivate *private;
453 
454   g_return_val_if_fail (GIMP_IS_TOOL_GUI (gui), FALSE);
455 
456   private = GET_PRIVATE (gui);
457 
458   if (private->overlay)
459     return gtk_widget_get_parent (private->dialog) != NULL;
460   else
461     return gtk_widget_get_visible (private->dialog);
462 }
463 
464 void
gimp_tool_gui_show(GimpToolGui * gui)465 gimp_tool_gui_show (GimpToolGui *gui)
466 {
467   GimpToolGuiPrivate *private;
468 
469   g_return_if_fail (GIMP_IS_TOOL_GUI (gui));
470 
471   private = GET_PRIVATE (gui);
472 
473   g_return_if_fail (private->shell != NULL);
474 
475   if (private->overlay)
476     {
477       if (! gtk_widget_get_parent (private->dialog))
478         {
479           gimp_overlay_box_add_child (GIMP_OVERLAY_BOX (private->shell->canvas),
480                                       private->dialog, 1.0, 0.0);
481           gtk_widget_show (private->dialog);
482         }
483     }
484   else
485     {
486       if (gtk_widget_get_visible (private->dialog))
487         gdk_window_show (gtk_widget_get_window (private->dialog));
488       else
489         gtk_widget_show (private->dialog);
490     }
491 }
492 
493 void
gimp_tool_gui_hide(GimpToolGui * gui)494 gimp_tool_gui_hide (GimpToolGui *gui)
495 {
496   GimpToolGuiPrivate *private;
497 
498   g_return_if_fail (GIMP_IS_TOOL_GUI (gui));
499 
500   private = GET_PRIVATE (gui);
501 
502   if (private->overlay)
503     {
504       if (gtk_widget_get_parent (private->dialog))
505         {
506           gtk_container_remove (GTK_CONTAINER (gtk_widget_get_parent (private->dialog)),
507                                 private->dialog);
508           gtk_widget_hide (private->dialog);
509         }
510     }
511   else
512     {
513       if (gimp_dialog_factory_from_widget (private->dialog, NULL))
514         {
515           gimp_dialog_factory_hide_dialog (private->dialog);
516         }
517       else
518         {
519           gtk_widget_hide (private->dialog);
520         }
521     }
522 }
523 
524 void
gimp_tool_gui_set_overlay(GimpToolGui * gui,GdkScreen * screen,gint monitor,gboolean overlay)525 gimp_tool_gui_set_overlay (GimpToolGui *gui,
526                            GdkScreen   *screen,
527                            gint         monitor,
528                            gboolean     overlay)
529 {
530   GimpToolGuiPrivate *private;
531   gboolean            visible;
532 
533   g_return_if_fail (GIMP_IS_TOOL_GUI (gui));
534 
535   private = GET_PRIVATE (gui);
536 
537   if (private->overlay == overlay)
538     return;
539 
540   if (! private->dialog)
541     {
542       private->overlay = overlay;
543       return;
544     }
545 
546   visible = gtk_widget_get_visible (private->dialog);
547 
548   if (visible)
549     gimp_tool_gui_hide (gui);
550 
551   gtk_container_remove (GTK_CONTAINER (gtk_widget_get_parent (private->vbox)),
552                         private->vbox);
553 
554   if (private->overlay)
555     g_object_unref (private->dialog);
556   else
557     gtk_widget_destroy (private->dialog);
558 
559   private->overlay = overlay;
560 
561   gimp_tool_gui_create_dialog (gui, screen, monitor);
562 
563   if (visible)
564     gimp_tool_gui_show (gui);
565 }
566 
567 gboolean
gimp_tool_gui_get_overlay(GimpToolGui * gui)568 gimp_tool_gui_get_overlay (GimpToolGui *gui)
569 {
570   g_return_val_if_fail (GIMP_IS_TOOL_GUI (gui), FALSE);
571 
572   return GET_PRIVATE (gui)->overlay;
573 }
574 
575 void
gimp_tool_gui_set_auto_overlay(GimpToolGui * gui,gboolean auto_overlay)576 gimp_tool_gui_set_auto_overlay (GimpToolGui *gui,
577                                 gboolean     auto_overlay)
578 {
579   GimpToolGuiPrivate *private;
580 
581   g_return_if_fail (GIMP_IS_TOOL_GUI (gui));
582 
583   private = GET_PRIVATE (gui);
584 
585   if (private->auto_overlay != auto_overlay)
586     {
587       private->auto_overlay = auto_overlay;
588 
589       if (private->shell)
590         gimp_tool_gui_canvas_resized (private->shell->canvas, NULL, gui);
591     }
592 }
593 
594 gboolean
gimp_tool_gui_get_auto_overlay(GimpToolGui * gui)595 gimp_tool_gui_get_auto_overlay (GimpToolGui *gui)
596 {
597   g_return_val_if_fail (GIMP_IS_TOOL_GUI (gui), FALSE);
598 
599   return GET_PRIVATE (gui)->auto_overlay;
600 }
601 
602 void
gimp_tool_gui_set_focus_on_map(GimpToolGui * gui,gboolean focus_on_map)603 gimp_tool_gui_set_focus_on_map (GimpToolGui *gui,
604                                 gboolean     focus_on_map)
605 {
606   GimpToolGuiPrivate *private;
607 
608   g_return_if_fail (GIMP_IS_TOOL_GUI (gui));
609 
610   private = GET_PRIVATE (gui);
611 
612   if (private->focus_on_map == focus_on_map)
613     return;
614 
615   private->focus_on_map = focus_on_map ? TRUE : FALSE;
616 
617   if (! private->overlay)
618     {
619       gtk_window_set_focus_on_map (GTK_WINDOW (private->dialog),
620                                    private->focus_on_map);
621     }
622 }
623 
624 gboolean
gimp_tool_gui_get_focus_on_map(GimpToolGui * gui)625 gimp_tool_gui_get_focus_on_map (GimpToolGui *gui)
626 {
627   g_return_val_if_fail (GIMP_IS_TOOL_GUI (gui), FALSE);
628 
629   return GET_PRIVATE (gui)->focus_on_map;
630 }
631 
632 void
gimp_tool_gui_add_buttons_valist(GimpToolGui * gui,va_list args)633 gimp_tool_gui_add_buttons_valist (GimpToolGui *gui,
634                                   va_list      args)
635 {
636   const gchar *button_text;
637   gint         response_id;
638 
639   g_return_if_fail (GIMP_IS_TOOL_GUI (gui));
640 
641   while ((button_text = va_arg (args, const gchar *)))
642     {
643       response_id = va_arg (args, gint);
644 
645       gimp_tool_gui_add_button (gui, button_text, response_id);
646     }
647 }
648 
649 void
gimp_tool_gui_add_button(GimpToolGui * gui,const gchar * button_text,gint response_id)650 gimp_tool_gui_add_button (GimpToolGui *gui,
651                           const gchar *button_text,
652                           gint         response_id)
653 {
654   GimpToolGuiPrivate *private;
655   ResponseEntry     *entry;
656 
657   g_return_if_fail (GIMP_IS_TOOL_GUI (gui));
658   g_return_if_fail (button_text != NULL);
659 
660   private = GET_PRIVATE (gui);
661 
662   entry = response_entry_new (response_id, button_text);
663 
664   private->response_entries = g_list_append (private->response_entries,
665                                              entry);
666 
667   if (private->dialog)
668     gimp_tool_gui_add_dialog_button (gui, entry);
669 }
670 
671 void
gimp_tool_gui_set_default_response(GimpToolGui * gui,gint response_id)672 gimp_tool_gui_set_default_response (GimpToolGui *gui,
673                                     gint         response_id)
674 {
675   GimpToolGuiPrivate *private;
676 
677   g_return_if_fail (GIMP_IS_TOOL_GUI (gui));
678 
679   private = GET_PRIVATE (gui);
680 
681   g_return_if_fail (response_entry_find (private->response_entries,
682                                          response_id) != NULL);
683 
684   private->default_response = response_id;
685 
686   if (private->overlay)
687     {
688       gimp_overlay_dialog_set_default_response (GIMP_OVERLAY_DIALOG (private->dialog),
689                                                 response_id);
690     }
691   else
692     {
693       gtk_dialog_set_default_response (GTK_DIALOG (private->dialog),
694                                        response_id);
695     }
696 }
697 
698 void
gimp_tool_gui_set_response_sensitive(GimpToolGui * gui,gint response_id,gboolean sensitive)699 gimp_tool_gui_set_response_sensitive (GimpToolGui *gui,
700                                       gint         response_id,
701                                       gboolean     sensitive)
702 {
703   GimpToolGuiPrivate *private;
704   ResponseEntry      *entry;
705 
706   g_return_if_fail (GIMP_IS_TOOL_GUI (gui));
707 
708   private = GET_PRIVATE (gui);
709 
710   entry = response_entry_find (private->response_entries, response_id);
711 
712   if (! entry)
713     return;
714 
715   entry->sensitive = sensitive;
716 
717   if (private->overlay)
718     {
719       gimp_overlay_dialog_set_response_sensitive (GIMP_OVERLAY_DIALOG (private->dialog),
720                                                   response_id, sensitive);
721     }
722   else
723     {
724       gtk_dialog_set_response_sensitive (GTK_DIALOG (private->dialog),
725                                          response_id, sensitive);
726     }
727 }
728 
729 void
gimp_tool_gui_set_alternative_button_order(GimpToolGui * gui,...)730 gimp_tool_gui_set_alternative_button_order (GimpToolGui *gui,
731                                             ...)
732 {
733   GimpToolGuiPrivate *private;
734   va_list             args;
735   gint                response_id;
736   gint                i;
737 
738   g_return_if_fail (GIMP_IS_TOOL_GUI (gui));
739 
740   private = GET_PRIVATE (gui);
741 
742   va_start (args, gui);
743 
744   for (response_id = va_arg (args, gint), i = 0;
745        response_id != -1;
746        response_id = va_arg (args, gint), i++)
747     {
748       ResponseEntry *entry = response_entry_find (private->response_entries,
749                                                   response_id);
750 
751       if (entry)
752         entry->alternative_position = i;
753     }
754 
755   va_end (args);
756 
757   gimp_tool_gui_update_buttons (gui);
758 }
759 
760 
761 /*  private functions  */
762 
763 static void
gimp_tool_gui_create_dialog(GimpToolGui * gui,GdkScreen * screen,gint monitor)764 gimp_tool_gui_create_dialog (GimpToolGui *gui,
765                              GdkScreen   *screen,
766                              gint         monitor)
767 {
768   GimpToolGuiPrivate *private = GET_PRIVATE (gui);
769   GList              *list;
770 
771   if (private->overlay)
772     {
773       private->dialog = gimp_overlay_dialog_new (private->tool_info,
774                                                  private->description,
775                                                  NULL);
776       g_object_ref_sink (private->dialog);
777 
778       for (list = private->response_entries; list; list = g_list_next (list))
779         {
780           ResponseEntry *entry = list->data;
781 
782           gimp_tool_gui_add_dialog_button (gui, entry);
783         }
784 
785       if (private->default_response != -1)
786         gimp_overlay_dialog_set_default_response (GIMP_OVERLAY_DIALOG (private->dialog),
787                                                   private->default_response);
788 
789       gtk_container_set_border_width (GTK_CONTAINER (private->dialog), 6);
790 
791       gtk_container_set_border_width (GTK_CONTAINER (private->vbox), 0);
792       gtk_container_add (GTK_CONTAINER (private->dialog), private->vbox);
793       gtk_widget_show (private->vbox);
794     }
795   else
796     {
797       private->dialog = gimp_tool_dialog_new (private->tool_info,
798                                               screen, monitor,
799                                               private->title,
800                                               private->description,
801                                               private->icon_name,
802                                               private->help_id,
803                                               NULL);
804 
805       for (list = private->response_entries; list; list = g_list_next (list))
806         {
807           ResponseEntry *entry = list->data;
808 
809           gimp_tool_gui_add_dialog_button (gui, entry);
810         }
811 
812       if (private->default_response != -1)
813         gtk_dialog_set_default_response (GTK_DIALOG (private->dialog),
814                                          private->default_response);
815 
816       gtk_window_set_focus_on_map (GTK_WINDOW (private->dialog),
817                                    private->focus_on_map);
818 
819       gtk_container_set_border_width (GTK_CONTAINER (private->vbox), 6);
820       gtk_box_pack_start (GTK_BOX (gtk_dialog_get_content_area (GTK_DIALOG (private->dialog))),
821                           private->vbox, TRUE, TRUE, 0);
822       gtk_widget_show (private->vbox);
823     }
824 
825   gimp_tool_gui_update_buttons (gui);
826 
827   if (private->shell)
828     gimp_tool_gui_update_shell (gui);
829 
830   if (private->viewable)
831     gimp_tool_gui_update_viewable (gui);
832 
833   g_signal_connect_object (private->dialog, "response",
834                            G_CALLBACK (gimp_tool_gui_dialog_response),
835                            G_OBJECT (gui), 0);
836 }
837 
838 static void
gimp_tool_gui_add_dialog_button(GimpToolGui * gui,ResponseEntry * entry)839 gimp_tool_gui_add_dialog_button (GimpToolGui   *gui,
840                                  ResponseEntry *entry)
841 {
842   GimpToolGuiPrivate *private = GET_PRIVATE (gui);
843 
844   if (private->overlay)
845     {
846       gimp_overlay_dialog_add_button (GIMP_OVERLAY_DIALOG (private->dialog),
847                                       entry->button_text,
848                                       entry->response_id);
849 
850       if (! entry->sensitive)
851         {
852           gimp_overlay_dialog_set_response_sensitive (
853             GIMP_OVERLAY_DIALOG (private->dialog),
854             entry->response_id, FALSE);
855         }
856     }
857   else
858     {
859       gimp_dialog_add_button (GIMP_DIALOG (private->dialog),
860                               entry->button_text,
861                               entry->response_id);
862 
863       if (! entry->sensitive)
864         gtk_dialog_set_response_sensitive (GTK_DIALOG (private->dialog),
865                                            entry->response_id,
866                                            FALSE);
867     }
868 }
869 
870 static void
gimp_tool_gui_update_buttons(GimpToolGui * gui)871 gimp_tool_gui_update_buttons (GimpToolGui *gui)
872 {
873   GimpToolGuiPrivate *private = GET_PRIVATE (gui);
874   GList              *list;
875   gint               *ids;
876   gint                n_ids;
877   gint                n_alternatives = 0;
878   gint                i;
879 
880   n_ids = g_list_length (private->response_entries);
881   ids   = g_new0 (gint, n_ids);
882 
883   for (list = private->response_entries, i = 0;
884        list;
885        list = g_list_next (list), i++)
886     {
887       ResponseEntry *entry = list->data;
888 
889       if (entry->alternative_position >= 0 &&
890           entry->alternative_position < n_ids)
891         {
892           ids[entry->alternative_position] = entry->response_id;
893           n_alternatives++;
894         }
895     }
896 
897   if (n_ids == n_alternatives)
898     {
899       if (private->overlay)
900         {
901           gimp_overlay_dialog_set_alternative_button_order (GIMP_OVERLAY_DIALOG (private->dialog),
902                                                             n_ids, ids);
903         }
904       else
905         {
906           gtk_dialog_set_alternative_button_order_from_array (GTK_DIALOG (private->dialog),
907                                                               n_ids, ids);
908         }
909     }
910 
911   g_free (ids);
912 }
913 
914 static void
gimp_tool_gui_update_shell(GimpToolGui * gui)915 gimp_tool_gui_update_shell (GimpToolGui *gui)
916 {
917   GimpToolGuiPrivate *private = GET_PRIVATE (gui);
918 
919   if (private->overlay)
920     {
921       if (gtk_widget_get_parent (private->dialog))
922         {
923           gimp_tool_gui_hide (gui);
924 
925           if (private->shell)
926             gimp_tool_gui_show (gui);
927         }
928     }
929   else
930     {
931       gimp_tool_dialog_set_shell (GIMP_TOOL_DIALOG (private->dialog),
932                                   private->shell);
933     }
934 }
935 
936 static void
gimp_tool_gui_update_viewable(GimpToolGui * gui)937 gimp_tool_gui_update_viewable (GimpToolGui *gui)
938 {
939   GimpToolGuiPrivate *private = GET_PRIVATE (gui);
940 
941   if (! private->overlay)
942     {
943       GimpContext *context = NULL;
944 
945       if (private->tool_info)
946         context = GIMP_CONTEXT (private->tool_info->tool_options);
947 
948       gimp_viewable_dialog_set_viewable (GIMP_VIEWABLE_DIALOG (private->dialog),
949                                          private->viewable, context);
950     }
951 }
952 
953 static void
gimp_tool_gui_dialog_response(GtkWidget * dialog,gint response_id,GimpToolGui * gui)954 gimp_tool_gui_dialog_response (GtkWidget   *dialog,
955                                gint         response_id,
956                                GimpToolGui *gui)
957 {
958   if (response_id == GIMP_RESPONSE_DETACH)
959     {
960       gimp_tool_gui_set_auto_overlay (gui, FALSE);
961       gimp_tool_gui_set_overlay (gui,
962                                  gtk_widget_get_screen (dialog),
963                                  gimp_widget_get_monitor (dialog),
964                                  FALSE);
965     }
966   else
967     {
968       g_signal_emit (gui, signals[RESPONSE], 0,
969                      response_id);
970     }
971 }
972 
973 static void
gimp_tool_gui_canvas_resized(GtkWidget * canvas,GtkAllocation * unused,GimpToolGui * gui)974 gimp_tool_gui_canvas_resized (GtkWidget     *canvas,
975                               GtkAllocation *unused,
976                               GimpToolGui   *gui)
977 {
978   GimpToolGuiPrivate *private = GET_PRIVATE (gui);
979 
980   if (private->auto_overlay)
981     {
982       GtkRequisition requisition;
983       GtkAllocation  allocation;
984       gboolean       overlay = FALSE;
985 
986       gtk_widget_size_request (private->vbox, &requisition);
987       gtk_widget_get_allocation (canvas, &allocation);
988 
989       if (allocation.width  > 2 * requisition.width &&
990           allocation.height > 3 * requisition.height)
991         {
992           overlay = TRUE;
993         }
994 
995       gimp_tool_gui_set_overlay (gui,
996                                  gtk_widget_get_screen (private->dialog),
997                                  gimp_widget_get_monitor (private->dialog),
998                                  overlay);
999     }
1000 }
1001 
1002 static ResponseEntry *
response_entry_new(gint response_id,const gchar * button_text)1003 response_entry_new (gint         response_id,
1004                     const gchar *button_text)
1005 {
1006   ResponseEntry *entry = g_slice_new0 (ResponseEntry);
1007 
1008   entry->response_id          = response_id;
1009   entry->button_text          = g_strdup (button_text);
1010   entry->alternative_position = -1;
1011   entry->sensitive            = TRUE;
1012 
1013   return entry;
1014 }
1015 
1016 static void
response_entry_free(ResponseEntry * entry)1017 response_entry_free (ResponseEntry *entry)
1018 {
1019   g_free (entry->button_text);
1020 
1021   g_slice_free (ResponseEntry, entry);
1022 }
1023 
1024 static ResponseEntry *
response_entry_find(GList * entries,gint response_id)1025 response_entry_find (GList *entries,
1026                      gint   response_id)
1027 {
1028   for (; entries; entries = g_list_next (entries))
1029     {
1030       ResponseEntry *entry = entries->data;
1031 
1032       if (entry->response_id == response_id)
1033         return entry;
1034     }
1035 
1036   return NULL;
1037 }
1038