1 /* GIMP - The GNU Image Manipulation Program
2  * Copyright (C) 1995 Spencer Kimball and Peter Mattis
3  *
4  * gimptoolwidgetgroup.c
5  * Copyright (C) 2018 Ell
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 "display-types.h"
27 
28 #include "core/gimpcontainer.h"
29 #include "core/gimplist.h"
30 
31 #include "gimpcanvasgroup.h"
32 #include "gimpdisplayshell.h"
33 #include "gimptoolwidgetgroup.h"
34 
35 
36 struct _GimpToolWidgetGroupPrivate
37 {
38   GimpContainer  *children;
39 
40   GimpToolWidget *focus_widget;
41   GimpToolWidget *hover_widget;
42 
43   gboolean        auto_raise;
44 };
45 
46 
47 /*  local function prototypes  */
48 
49 static void             gimp_tool_widget_group_finalize            (GObject               *object);
50 
51 static void             gimp_tool_widget_group_focus_changed       (GimpToolWidget        *widget);
52 static gint             gimp_tool_widget_group_button_press        (GimpToolWidget        *widget,
53                                                                     const GimpCoords      *coords,
54                                                                     guint32                time,
55                                                                     GdkModifierType        state,
56                                                                     GimpButtonPressType    press_type);
57 static void             gimp_tool_widget_group_button_release      (GimpToolWidget        *widget,
58                                                                     const GimpCoords      *coords,
59                                                                     guint32                time,
60                                                                     GdkModifierType        state,
61                                                                     GimpButtonReleaseType  release_type);
62 static void             gimp_tool_widget_group_motion              (GimpToolWidget        *widget,
63                                                                     const GimpCoords      *coords,
64                                                                     guint32                time,
65                                                                     GdkModifierType        state);
66 static GimpHit          gimp_tool_widget_group_hit                 (GimpToolWidget        *widget,
67                                                                     const GimpCoords      *coords,
68                                                                     GdkModifierType        state,
69                                                                     gboolean               proximity);
70 static void             gimp_tool_widget_group_hover               (GimpToolWidget        *widget,
71                                                                     const GimpCoords      *coords,
72                                                                     GdkModifierType        state,
73                                                                     gboolean               proximity);
74 static void             gimp_tool_widget_group_leave_notify        (GimpToolWidget        *widget);
75 static gboolean         gimp_tool_widget_group_key_press           (GimpToolWidget        *widget,
76                                                                     GdkEventKey           *kevent);
77 static gboolean         gimp_tool_widget_group_key_release         (GimpToolWidget        *widget,
78                                                                     GdkEventKey           *kevent);
79 static void             gimp_tool_widget_group_motion_modifier     (GimpToolWidget        *widget,
80                                                                     GdkModifierType        key,
81                                                                     gboolean               press,
82                                                                     GdkModifierType        state);
83 static void             gimp_tool_widget_group_hover_modifier      (GimpToolWidget        *widget,
84                                                                     GdkModifierType        key,
85                                                                     gboolean               press,
86                                                                     GdkModifierType        state);
87 static gboolean         gimp_tool_widget_group_get_cursor          (GimpToolWidget        *widget,
88                                                                     const GimpCoords      *coords,
89                                                                     GdkModifierType        state,
90                                                                     GimpCursorType        *cursor,
91                                                                     GimpToolCursorType    *tool_cursor,
92                                                                     GimpCursorModifier    *modifier);
93 
94 static void             gimp_tool_widget_group_children_add        (GimpContainer         *container,
95                                                                     GimpToolWidget        *child,
96                                                                     GimpToolWidgetGroup   *group);
97 static void             gimp_tool_widget_group_children_remove     (GimpContainer         *container,
98                                                                     GimpToolWidget        *child,
99                                                                     GimpToolWidgetGroup   *group);
100 static void             gimp_tool_widget_group_children_reorder    (GimpContainer         *container,
101                                                                     GimpToolWidget        *child,
102                                                                     gint                   new_index,
103                                                                     GimpToolWidgetGroup   *group);
104 
105 static void             gimp_tool_widget_group_child_changed       (GimpToolWidget        *child,
106                                                                     GimpToolWidgetGroup   *group);
107 static void             gimp_tool_widget_group_child_response      (GimpToolWidget        *child,
108                                                                     gint                   response_id,
109                                                                     GimpToolWidgetGroup   *group);
110 static void             gimp_tool_widget_group_child_snap_offsets  (GimpToolWidget        *child,
111                                                                     gint                   offset_x,
112                                                                     gint                   offset_y,
113                                                                     gint                   width,
114                                                                     gint                   height,
115                                                                     GimpToolWidgetGroup   *group);
116 static void             gimp_tool_widget_group_child_status        (GimpToolWidget        *child,
117                                                                     const gchar           *status,
118                                                                     GimpToolWidgetGroup   *group);
119 static void             gimp_tool_widget_group_child_status_coords (GimpToolWidget        *child,
120                                                                     const gchar           *title,
121                                                                     gdouble                x,
122                                                                     const gchar           *separator,
123                                                                     gdouble                y,
124                                                                     const gchar           *help,
125                                                                     GimpToolWidgetGroup   *group);
126 static void             gimp_tool_widget_group_child_message       (GimpToolWidget        *child,
127                                                                     const gchar           *message,
128                                                                     GimpToolWidgetGroup   *group);
129 static void             gimp_tool_widget_group_child_focus_changed (GimpToolWidget        *child,
130                                                                     GimpToolWidgetGroup   *group);
131 
132 static GimpToolWidget * gimp_tool_widget_group_get_hover_widget    (GimpToolWidgetGroup   *group,
133                                                                     const GimpCoords      *coords,
134                                                                     GdkModifierType        state,
135                                                                     gboolean               proximity,
136                                                                     GimpHit               *hit);
137 
138 
G_DEFINE_TYPE_WITH_PRIVATE(GimpToolWidgetGroup,gimp_tool_widget_group,GIMP_TYPE_TOOL_WIDGET)139 G_DEFINE_TYPE_WITH_PRIVATE (GimpToolWidgetGroup, gimp_tool_widget_group,
140                             GIMP_TYPE_TOOL_WIDGET)
141 
142 #define parent_class gimp_tool_widget_group_parent_class
143 
144 
145 /*  priv functions  */
146 
147 
148 static void
149 gimp_tool_widget_group_class_init (GimpToolWidgetGroupClass *klass)
150 {
151   GObjectClass        *object_class = G_OBJECT_CLASS (klass);
152   GimpToolWidgetClass *widget_class = GIMP_TOOL_WIDGET_CLASS (klass);
153 
154   object_class->finalize        = gimp_tool_widget_group_finalize;
155 
156   widget_class->focus_changed   = gimp_tool_widget_group_focus_changed;
157   widget_class->button_press    = gimp_tool_widget_group_button_press;
158   widget_class->button_release  = gimp_tool_widget_group_button_release;
159   widget_class->motion          = gimp_tool_widget_group_motion;
160   widget_class->hit             = gimp_tool_widget_group_hit;
161   widget_class->hover           = gimp_tool_widget_group_hover;
162   widget_class->leave_notify    = gimp_tool_widget_group_leave_notify;
163   widget_class->key_press       = gimp_tool_widget_group_key_press;
164   widget_class->key_release     = gimp_tool_widget_group_key_release;
165   widget_class->motion_modifier = gimp_tool_widget_group_motion_modifier;
166   widget_class->hover_modifier  = gimp_tool_widget_group_hover_modifier;
167   widget_class->get_cursor      = gimp_tool_widget_group_get_cursor;
168 }
169 
170 static void
gimp_tool_widget_group_init(GimpToolWidgetGroup * group)171 gimp_tool_widget_group_init (GimpToolWidgetGroup *group)
172 {
173   GimpToolWidgetGroupPrivate *priv;
174 
175   priv = group->priv = gimp_tool_widget_group_get_instance_private (group);
176 
177   priv->children = g_object_new (GIMP_TYPE_LIST,
178                                  "children-type", GIMP_TYPE_TOOL_WIDGET,
179                                  "append",        TRUE,
180                                  NULL);
181 
182   g_signal_connect (priv->children, "add",
183                     G_CALLBACK (gimp_tool_widget_group_children_add),
184                     group);
185   g_signal_connect (priv->children, "remove",
186                     G_CALLBACK (gimp_tool_widget_group_children_remove),
187                     group);
188   g_signal_connect (priv->children, "reorder",
189                     G_CALLBACK (gimp_tool_widget_group_children_reorder),
190                     group);
191 
192   gimp_container_add_handler (priv->children, "changed",
193                               G_CALLBACK (gimp_tool_widget_group_child_changed),
194                               group);
195   gimp_container_add_handler (priv->children, "response",
196                               G_CALLBACK (gimp_tool_widget_group_child_response),
197                               group);
198   gimp_container_add_handler (priv->children, "snap-offsets",
199                               G_CALLBACK (gimp_tool_widget_group_child_snap_offsets),
200                               group);
201   gimp_container_add_handler (priv->children, "status",
202                               G_CALLBACK (gimp_tool_widget_group_child_status),
203                               group);
204   gimp_container_add_handler (priv->children, "status-coords",
205                               G_CALLBACK (gimp_tool_widget_group_child_status_coords),
206                               group);
207   gimp_container_add_handler (priv->children, "message",
208                               G_CALLBACK (gimp_tool_widget_group_child_message),
209                               group);
210   gimp_container_add_handler (priv->children, "focus-changed",
211                               G_CALLBACK (gimp_tool_widget_group_child_focus_changed),
212                               group);
213 }
214 
215 static void
gimp_tool_widget_group_finalize(GObject * object)216 gimp_tool_widget_group_finalize (GObject *object)
217 {
218   GimpToolWidgetGroup        *group = GIMP_TOOL_WIDGET_GROUP (object);
219   GimpToolWidgetGroupPrivate *priv  = group->priv;
220 
221   g_clear_object (&priv->children);
222 
223   G_OBJECT_CLASS (parent_class)->finalize (object);
224 }
225 
226 static gint
gimp_tool_widget_group_button_press(GimpToolWidget * widget,const GimpCoords * coords,guint32 time,GdkModifierType state,GimpButtonPressType press_type)227 gimp_tool_widget_group_button_press (GimpToolWidget      *widget,
228                                      const GimpCoords    *coords,
229                                      guint32              time,
230                                      GdkModifierType      state,
231                                      GimpButtonPressType  press_type)
232 {
233   GimpToolWidgetGroup        *group = GIMP_TOOL_WIDGET_GROUP (widget);
234   GimpToolWidgetGroupPrivate *priv  = group->priv;
235 
236   gimp_tool_widget_group_hover (widget, coords, state, TRUE);
237 
238   if (priv->focus_widget != priv->hover_widget)
239     {
240       if (priv->hover_widget)
241         gimp_tool_widget_set_focus (priv->hover_widget, TRUE);
242       else if (priv->focus_widget)
243         gimp_tool_widget_set_focus (priv->focus_widget, FALSE);
244     }
245 
246   if (priv->hover_widget)
247     {
248       if (priv->auto_raise)
249         {
250           gimp_container_reorder (priv->children,
251                                   GIMP_OBJECT (priv->hover_widget), -1);
252         }
253 
254       return gimp_tool_widget_button_press (priv->hover_widget,
255                                             coords, time, state, press_type);
256     }
257 
258   return FALSE;
259 }
260 
261 static void
gimp_tool_widget_group_focus_changed(GimpToolWidget * widget)262 gimp_tool_widget_group_focus_changed (GimpToolWidget *widget)
263 {
264   GimpToolWidgetGroup        *group = GIMP_TOOL_WIDGET_GROUP (widget);
265   GimpToolWidgetGroupPrivate *priv  = group->priv;
266 
267   if (priv->focus_widget)
268     {
269       GimpToolWidget *focus_widget = priv->focus_widget;
270 
271       gimp_tool_widget_set_focus (priv->focus_widget,
272                                   gimp_tool_widget_get_focus (widget));
273 
274       priv->focus_widget = focus_widget;
275     }
276 }
277 
278 static void
gimp_tool_widget_group_button_release(GimpToolWidget * widget,const GimpCoords * coords,guint32 time,GdkModifierType state,GimpButtonReleaseType release_type)279 gimp_tool_widget_group_button_release (GimpToolWidget        *widget,
280                                        const GimpCoords      *coords,
281                                        guint32                time,
282                                        GdkModifierType        state,
283                                        GimpButtonReleaseType  release_type)
284 {
285   GimpToolWidgetGroup        *group = GIMP_TOOL_WIDGET_GROUP (widget);
286   GimpToolWidgetGroupPrivate *priv  = group->priv;
287 
288   if (priv->hover_widget)
289     {
290       gimp_tool_widget_button_release (priv->hover_widget,
291                                        coords, time, state, release_type);
292     }
293 }
294 
295 static void
gimp_tool_widget_group_motion(GimpToolWidget * widget,const GimpCoords * coords,guint32 time,GdkModifierType state)296 gimp_tool_widget_group_motion (GimpToolWidget   *widget,
297                         const GimpCoords *coords,
298                         guint32           time,
299                         GdkModifierType   state)
300 {
301   GimpToolWidgetGroup        *group = GIMP_TOOL_WIDGET_GROUP (widget);
302   GimpToolWidgetGroupPrivate *priv = group->priv;
303 
304   if (priv->hover_widget)
305     gimp_tool_widget_motion (priv->hover_widget, coords, time, state);
306 }
307 
308 static GimpHit
gimp_tool_widget_group_hit(GimpToolWidget * widget,const GimpCoords * coords,GdkModifierType state,gboolean proximity)309 gimp_tool_widget_group_hit (GimpToolWidget   *widget,
310                             const GimpCoords *coords,
311                             GdkModifierType   state,
312                             gboolean          proximity)
313 {
314   GimpToolWidgetGroup *group = GIMP_TOOL_WIDGET_GROUP (widget);
315   GimpHit              hit;
316 
317   gimp_tool_widget_group_get_hover_widget (group,
318                                            coords, state, proximity,
319                                            &hit);
320 
321   return hit;
322 }
323 
324 static void
gimp_tool_widget_group_hover(GimpToolWidget * widget,const GimpCoords * coords,GdkModifierType state,gboolean proximity)325 gimp_tool_widget_group_hover (GimpToolWidget   *widget,
326                               const GimpCoords *coords,
327                               GdkModifierType   state,
328                               gboolean          proximity)
329 {
330   GimpToolWidgetGroup        *group = GIMP_TOOL_WIDGET_GROUP (widget);
331   GimpToolWidgetGroupPrivate *priv  = group->priv;
332   GimpToolWidget             *hover_widget;
333 
334   hover_widget =
335     gimp_tool_widget_group_get_hover_widget (group,
336                                              coords, state, proximity,
337                                              NULL);
338 
339   if (priv->hover_widget && priv->hover_widget != hover_widget)
340     gimp_tool_widget_leave_notify (priv->hover_widget);
341 
342   priv->hover_widget = hover_widget;
343 
344   if (priv->hover_widget)
345     gimp_tool_widget_hover (priv->hover_widget, coords, state, proximity);
346 }
347 
348 static void
gimp_tool_widget_group_leave_notify(GimpToolWidget * widget)349 gimp_tool_widget_group_leave_notify (GimpToolWidget *widget)
350 {
351   GimpToolWidgetGroup        *group = GIMP_TOOL_WIDGET_GROUP (widget);
352   GimpToolWidgetGroupPrivate *priv  = group->priv;
353 
354   if (priv->hover_widget)
355     {
356       gimp_tool_widget_leave_notify (priv->hover_widget);
357 
358       priv->hover_widget = NULL;
359     }
360 
361   GIMP_TOOL_WIDGET_CLASS (parent_class)->leave_notify (widget);
362 }
363 
364 static gboolean
gimp_tool_widget_group_key_press(GimpToolWidget * widget,GdkEventKey * kevent)365 gimp_tool_widget_group_key_press (GimpToolWidget *widget,
366                                   GdkEventKey    *kevent)
367 {
368   GimpToolWidgetGroup        *group = GIMP_TOOL_WIDGET_GROUP (widget);
369   GimpToolWidgetGroupPrivate *priv  = group->priv;
370 
371   if (priv->focus_widget)
372     return gimp_tool_widget_key_press (priv->focus_widget, kevent);
373 
374   return GIMP_TOOL_WIDGET_CLASS (parent_class)->key_press (widget, kevent);
375 }
376 
377 static gboolean
gimp_tool_widget_group_key_release(GimpToolWidget * widget,GdkEventKey * kevent)378 gimp_tool_widget_group_key_release (GimpToolWidget *widget,
379                                     GdkEventKey    *kevent)
380 {
381   GimpToolWidgetGroup        *group = GIMP_TOOL_WIDGET_GROUP (widget);
382   GimpToolWidgetGroupPrivate *priv  = group->priv;
383 
384   if (priv->focus_widget)
385     return gimp_tool_widget_key_release (priv->focus_widget, kevent);
386 
387   return FALSE;
388 }
389 
390 static void
gimp_tool_widget_group_motion_modifier(GimpToolWidget * widget,GdkModifierType key,gboolean press,GdkModifierType state)391 gimp_tool_widget_group_motion_modifier (GimpToolWidget  *widget,
392                                         GdkModifierType  key,
393                                         gboolean         press,
394                                         GdkModifierType  state)
395 {
396   GimpToolWidgetGroup        *group = GIMP_TOOL_WIDGET_GROUP (widget);
397   GimpToolWidgetGroupPrivate *priv  = group->priv;
398 
399   if (priv->hover_widget)
400     gimp_tool_widget_motion_modifier (priv->hover_widget, key, press, state);
401 }
402 
403 static void
gimp_tool_widget_group_hover_modifier(GimpToolWidget * widget,GdkModifierType key,gboolean press,GdkModifierType state)404 gimp_tool_widget_group_hover_modifier (GimpToolWidget  *widget,
405                                        GdkModifierType  key,
406                                        gboolean         press,
407                                        GdkModifierType  state)
408 {
409   GimpToolWidgetGroup        *group = GIMP_TOOL_WIDGET_GROUP (widget);
410   GimpToolWidgetGroupPrivate *priv  = group->priv;
411   GList                      *iter;
412 
413   for (iter = g_queue_peek_head_link (GIMP_LIST (priv->children)->queue);
414        iter;
415        iter = g_list_next (iter))
416     {
417       gimp_tool_widget_hover_modifier (iter->data, key, press, state);
418     }
419 }
420 
421 static gboolean
gimp_tool_widget_group_get_cursor(GimpToolWidget * widget,const GimpCoords * coords,GdkModifierType state,GimpCursorType * cursor,GimpToolCursorType * tool_cursor,GimpCursorModifier * modifier)422 gimp_tool_widget_group_get_cursor (GimpToolWidget     *widget,
423                                    const GimpCoords   *coords,
424                                    GdkModifierType     state,
425                                    GimpCursorType     *cursor,
426                                    GimpToolCursorType *tool_cursor,
427                                    GimpCursorModifier *modifier)
428 {
429   GimpToolWidgetGroup        *group = GIMP_TOOL_WIDGET_GROUP (widget);
430   GimpToolWidgetGroupPrivate *priv  = group->priv;
431 
432   if (priv->hover_widget)
433     {
434       return gimp_tool_widget_get_cursor (priv->hover_widget,
435                                           coords, state,
436                                           cursor, tool_cursor, modifier);
437     }
438 
439   return FALSE;
440 }
441 
442 static void
gimp_tool_widget_group_children_add(GimpContainer * container,GimpToolWidget * child,GimpToolWidgetGroup * group)443 gimp_tool_widget_group_children_add (GimpContainer       *container,
444                                      GimpToolWidget      *child,
445                                      GimpToolWidgetGroup *group)
446 {
447   GimpToolWidgetGroupPrivate *priv   = group->priv;
448   GimpToolWidget             *widget = GIMP_TOOL_WIDGET (group);
449   GimpCanvasGroup            *canvas_group;
450 
451   canvas_group = GIMP_CANVAS_GROUP (gimp_tool_widget_get_item (widget));
452 
453   gimp_canvas_group_add_item (canvas_group,
454                               gimp_tool_widget_get_item (child));
455 
456   if (gimp_tool_widget_get_focus (child) && priv->focus_widget)
457     {
458       gimp_tool_widget_set_focus (priv->focus_widget, FALSE);
459 
460       priv->focus_widget = NULL;
461     }
462 
463   if (! priv->focus_widget)
464     {
465       priv->focus_widget = child;
466 
467       gimp_tool_widget_set_focus (child, gimp_tool_widget_get_focus (widget));
468     }
469 
470   gimp_tool_widget_changed (widget);
471 }
472 
473 static void
gimp_tool_widget_group_children_remove(GimpContainer * container,GimpToolWidget * child,GimpToolWidgetGroup * group)474 gimp_tool_widget_group_children_remove (GimpContainer       *container,
475                                         GimpToolWidget      *child,
476                                         GimpToolWidgetGroup *group)
477 {
478   GimpToolWidgetGroupPrivate *priv   = group->priv;
479   GimpToolWidget             *widget = GIMP_TOOL_WIDGET (group);
480   GimpCanvasGroup            *canvas_group;
481 
482   canvas_group = GIMP_CANVAS_GROUP (gimp_tool_widget_get_item (widget));
483 
484   if (priv->focus_widget == child)
485     {
486       gimp_tool_widget_set_focus (child, FALSE);
487 
488       priv->focus_widget = NULL;
489     }
490 
491   if (priv->hover_widget == child)
492     {
493       gimp_tool_widget_leave_notify (child);
494 
495       priv->hover_widget = NULL;
496     }
497 
498   if (! priv->focus_widget)
499     {
500       priv->focus_widget =
501         GIMP_TOOL_WIDGET (gimp_container_get_last_child (container));
502 
503       if (priv->focus_widget)
504         gimp_tool_widget_set_focus (priv->focus_widget, TRUE);
505     }
506 
507   gimp_canvas_group_remove_item (canvas_group,
508                                  gimp_tool_widget_get_item (child));
509 
510   gimp_tool_widget_changed (widget);
511 }
512 
513 static void
gimp_tool_widget_group_children_reorder(GimpContainer * container,GimpToolWidget * child,gint new_index,GimpToolWidgetGroup * group)514 gimp_tool_widget_group_children_reorder (GimpContainer       *container,
515                                          GimpToolWidget      *child,
516                                          gint                 new_index,
517                                          GimpToolWidgetGroup *group)
518 {
519   GimpToolWidget  *widget = GIMP_TOOL_WIDGET (group);
520   GimpCanvasGroup *canvas_group;
521   GList           *iter;
522 
523   canvas_group = GIMP_CANVAS_GROUP (gimp_tool_widget_get_item (widget));
524 
525   for (iter = g_queue_peek_head_link (GIMP_LIST (container)->queue);
526        iter;
527        iter = g_list_next (iter))
528     {
529       GimpCanvasItem *item = gimp_tool_widget_get_item (iter->data);
530 
531       gimp_canvas_group_remove_item (canvas_group, item);
532       gimp_canvas_group_add_item    (canvas_group, item);
533     }
534 
535   gimp_tool_widget_changed (widget);
536 }
537 
538 static void
gimp_tool_widget_group_child_changed(GimpToolWidget * child,GimpToolWidgetGroup * group)539 gimp_tool_widget_group_child_changed (GimpToolWidget      *child,
540                                       GimpToolWidgetGroup *group)
541 {
542   GimpToolWidget *widget = GIMP_TOOL_WIDGET (group);
543 
544   gimp_tool_widget_changed (widget);
545 }
546 
547 static void
gimp_tool_widget_group_child_response(GimpToolWidget * child,gint response_id,GimpToolWidgetGroup * group)548 gimp_tool_widget_group_child_response (GimpToolWidget      *child,
549                                        gint                 response_id,
550                                        GimpToolWidgetGroup *group)
551 {
552   GimpToolWidgetGroupPrivate *priv   = group->priv;
553   GimpToolWidget             *widget = GIMP_TOOL_WIDGET (group);
554 
555   if (priv->focus_widget == child)
556     gimp_tool_widget_response (widget, response_id);
557 }
558 
559 static void
gimp_tool_widget_group_child_snap_offsets(GimpToolWidget * child,gint offset_x,gint offset_y,gint width,gint height,GimpToolWidgetGroup * group)560 gimp_tool_widget_group_child_snap_offsets (GimpToolWidget      *child,
561                                            gint                 offset_x,
562                                            gint                 offset_y,
563                                            gint                 width,
564                                            gint                 height,
565                                            GimpToolWidgetGroup *group)
566 {
567   GimpToolWidgetGroupPrivate *priv   = group->priv;
568   GimpToolWidget             *widget = GIMP_TOOL_WIDGET (group);
569 
570   if (priv->hover_widget == child)
571     {
572       gimp_tool_widget_set_snap_offsets (widget,
573                                          offset_x, offset_y, width, height);
574     }
575 }
576 
577 static void
gimp_tool_widget_group_child_status(GimpToolWidget * child,const gchar * status,GimpToolWidgetGroup * group)578 gimp_tool_widget_group_child_status (GimpToolWidget      *child,
579                                      const gchar         *status,
580                                      GimpToolWidgetGroup *group)
581 {
582   GimpToolWidgetGroupPrivate *priv   = group->priv;
583   GimpToolWidget             *widget = GIMP_TOOL_WIDGET (group);
584 
585   if (priv->hover_widget == child)
586     gimp_tool_widget_set_status (widget, status);
587 }
588 
589 static void
gimp_tool_widget_group_child_status_coords(GimpToolWidget * child,const gchar * title,gdouble x,const gchar * separator,gdouble y,const gchar * help,GimpToolWidgetGroup * group)590 gimp_tool_widget_group_child_status_coords (GimpToolWidget      *child,
591                                             const gchar         *title,
592                                             gdouble              x,
593                                             const gchar         *separator,
594                                             gdouble              y,
595                                             const gchar         *help,
596                                             GimpToolWidgetGroup *group)
597 {
598   GimpToolWidgetGroupPrivate *priv   = group->priv;
599   GimpToolWidget             *widget = GIMP_TOOL_WIDGET (group);
600 
601   if (priv->hover_widget == child)
602     gimp_tool_widget_set_status_coords (widget, title, x, separator, y, help);
603 }
604 
605 static void
gimp_tool_widget_group_child_message(GimpToolWidget * child,const gchar * message,GimpToolWidgetGroup * group)606 gimp_tool_widget_group_child_message (GimpToolWidget      *child,
607                                       const gchar         *message,
608                                       GimpToolWidgetGroup *group)
609 {
610   GimpToolWidgetGroupPrivate *priv   = group->priv;
611   GimpToolWidget             *widget = GIMP_TOOL_WIDGET (group);
612 
613   if (priv->focus_widget == child)
614     gimp_tool_widget_message_literal (widget, message);
615 }
616 
617 static void
gimp_tool_widget_group_child_focus_changed(GimpToolWidget * child,GimpToolWidgetGroup * group)618 gimp_tool_widget_group_child_focus_changed (GimpToolWidget      *child,
619                                             GimpToolWidgetGroup *group)
620 {
621   GimpToolWidgetGroupPrivate *priv   = group->priv;
622   GimpToolWidget             *widget = GIMP_TOOL_WIDGET (group);
623 
624   if (gimp_tool_widget_get_focus (child))
625     {
626       if (priv->focus_widget && priv->focus_widget != child)
627         gimp_tool_widget_set_focus (priv->focus_widget, FALSE);
628 
629       priv->focus_widget = child;
630 
631       gimp_tool_widget_set_focus (widget, TRUE);
632     }
633   else
634     {
635       if (priv->focus_widget == child)
636         priv->focus_widget = NULL;
637     }
638 }
639 
640 static GimpToolWidget *
gimp_tool_widget_group_get_hover_widget(GimpToolWidgetGroup * group,const GimpCoords * coords,GdkModifierType state,gboolean proximity,GimpHit * hit)641 gimp_tool_widget_group_get_hover_widget (GimpToolWidgetGroup *group,
642                                          const GimpCoords    *coords,
643                                          GdkModifierType      state,
644                                          gboolean             proximity,
645                                          GimpHit             *hit)
646 {
647   GimpToolWidgetGroupPrivate *priv           = group->priv;
648   GimpToolWidget             *indirect_child = NULL;
649   gboolean                    indirect       = FALSE;
650   GList                      *iter;
651 
652   for (iter = g_queue_peek_tail_link (GIMP_LIST (priv->children)->queue);
653        iter;
654        iter = g_list_previous (iter))
655     {
656       GimpToolWidget *child = iter->data;
657 
658       switch (gimp_tool_widget_hit (child, coords, state, proximity))
659         {
660         case GIMP_HIT_DIRECT:
661           if (hit) *hit = GIMP_HIT_DIRECT;
662 
663           return child;
664 
665         case GIMP_HIT_INDIRECT:
666           if (! indirect || child == priv->focus_widget)
667             indirect_child = child;
668           else if (indirect_child != priv->focus_widget)
669             indirect_child = NULL;
670 
671           indirect = TRUE;
672 
673           break;
674 
675         case GIMP_HIT_NONE:
676           break;
677         }
678     }
679 
680   if (hit) *hit = indirect_child ? GIMP_HIT_INDIRECT : GIMP_HIT_NONE;
681 
682   return indirect_child;
683 }
684 
685 
686 /*  public functions  */
687 
688 
689 GimpToolWidget *
gimp_tool_widget_group_new(GimpDisplayShell * shell)690 gimp_tool_widget_group_new (GimpDisplayShell *shell)
691 {
692   g_return_val_if_fail (GIMP_IS_DISPLAY_SHELL (shell), NULL);
693 
694   return g_object_new (GIMP_TYPE_TOOL_WIDGET_GROUP,
695                        "shell", shell,
696                        NULL);
697 }
698 
699 GimpContainer *
gimp_tool_widget_group_get_children(GimpToolWidgetGroup * group)700 gimp_tool_widget_group_get_children (GimpToolWidgetGroup *group)
701 {
702   g_return_val_if_fail (GIMP_IS_TOOL_WIDGET_GROUP (group), NULL);
703 
704   return group->priv->children;
705 }
706 
707 GimpToolWidget *
gimp_tool_widget_group_get_focus_widget(GimpToolWidgetGroup * group)708 gimp_tool_widget_group_get_focus_widget (GimpToolWidgetGroup *group)
709 {
710   g_return_val_if_fail (GIMP_IS_TOOL_WIDGET_GROUP (group), NULL);
711 
712   return group->priv->focus_widget;
713 }
714 
715 void
gimp_tool_widget_group_set_auto_raise(GimpToolWidgetGroup * group,gboolean auto_raise)716 gimp_tool_widget_group_set_auto_raise (GimpToolWidgetGroup *group,
717                                        gboolean             auto_raise)
718 {
719   g_return_if_fail (GIMP_IS_TOOL_WIDGET_GROUP (group));
720 
721   group->priv->auto_raise = auto_raise;
722 }
723 
724 gboolean
gimp_tool_widget_group_get_auto_raise(GimpToolWidgetGroup * group)725 gimp_tool_widget_group_get_auto_raise (GimpToolWidgetGroup *group)
726 {
727   g_return_val_if_fail (GIMP_IS_TOOL_WIDGET_GROUP (group), FALSE);
728 
729   return group->priv->auto_raise;
730 }
731 
732