1/* gtkshortcutsgroup.c
2 *
3 * Copyright (C) 2015 Christian Hergert <christian@hergert.me>
4 *
5 * This library is free software; you can redistribute it and/or
6 * modify it under the terms of the GNU Library General Public License as
7 * published by the Free Software Foundation; either version 2 of the
8 * License, or (at your option) any later version.
9 *
10 * This library is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 * Library General Public License for more details.
14 *
15 * You should have received a copy of the GNU Library General Public
16 * License along with this library. If not, see <http://www.gnu.org/licenses/>.
17 */
18
19#include "config.h"
20
21#include "gtkshortcutsgroup.h"
22
23#include "gtkbox.h"
24#include "gtkbuildable.h"
25#include "gtkintl.h"
26#include "gtklabel.h"
27#include "gtkorientable.h"
28#include "gtkprivate.h"
29#include "gtkshortcutsshortcut.h"
30#include "gtksizegroup.h"
31
32/**
33 * GtkShortcutsGroup:
34 *
35 * A `GtkShortcutsGroup` represents a group of related keyboard shortcuts
36 * or gestures.
37 *
38 * The group has a title. It may optionally be associated with a view
39 * of the application, which can be used to show only relevant shortcuts
40 * depending on the application context.
41 *
42 * This widget is only meant to be used with [class@Gtk.ShortcutsWindow].
43 */
44
45struct _GtkShortcutsGroup
46{
47 GtkBox parent_instance;
48
49 GtkLabel *title;
50 char *view;
51 guint height;
52
53 GtkSizeGroup *accel_size_group;
54 GtkSizeGroup *title_size_group;
55};
56
57struct _GtkShortcutsGroupClass
58{
59 GtkBoxClass parent_class;
60};
61
62static void gtk_shortcuts_group_buildable_iface_init (GtkBuildableIface *iface);
63
64G_DEFINE_TYPE_WITH_CODE (GtkShortcutsGroup, gtk_shortcuts_group, GTK_TYPE_BOX,
65 G_IMPLEMENT_INTERFACE (GTK_TYPE_BUILDABLE,
66 gtk_shortcuts_group_buildable_iface_init))
67
68enum {
69 PROP_0,
70 PROP_TITLE,
71 PROP_VIEW,
72 PROP_ACCEL_SIZE_GROUP,
73 PROP_TITLE_SIZE_GROUP,
74 PROP_HEIGHT,
75 LAST_PROP
76};
77
78static GParamSpec *properties[LAST_PROP];
79
80static void
81gtk_shortcuts_group_apply_accel_size_group (GtkShortcutsGroup *group,
82 GtkWidget *child)
83{
84 if (GTK_IS_SHORTCUTS_SHORTCUT (child))
85 g_object_set (object: child, first_property_name: "accel-size-group", group->accel_size_group, NULL);
86}
87
88static void
89gtk_shortcuts_group_apply_title_size_group (GtkShortcutsGroup *group,
90 GtkWidget *child)
91{
92 if (GTK_IS_SHORTCUTS_SHORTCUT (child))
93 g_object_set (object: child, first_property_name: "title-size-group", group->title_size_group, NULL);
94}
95
96static void
97gtk_shortcuts_group_set_accel_size_group (GtkShortcutsGroup *group,
98 GtkSizeGroup *size_group)
99{
100 GtkWidget *child;
101
102 g_set_object (&group->accel_size_group, size_group);
103
104 for (child = gtk_widget_get_first_child (GTK_WIDGET (group));
105 child != NULL;
106 child = gtk_widget_get_next_sibling (widget: child))
107 gtk_shortcuts_group_apply_accel_size_group (group, child);
108}
109
110static void
111gtk_shortcuts_group_set_title_size_group (GtkShortcutsGroup *group,
112 GtkSizeGroup *size_group)
113{
114 GtkWidget *child;
115
116 g_set_object (&group->title_size_group, size_group);
117
118 for (child = gtk_widget_get_first_child (GTK_WIDGET (group));
119 child != NULL;
120 child = gtk_widget_get_next_sibling (widget: child))
121 gtk_shortcuts_group_apply_title_size_group (group, child);
122}
123
124static guint
125gtk_shortcuts_group_get_height (GtkShortcutsGroup *group)
126{
127 GtkWidget *child;
128 guint height;
129
130 height = 1;
131
132 for (child = gtk_widget_get_first_child (GTK_WIDGET (group));
133 child != NULL;
134 child = gtk_widget_get_next_sibling (widget: child))
135 {
136 if (!gtk_widget_get_visible (widget: child))
137 continue;
138 else if (GTK_IS_SHORTCUTS_SHORTCUT (child))
139 height += 1;
140 }
141
142 return height;
143}
144
145static GtkBuildableIface *parent_buildable_iface;
146
147static void
148gtk_shortcuts_group_buildable_add_child (GtkBuildable *buildable,
149 GtkBuilder *builder,
150 GObject *child,
151 const char *type)
152{
153 if (GTK_IS_SHORTCUTS_SHORTCUT (child))
154 {
155 gtk_box_append (GTK_BOX (buildable), GTK_WIDGET (child));
156 gtk_shortcuts_group_apply_accel_size_group (GTK_SHORTCUTS_GROUP (buildable), GTK_WIDGET (child));
157 gtk_shortcuts_group_apply_title_size_group (GTK_SHORTCUTS_GROUP (buildable), GTK_WIDGET (child));
158 }
159 else
160 parent_buildable_iface->add_child (buildable, builder, child, type);
161}
162
163static void
164gtk_shortcuts_group_buildable_iface_init (GtkBuildableIface *iface)
165{
166 parent_buildable_iface = g_type_interface_peek_parent (g_iface: iface);
167
168 iface->add_child = gtk_shortcuts_group_buildable_add_child;
169}
170
171static void
172gtk_shortcuts_group_get_property (GObject *object,
173 guint prop_id,
174 GValue *value,
175 GParamSpec *pspec)
176{
177 GtkShortcutsGroup *self = GTK_SHORTCUTS_GROUP (object);
178
179 switch (prop_id)
180 {
181 case PROP_TITLE:
182 g_value_set_string (value, v_string: gtk_label_get_label (self: self->title));
183 break;
184
185 case PROP_VIEW:
186 g_value_set_string (value, v_string: self->view);
187 break;
188
189 case PROP_HEIGHT:
190 g_value_set_uint (value, v_uint: gtk_shortcuts_group_get_height (group: self));
191 break;
192
193 default:
194 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
195 }
196}
197
198static void
199gtk_shortcuts_group_direction_changed (GtkWidget *widget,
200 GtkTextDirection previous_dir)
201{
202 GTK_WIDGET_CLASS (gtk_shortcuts_group_parent_class)->direction_changed (widget, previous_dir);
203 g_object_notify (G_OBJECT (widget), property_name: "height");
204}
205
206static void
207gtk_shortcuts_group_set_property (GObject *object,
208 guint prop_id,
209 const GValue *value,
210 GParamSpec *pspec)
211{
212 GtkShortcutsGroup *self = GTK_SHORTCUTS_GROUP (object);
213
214 switch (prop_id)
215 {
216 case PROP_TITLE:
217 gtk_label_set_label (self: self->title, str: g_value_get_string (value));
218 break;
219
220 case PROP_VIEW:
221 g_free (mem: self->view);
222 self->view = g_value_dup_string (value);
223 break;
224
225 case PROP_ACCEL_SIZE_GROUP:
226 gtk_shortcuts_group_set_accel_size_group (group: self, GTK_SIZE_GROUP (g_value_get_object (value)));
227 break;
228
229 case PROP_TITLE_SIZE_GROUP:
230 gtk_shortcuts_group_set_title_size_group (group: self, GTK_SIZE_GROUP (g_value_get_object (value)));
231 break;
232
233 default:
234 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
235 }
236}
237
238static void
239gtk_shortcuts_group_finalize (GObject *object)
240{
241 GtkShortcutsGroup *self = GTK_SHORTCUTS_GROUP (object);
242
243 g_free (mem: self->view);
244 g_set_object (&self->accel_size_group, NULL);
245 g_set_object (&self->title_size_group, NULL);
246
247 G_OBJECT_CLASS (gtk_shortcuts_group_parent_class)->finalize (object);
248}
249
250static void
251gtk_shortcuts_group_dispose (GObject *object)
252{
253 GtkShortcutsGroup *self = GTK_SHORTCUTS_GROUP (object);
254
255 g_clear_pointer ((GtkWidget **)&self->title, gtk_widget_unparent);
256
257 G_OBJECT_CLASS (gtk_shortcuts_group_parent_class)->dispose (object);
258}
259
260static void
261gtk_shortcuts_group_class_init (GtkShortcutsGroupClass *klass)
262{
263 GObjectClass *object_class = G_OBJECT_CLASS (klass);
264 GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (klass);
265
266 object_class->finalize = gtk_shortcuts_group_finalize;
267 object_class->get_property = gtk_shortcuts_group_get_property;
268 object_class->set_property = gtk_shortcuts_group_set_property;
269 object_class->dispose = gtk_shortcuts_group_dispose;
270
271 widget_class->direction_changed = gtk_shortcuts_group_direction_changed;
272
273 /**
274 * GtkShortcutsGroup:title:
275 *
276 * The title for this group of shortcuts.
277 */
278 properties[PROP_TITLE] =
279 g_param_spec_string (name: "title", P_("Title"), P_("Title"),
280 default_value: "",
281 flags: (G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
282
283 /**
284 * GtkShortcutsGroup:view:
285 *
286 * An optional view that the shortcuts in this group are relevant for.
287 *
288 * The group will be hidden if the [property@Gtk.ShortcutsWindow:view-name]
289 * property does not match the view of this group.
290 *
291 * Set this to %NULL to make the group always visible.
292 */
293 properties[PROP_VIEW] =
294 g_param_spec_string (name: "view", P_("View"), P_("View"),
295 NULL,
296 flags: (G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
297
298 /**
299 * GtkShortcutsGroup:accel-size-group:
300 *
301 * The size group for the accelerator portion of shortcuts in this group.
302 *
303 * This is used internally by GTK, and must not be modified by applications.
304 */
305 properties[PROP_ACCEL_SIZE_GROUP] =
306 g_param_spec_object (name: "accel-size-group",
307 P_("Accelerator Size Group"),
308 P_("Accelerator Size Group"),
309 GTK_TYPE_SIZE_GROUP,
310 flags: (G_PARAM_WRITABLE | G_PARAM_STATIC_STRINGS));
311
312 /**
313 * GtkShortcutsGroup:title-size-group:
314 *
315 * The size group for the textual portion of shortcuts in this group.
316 *
317 * This is used internally by GTK, and must not be modified by applications.
318 */
319 properties[PROP_TITLE_SIZE_GROUP] =
320 g_param_spec_object (name: "title-size-group",
321 P_("Title Size Group"),
322 P_("Title Size Group"),
323 GTK_TYPE_SIZE_GROUP,
324 flags: (G_PARAM_WRITABLE | G_PARAM_STATIC_STRINGS));
325
326 /**
327 * GtkShortcutsGroup:height:
328 *
329 * A rough measure for the number of lines in this group.
330 *
331 * This is used internally by GTK, and is not useful for applications.
332 */
333 properties[PROP_HEIGHT] =
334 g_param_spec_uint (name: "height", P_("Height"), P_("Height"),
335 minimum: 0, G_MAXUINT, default_value: 1,
336 flags: (G_PARAM_READABLE | G_PARAM_STATIC_STRINGS));
337
338 g_object_class_install_properties (oclass: object_class, n_pspecs: LAST_PROP, pspecs: properties);
339
340 gtk_widget_class_set_css_name (widget_class, I_("shortcuts-group"));
341}
342
343static void
344gtk_shortcuts_group_init (GtkShortcutsGroup *self)
345{
346 PangoAttrList *attrs;
347
348 gtk_orientable_set_orientation (GTK_ORIENTABLE (self), orientation: GTK_ORIENTATION_VERTICAL);
349 gtk_box_set_spacing (GTK_BOX (self), spacing: 10);
350
351 attrs = pango_attr_list_new ();
352 pango_attr_list_insert (list: attrs, attr: pango_attr_weight_new (weight: PANGO_WEIGHT_BOLD));
353 self->title = g_object_new (GTK_TYPE_LABEL,
354 first_property_name: "attributes", attrs,
355 "visible", TRUE,
356 "xalign", 0.0f,
357 NULL);
358 pango_attr_list_unref (list: attrs);
359
360 gtk_box_append (GTK_BOX (self), GTK_WIDGET (self->title));
361}
362

source code of gtk/gtk/gtkshortcutsgroup.c