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 "controllers.h" |
22 | |
23 | #include "gtkbinlayout.h" |
24 | #include "gtkdropdown.h" |
25 | #include "gtkbox.h" |
26 | #include "gtkcustomsorter.h" |
27 | #include "gtkgesture.h" |
28 | #include "gtklabel.h" |
29 | #include "gtkscrolledwindow.h" |
30 | #include "gtksortlistmodel.h" |
31 | #include "gtkstack.h" |
32 | #include "gtkwidgetprivate.h" |
33 | #include "window.h" |
34 | #include "gtksignallistitemfactory.h" |
35 | #include "gtkcolumnview.h" |
36 | #include "gtkcolumnviewcolumn.h" |
37 | #include "gtklistitem.h" |
38 | #include "gtknoselection.h" |
39 | |
40 | struct _GtkInspectorControllers |
41 | { |
42 | GtkWidget parent_instance; |
43 | |
44 | GtkWidget *view; |
45 | }; |
46 | |
47 | struct _GtkInspectorControllersClass |
48 | { |
49 | GtkWidgetClass parent_class; |
50 | }; |
51 | |
52 | G_DEFINE_TYPE (GtkInspectorControllers, gtk_inspector_controllers, GTK_TYPE_WIDGET) |
53 | |
54 | static void |
55 | row_activated (GtkColumnView *view, |
56 | guint position, |
57 | GtkInspectorControllers *self) |
58 | { |
59 | GtkInspectorWindow *iw; |
60 | GListModel *model; |
61 | GObject *controller; |
62 | |
63 | iw = GTK_INSPECTOR_WINDOW (gtk_widget_get_ancestor (GTK_WIDGET (self), GTK_TYPE_INSPECTOR_WINDOW)); |
64 | |
65 | model = G_LIST_MODEL (ptr: gtk_column_view_get_model (self: view)); |
66 | controller = g_list_model_get_item (list: model, position); |
67 | gtk_inspector_window_push_object (iw, object: controller, kind: CHILD_KIND_CONTROLLER, position: 0); |
68 | g_object_unref (object: controller); |
69 | } |
70 | |
71 | static void |
72 | setup_row (GtkSignalListItemFactory *factory, |
73 | GtkListItem *list_item, |
74 | gpointer data) |
75 | { |
76 | GtkWidget *label; |
77 | |
78 | label = gtk_label_new (str: "" ); |
79 | gtk_label_set_xalign (GTK_LABEL (label), xalign: 0); |
80 | gtk_list_item_set_child (self: list_item, child: label); |
81 | } |
82 | |
83 | static void |
84 | bind_type (GtkSignalListItemFactory *factory, |
85 | GtkListItem *list_item, |
86 | gpointer data) |
87 | { |
88 | GtkWidget *label; |
89 | GtkEventController *controller; |
90 | |
91 | label = gtk_list_item_get_child (self: list_item); |
92 | controller = gtk_list_item_get_item (self: list_item); |
93 | |
94 | gtk_label_set_label (GTK_LABEL (label), G_OBJECT_TYPE_NAME (controller)); |
95 | } |
96 | |
97 | static void |
98 | bind_name (GtkSignalListItemFactory *factory, |
99 | GtkListItem *list_item, |
100 | gpointer data) |
101 | { |
102 | GtkWidget *label; |
103 | GtkEventController *controller; |
104 | |
105 | label = gtk_list_item_get_child (self: list_item); |
106 | controller = gtk_list_item_get_item (self: list_item); |
107 | |
108 | gtk_label_set_label (GTK_LABEL (label), str: gtk_event_controller_get_name (controller)); |
109 | } |
110 | |
111 | static void |
112 | bind_phase (GtkSignalListItemFactory *factory, |
113 | GtkListItem *list_item, |
114 | gpointer data) |
115 | { |
116 | GtkWidget *label; |
117 | GtkEventController *controller; |
118 | const char *name; |
119 | |
120 | label = gtk_list_item_get_child (self: list_item); |
121 | controller = gtk_list_item_get_item (self: list_item); |
122 | |
123 | switch (gtk_event_controller_get_propagation_phase (controller)) |
124 | { |
125 | case GTK_PHASE_NONE: |
126 | name = C_("event phase" , "None" ); |
127 | break; |
128 | case GTK_PHASE_CAPTURE: |
129 | name = C_("event phase" , "Capture" ); |
130 | break; |
131 | case GTK_PHASE_BUBBLE: |
132 | name = C_("event phase" , "Bubble" ); |
133 | break; |
134 | case GTK_PHASE_TARGET: |
135 | name = C_("event phase" , "Target" ); |
136 | break; |
137 | default: |
138 | g_assert_not_reached (); |
139 | } |
140 | |
141 | gtk_label_set_label (GTK_LABEL (label), str: name); |
142 | } |
143 | |
144 | static void |
145 | bind_limit (GtkSignalListItemFactory *factory, |
146 | GtkListItem *list_item, |
147 | gpointer data) |
148 | { |
149 | GtkWidget *label; |
150 | GtkEventController *controller; |
151 | |
152 | label = gtk_list_item_get_child (self: list_item); |
153 | controller = gtk_list_item_get_item (self: list_item); |
154 | |
155 | if (gtk_event_controller_get_propagation_limit (controller) == GTK_LIMIT_SAME_NATIVE) |
156 | gtk_label_set_label (GTK_LABEL (label), C_("propagation limit" , "Native" )); |
157 | else |
158 | gtk_label_set_label (GTK_LABEL (label), str: "" ); |
159 | } |
160 | |
161 | static void |
162 | gtk_inspector_controllers_init (GtkInspectorControllers *self) |
163 | { |
164 | GtkWidget *sw; |
165 | GtkListItemFactory *factory; |
166 | GtkColumnViewColumn *column; |
167 | |
168 | sw = gtk_scrolled_window_new (); |
169 | |
170 | self->view = gtk_column_view_new (NULL); |
171 | |
172 | factory = gtk_signal_list_item_factory_new (); |
173 | g_signal_connect (factory, "setup" , G_CALLBACK (setup_row), NULL); |
174 | g_signal_connect (factory, "bind" , G_CALLBACK (bind_type), NULL); |
175 | |
176 | column = gtk_column_view_column_new (title: "Type" , factory); |
177 | gtk_column_view_append_column (GTK_COLUMN_VIEW (self->view), column); |
178 | g_object_unref (object: column); |
179 | |
180 | factory = gtk_signal_list_item_factory_new (); |
181 | g_signal_connect (factory, "setup" , G_CALLBACK (setup_row), NULL); |
182 | g_signal_connect (factory, "bind" , G_CALLBACK (bind_name), NULL); |
183 | |
184 | column = gtk_column_view_column_new (title: "Name" , factory); |
185 | gtk_column_view_column_set_expand (self: column, TRUE); |
186 | gtk_column_view_append_column (GTK_COLUMN_VIEW (self->view), column); |
187 | g_object_unref (object: column); |
188 | |
189 | factory = gtk_signal_list_item_factory_new (); |
190 | g_signal_connect (factory, "setup" , G_CALLBACK (setup_row), NULL); |
191 | g_signal_connect (factory, "bind" , G_CALLBACK (bind_phase), NULL); |
192 | |
193 | column = gtk_column_view_column_new (title: "Phase" , factory); |
194 | gtk_column_view_append_column (GTK_COLUMN_VIEW (self->view), column); |
195 | g_object_unref (object: column); |
196 | |
197 | factory = gtk_signal_list_item_factory_new (); |
198 | g_signal_connect (factory, "setup" , G_CALLBACK (setup_row), NULL); |
199 | g_signal_connect (factory, "bind" , G_CALLBACK (bind_limit), NULL); |
200 | |
201 | column = gtk_column_view_column_new (title: "Limit" , factory); |
202 | gtk_column_view_append_column (GTK_COLUMN_VIEW (self->view), column); |
203 | g_object_unref (object: column); |
204 | |
205 | g_signal_connect (self->view, "activate" , G_CALLBACK (row_activated), self); |
206 | |
207 | gtk_scrolled_window_set_child (GTK_SCROLLED_WINDOW (sw), child: self->view); |
208 | |
209 | gtk_widget_set_parent (widget: sw, GTK_WIDGET (self)); |
210 | } |
211 | |
212 | static int |
213 | compare_phases (GtkPropagationPhase first, |
214 | GtkPropagationPhase second) |
215 | { |
216 | int priorities[] = { |
217 | [GTK_PHASE_NONE] = 0, |
218 | [GTK_PHASE_CAPTURE] = 1, |
219 | [GTK_PHASE_BUBBLE] = 3, |
220 | [GTK_PHASE_TARGET] = 2 |
221 | }; |
222 | |
223 | return priorities[first] - priorities[second]; |
224 | } |
225 | |
226 | static int |
227 | compare_controllers (gconstpointer _first, |
228 | gconstpointer _second, |
229 | gpointer unused) |
230 | { |
231 | GtkEventController *first = GTK_EVENT_CONTROLLER (_first); |
232 | GtkEventController *second = GTK_EVENT_CONTROLLER (_second); |
233 | GtkPropagationPhase first_phase, second_phase; |
234 | GtkWidget *first_widget, *second_widget; |
235 | int result; |
236 | |
237 | |
238 | first_phase = gtk_event_controller_get_propagation_phase (controller: first); |
239 | second_phase = gtk_event_controller_get_propagation_phase (controller: second); |
240 | result = compare_phases (first: first_phase, second: second_phase); |
241 | if (result != 0) |
242 | return result; |
243 | |
244 | first_widget = gtk_event_controller_get_widget (controller: first); |
245 | second_widget = gtk_event_controller_get_widget (controller: second); |
246 | if (first_widget == second_widget) |
247 | return 0; |
248 | |
249 | if (gtk_widget_is_ancestor (widget: first_widget, ancestor: second_widget)) |
250 | result = -1; |
251 | else |
252 | result = 1; |
253 | |
254 | if (first_phase == GTK_PHASE_BUBBLE) |
255 | result = -result; |
256 | |
257 | return result; |
258 | } |
259 | |
260 | void |
261 | gtk_inspector_controllers_set_object (GtkInspectorControllers *self, |
262 | GObject *object) |
263 | { |
264 | GtkWidget *stack; |
265 | GtkStackPage *page; |
266 | GListModel *model; |
267 | GtkSortListModel *sort_model; |
268 | GtkSorter *sorter; |
269 | GtkNoSelection *no_selection; |
270 | |
271 | stack = gtk_widget_get_parent (GTK_WIDGET (self)); |
272 | page = gtk_stack_get_page (GTK_STACK (stack), GTK_WIDGET (self)); |
273 | |
274 | if (!GTK_IS_WIDGET (object)) |
275 | { |
276 | gtk_column_view_set_model (GTK_COLUMN_VIEW (self->view), NULL); |
277 | g_object_set (object: page, first_property_name: "visible" , FALSE, NULL); |
278 | return; |
279 | } |
280 | |
281 | g_object_set (object: page, first_property_name: "visible" , TRUE, NULL); |
282 | |
283 | model = gtk_widget_observe_controllers (GTK_WIDGET (object)); |
284 | sorter = GTK_SORTER (ptr: gtk_custom_sorter_new (sort_func: compare_controllers, NULL, NULL)); |
285 | sort_model = gtk_sort_list_model_new (model, sorter); |
286 | no_selection = gtk_no_selection_new (model: G_LIST_MODEL (ptr: sort_model)); |
287 | |
288 | gtk_column_view_set_model (GTK_COLUMN_VIEW (self->view), model: GTK_SELECTION_MODEL (ptr: no_selection)); |
289 | |
290 | g_object_unref (object: no_selection); |
291 | } |
292 | |
293 | static void |
294 | gtk_inspector_controllers_dispose (GObject *object) |
295 | { |
296 | GtkInspectorControllers *self = GTK_INSPECTOR_CONTROLLERS (ptr: object); |
297 | |
298 | gtk_widget_unparent (widget: gtk_widget_get_first_child (GTK_WIDGET (self))); |
299 | |
300 | G_OBJECT_CLASS (gtk_inspector_controllers_parent_class)->dispose (object); |
301 | } |
302 | |
303 | static void |
304 | gtk_inspector_controllers_class_init (GtkInspectorControllersClass *klass) |
305 | { |
306 | GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (klass); |
307 | GObjectClass *object_class = G_OBJECT_CLASS (klass); |
308 | |
309 | object_class->dispose = gtk_inspector_controllers_dispose; |
310 | |
311 | gtk_widget_class_set_layout_manager_type (widget_class, GTK_TYPE_BIN_LAYOUT); |
312 | } |
313 | |
314 | // vim: set et sw=2 ts=2: |
315 | |