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 "size-groups.h" |
22 | |
23 | #include "highlightoverlay.h" |
24 | #include "window.h" |
25 | |
26 | #include "gtkdropdown.h" |
27 | #include "gtkframe.h" |
28 | #include "gtklabel.h" |
29 | #include "gtklistbox.h" |
30 | #include "gtksizegroup.h" |
31 | #include "gtkswitch.h" |
32 | #include "gtkwidgetprivate.h" |
33 | #include "gtkstack.h" |
34 | #include "gtkstringlist.h" |
35 | |
36 | |
37 | typedef struct { |
38 | GtkListBoxRow parent; |
39 | GtkInspectorOverlay *highlight; |
40 | GtkWidget *widget; |
41 | } SizeGroupRow; |
42 | |
43 | typedef struct { |
44 | GtkListBoxRowClass parent; |
45 | } SizeGroupRowClass; |
46 | |
47 | enum { |
48 | PROP_WIDGET = 1, |
49 | LAST_PROPERTY |
50 | }; |
51 | |
52 | GParamSpec *properties[LAST_PROPERTY] = { NULL }; |
53 | |
54 | GType size_group_row_get_type (void); |
55 | |
56 | G_DEFINE_TYPE (SizeGroupRow, size_group_row, GTK_TYPE_LIST_BOX_ROW) |
57 | |
58 | static void |
59 | size_group_row_init (SizeGroupRow *row) |
60 | { |
61 | } |
62 | |
63 | static void |
64 | size_group_row_get_property (GObject *object, |
65 | guint property_id, |
66 | GValue *value, |
67 | GParamSpec *pspec) |
68 | { |
69 | SizeGroupRow *row = (SizeGroupRow*)object; |
70 | |
71 | switch (property_id) |
72 | { |
73 | case PROP_WIDGET: |
74 | g_value_set_pointer (value, v_pointer: row->widget); |
75 | break; |
76 | default: |
77 | G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec); |
78 | break; |
79 | } |
80 | } |
81 | |
82 | static void |
83 | size_group_row_widget_destroyed (GtkWidget *widget, SizeGroupRow *row) |
84 | { |
85 | GtkWidget *parent; |
86 | |
87 | parent = gtk_widget_get_parent (GTK_WIDGET (row)); |
88 | if (parent) |
89 | gtk_box_remove (GTK_BOX (parent), GTK_WIDGET (row)); |
90 | } |
91 | |
92 | static void |
93 | set_widget (SizeGroupRow *row, GtkWidget *widget) |
94 | { |
95 | if (row->widget) |
96 | g_signal_handlers_disconnect_by_func (row->widget, |
97 | size_group_row_widget_destroyed, row); |
98 | |
99 | row->widget = widget; |
100 | |
101 | if (row->widget) |
102 | g_signal_connect (row->widget, "destroy" , |
103 | G_CALLBACK (size_group_row_widget_destroyed), row); |
104 | } |
105 | |
106 | static void |
107 | size_group_row_set_property (GObject *object, |
108 | guint property_id, |
109 | const GValue *value, |
110 | GParamSpec *pspec) |
111 | { |
112 | SizeGroupRow *row = (SizeGroupRow*)object; |
113 | |
114 | switch (property_id) |
115 | { |
116 | case PROP_WIDGET: |
117 | set_widget (row, widget: g_value_get_pointer (value)); |
118 | break; |
119 | default: |
120 | G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec); |
121 | break; |
122 | } |
123 | } |
124 | static void |
125 | size_group_row_finalize (GObject *object) |
126 | { |
127 | SizeGroupRow *row = (SizeGroupRow *)object; |
128 | |
129 | set_widget (row, NULL); |
130 | |
131 | G_OBJECT_CLASS (size_group_row_parent_class)->finalize (object); |
132 | } |
133 | |
134 | static void |
135 | size_group_state_flags_changed (GtkWidget *widget, |
136 | GtkStateFlags old_state) |
137 | { |
138 | SizeGroupRow *row = (SizeGroupRow*)widget; |
139 | GtkStateFlags state; |
140 | |
141 | if (!row->widget) |
142 | return; |
143 | |
144 | state = gtk_widget_get_state_flags (widget); |
145 | if ((state & GTK_STATE_FLAG_PRELIGHT) != (old_state & GTK_STATE_FLAG_PRELIGHT)) |
146 | { |
147 | GtkInspectorWindow *iw = GTK_INSPECTOR_WINDOW (gtk_widget_get_root (widget)); |
148 | |
149 | if (state & GTK_STATE_FLAG_PRELIGHT) |
150 | { |
151 | row->highlight = gtk_highlight_overlay_new (widget: row->widget); |
152 | gtk_inspector_window_add_overlay (iw, overlay: row->highlight); |
153 | } |
154 | else |
155 | { |
156 | gtk_inspector_window_remove_overlay (iw, overlay: row->highlight); |
157 | g_clear_object (&row->highlight); |
158 | } |
159 | } |
160 | } |
161 | |
162 | static void |
163 | size_group_row_class_init (SizeGroupRowClass *class) |
164 | { |
165 | GObjectClass *object_class = G_OBJECT_CLASS (class); |
166 | GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (class); |
167 | |
168 | object_class->finalize = size_group_row_finalize; |
169 | object_class->get_property = size_group_row_get_property; |
170 | object_class->set_property = size_group_row_set_property; |
171 | |
172 | widget_class->state_flags_changed = size_group_state_flags_changed; |
173 | |
174 | properties[PROP_WIDGET] = |
175 | g_param_spec_pointer (name: "widget" , nick: "Widget" , blurb: "Widget" , flags: G_PARAM_READWRITE); |
176 | |
177 | g_object_class_install_properties (oclass: object_class, n_pspecs: LAST_PROPERTY, pspecs: properties); |
178 | |
179 | } |
180 | |
181 | G_DEFINE_TYPE (GtkInspectorSizeGroups, gtk_inspector_size_groups, GTK_TYPE_BOX) |
182 | |
183 | static void |
184 | clear_view (GtkInspectorSizeGroups *sl) |
185 | { |
186 | GtkWidget *child; |
187 | |
188 | while ((child = gtk_widget_get_first_child (GTK_WIDGET (sl)))) |
189 | gtk_box_remove (GTK_BOX (sl), child); |
190 | } |
191 | |
192 | static void |
193 | add_widget (GtkInspectorSizeGroups *sl, |
194 | GtkListBox *listbox, |
195 | GtkWidget *widget) |
196 | { |
197 | GtkWidget *row; |
198 | GtkWidget *label; |
199 | char *text; |
200 | |
201 | row = g_object_new (object_type: size_group_row_get_type (), first_property_name: "widget" , widget, NULL); |
202 | text = g_strdup_printf (format: "%p (%s)" , widget, g_type_name_from_instance (instance: (GTypeInstance*)widget)); |
203 | label = gtk_label_new (str: text); |
204 | g_free (mem: text); |
205 | gtk_widget_set_margin_start (widget: label, margin: 10); |
206 | gtk_widget_set_margin_end (widget: label, margin: 10); |
207 | gtk_widget_set_margin_top (widget: label, margin: 10); |
208 | gtk_widget_set_margin_bottom (widget: label, margin: 10); |
209 | gtk_widget_set_halign (widget: label, align: GTK_ALIGN_START); |
210 | gtk_widget_set_valign (widget: label, align: GTK_ALIGN_BASELINE); |
211 | gtk_list_box_row_set_child (GTK_LIST_BOX_ROW (row), child: label); |
212 | gtk_list_box_insert (box: listbox, child: row, position: -1); |
213 | } |
214 | |
215 | static void |
216 | add_size_group (GtkInspectorSizeGroups *sl, |
217 | GtkSizeGroup *group) |
218 | { |
219 | GtkWidget *frame, *box, *box2; |
220 | GtkWidget *label, *dropdown; |
221 | GSList *widgets, *l; |
222 | GtkWidget *listbox; |
223 | const char *modes[5]; |
224 | |
225 | modes[0] = C_("sizegroup mode" , "None" ); |
226 | modes[1] = C_("sizegroup mode" , "Horizontal" ); |
227 | modes[2] = C_("sizegroup mode" , "Vertical" ); |
228 | modes[3] = C_("sizegroup mode" , "Both" ); |
229 | modes[4] = NULL; |
230 | |
231 | frame = gtk_frame_new (NULL); |
232 | gtk_box_append (GTK_BOX (sl), child: frame); |
233 | box = gtk_box_new (orientation: GTK_ORIENTATION_VERTICAL, spacing: 0); |
234 | gtk_widget_add_css_class (widget: box, css_class: "view" ); |
235 | gtk_frame_set_child (GTK_FRAME (frame), child: box); |
236 | |
237 | box2 = gtk_box_new (orientation: GTK_ORIENTATION_HORIZONTAL, spacing: 10); |
238 | gtk_box_append (GTK_BOX (box), child: box2); |
239 | |
240 | label = gtk_label_new (_("Mode" )); |
241 | gtk_widget_set_margin_start (widget: label, margin: 10); |
242 | gtk_widget_set_margin_end (widget: label, margin: 10); |
243 | gtk_widget_set_margin_top (widget: label, margin: 10); |
244 | gtk_widget_set_margin_bottom (widget: label, margin: 10); |
245 | gtk_widget_set_halign (widget: label, align: GTK_ALIGN_START); |
246 | gtk_widget_set_valign (widget: label, align: GTK_ALIGN_BASELINE); |
247 | gtk_box_append (GTK_BOX (box2), child: label); |
248 | |
249 | dropdown = gtk_drop_down_new_from_strings (strings: modes); |
250 | g_object_set (object: dropdown, first_property_name: "margin" , 10, NULL); |
251 | gtk_widget_set_halign (widget: dropdown, align: GTK_ALIGN_END); |
252 | gtk_widget_set_valign (widget: dropdown, align: GTK_ALIGN_BASELINE); |
253 | g_object_bind_property (source: group, source_property: "mode" , |
254 | target: dropdown, target_property: "selected" , |
255 | flags: G_BINDING_BIDIRECTIONAL | G_BINDING_SYNC_CREATE); |
256 | gtk_box_append (GTK_BOX (box2), child: dropdown); |
257 | |
258 | listbox = gtk_list_box_new (); |
259 | gtk_box_append (GTK_BOX (box), child: listbox); |
260 | gtk_list_box_set_selection_mode (GTK_LIST_BOX (listbox), mode: GTK_SELECTION_NONE); |
261 | |
262 | widgets = gtk_size_group_get_widgets (size_group: group); |
263 | for (l = widgets; l; l = l->next) |
264 | add_widget (sl, GTK_LIST_BOX (listbox), GTK_WIDGET (l->data)); |
265 | } |
266 | |
267 | void |
268 | gtk_inspector_size_groups_set_object (GtkInspectorSizeGroups *sl, |
269 | GObject *object) |
270 | { |
271 | GSList *groups, *l; |
272 | GtkWidget *stack; |
273 | GtkStackPage *page; |
274 | |
275 | stack = gtk_widget_get_parent (GTK_WIDGET (sl)); |
276 | page = gtk_stack_get_page (GTK_STACK (stack), GTK_WIDGET (sl)); |
277 | |
278 | g_object_set (object: page, first_property_name: "visible" , FALSE, NULL); |
279 | |
280 | clear_view (sl); |
281 | |
282 | if (!GTK_IS_WIDGET (object)) |
283 | return; |
284 | |
285 | groups = _gtk_widget_get_sizegroups (GTK_WIDGET (object)); |
286 | if (groups) |
287 | g_object_set (object: page, first_property_name: "visible" , TRUE, NULL); |
288 | for (l = groups; l; l = l->next) |
289 | { |
290 | GtkSizeGroup *group = l->data; |
291 | add_size_group (sl, group); |
292 | } |
293 | } |
294 | |
295 | static void |
296 | gtk_inspector_size_groups_init (GtkInspectorSizeGroups *sl) |
297 | { |
298 | g_object_set (object: sl, |
299 | first_property_name: "orientation" , GTK_ORIENTATION_VERTICAL, |
300 | "margin-start" , 60, |
301 | "margin-end" , 60, |
302 | "margin-bottom" , 60, |
303 | "margin-bottom" , 30, |
304 | "spacing" , 10, |
305 | NULL); |
306 | } |
307 | |
308 | static void |
309 | gtk_inspector_size_groups_class_init (GtkInspectorSizeGroupsClass *klass) |
310 | { |
311 | } |
312 | |
313 | // vim: set et sw=2 ts=2: |
314 | |