1 /*
2  * Copyright (c) 2014 Red Hat, Inc.
3  *
4  * This library is free software; you can redistribute it and/or
5  * modify it under the terms of the GNU Lesser General Public
6  * License as published by the Free Software Foundation; either
7  * version 2 of the License, or (at your option) any later version.
8  *
9  * This library 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 GNU
12  * Lesser General Public License for more details.
13  *
14  * You should have received a copy of the GNU Lesser General Public
15  * License along with this library. If not, see <http://www.gnu.org/licenses/>.
16  */
17 
18 #include "config.h"
19 #include <glib/gi18n-lib.h>
20 
21 #include "gestures.h"
22 #include "object-tree.h"
23 
24 #include "gtksizegroup.h"
25 #include "gtkcomboboxtext.h"
26 #include "gtklistbox.h"
27 #include "gtkgesture.h"
28 #include "gtklabel.h"
29 #include "gtkframe.h"
30 #include "gtkwidgetprivate.h"
31 
32 enum
33 {
34   PROP_0,
35   PROP_OBJECT_TREE
36 };
37 
38 struct _GtkInspectorGesturesPrivate
39 {
40   GtkSizeGroup *sizegroup;
41   GObject *object;
42   GtkInspectorObjectTree *object_tree;
43 };
44 
G_DEFINE_TYPE_WITH_PRIVATE(GtkInspectorGestures,gtk_inspector_gestures,GTK_TYPE_BOX)45 G_DEFINE_TYPE_WITH_PRIVATE (GtkInspectorGestures, gtk_inspector_gestures, GTK_TYPE_BOX)
46 
47 static void
48 gtk_inspector_gestures_init (GtkInspectorGestures *sl)
49 {
50   sl->priv = gtk_inspector_gestures_get_instance_private (sl);
51   sl->priv->sizegroup = gtk_size_group_new (GTK_SIZE_GROUP_HORIZONTAL);
52   g_object_set (sl,
53                 "orientation", GTK_ORIENTATION_VERTICAL,
54                 "margin-start", 60,
55                 "margin-end", 60,
56                 "margin-top", 60,
57                 "margin-bottom", 30,
58                 "spacing", 10,
59                 NULL);
60 }
61 
62 static void
clear_all(GtkInspectorGestures * sl)63 clear_all (GtkInspectorGestures *sl)
64 {
65   GList *children, *l;
66   GtkWidget *child;
67 
68   children = gtk_container_get_children (GTK_CONTAINER (sl));
69   for (l = children; l; l = l->next)
70     {
71       child = l->data;
72       gtk_container_remove (GTK_CONTAINER (sl), child);
73     }
74   g_list_free (children);
75 }
76 
77 static void
phase_changed_cb(GtkComboBox * combo,GtkInspectorGestures * sl)78 phase_changed_cb (GtkComboBox *combo, GtkInspectorGestures *sl)
79 {
80   GtkWidget *row;
81   GtkPropagationPhase phase;
82   GtkGesture *gesture;
83 
84   phase = gtk_combo_box_get_active (combo);
85   row = gtk_widget_get_ancestor (GTK_WIDGET (combo), GTK_TYPE_LIST_BOX_ROW);
86   gesture = GTK_GESTURE (g_object_get_data (G_OBJECT (row), "gesture"));
87   gtk_event_controller_set_propagation_phase (GTK_EVENT_CONTROLLER (gesture), phase);
88 }
89 
90 static void
row_activated(GtkListBox * box,GtkListBoxRow * row,GtkInspectorGestures * sl)91 row_activated (GtkListBox           *box,
92                GtkListBoxRow        *row,
93                GtkInspectorGestures *sl)
94 {
95   GObject *gesture;
96 
97   gesture = G_OBJECT (g_object_get_data (G_OBJECT (row), "gesture"));
98   gtk_inspector_object_tree_select_object (sl->priv->object_tree, gesture);
99 }
100 
101 static void
add_gesture(GtkInspectorGestures * sl,GObject * object,GtkWidget * listbox,GtkGesture * gesture,GtkPropagationPhase phase)102 add_gesture (GtkInspectorGestures *sl,
103              GObject              *object,
104              GtkWidget            *listbox,
105              GtkGesture           *gesture,
106              GtkPropagationPhase   phase)
107 {
108   GtkWidget *row;
109   GtkWidget *box;
110   GtkWidget *label;
111   GtkWidget *combo;
112 
113   row = gtk_list_box_row_new ();
114   gtk_container_add (GTK_CONTAINER (listbox), row);
115   gtk_widget_show (row);
116   box = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 40);
117   gtk_container_add (GTK_CONTAINER (row), box);
118   g_object_set (box, "margin", 10, NULL);
119   gtk_widget_show (box);
120   label = gtk_label_new (g_type_name_from_instance ((GTypeInstance*)gesture));
121   g_object_set (label, "xalign", 0.0, NULL);
122   gtk_container_add (GTK_CONTAINER (box), label);
123   gtk_size_group_add_widget (sl->priv->sizegroup, label);
124   gtk_widget_show (label);
125   gtk_widget_set_halign (label, GTK_ALIGN_START);
126   gtk_widget_set_valign (label, GTK_ALIGN_BASELINE);
127 
128   combo = gtk_combo_box_text_new ();
129   gtk_combo_box_text_insert_text (GTK_COMBO_BOX_TEXT (combo), GTK_PHASE_NONE, C_("event phase", "None"));
130   gtk_combo_box_text_insert_text (GTK_COMBO_BOX_TEXT (combo), GTK_PHASE_CAPTURE, C_("event phase", "Capture"));
131   gtk_combo_box_text_insert_text (GTK_COMBO_BOX_TEXT (combo), GTK_PHASE_BUBBLE, C_("event phase", "Bubble"));
132   gtk_combo_box_text_insert_text (GTK_COMBO_BOX_TEXT (combo), GTK_PHASE_TARGET, C_("event phase", "Target"));
133   gtk_combo_box_set_active (GTK_COMBO_BOX (combo), phase);
134   gtk_container_add (GTK_CONTAINER (box), combo);
135   gtk_widget_show (combo);
136   gtk_widget_set_halign (label, GTK_ALIGN_END);
137   gtk_widget_set_valign (label, GTK_ALIGN_BASELINE);
138 
139   g_object_set_data (G_OBJECT (row), "gesture", gesture);
140   g_signal_connect (combo, "changed", G_CALLBACK (phase_changed_cb), sl);
141 }
142 
143 static void
add_gesture_group(GtkInspectorGestures * sl,GObject * object,GtkGesture * gesture,GHashTable * hash)144 add_gesture_group (GtkInspectorGestures *sl,
145                    GObject              *object,
146                    GtkGesture           *gesture,
147                    GHashTable           *hash)
148 {
149   GtkWidget *frame;
150   GtkWidget *listbox;
151   GList *list, *l;
152   GtkGesture *g;
153   GtkPropagationPhase phase;
154 
155   frame = gtk_frame_new (NULL);
156   gtk_widget_show (frame);
157   gtk_widget_set_halign (frame, GTK_ALIGN_CENTER);
158 
159   listbox = gtk_list_box_new ();
160   g_signal_connect (listbox, "row-activated", G_CALLBACK (row_activated), sl);
161   gtk_container_add (GTK_CONTAINER (frame), listbox);
162   gtk_widget_show (listbox);
163   gtk_list_box_set_selection_mode (GTK_LIST_BOX (listbox), GTK_SELECTION_NONE);
164 
165   list = gtk_gesture_get_group (gesture);
166   for (l = list; l; l = l->next)
167     {
168       g = l->data;
169       phase = GPOINTER_TO_INT (g_hash_table_lookup (hash, g));
170       add_gesture (sl, object, listbox, g, phase);
171       g_hash_table_remove (hash, g);
172     }
173   g_list_free (list);
174 
175   gtk_container_add (GTK_CONTAINER (sl), frame);
176 }
177 
178 void
gtk_inspector_gestures_set_object(GtkInspectorGestures * sl,GObject * object)179 gtk_inspector_gestures_set_object (GtkInspectorGestures *sl,
180                                    GObject              *object)
181 {
182   GHashTable *hash;
183   GHashTableIter iter;
184   GList *list, *l;
185   gint phase;
186 
187   clear_all (sl);
188   gtk_widget_hide (GTK_WIDGET (sl));
189 
190   if (!GTK_IS_WIDGET (object))
191     return;
192 
193   hash = g_hash_table_new (g_direct_hash, g_direct_equal);
194   for (phase = GTK_PHASE_NONE; phase <= GTK_PHASE_TARGET; phase++)
195     {
196       list = _gtk_widget_list_controllers (GTK_WIDGET (object), phase);
197       for (l = list; l; l = l->next)
198         {
199           GtkEventController *controller = l->data;
200 
201           if (GTK_IS_GESTURE (controller))
202             g_hash_table_insert (hash, controller, GINT_TO_POINTER (phase));
203         }
204       g_list_free (list);
205     }
206 
207   if (g_hash_table_size (hash))
208     gtk_widget_show (GTK_WIDGET (sl));
209 
210   while (g_hash_table_size (hash) > 0)
211     {
212       gpointer key, value;
213       GtkGesture *gesture;
214       g_hash_table_iter_init (&iter, hash);
215       (void)g_hash_table_iter_next (&iter, &key, &value);
216       gesture = key;
217       add_gesture_group (sl, object, gesture, hash);
218     }
219 
220   g_hash_table_unref (hash);
221 }
222 
223 static void
get_property(GObject * object,guint param_id,GValue * value,GParamSpec * pspec)224 get_property (GObject    *object,
225               guint       param_id,
226               GValue     *value,
227               GParamSpec *pspec)
228 {
229   GtkInspectorGestures *sl = GTK_INSPECTOR_GESTURES (object);
230 
231   switch (param_id)
232     {
233       case PROP_OBJECT_TREE:
234         g_value_take_object (value, sl->priv->object_tree);
235         break;
236 
237       default:
238         G_OBJECT_WARN_INVALID_PROPERTY_ID (object, param_id, pspec);
239         break;
240     }
241 }
242 
243 static void
set_property(GObject * object,guint param_id,const GValue * value,GParamSpec * pspec)244 set_property (GObject      *object,
245               guint         param_id,
246               const GValue *value,
247               GParamSpec   *pspec)
248 {
249   GtkInspectorGestures *sl = GTK_INSPECTOR_GESTURES (object);
250 
251   switch (param_id)
252     {
253       case PROP_OBJECT_TREE:
254         sl->priv->object_tree = g_value_get_object (value);
255         break;
256 
257       default:
258         G_OBJECT_WARN_INVALID_PROPERTY_ID (object, param_id, pspec);
259         break;
260     }
261 }
262 
263 static void
gtk_inspector_gestures_class_init(GtkInspectorGesturesClass * klass)264 gtk_inspector_gestures_class_init (GtkInspectorGesturesClass *klass)
265 {
266   GObjectClass *object_class = G_OBJECT_CLASS (klass);
267 
268   object_class->get_property = get_property;
269   object_class->set_property = set_property;
270 
271   g_object_class_install_property (object_class, PROP_OBJECT_TREE,
272       g_param_spec_object ("object-tree", "Widget Tree", "Widget tree",
273                            GTK_TYPE_WIDGET, G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY));
274 }
275 
276 // vim: set et sw=2 ts=2:
277