1/* gtkshortcutsshortcut.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 "gtkshortcutsshortcutprivate.h"
22
23#include "gtkimage.h"
24#include "gtkbox.h"
25#include "gtkintl.h"
26#include "gtklabel.h"
27#include "gtkprivate.h"
28#include "gtkwidgetprivate.h"
29#include "gtkshortcutlabel.h"
30#include "gtkshortcutswindowprivate.h"
31#include "gtksizegroup.h"
32#include "gtktypebuiltins.h"
33
34/**
35 * GtkShortcutsShortcut:
36 *
37 * A `GtkShortcutsShortcut` represents a single keyboard shortcut or gesture
38 * with a short text.
39 *
40 * This widget is only meant to be used with `GtkShortcutsWindow`.
41 */
42
43struct _GtkShortcutsShortcut
44{
45 GtkWidget parent_instance;
46
47 GtkBox *box;
48 GtkImage *image;
49 GtkShortcutLabel *accelerator;
50 GtkLabel *title;
51 GtkLabel *subtitle;
52 GtkLabel *title_box;
53
54 GtkSizeGroup *accel_size_group;
55 GtkSizeGroup *title_size_group;
56
57 gboolean subtitle_set;
58 gboolean icon_set;
59 GtkTextDirection direction;
60 char *action_name;
61 GtkShortcutType shortcut_type;
62};
63
64struct _GtkShortcutsShortcutClass
65{
66 GtkWidgetClass parent_class;
67};
68
69G_DEFINE_TYPE (GtkShortcutsShortcut, gtk_shortcuts_shortcut, GTK_TYPE_WIDGET)
70
71enum {
72 PROP_0,
73 PROP_ACCELERATOR,
74 PROP_ICON,
75 PROP_ICON_SET,
76 PROP_TITLE,
77 PROP_SUBTITLE,
78 PROP_SUBTITLE_SET,
79 PROP_ACCEL_SIZE_GROUP,
80 PROP_TITLE_SIZE_GROUP,
81 PROP_DIRECTION,
82 PROP_SHORTCUT_TYPE,
83 PROP_ACTION_NAME,
84 LAST_PROP
85};
86
87static GParamSpec *properties[LAST_PROP];
88
89static void
90gtk_shortcuts_shortcut_set_accelerator (GtkShortcutsShortcut *self,
91 const char *accelerator)
92{
93 gtk_shortcut_label_set_accelerator (self: self->accelerator, accelerator);
94}
95
96static void
97gtk_shortcuts_shortcut_set_accel_size_group (GtkShortcutsShortcut *self,
98 GtkSizeGroup *group)
99{
100 if (self->accel_size_group)
101 {
102 gtk_size_group_remove_widget (size_group: self->accel_size_group, GTK_WIDGET (self->accelerator));
103 gtk_size_group_remove_widget (size_group: self->accel_size_group, GTK_WIDGET (self->image));
104 }
105
106 if (group)
107 {
108 gtk_size_group_add_widget (size_group: group, GTK_WIDGET (self->accelerator));
109 gtk_size_group_add_widget (size_group: group, GTK_WIDGET (self->image));
110 }
111
112 g_set_object (&self->accel_size_group, group);
113}
114
115static void
116gtk_shortcuts_shortcut_set_title_size_group (GtkShortcutsShortcut *self,
117 GtkSizeGroup *group)
118{
119 if (self->title_size_group)
120 gtk_size_group_remove_widget (size_group: self->title_size_group, GTK_WIDGET (self->title_box));
121 if (group)
122 gtk_size_group_add_widget (size_group: group, GTK_WIDGET (self->title_box));
123
124 g_set_object (&self->title_size_group, group);
125}
126
127static void
128update_subtitle_from_type (GtkShortcutsShortcut *self)
129{
130 const char *subtitle;
131
132 if (self->subtitle_set)
133 return;
134
135 switch (self->shortcut_type)
136 {
137 case GTK_SHORTCUT_ACCELERATOR:
138 case GTK_SHORTCUT_GESTURE:
139 subtitle = NULL;
140 break;
141
142 case GTK_SHORTCUT_GESTURE_PINCH:
143 subtitle = _("Two finger pinch");
144 break;
145
146 case GTK_SHORTCUT_GESTURE_STRETCH:
147 subtitle = _("Two finger stretch");
148 break;
149
150 case GTK_SHORTCUT_GESTURE_ROTATE_CLOCKWISE:
151 subtitle = _("Rotate clockwise");
152 break;
153
154 case GTK_SHORTCUT_GESTURE_ROTATE_COUNTERCLOCKWISE:
155 subtitle = _("Rotate counterclockwise");
156 break;
157
158 case GTK_SHORTCUT_GESTURE_TWO_FINGER_SWIPE_LEFT:
159 subtitle = _("Two finger swipe left");
160 break;
161
162 case GTK_SHORTCUT_GESTURE_TWO_FINGER_SWIPE_RIGHT:
163 subtitle = _("Two finger swipe right");
164 break;
165
166 case GTK_SHORTCUT_GESTURE_SWIPE_LEFT:
167 subtitle = _("Swipe left");
168 break;
169
170 case GTK_SHORTCUT_GESTURE_SWIPE_RIGHT:
171 subtitle = _("Swipe right");
172 break;
173
174 default:
175 subtitle = NULL;
176 break;
177 }
178
179 gtk_label_set_label (self: self->subtitle, str: subtitle);
180 gtk_widget_set_visible (GTK_WIDGET (self->subtitle), visible: subtitle != NULL);
181 g_object_notify (G_OBJECT (self), property_name: "subtitle");
182}
183
184static void
185gtk_shortcuts_shortcut_set_subtitle_set (GtkShortcutsShortcut *self,
186 gboolean subtitle_set)
187{
188 if (self->subtitle_set != subtitle_set)
189 {
190 self->subtitle_set = subtitle_set;
191 g_object_notify (G_OBJECT (self), property_name: "subtitle-set");
192 }
193 update_subtitle_from_type (self);
194}
195
196static void
197gtk_shortcuts_shortcut_set_subtitle (GtkShortcutsShortcut *self,
198 const char *subtitle)
199{
200 gtk_label_set_label (self: self->subtitle, str: subtitle);
201 gtk_widget_set_visible (GTK_WIDGET (self->subtitle), visible: subtitle && subtitle[0]);
202 gtk_shortcuts_shortcut_set_subtitle_set (self, subtitle_set: subtitle && subtitle[0]);
203
204 g_object_notify (G_OBJECT (self), property_name: "subtitle");
205}
206
207static void
208update_icon_from_type (GtkShortcutsShortcut *self)
209{
210 GIcon *icon;
211
212 if (self->icon_set)
213 return;
214
215 switch (self->shortcut_type)
216 {
217 case GTK_SHORTCUT_GESTURE_PINCH:
218 icon = g_themed_icon_new (iconname: "gesture-pinch-symbolic");
219 break;
220
221 case GTK_SHORTCUT_GESTURE_STRETCH:
222 icon = g_themed_icon_new (iconname: "gesture-stretch-symbolic");
223 break;
224
225 case GTK_SHORTCUT_GESTURE_ROTATE_CLOCKWISE:
226 icon = g_themed_icon_new (iconname: "gesture-rotate-clockwise-symbolic");
227 break;
228
229 case GTK_SHORTCUT_GESTURE_ROTATE_COUNTERCLOCKWISE:
230 icon = g_themed_icon_new (iconname: "gesture-rotate-anticlockwise-symbolic");
231 break;
232
233 case GTK_SHORTCUT_GESTURE_TWO_FINGER_SWIPE_LEFT:
234 icon = g_themed_icon_new (iconname: "gesture-two-finger-swipe-left-symbolic");
235 break;
236
237 case GTK_SHORTCUT_GESTURE_TWO_FINGER_SWIPE_RIGHT:
238 icon = g_themed_icon_new (iconname: "gesture-two-finger-swipe-right-symbolic");
239 break;
240
241 case GTK_SHORTCUT_GESTURE_SWIPE_LEFT:
242 icon = g_themed_icon_new (iconname: "gesture-swipe-left-symbolic");
243 break;
244
245 case GTK_SHORTCUT_GESTURE_SWIPE_RIGHT:
246 icon = g_themed_icon_new (iconname: "gesture-swipe-right-symbolic");
247 break;
248
249 case GTK_SHORTCUT_ACCELERATOR:
250 case GTK_SHORTCUT_GESTURE:
251 default:
252 icon = NULL;
253 break;
254 }
255
256 if (icon)
257 {
258 gtk_image_set_from_gicon (image: self->image, icon);
259 gtk_image_set_pixel_size (image: self->image, pixel_size: 64);
260 g_object_unref (object: icon);
261 }
262}
263
264static void
265gtk_shortcuts_shortcut_set_icon_set (GtkShortcutsShortcut *self,
266 gboolean icon_set)
267{
268 if (self->icon_set != icon_set)
269 {
270 self->icon_set = icon_set;
271 g_object_notify (G_OBJECT (self), property_name: "icon-set");
272 }
273 update_icon_from_type (self);
274}
275
276static void
277gtk_shortcuts_shortcut_set_icon (GtkShortcutsShortcut *self,
278 GIcon *gicon)
279{
280 gtk_image_set_from_gicon (image: self->image, icon: gicon);
281 gtk_shortcuts_shortcut_set_icon_set (self, icon_set: gicon != NULL);
282 g_object_notify (G_OBJECT (self), property_name: "icon");
283}
284
285static void
286update_visible_from_direction (GtkShortcutsShortcut *self)
287{
288 if (self->direction == GTK_TEXT_DIR_NONE ||
289 self->direction == gtk_widget_get_direction (GTK_WIDGET (self)))
290 {
291 gtk_widget_show (GTK_WIDGET (self));
292 }
293 else
294 {
295 gtk_widget_hide (GTK_WIDGET (self));
296 }
297}
298
299static void
300gtk_shortcuts_shortcut_set_direction (GtkShortcutsShortcut *self,
301 GtkTextDirection direction)
302{
303 if (self->direction == direction)
304 return;
305
306 self->direction = direction;
307
308 update_visible_from_direction (self);
309
310 g_object_notify (G_OBJECT (self), property_name: "direction");
311}
312
313static void
314gtk_shortcuts_shortcut_direction_changed (GtkWidget *widget,
315 GtkTextDirection previous_dir)
316{
317 update_visible_from_direction (GTK_SHORTCUTS_SHORTCUT (widget));
318
319 GTK_WIDGET_CLASS (gtk_shortcuts_shortcut_parent_class)->direction_changed (widget, previous_dir);
320}
321
322static void
323gtk_shortcuts_shortcut_set_type (GtkShortcutsShortcut *self,
324 GtkShortcutType type)
325{
326 if (self->shortcut_type == type)
327 return;
328
329 self->shortcut_type = type;
330
331 update_subtitle_from_type (self);
332 update_icon_from_type (self);
333
334 gtk_widget_set_visible (GTK_WIDGET (self->accelerator), visible: type == GTK_SHORTCUT_ACCELERATOR);
335 gtk_widget_set_visible (GTK_WIDGET (self->image), visible: type != GTK_SHORTCUT_ACCELERATOR);
336
337
338 g_object_notify (G_OBJECT (self), property_name: "shortcut-type");
339}
340
341static void
342gtk_shortcuts_shortcut_set_action_name (GtkShortcutsShortcut *self,
343 const char *action_name)
344{
345 g_free (mem: self->action_name);
346 self->action_name = g_strdup (str: action_name);
347
348 g_object_notify (G_OBJECT (self), property_name: "action-name");
349}
350
351static void
352gtk_shortcuts_shortcut_get_property (GObject *object,
353 guint prop_id,
354 GValue *value,
355 GParamSpec *pspec)
356{
357 GtkShortcutsShortcut *self = GTK_SHORTCUTS_SHORTCUT (object);
358
359 switch (prop_id)
360 {
361 case PROP_TITLE:
362 g_value_set_string (value, v_string: gtk_label_get_label (self: self->title));
363 break;
364
365 case PROP_SUBTITLE:
366 g_value_set_string (value, v_string: gtk_label_get_label (self: self->subtitle));
367 break;
368
369 case PROP_SUBTITLE_SET:
370 g_value_set_boolean (value, v_boolean: self->subtitle_set);
371 break;
372
373 case PROP_ACCELERATOR:
374 g_value_set_string (value, v_string: gtk_shortcut_label_get_accelerator (self: self->accelerator));
375 break;
376
377 case PROP_ICON:
378 g_value_set_object (value, v_object: gtk_image_get_gicon (image: self->image));
379 break;
380
381 case PROP_ICON_SET:
382 g_value_set_boolean (value, v_boolean: self->icon_set);
383 break;
384
385 case PROP_DIRECTION:
386 g_value_set_enum (value, v_enum: self->direction);
387 break;
388
389 case PROP_SHORTCUT_TYPE:
390 g_value_set_enum (value, v_enum: self->shortcut_type);
391 break;
392
393 case PROP_ACTION_NAME:
394 g_value_set_string (value, v_string: self->action_name);
395 break;
396
397 default:
398 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
399 }
400}
401
402static void
403gtk_shortcuts_shortcut_set_property (GObject *object,
404 guint prop_id,
405 const GValue *value,
406 GParamSpec *pspec)
407{
408 GtkShortcutsShortcut *self = GTK_SHORTCUTS_SHORTCUT (object);
409
410 switch (prop_id)
411 {
412 case PROP_ACCELERATOR:
413 gtk_shortcuts_shortcut_set_accelerator (self, accelerator: g_value_get_string (value));
414 break;
415
416 case PROP_ICON:
417 gtk_shortcuts_shortcut_set_icon (self, gicon: g_value_get_object (value));
418 break;
419
420 case PROP_ICON_SET:
421 gtk_shortcuts_shortcut_set_icon_set (self, icon_set: g_value_get_boolean (value));
422 break;
423
424 case PROP_ACCEL_SIZE_GROUP:
425 gtk_shortcuts_shortcut_set_accel_size_group (self, GTK_SIZE_GROUP (g_value_get_object (value)));
426 break;
427
428 case PROP_TITLE:
429 gtk_label_set_label (self: self->title, str: g_value_get_string (value));
430 break;
431
432 case PROP_SUBTITLE:
433 gtk_shortcuts_shortcut_set_subtitle (self, subtitle: g_value_get_string (value));
434 break;
435
436 case PROP_SUBTITLE_SET:
437 gtk_shortcuts_shortcut_set_subtitle_set (self, subtitle_set: g_value_get_boolean (value));
438 break;
439
440 case PROP_TITLE_SIZE_GROUP:
441 gtk_shortcuts_shortcut_set_title_size_group (self, GTK_SIZE_GROUP (g_value_get_object (value)));
442 break;
443
444 case PROP_DIRECTION:
445 gtk_shortcuts_shortcut_set_direction (self, direction: g_value_get_enum (value));
446 break;
447
448 case PROP_SHORTCUT_TYPE:
449 gtk_shortcuts_shortcut_set_type (self, type: g_value_get_enum (value));
450 break;
451
452 case PROP_ACTION_NAME:
453 gtk_shortcuts_shortcut_set_action_name (self, action_name: g_value_get_string (value));
454 break;
455
456 default:
457 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
458 break;
459 }
460}
461
462static void
463gtk_shortcuts_shortcut_finalize (GObject *object)
464{
465 GtkShortcutsShortcut *self = GTK_SHORTCUTS_SHORTCUT (object);
466
467 g_clear_object (&self->accel_size_group);
468 g_clear_object (&self->title_size_group);
469 g_free (mem: self->action_name);
470 gtk_widget_unparent (GTK_WIDGET (self->box));
471
472 G_OBJECT_CLASS (gtk_shortcuts_shortcut_parent_class)->finalize (object);
473}
474
475void
476gtk_shortcuts_shortcut_update_accel (GtkShortcutsShortcut *self,
477 GtkWindow *window)
478{
479 GtkApplication *app;
480 char **accels;
481 char *str;
482
483 if (self->action_name == NULL)
484 return;
485
486 app = gtk_window_get_application (window);
487 if (app == NULL)
488 return;
489
490 accels = gtk_application_get_accels_for_action (application: app, detailed_action_name: self->action_name);
491 str = g_strjoinv (separator: " ", str_array: accels);
492
493 gtk_shortcuts_shortcut_set_accelerator (self, accelerator: str);
494
495 g_free (mem: str);
496 g_strfreev (str_array: accels);
497}
498
499static void
500gtk_shortcuts_shortcut_measure (GtkWidget *widget,
501 GtkOrientation orientation,
502 int for_size,
503 int *minimum,
504 int *natural,
505 int *minimum_baseline,
506 int *natural_baseline)
507{
508 gtk_widget_measure (GTK_WIDGET (GTK_SHORTCUTS_SHORTCUT (widget)->box),
509 orientation, for_size,
510 minimum, natural,
511 minimum_baseline, natural_baseline);
512}
513
514static void
515gtk_shortcuts_shortcut_snapshot (GtkWidget *widget,
516 GtkSnapshot *snapshot)
517{
518 gtk_widget_snapshot_child (widget, GTK_WIDGET (GTK_SHORTCUTS_SHORTCUT (widget)->box), snapshot);
519}
520
521static void
522gtk_shortcuts_shortcut_size_allocate (GtkWidget *widget,
523 int width,
524 int height,
525 int baseline)
526{
527 GTK_WIDGET_CLASS (gtk_shortcuts_shortcut_parent_class)->size_allocate (widget, width, height, baseline);
528
529 gtk_widget_size_allocate (GTK_WIDGET (GTK_SHORTCUTS_SHORTCUT (widget)->box),
530 allocation: &(GtkAllocation) {
531 0, 0,
532 width, height
533 }, baseline: -1);
534}
535
536static void
537gtk_shortcuts_shortcut_class_init (GtkShortcutsShortcutClass *klass)
538{
539 GObjectClass *object_class = G_OBJECT_CLASS (klass);
540 GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (klass);
541
542 object_class->finalize = gtk_shortcuts_shortcut_finalize;
543 object_class->get_property = gtk_shortcuts_shortcut_get_property;
544 object_class->set_property = gtk_shortcuts_shortcut_set_property;
545
546 widget_class->direction_changed = gtk_shortcuts_shortcut_direction_changed;
547 widget_class->measure = gtk_shortcuts_shortcut_measure;
548 widget_class->snapshot = gtk_shortcuts_shortcut_snapshot;
549 widget_class->size_allocate = gtk_shortcuts_shortcut_size_allocate;
550
551 /**
552 * GtkShortcutsShortcut:accelerator:
553 *
554 * The accelerator(s) represented by this object.
555 *
556 * This property is used if [property@Gtk.ShortcutsShortcut:shortcut-type]
557 * is set to %GTK_SHORTCUT_ACCELERATOR.
558 *
559 * The syntax of this property is (an extension of) the syntax understood
560 * by [func@Gtk.accelerator_parse]. Multiple accelerators can be specified
561 * by separating them with a space, but keep in mind that the available width
562 * is limited.
563 *
564 * It is also possible to specify ranges of shortcuts, using "..." between
565 * the keys. Sequences of keys can be specified using a "+" or "&" between
566 * the keys.
567 *
568 * Examples:
569 *
570 * - A single shortcut: <ctl><alt>delete
571 * - Two alternative shortcuts: <shift>a Home
572 * - A range of shortcuts: <alt>1...<alt>9
573 * - Several keys pressed together: Control_L&Control_R
574 * - A sequence of shortcuts or keys: <ctl>c+<ctl>x
575 *
576 * Use "+" instead of "&" when the keys may (or have to be) pressed
577 * sequentially (e.g use "t+t" for 'press the t key twice').
578 *
579 * Note that <, > and & need to be escaped as &lt;, &gt; and &amp; when used
580 * in .ui files.
581 */
582 properties[PROP_ACCELERATOR] =
583 g_param_spec_string (name: "accelerator",
584 P_("Accelerator"),
585 P_("The accelerator keys for shortcuts of type “Accelerator”"),
586 NULL,
587 flags: (G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
588
589 /**
590 * GtkShortcutsShortcut:icon:
591 *
592 * An icon to represent the shortcut or gesture.
593 *
594 * This property is used if [property@Gtk.ShortcutsShortcut:shortcut-type]
595 * is set to %GTK_SHORTCUT_GESTURE.
596 *
597 * For the other predefined gesture types, GTK provides an icon on its own.
598 */
599 properties[PROP_ICON] =
600 g_param_spec_object (name: "icon",
601 P_("Icon"),
602 P_("The icon to show for shortcuts of type “Other Gesture”"),
603 G_TYPE_ICON,
604 flags: (G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
605
606 /**
607 * GtkShortcutsShortcut:icon-set:
608 *
609 * %TRUE if an icon has been set.
610 */
611 properties[PROP_ICON_SET] =
612 g_param_spec_boolean (name: "icon-set",
613 P_("Icon Set"),
614 P_("Whether an icon has been set"),
615 FALSE,
616 flags: (G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
617
618 /**
619 * GtkShortcutsShortcut:title:
620 *
621 * The textual description for the shortcut or gesture represented by
622 * this object.
623 *
624 * This should be a short string that can fit in a single line.
625 */
626 properties[PROP_TITLE] =
627 g_param_spec_string (name: "title",
628 P_("Title"),
629 P_("A short description for the shortcut"),
630 default_value: "",
631 flags: (G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
632
633 /**
634 * GtkShortcutsShortcut:subtitle:
635 *
636 * The subtitle for the shortcut or gesture.
637 *
638 * This is typically used for gestures and should be a short, one-line
639 * text that describes the gesture itself. For the predefined gesture
640 * types, GTK provides a subtitle on its own.
641 */
642 properties[PROP_SUBTITLE] =
643 g_param_spec_string (name: "subtitle",
644 P_("Subtitle"),
645 P_("A short description for the gesture"),
646 default_value: "",
647 flags: (G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
648
649 /**
650 * GtkShortcutsShortcut:subtitle-set:
651 *
652 * %TRUE if a subtitle has been set.
653 */
654 properties[PROP_SUBTITLE_SET] =
655 g_param_spec_boolean (name: "subtitle-set",
656 P_("Subtitle Set"),
657 P_("Whether a subtitle has been set"),
658 FALSE,
659 flags: (G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
660
661 /**
662 * GtkShortcutsShortcut:accel-size-group:
663 *
664 * The size group for the accelerator portion of this shortcut.
665 *
666 * This is used internally by GTK, and must not be modified by applications.
667 */
668 properties[PROP_ACCEL_SIZE_GROUP] =
669 g_param_spec_object (name: "accel-size-group",
670 P_("Accelerator Size Group"),
671 P_("Accelerator Size Group"),
672 GTK_TYPE_SIZE_GROUP,
673 flags: (G_PARAM_WRITABLE | G_PARAM_STATIC_STRINGS));
674
675 /**
676 * GtkShortcutsShortcut:title-size-group:
677 *
678 * The size group for the textual portion of this shortcut.
679 *
680 * This is used internally by GTK, and must not be modified by applications.
681 */
682 properties[PROP_TITLE_SIZE_GROUP] =
683 g_param_spec_object (name: "title-size-group",
684 P_("Title Size Group"),
685 P_("Title Size Group"),
686 GTK_TYPE_SIZE_GROUP,
687 flags: (G_PARAM_WRITABLE | G_PARAM_STATIC_STRINGS));
688
689 /**
690 * GtkShortcutsShortcut:direction:
691 *
692 * The text direction for which this shortcut is active.
693 *
694 * If the shortcut is used regardless of the text direction,
695 * set this property to %GTK_TEXT_DIR_NONE.
696 */
697 properties[PROP_DIRECTION] =
698 g_param_spec_enum (name: "direction",
699 P_("Direction"),
700 P_("Text direction for which this shortcut is active"),
701 enum_type: GTK_TYPE_TEXT_DIRECTION,
702 default_value: GTK_TEXT_DIR_NONE,
703 flags: (G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS | G_PARAM_EXPLICIT_NOTIFY));
704
705 /**
706 * GtkShortcutsShortcut:shortcut-type:
707 *
708 * The type of shortcut that is represented.
709 */
710 properties[PROP_SHORTCUT_TYPE] =
711 g_param_spec_enum (name: "shortcut-type",
712 P_("Shortcut Type"),
713 P_("The type of shortcut that is represented"),
714 enum_type: GTK_TYPE_SHORTCUT_TYPE,
715 default_value: GTK_SHORTCUT_ACCELERATOR,
716 flags: (G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS | G_PARAM_EXPLICIT_NOTIFY));
717
718 /**
719 * GtkShortcutsShortcut:action-name:
720 *
721 * A detailed action name.
722 *
723 * If this is set for a shortcut of type %GTK_SHORTCUT_ACCELERATOR,
724 * then GTK will use the accelerators that are associated with the
725 * action via [method@Gtk.Application.set_accels_for_action], and
726 * setting [property@Gtk.ShortcutsShortcut:accelerator] is not necessary.
727 */
728 properties[PROP_ACTION_NAME] =
729 g_param_spec_string (name: "action-name",
730 P_("Action Name"),
731 P_("The name of the action"),
732 NULL,
733 flags: G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS | G_PARAM_EXPLICIT_NOTIFY);
734
735 g_object_class_install_properties (oclass: object_class, n_pspecs: LAST_PROP, pspecs: properties);
736 gtk_widget_class_set_css_name (widget_class, I_("shortcut"));
737 gtk_widget_class_set_accessible_role (widget_class, accessible_role: GTK_ACCESSIBLE_ROLE_GROUP);
738}
739
740static void
741gtk_shortcuts_shortcut_init (GtkShortcutsShortcut *self)
742{
743 self->box = g_object_new (GTK_TYPE_BOX,
744 first_property_name: "orientation", GTK_ORIENTATION_HORIZONTAL,
745 "spacing", 12,
746 NULL);
747 gtk_widget_set_parent (GTK_WIDGET (self->box), GTK_WIDGET (self));
748
749 self->direction = GTK_TEXT_DIR_NONE;
750 self->shortcut_type = GTK_SHORTCUT_ACCELERATOR;
751
752 self->image = g_object_new (GTK_TYPE_IMAGE,
753 first_property_name: "visible", FALSE,
754 "valign", GTK_ALIGN_CENTER,
755 "accessible-role", GTK_ACCESSIBLE_ROLE_PRESENTATION,
756 NULL);
757 gtk_box_append (GTK_BOX (self->box), GTK_WIDGET (self->image));
758
759 self->accelerator = g_object_new (GTK_TYPE_SHORTCUT_LABEL,
760 first_property_name: "visible", TRUE,
761 "valign", GTK_ALIGN_CENTER,
762 NULL);
763 gtk_box_append (GTK_BOX (self->box), GTK_WIDGET (self->accelerator));
764
765 self->title_box = g_object_new (GTK_TYPE_BOX,
766 first_property_name: "visible", TRUE,
767 "valign", GTK_ALIGN_CENTER,
768 "hexpand", TRUE,
769 "orientation", GTK_ORIENTATION_VERTICAL,
770 NULL);
771 gtk_box_append (GTK_BOX (self->box), GTK_WIDGET (self->title_box));
772
773 self->title = g_object_new (GTK_TYPE_LABEL,
774 first_property_name: "visible", TRUE,
775 "xalign", 0.0f,
776 NULL);
777 gtk_box_append (GTK_BOX (self->title_box), GTK_WIDGET (self->title));
778
779 self->subtitle = g_object_new (GTK_TYPE_LABEL,
780 first_property_name: "visible", FALSE,
781 "xalign", 0.0f,
782 NULL);
783 gtk_widget_add_css_class (GTK_WIDGET (self->subtitle), css_class: "dim-label");
784 gtk_box_append (GTK_BOX (self->title_box), GTK_WIDGET (self->subtitle));
785}
786

source code of gtk/gtk/gtkshortcutsshortcut.c