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