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
37typedef struct {
38 GtkListBoxRow parent;
39 GtkInspectorOverlay *highlight;
40 GtkWidget *widget;
41} SizeGroupRow;
42
43typedef struct {
44 GtkListBoxRowClass parent;
45} SizeGroupRowClass;
46
47enum {
48 PROP_WIDGET = 1,
49 LAST_PROPERTY
50};
51
52GParamSpec *properties[LAST_PROPERTY] = { NULL };
53
54GType size_group_row_get_type (void);
55
56G_DEFINE_TYPE (SizeGroupRow, size_group_row, GTK_TYPE_LIST_BOX_ROW)
57
58static void
59size_group_row_init (SizeGroupRow *row)
60{
61}
62
63static void
64size_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
82static void
83size_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
92static void
93set_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
106static void
107size_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}
124static void
125size_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
134static void
135size_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
162static void
163size_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
181G_DEFINE_TYPE (GtkInspectorSizeGroups, gtk_inspector_size_groups, GTK_TYPE_BOX)
182
183static void
184clear_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
192static void
193add_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
215static void
216add_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
267void
268gtk_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
295static void
296gtk_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
308static void
309gtk_inspector_size_groups_class_init (GtkInspectorSizeGroupsClass *klass)
310{
311}
312
313// vim: set et sw=2 ts=2:
314

source code of gtk/gtk/inspector/size-groups.c