1 /* GIMP - The GNU Image Manipulation Program
2  * Copyright (C) 1995 Spencer Kimball and Peter Mattis
3  *
4  * This program is free software: you can redistribute it and/or modify
5  * it under the terms of the GNU General Public License as published by
6  * the Free Software Foundation; either version 3 of the License, or
7  * (at your option) any later version.
8  *
9  * This program is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12  * GNU General Public License for more details.
13  *
14  * You should have received a copy of the GNU General Public License
15  * along with this program.  If not, see <https://www.gnu.org/licenses/>.
16  */
17 
18 #include "config.h"
19 
20 #include <string.h>
21 
22 #undef GSEAL_ENABLE
23 
24 #include <gegl.h>
25 #include <gtk/gtk.h>
26 
27 #include "libgimpbase/gimpbase.h"
28 #include "libgimpwidgets/gimpwidgets.h"
29 
30 #include "widgets-types.h"
31 
32 #include "config/gimpguiconfig.h"
33 
34 #include "core/gimp.h"
35 #include "core/gimpcontext.h"
36 
37 #include "file/file-open.h"
38 
39 #include "gimpcairo-wilber.h"
40 #include "gimpdevices.h"
41 #include "gimpdialogfactory.h"
42 #include "gimpdockwindow.h"
43 #include "gimphelp-ids.h"
44 #include "gimppanedbox.h"
45 #include "gimptoolbox.h"
46 #include "gimptoolbox-color-area.h"
47 #include "gimptoolbox-dnd.h"
48 #include "gimptoolbox-image-area.h"
49 #include "gimptoolbox-indicator-area.h"
50 #include "gimptoolpalette.h"
51 #include "gimpuimanager.h"
52 #include "gimpwidgets-utils.h"
53 #include "gtkhwrapbox.h"
54 
55 #include "about.h"
56 
57 #include "gimp-intl.h"
58 
59 
60 enum
61 {
62   PROP_0,
63   PROP_CONTEXT
64 };
65 
66 
67 struct _GimpToolboxPrivate
68 {
69   GimpContext       *context;
70 
71   GtkWidget         *vbox;
72 
73   GtkWidget         *header;
74   GtkWidget         *tool_palette;
75   GtkWidget         *area_wbox;
76   GtkWidget         *color_area;
77   GtkWidget         *foo_area;
78   GtkWidget         *image_area;
79 
80   gint               area_rows;
81   gint               area_columns;
82 
83   GimpPanedBox      *drag_handler;
84 
85   gboolean           in_destruction;
86 };
87 
88 
89 static void        gimp_toolbox_constructed             (GObject        *object);
90 static void        gimp_toolbox_dispose                 (GObject        *object);
91 static void        gimp_toolbox_set_property            (GObject        *object,
92                                                          guint           property_id,
93                                                          const GValue   *value,
94                                                          GParamSpec     *pspec);
95 static void        gimp_toolbox_get_property            (GObject        *object,
96                                                          guint           property_id,
97                                                          GValue         *value,
98                                                          GParamSpec     *pspec);
99 static void        gimp_toolbox_size_allocate           (GtkWidget      *widget,
100                                                          GtkAllocation  *allocation);
101 static gboolean    gimp_toolbox_button_press_event      (GtkWidget      *widget,
102                                                          GdkEventButton *event);
103 static void        gimp_toolbox_drag_leave              (GtkWidget      *widget,
104                                                          GdkDragContext *context,
105                                                          guint           time,
106                                                          GimpToolbox    *toolbox);
107 static gboolean    gimp_toolbox_drag_motion             (GtkWidget      *widget,
108                                                          GdkDragContext *context,
109                                                          gint            x,
110                                                          gint            y,
111                                                          guint           time,
112                                                          GimpToolbox    *toolbox);
113 static gboolean    gimp_toolbox_drag_drop               (GtkWidget      *widget,
114                                                          GdkDragContext *context,
115                                                          gint            x,
116                                                          gint            y,
117                                                          guint           time,
118                                                          GimpToolbox    *toolbox);
119 static gchar     * gimp_toolbox_get_description         (GimpDock       *dock,
120                                                          gboolean        complete);
121 static void        gimp_toolbox_set_host_geometry_hints (GimpDock       *dock,
122                                                          GtkWindow      *window);
123 static void        gimp_toolbox_book_added              (GimpDock       *dock,
124                                                          GimpDockbook   *dockbook);
125 static void        gimp_toolbox_book_removed            (GimpDock       *dock,
126                                                          GimpDockbook   *dockbook);
127 static void        gimp_toolbox_size_request_wilber     (GtkWidget      *widget,
128                                                          GtkRequisition *requisition,
129                                                          GimpToolbox    *toolbox);
130 static gboolean    gimp_toolbox_expose_wilber           (GtkWidget      *widget,
131                                                          GdkEventExpose *event);
132 static GtkWidget * toolbox_create_color_area            (GimpToolbox    *toolbox,
133                                                          GimpContext    *context);
134 static GtkWidget * toolbox_create_foo_area              (GimpToolbox    *toolbox,
135                                                          GimpContext    *context);
136 static GtkWidget * toolbox_create_image_area            (GimpToolbox    *toolbox,
137                                                          GimpContext    *context);
138 static void        toolbox_area_notify                  (GimpGuiConfig  *config,
139                                                          GParamSpec     *pspec,
140                                                          GtkWidget      *area);
141 static void        toolbox_paste_received               (GtkClipboard   *clipboard,
142                                                          const gchar    *text,
143                                                          gpointer        data);
144 
145 
G_DEFINE_TYPE_WITH_PRIVATE(GimpToolbox,gimp_toolbox,GIMP_TYPE_DOCK)146 G_DEFINE_TYPE_WITH_PRIVATE (GimpToolbox, gimp_toolbox, GIMP_TYPE_DOCK)
147 
148 #define parent_class gimp_toolbox_parent_class
149 
150 
151 static void
152 gimp_toolbox_class_init (GimpToolboxClass *klass)
153 {
154   GObjectClass   *object_class = G_OBJECT_CLASS (klass);
155   GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (klass);
156   GimpDockClass  *dock_class   = GIMP_DOCK_CLASS (klass);
157 
158   object_class->constructed           = gimp_toolbox_constructed;
159   object_class->dispose               = gimp_toolbox_dispose;
160   object_class->set_property          = gimp_toolbox_set_property;
161   object_class->get_property          = gimp_toolbox_get_property;
162 
163   widget_class->size_allocate         = gimp_toolbox_size_allocate;
164   widget_class->button_press_event    = gimp_toolbox_button_press_event;
165 
166   dock_class->get_description         = gimp_toolbox_get_description;
167   dock_class->set_host_geometry_hints = gimp_toolbox_set_host_geometry_hints;
168   dock_class->book_added              = gimp_toolbox_book_added;
169   dock_class->book_removed            = gimp_toolbox_book_removed;
170 
171   g_object_class_install_property (object_class, PROP_CONTEXT,
172                                    g_param_spec_object ("context",
173                                                         NULL, NULL,
174                                                         GIMP_TYPE_CONTEXT,
175                                                         GIMP_PARAM_READWRITE |
176                                                         G_PARAM_CONSTRUCT));
177 }
178 
179 static void
gimp_toolbox_init(GimpToolbox * toolbox)180 gimp_toolbox_init (GimpToolbox *toolbox)
181 {
182   toolbox->p = gimp_toolbox_get_instance_private (toolbox);
183 
184   gimp_help_connect (GTK_WIDGET (toolbox), gimp_standard_help_func,
185                      GIMP_HELP_TOOLBOX, NULL);
186 }
187 
188 static void
gimp_toolbox_constructed(GObject * object)189 gimp_toolbox_constructed (GObject *object)
190 {
191   GimpToolbox   *toolbox = GIMP_TOOLBOX (object);
192   GimpGuiConfig *config;
193   GtkWidget     *main_vbox;
194   GdkDisplay    *display;
195   GList         *list;
196 
197   gimp_assert (GIMP_IS_CONTEXT (toolbox->p->context));
198 
199   config = GIMP_GUI_CONFIG (toolbox->p->context->gimp->config);
200 
201   main_vbox = gimp_dock_get_main_vbox (GIMP_DOCK (toolbox));
202 
203   toolbox->p->vbox = gtk_box_new (GTK_ORIENTATION_VERTICAL, 2);
204   gtk_box_pack_start (GTK_BOX (main_vbox), toolbox->p->vbox, FALSE, FALSE, 0);
205   gtk_box_reorder_child (GTK_BOX (main_vbox), toolbox->p->vbox, 0);
206   gtk_widget_show (toolbox->p->vbox);
207 
208   /* Use g_signal_connect() also for the toolbox itself so we can pass
209    * data and reuse the same function for the vbox
210    */
211   g_signal_connect (toolbox, "drag-leave",
212                     G_CALLBACK (gimp_toolbox_drag_leave),
213                     toolbox);
214   g_signal_connect (toolbox, "drag-motion",
215                     G_CALLBACK (gimp_toolbox_drag_motion),
216                     toolbox);
217   g_signal_connect (toolbox, "drag-drop",
218                     G_CALLBACK (gimp_toolbox_drag_drop),
219                     toolbox);
220   g_signal_connect (toolbox->p->vbox, "drag-leave",
221                     G_CALLBACK (gimp_toolbox_drag_leave),
222                     toolbox);
223   g_signal_connect (toolbox->p->vbox, "drag-motion",
224                     G_CALLBACK (gimp_toolbox_drag_motion),
225                     toolbox);
226   g_signal_connect (toolbox->p->vbox, "drag-drop",
227                     G_CALLBACK (gimp_toolbox_drag_drop),
228                     toolbox);
229 
230   toolbox->p->header = gtk_frame_new (NULL);
231   gtk_frame_set_shadow_type (GTK_FRAME (toolbox->p->header), GTK_SHADOW_NONE);
232   gtk_box_pack_start (GTK_BOX (toolbox->p->vbox), toolbox->p->header,
233                       FALSE, FALSE, 0);
234 
235   g_object_bind_property (config,             "toolbox-wilber",
236                           toolbox->p->header, "visible",
237                           G_BINDING_SYNC_CREATE);
238 
239   g_signal_connect (toolbox->p->header, "size-request",
240                     G_CALLBACK (gimp_toolbox_size_request_wilber),
241                     toolbox);
242   g_signal_connect (toolbox->p->header, "expose-event",
243                     G_CALLBACK (gimp_toolbox_expose_wilber),
244                     toolbox);
245 
246   gimp_help_set_help_data (toolbox->p->header,
247                            _("Drop image files here to open them"), NULL);
248 
249   toolbox->p->tool_palette = gimp_tool_palette_new ();
250   gimp_tool_palette_set_toolbox (GIMP_TOOL_PALETTE (toolbox->p->tool_palette),
251                                  toolbox);
252   gtk_box_pack_start (GTK_BOX (toolbox->p->vbox), toolbox->p->tool_palette,
253                       FALSE, FALSE, 0);
254   gtk_widget_show (toolbox->p->tool_palette);
255 
256   toolbox->p->area_wbox = gtk_hwrap_box_new (FALSE);
257   gtk_wrap_box_set_justify (GTK_WRAP_BOX (toolbox->p->area_wbox), GTK_JUSTIFY_TOP);
258   gtk_wrap_box_set_line_justify (GTK_WRAP_BOX (toolbox->p->area_wbox),
259                                  GTK_JUSTIFY_LEFT);
260   gtk_wrap_box_set_aspect_ratio (GTK_WRAP_BOX (toolbox->p->area_wbox),
261                                  2.0 / 15.0);
262 
263   gtk_box_pack_start (GTK_BOX (toolbox->p->vbox), toolbox->p->area_wbox,
264                       FALSE, FALSE, 0);
265   gtk_widget_show (toolbox->p->area_wbox);
266 
267   /* We need to know when the current device changes, so we can update
268    * the correct tool - to do this we connect to motion events.
269    * We can't just use EXTENSION_EVENTS_CURSOR though, since that
270    * would get us extension events for the mouse pointer, and our
271    * device would change to that and not change back. So we check
272    * manually that all devices have a cursor, before establishing the check.
273    */
274   display = gtk_widget_get_display (GTK_WIDGET (toolbox));
275   for (list = gdk_display_list_devices (display); list; list = list->next)
276     if (! ((GdkDevice *) (list->data))->has_cursor)
277       break;
278 
279   if (! list)  /* all devices have cursor */
280     {
281       gtk_widget_add_events (GTK_WIDGET (toolbox), GDK_POINTER_MOTION_MASK);
282       gimp_devices_add_widget (toolbox->p->context->gimp, GTK_WIDGET (toolbox));
283     }
284 
285   toolbox->p->color_area = toolbox_create_color_area (toolbox,
286                                                       toolbox->p->context);
287   gtk_wrap_box_pack_wrapped (GTK_WRAP_BOX (toolbox->p->area_wbox),
288                              toolbox->p->color_area,
289                              TRUE, TRUE, FALSE, TRUE, TRUE);
290   if (config->toolbox_color_area)
291     gtk_widget_show (toolbox->p->color_area);
292 
293   g_signal_connect_object (config, "notify::toolbox-color-area",
294                            G_CALLBACK (toolbox_area_notify),
295                            toolbox->p->color_area, 0);
296 
297   toolbox->p->foo_area = toolbox_create_foo_area (toolbox, toolbox->p->context);
298   gtk_wrap_box_pack (GTK_WRAP_BOX (toolbox->p->area_wbox), toolbox->p->foo_area,
299                      TRUE, TRUE, FALSE, TRUE);
300   if (config->toolbox_foo_area)
301     gtk_widget_show (toolbox->p->foo_area);
302 
303   g_signal_connect_object (config, "notify::toolbox-foo-area",
304                            G_CALLBACK (toolbox_area_notify),
305                            toolbox->p->foo_area, 0);
306 
307   toolbox->p->image_area = toolbox_create_image_area (toolbox,
308                                                       toolbox->p->context);
309   gtk_wrap_box_pack (GTK_WRAP_BOX (toolbox->p->area_wbox), toolbox->p->image_area,
310                      TRUE, TRUE, FALSE, TRUE);
311   if (config->toolbox_image_area)
312     gtk_widget_show (toolbox->p->image_area);
313 
314   g_signal_connect_object (config, "notify::toolbox-image-area",
315                            G_CALLBACK (toolbox_area_notify),
316                            toolbox->p->image_area, 0);
317 
318   gimp_toolbox_dnd_init (GIMP_TOOLBOX (toolbox), toolbox->p->vbox);
319 }
320 
321 static void
gimp_toolbox_dispose(GObject * object)322 gimp_toolbox_dispose (GObject *object)
323 {
324   GimpToolbox *toolbox = GIMP_TOOLBOX (object);
325 
326   toolbox->p->in_destruction = TRUE;
327 
328   g_clear_object (&toolbox->p->context);
329 
330   G_OBJECT_CLASS (parent_class)->dispose (object);
331 
332   toolbox->p->in_destruction = FALSE;
333 }
334 
335 static void
gimp_toolbox_set_property(GObject * object,guint property_id,const GValue * value,GParamSpec * pspec)336 gimp_toolbox_set_property (GObject      *object,
337                            guint         property_id,
338                            const GValue *value,
339                            GParamSpec   *pspec)
340 {
341   GimpToolbox *toolbox = GIMP_TOOLBOX (object);
342 
343   switch (property_id)
344     {
345     case PROP_CONTEXT:
346       toolbox->p->context = g_value_dup_object (value);
347       break;
348 
349     default:
350       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
351       break;
352     }
353 }
354 
355 static void
gimp_toolbox_get_property(GObject * object,guint property_id,GValue * value,GParamSpec * pspec)356 gimp_toolbox_get_property (GObject    *object,
357                            guint       property_id,
358                            GValue     *value,
359                            GParamSpec *pspec)
360 {
361   GimpToolbox *toolbox = GIMP_TOOLBOX (object);
362 
363   switch (property_id)
364     {
365     case PROP_CONTEXT:
366       g_value_set_object (value, toolbox->p->context);
367       break;
368 
369     default:
370       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
371       break;
372     }
373 }
374 
375 static void
gimp_toolbox_size_allocate(GtkWidget * widget,GtkAllocation * allocation)376 gimp_toolbox_size_allocate (GtkWidget     *widget,
377                             GtkAllocation *allocation)
378 {
379   GimpToolbox    *toolbox = GIMP_TOOLBOX (widget);
380   GimpGuiConfig  *config;
381   GtkRequisition  color_requisition;
382   GtkRequisition  foo_requisition;
383   GtkRequisition  image_requisition;
384   gint            width;
385   gint            height;
386   gint            n_areas;
387   gint            area_rows;
388   gint            area_columns;
389 
390   GTK_WIDGET_CLASS (parent_class)->size_allocate (widget, allocation);
391 
392   config = GIMP_GUI_CONFIG (toolbox->p->context->gimp->config);
393 
394   gtk_widget_size_request (toolbox->p->color_area, &color_requisition);
395   gtk_widget_size_request (toolbox->p->foo_area,   &foo_requisition);
396   gtk_widget_size_request (toolbox->p->image_area, &image_requisition);
397 
398   width  = MAX (color_requisition.width,
399                 MAX (foo_requisition.width,
400                      image_requisition.width));
401   height = MAX (color_requisition.height,
402                 MAX (foo_requisition.height,
403                      image_requisition.height));
404 
405   n_areas = (config->toolbox_color_area +
406              config->toolbox_foo_area   +
407              config->toolbox_image_area);
408 
409   area_columns = MAX (1, (allocation->width / width));
410   area_rows    = n_areas / area_columns;
411 
412   if (n_areas % area_columns)
413     area_rows++;
414 
415   if (toolbox->p->area_rows    != area_rows  ||
416       toolbox->p->area_columns != area_columns)
417     {
418       toolbox->p->area_rows    = area_rows;
419       toolbox->p->area_columns = area_columns;
420 
421       gtk_widget_set_size_request (toolbox->p->area_wbox, -1,
422                                    area_rows * height);
423     }
424 }
425 
426 static gboolean
gimp_toolbox_button_press_event(GtkWidget * widget,GdkEventButton * event)427 gimp_toolbox_button_press_event (GtkWidget      *widget,
428                                  GdkEventButton *event)
429 {
430   GimpToolbox *toolbox = GIMP_TOOLBOX (widget);
431 
432   if (event->type == GDK_BUTTON_PRESS && event->button == 2)
433     {
434       GtkClipboard *clipboard;
435 
436       clipboard = gtk_widget_get_clipboard (widget, GDK_SELECTION_PRIMARY);
437       gtk_clipboard_request_text (clipboard,
438                                   toolbox_paste_received,
439                                   g_object_ref (toolbox));
440 
441       return TRUE;
442     }
443 
444   return FALSE;
445 }
446 
447 static void
gimp_toolbox_drag_leave(GtkWidget * widget,GdkDragContext * context,guint time,GimpToolbox * toolbox)448 gimp_toolbox_drag_leave (GtkWidget      *widget,
449                          GdkDragContext *context,
450                          guint           time,
451                          GimpToolbox    *toolbox)
452 {
453   gimp_highlight_widget (widget, FALSE);
454 }
455 
456 static gboolean
gimp_toolbox_drag_motion(GtkWidget * widget,GdkDragContext * context,gint x,gint y,guint time,GimpToolbox * toolbox)457 gimp_toolbox_drag_motion (GtkWidget      *widget,
458                           GdkDragContext *context,
459                           gint            x,
460                           gint            y,
461                           guint           time,
462                           GimpToolbox    *toolbox)
463 {
464   gboolean handle;
465 
466   if (gimp_paned_box_will_handle_drag (toolbox->p->drag_handler,
467                                        widget,
468                                        context,
469                                        x, y,
470                                        time))
471     {
472       gdk_drag_status (context, 0, time);
473       gimp_highlight_widget (widget, FALSE);
474 
475       return FALSE;
476     }
477 
478   handle = (gtk_drag_dest_find_target (widget, context, NULL) != GDK_NONE);
479 
480   gdk_drag_status (context, handle ? GDK_ACTION_MOVE : 0, time);
481   gimp_highlight_widget (widget, handle);
482 
483   /* Return TRUE so drag_leave() is called */
484   return TRUE;
485 }
486 
487 static gboolean
gimp_toolbox_drag_drop(GtkWidget * widget,GdkDragContext * context,gint x,gint y,guint time,GimpToolbox * toolbox)488 gimp_toolbox_drag_drop (GtkWidget      *widget,
489                         GdkDragContext *context,
490                         gint            x,
491                         gint            y,
492                         guint           time,
493                         GimpToolbox    *toolbox)
494 {
495   GdkAtom  target;
496   gboolean dropped = FALSE;
497 
498   if (gimp_paned_box_will_handle_drag (toolbox->p->drag_handler,
499                                        widget,
500                                        context,
501                                        x, y,
502                                        time))
503     {
504       return FALSE;
505     }
506 
507   target = gtk_drag_dest_find_target (widget, context, NULL);
508 
509   if (target != GDK_NONE)
510     {
511       /* The URI handlers etc will handle this */
512       gtk_drag_get_data (widget, context, target, time);
513       dropped = TRUE;
514     }
515 
516   gtk_drag_finish (context, dropped, (context->action == GDK_ACTION_MOVE), time);
517 
518   return TRUE;
519 }
520 
521 static gchar *
gimp_toolbox_get_description(GimpDock * dock,gboolean complete)522 gimp_toolbox_get_description (GimpDock *dock,
523                               gboolean  complete)
524 {
525   GString *desc      = g_string_new (_("Toolbox"));
526   gchar   *dock_desc = GIMP_DOCK_CLASS (parent_class)->get_description (dock,
527                                                                         complete);
528 
529   if (dock_desc && strlen (dock_desc) > 0)
530     {
531       g_string_append (desc, GIMP_DOCK_BOOK_SEPARATOR);
532       g_string_append (desc, dock_desc);
533     }
534 
535   g_free (dock_desc);
536 
537   return g_string_free (desc, FALSE /*free_segment*/);
538 }
539 
540 static void
gimp_toolbox_book_added(GimpDock * dock,GimpDockbook * dockbook)541 gimp_toolbox_book_added (GimpDock     *dock,
542                          GimpDockbook *dockbook)
543 {
544   if (GIMP_DOCK_CLASS (parent_class)->book_added)
545     GIMP_DOCK_CLASS (parent_class)->book_added (dock, dockbook);
546 
547   if (g_list_length (gimp_dock_get_dockbooks (dock)) == 1)
548     {
549       gimp_dock_invalidate_geometry (dock);
550     }
551 }
552 
553 static void
gimp_toolbox_book_removed(GimpDock * dock,GimpDockbook * dockbook)554 gimp_toolbox_book_removed (GimpDock     *dock,
555                            GimpDockbook *dockbook)
556 {
557   GimpToolbox *toolbox = GIMP_TOOLBOX (dock);
558 
559   if (GIMP_DOCK_CLASS (parent_class)->book_removed)
560     GIMP_DOCK_CLASS (parent_class)->book_removed (dock, dockbook);
561 
562   if (! gimp_dock_get_dockbooks (dock) &&
563       ! toolbox->p->in_destruction)
564     {
565       gimp_dock_invalidate_geometry (dock);
566     }
567 }
568 
569 static void
gimp_toolbox_set_host_geometry_hints(GimpDock * dock,GtkWindow * window)570 gimp_toolbox_set_host_geometry_hints (GimpDock  *dock,
571                                       GtkWindow *window)
572 {
573   GimpToolbox *toolbox = GIMP_TOOLBOX (dock);
574   gint         button_width;
575   gint         button_height;
576 
577   if (gimp_tool_palette_get_button_size (GIMP_TOOL_PALETTE (toolbox->p->tool_palette),
578                                          &button_width, &button_height))
579     {
580       GdkGeometry geometry;
581 
582       geometry.min_width   = 2 * button_width;
583       geometry.min_height  = -1;
584       geometry.base_width  = button_width;
585       geometry.base_height = 0;
586       geometry.width_inc   = button_width;
587       geometry.height_inc  = 1;
588 
589       gtk_window_set_geometry_hints (window,
590                                      NULL,
591                                      &geometry,
592                                      GDK_HINT_MIN_SIZE   |
593                                      GDK_HINT_BASE_SIZE  |
594                                      GDK_HINT_RESIZE_INC |
595                                      GDK_HINT_USER_POS);
596 
597       gimp_dialog_factory_set_has_min_size (window, TRUE);
598     }
599 }
600 
601 GtkWidget *
gimp_toolbox_new(GimpDialogFactory * factory,GimpContext * context,GimpUIManager * ui_manager)602 gimp_toolbox_new (GimpDialogFactory *factory,
603                   GimpContext       *context,
604                   GimpUIManager     *ui_manager)
605 {
606   g_return_val_if_fail (GIMP_IS_DIALOG_FACTORY (factory), NULL);
607   g_return_val_if_fail (GIMP_IS_CONTEXT (context), NULL);
608   g_return_val_if_fail (GIMP_IS_UI_MANAGER (ui_manager), NULL);
609 
610   return g_object_new (GIMP_TYPE_TOOLBOX,
611                        "context", context,
612                        NULL);
613 }
614 
615 GimpContext *
gimp_toolbox_get_context(GimpToolbox * toolbox)616 gimp_toolbox_get_context (GimpToolbox *toolbox)
617 {
618   g_return_val_if_fail (GIMP_IS_TOOLBOX (toolbox), NULL);
619 
620   return toolbox->p->context;
621 }
622 
623 void
gimp_toolbox_set_drag_handler(GimpToolbox * toolbox,GimpPanedBox * drag_handler)624 gimp_toolbox_set_drag_handler (GimpToolbox  *toolbox,
625                                GimpPanedBox *drag_handler)
626 {
627   g_return_if_fail (GIMP_IS_TOOLBOX (toolbox));
628 
629   toolbox->p->drag_handler = drag_handler;
630 }
631 
632 
633 /*  private functions  */
634 
635 static void
gimp_toolbox_size_request_wilber(GtkWidget * widget,GtkRequisition * requisition,GimpToolbox * toolbox)636 gimp_toolbox_size_request_wilber (GtkWidget      *widget,
637                                   GtkRequisition *requisition,
638                                   GimpToolbox    *toolbox)
639 {
640   gint button_width;
641   gint button_height;
642 
643   if (gimp_tool_palette_get_button_size (GIMP_TOOL_PALETTE (toolbox->p->tool_palette),
644                                          &button_width, &button_height))
645     {
646       requisition->width  = button_width  * PANGO_SCALE_SMALL;
647       requisition->height = button_height * PANGO_SCALE_SMALL;
648     }
649   else
650     {
651       requisition->width  = 16;
652       requisition->height = 16;
653     }
654 }
655 
656 static gboolean
gimp_toolbox_expose_wilber(GtkWidget * widget,GdkEventExpose * event)657 gimp_toolbox_expose_wilber (GtkWidget      *widget,
658                             GdkEventExpose *event)
659 {
660   cairo_t *cr;
661 
662   cr = gdk_cairo_create (gtk_widget_get_window (widget));
663   gdk_cairo_region (cr, event->region);
664   cairo_clip (cr);
665 
666   gimp_cairo_draw_toolbox_wilber (widget, cr);
667 
668   cairo_destroy (cr);
669 
670   return FALSE;
671 }
672 
673 static GtkWidget *
toolbox_create_color_area(GimpToolbox * toolbox,GimpContext * context)674 toolbox_create_color_area (GimpToolbox *toolbox,
675                            GimpContext *context)
676 {
677   GtkWidget *alignment;
678   GtkWidget *col_area;
679 
680   alignment = gtk_alignment_new (0.5, 0.5, 0.0, 0.0);
681   gtk_container_set_border_width (GTK_CONTAINER (alignment), 2);
682 
683   gimp_help_set_help_data (alignment, NULL, GIMP_HELP_TOOLBOX_COLOR_AREA);
684 
685   col_area = gimp_toolbox_color_area_create (toolbox, 40, 38);
686   gtk_container_add (GTK_CONTAINER (alignment), col_area);
687   gtk_widget_show (col_area);
688 
689   return alignment;
690 }
691 
692 static GtkWidget *
toolbox_create_foo_area(GimpToolbox * toolbox,GimpContext * context)693 toolbox_create_foo_area (GimpToolbox *toolbox,
694                          GimpContext *context)
695 {
696   GtkWidget *alignment;
697   GtkWidget *foo_area;
698 
699   alignment = gtk_alignment_new (0.5, 0.5, 0.0, 0.0);
700   gtk_container_set_border_width (GTK_CONTAINER (alignment), 2);
701 
702   gimp_help_set_help_data (alignment, NULL, GIMP_HELP_TOOLBOX_INDICATOR_AREA);
703 
704   foo_area = gimp_toolbox_indicator_area_create (toolbox);
705   gtk_container_add (GTK_CONTAINER (alignment), foo_area);
706   gtk_widget_show (foo_area);
707 
708   return alignment;
709 }
710 
711 static GtkWidget *
toolbox_create_image_area(GimpToolbox * toolbox,GimpContext * context)712 toolbox_create_image_area (GimpToolbox *toolbox,
713                            GimpContext *context)
714 {
715   GtkWidget *alignment;
716   GtkWidget *image_area;
717 
718   alignment = gtk_alignment_new (0.5, 0.5, 0.0, 0.0);
719   gtk_container_set_border_width (GTK_CONTAINER (alignment), 2);
720 
721   gimp_help_set_help_data (alignment, NULL, GIMP_HELP_TOOLBOX_IMAGE_AREA);
722 
723   image_area = gimp_toolbox_image_area_create (toolbox, 52, 42);
724   gtk_container_add (GTK_CONTAINER (alignment), image_area);
725   gtk_widget_show (image_area);
726 
727   return alignment;
728 }
729 
730 static void
toolbox_area_notify(GimpGuiConfig * config,GParamSpec * pspec,GtkWidget * area)731 toolbox_area_notify (GimpGuiConfig *config,
732                      GParamSpec    *pspec,
733                      GtkWidget     *area)
734 {
735   GtkWidget *parent = gtk_widget_get_parent (area);
736   gboolean   visible;
737 
738   if (config->toolbox_color_area ||
739       config->toolbox_foo_area   ||
740       config->toolbox_image_area)
741     {
742       GtkRequisition req;
743 
744       gtk_widget_show (parent);
745 
746       gtk_widget_size_request (area, &req);
747       gtk_widget_set_size_request (parent, req.width, req.height);
748     }
749   else
750     {
751       gtk_widget_hide (parent);
752       gtk_widget_set_size_request (parent, -1, -1);
753     }
754 
755   g_object_get (config, pspec->name, &visible, NULL);
756   g_object_set (area, "visible", visible, NULL);
757 }
758 
759 static void
toolbox_paste_received(GtkClipboard * clipboard,const gchar * text,gpointer data)760 toolbox_paste_received (GtkClipboard *clipboard,
761                         const gchar  *text,
762                         gpointer      data)
763 {
764   GimpToolbox *toolbox = GIMP_TOOLBOX (data);
765   GimpContext *context = toolbox->p->context;
766 
767   if (text)
768     {
769       const gchar *newline = strchr (text, '\n');
770       gchar       *copy;
771       GFile       *file = NULL;
772 
773       if (newline)
774         copy = g_strndup (text, newline - text);
775       else
776         copy = g_strdup (text);
777 
778       g_strstrip (copy);
779 
780       if (strlen (copy))
781         file = g_file_new_for_commandline_arg (copy);
782 
783       g_free (copy);
784 
785       if (file)
786         {
787           GtkWidget         *widget = GTK_WIDGET (toolbox);
788           GimpImage         *image;
789           GimpPDBStatusType  status;
790           GError            *error = NULL;
791 
792           image = file_open_with_display (context->gimp, context, NULL,
793                                           file, FALSE,
794                                           G_OBJECT (gtk_widget_get_screen (widget)),
795                                           gimp_widget_get_monitor (widget),
796                                           &status, &error);
797 
798           if (! image && status != GIMP_PDB_CANCEL)
799             {
800               gimp_message (context->gimp, NULL, GIMP_MESSAGE_ERROR,
801                             _("Opening '%s' failed:\n\n%s"),
802                             gimp_file_get_utf8_name (file), error->message);
803               g_clear_error (&error);
804             }
805 
806           g_object_unref (file);
807         }
808     }
809 
810   g_object_unref (context);
811 }
812