1 /*
2 * Copyright (C) 2018 Purism SPC
3 *
4 * SPDX-License-Identifier: LGPL-2.1+
5 */
6
7 #include "config.h"
8 #include "hdy-action-row.h"
9
10 #include <glib/gi18n-lib.h>
11
12 /**
13 * SECTION:hdy-action-row
14 * @short_description: A #GtkListBox row used to present actions.
15 * @Title: HdyActionRow
16 *
17 * The #HdyActionRow widget can have a title, a subtitle and an icon. The row
18 * can receive action widgets at its end, prefix widgets at its start or widgets
19 * below it.
20 *
21 * Note that action widgets are packed starting from the end.
22 *
23 * It is convenient to present a list of preferences and their related actions.
24 *
25 * # HdyActionRow as GtkBuildable
26 *
27 * The GtkWindow implementation of the GtkBuildable interface supports setting a
28 * child as an action widget by specifying “action” as the “type” attribute of a
29 * <child> element.
30 *
31 * It also supports setting a child as a prefix widget by specifying “prefix” as
32 * the “type” attribute of a <child> element.
33 *
34 * Since: 0.0.6
35 */
36
37 typedef struct
38 {
39 GtkBox *box;
40 GtkBox *header;
41 GtkImage *image;
42 GtkBox *prefixes;
43 GtkLabel *subtitle;
44 GtkLabel *title;
45 GtkBox *title_box;
46
47 GtkWidget *previous_parent;
48
49 gboolean use_underline;
50 GtkWidget *activatable_widget;
51 } HdyActionRowPrivate;
52
53 static void hdy_action_row_buildable_init (GtkBuildableIface *iface);
54
55 G_DEFINE_TYPE_WITH_CODE (HdyActionRow, hdy_action_row, HDY_TYPE_PREFERENCES_ROW,
56 G_ADD_PRIVATE (HdyActionRow)
57 G_IMPLEMENT_INTERFACE (GTK_TYPE_BUILDABLE,
58 hdy_action_row_buildable_init))
59
60 static GtkBuildableIface *parent_buildable_iface;
61
62 enum {
63 PROP_0,
64 PROP_ICON_NAME,
65 PROP_ACTIVATABLE_WIDGET,
66 PROP_SUBTITLE,
67 PROP_TITLE,
68 PROP_USE_UNDERLINE,
69 LAST_PROP,
70 };
71
72 static GParamSpec *props[LAST_PROP];
73
74 static void
row_activated_cb(HdyActionRow * self,GtkListBoxRow * row)75 row_activated_cb (HdyActionRow *self,
76 GtkListBoxRow *row)
77 {
78 /* No need to use GTK_LIST_BOX_ROW() for a pointer comparison. */
79 if ((GtkListBoxRow *) self == row)
80 hdy_action_row_activate (self);
81 }
82
83 static void
parent_cb(HdyActionRow * self)84 parent_cb (HdyActionRow *self)
85 {
86 HdyActionRowPrivate *priv = hdy_action_row_get_instance_private (self);
87 GtkWidget *parent = gtk_widget_get_parent (GTK_WIDGET (self));
88
89 if (priv->previous_parent != NULL) {
90 g_signal_handlers_disconnect_by_func (priv->previous_parent, G_CALLBACK (row_activated_cb), self);
91 priv->previous_parent = NULL;
92 }
93
94 if (parent == NULL || !GTK_IS_LIST_BOX (parent))
95 return;
96
97 priv->previous_parent = parent;
98 g_signal_connect_swapped (parent, "row-activated", G_CALLBACK (row_activated_cb), self);
99 }
100
101 static void
update_subtitle_visibility(HdyActionRow * self)102 update_subtitle_visibility (HdyActionRow *self)
103 {
104 HdyActionRowPrivate *priv = hdy_action_row_get_instance_private (self);
105
106 gtk_widget_set_visible (GTK_WIDGET (priv->subtitle),
107 gtk_label_get_text (priv->subtitle) != NULL &&
108 g_strcmp0 (gtk_label_get_text (priv->subtitle), "") != 0);
109 }
110
111 static void
hdy_action_row_get_property(GObject * object,guint prop_id,GValue * value,GParamSpec * pspec)112 hdy_action_row_get_property (GObject *object,
113 guint prop_id,
114 GValue *value,
115 GParamSpec *pspec)
116 {
117 HdyActionRow *self = HDY_ACTION_ROW (object);
118
119 switch (prop_id) {
120 case PROP_ICON_NAME:
121 g_value_set_string (value, hdy_action_row_get_icon_name (self));
122 break;
123 case PROP_ACTIVATABLE_WIDGET:
124 g_value_set_object (value, (GObject *) hdy_action_row_get_activatable_widget (self));
125 break;
126 case PROP_SUBTITLE:
127 g_value_set_string (value, hdy_action_row_get_subtitle (self));
128 break;
129 case PROP_TITLE:
130 g_value_set_string (value, hdy_action_row_get_title (self));
131 break;
132 case PROP_USE_UNDERLINE:
133 g_value_set_boolean (value, hdy_action_row_get_use_underline (self));
134 break;
135 default:
136 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
137 }
138 }
139
140 static void
hdy_action_row_set_property(GObject * object,guint prop_id,const GValue * value,GParamSpec * pspec)141 hdy_action_row_set_property (GObject *object,
142 guint prop_id,
143 const GValue *value,
144 GParamSpec *pspec)
145 {
146 HdyActionRow *self = HDY_ACTION_ROW (object);
147
148 switch (prop_id) {
149 case PROP_ICON_NAME:
150 hdy_action_row_set_icon_name (self, g_value_get_string (value));
151 break;
152 case PROP_ACTIVATABLE_WIDGET:
153 hdy_action_row_set_activatable_widget (self, (GtkWidget*) g_value_get_object (value));
154 break;
155 case PROP_SUBTITLE:
156 hdy_action_row_set_subtitle (self, g_value_get_string (value));
157 break;
158 case PROP_TITLE:
159 hdy_action_row_set_title (self, g_value_get_string (value));
160 break;
161 case PROP_USE_UNDERLINE:
162 hdy_action_row_set_use_underline (self, g_value_get_boolean (value));
163 break;
164 default:
165 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
166 }
167 }
168
169 static void
hdy_action_row_dispose(GObject * object)170 hdy_action_row_dispose (GObject *object)
171 {
172 HdyActionRow *self = HDY_ACTION_ROW (object);
173 HdyActionRowPrivate *priv = hdy_action_row_get_instance_private (self);
174
175 if (priv->previous_parent != NULL) {
176 g_signal_handlers_disconnect_by_func (priv->previous_parent, G_CALLBACK (row_activated_cb), self);
177 priv->previous_parent = NULL;
178 }
179
180 G_OBJECT_CLASS (hdy_action_row_parent_class)->dispose (object);
181 }
182
183 static void
hdy_action_row_show_all(GtkWidget * widget)184 hdy_action_row_show_all (GtkWidget *widget)
185 {
186 HdyActionRow *self = HDY_ACTION_ROW (widget);
187 HdyActionRowPrivate *priv;
188
189 g_return_if_fail (HDY_IS_ACTION_ROW (self));
190
191 priv = hdy_action_row_get_instance_private (self);
192
193 gtk_container_foreach (GTK_CONTAINER (priv->prefixes),
194 (GtkCallback) gtk_widget_show_all,
195 NULL);
196 GTK_WIDGET_CLASS (hdy_action_row_parent_class)->show_all (widget);
197 }
198
199 static void
hdy_action_row_destroy(GtkWidget * widget)200 hdy_action_row_destroy (GtkWidget *widget)
201 {
202 HdyActionRow *self = HDY_ACTION_ROW (widget);
203 HdyActionRowPrivate *priv = hdy_action_row_get_instance_private (self);
204
205 if (priv->box) {
206 gtk_widget_destroy (GTK_WIDGET (priv->box));
207 priv->box = NULL;
208 }
209
210 hdy_action_row_set_activatable_widget (self, NULL);
211
212 priv->prefixes = NULL;
213 priv->header = NULL;
214
215 GTK_WIDGET_CLASS (hdy_action_row_parent_class)->destroy (widget);
216 }
217
218 static void
hdy_action_row_add(GtkContainer * container,GtkWidget * child)219 hdy_action_row_add (GtkContainer *container,
220 GtkWidget *child)
221 {
222 HdyActionRow *self = HDY_ACTION_ROW (container);
223 HdyActionRowPrivate *priv = hdy_action_row_get_instance_private (self);
224
225 /* When constructing the widget, we want the box to be added as the child of
226 * the GtkListBoxRow, as an implementation detail.
227 */
228 if (priv->box == NULL)
229 GTK_CONTAINER_CLASS (hdy_action_row_parent_class)->add (container, child);
230 else
231 gtk_container_add (GTK_CONTAINER (priv->box), child);
232 }
233
234 typedef struct {
235 HdyActionRow *row;
236 GtkCallback callback;
237 gpointer callback_data;
238 } ForallData;
239
240 static void
for_non_internal_child(GtkWidget * widget,gpointer callback_data)241 for_non_internal_child (GtkWidget *widget,
242 gpointer callback_data)
243 {
244 ForallData *data = callback_data;
245 HdyActionRowPrivate *priv = hdy_action_row_get_instance_private (data->row);
246
247 if (widget != (GtkWidget *) priv->box &&
248 widget != (GtkWidget *) priv->image &&
249 widget != (GtkWidget *) priv->prefixes &&
250 widget != (GtkWidget *) priv->title_box)
251 data->callback (widget, data->callback_data);
252 }
253
254 static void
hdy_action_row_forall(GtkContainer * container,gboolean include_internals,GtkCallback callback,gpointer callback_data)255 hdy_action_row_forall (GtkContainer *container,
256 gboolean include_internals,
257 GtkCallback callback,
258 gpointer callback_data)
259 {
260 HdyActionRow *self = HDY_ACTION_ROW (container);
261 HdyActionRowPrivate *priv = hdy_action_row_get_instance_private (self);
262 ForallData data;
263
264 if (include_internals) {
265 GTK_CONTAINER_CLASS (hdy_action_row_parent_class)->forall (GTK_CONTAINER (self), include_internals, callback, callback_data);
266
267 return;
268 }
269
270 data.row = self;
271 data.callback = callback;
272 data.callback_data = callback_data;
273
274 if (priv->prefixes)
275 GTK_CONTAINER_GET_CLASS (priv->prefixes)->forall (GTK_CONTAINER (priv->prefixes), include_internals, for_non_internal_child, &data);
276 if (priv->header)
277 GTK_CONTAINER_GET_CLASS (priv->header)->forall (GTK_CONTAINER (priv->header), include_internals, for_non_internal_child, &data);
278 if (priv->box)
279 GTK_CONTAINER_GET_CLASS (priv->box)->forall (GTK_CONTAINER (priv->box), include_internals, for_non_internal_child, &data);
280 }
281
282 static void
hdy_action_row_activate_real(HdyActionRow * self)283 hdy_action_row_activate_real (HdyActionRow *self)
284 {
285 HdyActionRowPrivate *priv = hdy_action_row_get_instance_private (self);
286
287 if (priv->activatable_widget)
288 gtk_widget_mnemonic_activate (priv->activatable_widget, FALSE);
289 }
290
291 static void
hdy_action_row_class_init(HdyActionRowClass * klass)292 hdy_action_row_class_init (HdyActionRowClass *klass)
293 {
294 GObjectClass *object_class = G_OBJECT_CLASS (klass);
295 GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (klass);
296 GtkContainerClass *container_class = GTK_CONTAINER_CLASS (klass);
297
298 object_class->get_property = hdy_action_row_get_property;
299 object_class->set_property = hdy_action_row_set_property;
300 object_class->dispose = hdy_action_row_dispose;
301
302 widget_class->destroy = hdy_action_row_destroy;
303 widget_class->show_all = hdy_action_row_show_all;
304
305 container_class->add = hdy_action_row_add;
306 container_class->forall = hdy_action_row_forall;
307
308 klass->activate = hdy_action_row_activate_real;
309
310 /**
311 * HdyActionRow:icon-name:
312 *
313 * The icon name for this row.
314 *
315 * Since: 0.0.6
316 */
317 props[PROP_ICON_NAME] =
318 g_param_spec_string ("icon-name",
319 _("Icon name"),
320 _("Icon name"),
321 "",
322 G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS | G_PARAM_EXPLICIT_NOTIFY);
323
324 /**
325 * HdyActionRow:activatable-widget:
326 *
327 * The activatable widget for this row.
328 *
329 * Since: 0.0.7
330 */
331 props[PROP_ACTIVATABLE_WIDGET] =
332 g_param_spec_object ("activatable-widget",
333 _("Activatable widget"),
334 _("The widget to be activated when the row is activated"),
335 GTK_TYPE_WIDGET,
336 G_PARAM_READWRITE);
337
338 /**
339 * HdyActionRow:subtitle:
340 *
341 * The subtitle for this row.
342 *
343 * Since: 0.0.6
344 */
345 props[PROP_SUBTITLE] =
346 g_param_spec_string ("subtitle",
347 _("Subtitle"),
348 _("Subtitle"),
349 "",
350 G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS | G_PARAM_EXPLICIT_NOTIFY);
351
352 /**
353 * HdyActionRow:title:
354 *
355 * The title for this row.
356 *
357 * Since: 0.0.6
358 */
359 props[PROP_TITLE] =
360 g_param_spec_string ("title",
361 _("Title"),
362 _("Title"),
363 "",
364 G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS | G_PARAM_EXPLICIT_NOTIFY);
365
366 /**
367 * HdyActionRow:use-underline:
368 *
369 * Whether an embedded underline in the text of the title and subtitle labels
370 * indicates a mnemonic.
371 *
372 * Since: 0.0.6
373 */
374 props[PROP_USE_UNDERLINE] =
375 g_param_spec_boolean ("use-underline",
376 _("Use underline"),
377 _("If set, an underline in the text indicates the next character should be used for the mnemonic accelerator key"),
378 FALSE,
379 G_PARAM_READWRITE | G_PARAM_EXPLICIT_NOTIFY);
380
381 g_object_class_install_properties (object_class, LAST_PROP, props);
382
383 gtk_widget_class_set_template_from_resource (widget_class,
384 "/sm/puri/handy/ui/hdy-action-row.ui");
385 gtk_widget_class_bind_template_child_private (widget_class, HdyActionRow, box);
386 gtk_widget_class_bind_template_child_private (widget_class, HdyActionRow, header);
387 gtk_widget_class_bind_template_child_private (widget_class, HdyActionRow, image);
388 gtk_widget_class_bind_template_child_private (widget_class, HdyActionRow, prefixes);
389 gtk_widget_class_bind_template_child_private (widget_class, HdyActionRow, subtitle);
390 gtk_widget_class_bind_template_child_private (widget_class, HdyActionRow, title);
391 gtk_widget_class_bind_template_child_private (widget_class, HdyActionRow, title_box);
392 }
393
394 static void
hdy_action_row_init(HdyActionRow * self)395 hdy_action_row_init (HdyActionRow *self)
396 {
397 gtk_widget_init_template (GTK_WIDGET (self));
398
399 update_subtitle_visibility (self);
400
401 g_signal_connect (self, "notify::parent", G_CALLBACK (parent_cb), NULL);
402
403 }
404
405 static void
hdy_action_row_buildable_add_child(GtkBuildable * buildable,GtkBuilder * builder,GObject * child,const gchar * type)406 hdy_action_row_buildable_add_child (GtkBuildable *buildable,
407 GtkBuilder *builder,
408 GObject *child,
409 const gchar *type)
410 {
411 if (type && strcmp (type, "action") == 0)
412 hdy_action_row_add_action (HDY_ACTION_ROW (buildable), GTK_WIDGET (child));
413 else if (type && strcmp (type, "prefix") == 0)
414 hdy_action_row_add_prefix (HDY_ACTION_ROW (buildable), GTK_WIDGET (child));
415 else
416 parent_buildable_iface->add_child (buildable, builder, child, type);
417 }
418
419 static void
hdy_action_row_buildable_init(GtkBuildableIface * iface)420 hdy_action_row_buildable_init (GtkBuildableIface *iface)
421 {
422 parent_buildable_iface = g_type_interface_peek_parent (iface);
423 iface->add_child = hdy_action_row_buildable_add_child;
424 }
425
426 /**
427 * hdy_action_row_new:
428 *
429 * Creates a new #HdyActionRow.
430 *
431 * Returns: a new #HdyActionRow
432 *
433 * Since: 0.0.6
434 */
435 HdyActionRow *
hdy_action_row_new(void)436 hdy_action_row_new (void)
437 {
438 return g_object_new (HDY_TYPE_ACTION_ROW, NULL);
439 }
440
441 /**
442 * hdy_action_row_get_title:
443 * @self: a #HdyActionRow
444 *
445 * Gets the title for @self.
446 *
447 * Returns: the title for @self.
448 *
449 * Since: 0.0.6
450 */
451 const gchar *
hdy_action_row_get_title(HdyActionRow * self)452 hdy_action_row_get_title (HdyActionRow *self)
453 {
454 HdyActionRowPrivate *priv;
455
456 g_return_val_if_fail (HDY_IS_ACTION_ROW (self), NULL);
457
458 priv = hdy_action_row_get_instance_private (self);
459
460 return gtk_label_get_text (priv->title);
461 }
462
463 /**
464 * hdy_action_row_set_title:
465 * @self: a #HdyActionRow
466 * @title: the title
467 *
468 * Sets the title for @self.
469 *
470 * Since: 0.0.6
471 */
472 void
hdy_action_row_set_title(HdyActionRow * self,const gchar * title)473 hdy_action_row_set_title (HdyActionRow *self,
474 const gchar *title)
475 {
476 HdyActionRowPrivate *priv;
477
478 g_return_if_fail (HDY_IS_ACTION_ROW (self));
479
480 priv = hdy_action_row_get_instance_private (self);
481 hdy_preferences_row_set_title (HDY_PREFERENCES_ROW (self), title);
482
483 if (g_strcmp0 (gtk_label_get_text (priv->title), title) == 0)
484 return;
485
486 gtk_label_set_text (priv->title, title);
487 gtk_widget_set_visible (GTK_WIDGET (priv->title),
488 title != NULL && g_strcmp0 (title, "") != 0);
489
490 g_object_notify_by_pspec (G_OBJECT (self), props[PROP_TITLE]);
491 }
492
493 /**
494 * hdy_action_row_get_subtitle:
495 * @self: a #HdyActionRow
496 *
497 * Gets the subtitle for @self.
498 *
499 * Returns: the subtitle for @self.
500 *
501 * Since: 0.0.6
502 */
503 const gchar *
hdy_action_row_get_subtitle(HdyActionRow * self)504 hdy_action_row_get_subtitle (HdyActionRow *self)
505 {
506 HdyActionRowPrivate *priv;
507
508 g_return_val_if_fail (HDY_IS_ACTION_ROW (self), NULL);
509
510 priv = hdy_action_row_get_instance_private (self);
511
512 return gtk_label_get_text (priv->subtitle);
513 }
514
515 /**
516 * hdy_action_row_set_subtitle:
517 * @self: a #HdyActionRow
518 * @subtitle: the subtitle
519 *
520 * Sets the subtitle for @self.
521 *
522 * Since: 0.0.6
523 */
524 void
hdy_action_row_set_subtitle(HdyActionRow * self,const gchar * subtitle)525 hdy_action_row_set_subtitle (HdyActionRow *self,
526 const gchar *subtitle)
527 {
528 HdyActionRowPrivate *priv;
529
530 g_return_if_fail (HDY_IS_ACTION_ROW (self));
531
532 priv = hdy_action_row_get_instance_private (self);
533
534 if (g_strcmp0 (gtk_label_get_text (priv->subtitle), subtitle) == 0)
535 return;
536
537 gtk_label_set_text (priv->subtitle, subtitle);
538 gtk_widget_set_visible (GTK_WIDGET (priv->subtitle),
539 subtitle != NULL && g_strcmp0 (subtitle, "") != 0);
540
541 g_object_notify_by_pspec (G_OBJECT (self), props[PROP_SUBTITLE]);
542 }
543
544 /**
545 * hdy_action_row_get_icon_name:
546 * @self: a #HdyActionRow
547 *
548 * Gets the icon name for @self.
549 *
550 * Returns: the icon name for @self.
551 *
552 * Since: 0.0.6
553 */
554 const gchar *
hdy_action_row_get_icon_name(HdyActionRow * self)555 hdy_action_row_get_icon_name (HdyActionRow *self)
556 {
557 HdyActionRowPrivate *priv;
558 const gchar *icon_name;
559
560 g_return_val_if_fail (HDY_IS_ACTION_ROW (self), NULL);
561
562 priv = hdy_action_row_get_instance_private (self);
563
564 gtk_image_get_icon_name (priv->image, &icon_name, NULL);
565
566 return icon_name;
567 }
568
569 /**
570 * hdy_action_row_set_icon_name:
571 * @self: a #HdyActionRow
572 * @icon_name: the icon name
573 *
574 * Sets the icon name for @self.
575 *
576 * Since: 0.0.6
577 */
578 void
hdy_action_row_set_icon_name(HdyActionRow * self,const gchar * icon_name)579 hdy_action_row_set_icon_name (HdyActionRow *self,
580 const gchar *icon_name)
581 {
582 HdyActionRowPrivate *priv;
583 const gchar *old_icon_name;
584
585 g_return_if_fail (HDY_IS_ACTION_ROW (self));
586
587 priv = hdy_action_row_get_instance_private (self);
588
589 gtk_image_get_icon_name (priv->image, &old_icon_name, NULL);
590 if (g_strcmp0 (old_icon_name, icon_name) == 0)
591 return;
592
593 gtk_image_set_from_icon_name (priv->image, icon_name, GTK_ICON_SIZE_INVALID);
594 gtk_widget_set_visible (GTK_WIDGET (priv->image),
595 icon_name != NULL && g_strcmp0 (icon_name, "") != 0);
596
597 g_object_notify_by_pspec (G_OBJECT (self), props[PROP_ICON_NAME]);
598 }
599
600 /**
601 * hdy_action_row_get_activatable_widget:
602 * @self: a #HdyActionRow
603 *
604 * Gets the widget activated when @self is activated.
605 *
606 * Returns: (nullable) (transfer none): the widget activated when @self is
607 * activated, or %NULL if none has been set.
608 *
609 * Since: 0.0.7
610 */
611 GtkWidget *
hdy_action_row_get_activatable_widget(HdyActionRow * self)612 hdy_action_row_get_activatable_widget (HdyActionRow *self)
613 {
614 HdyActionRowPrivate *priv;
615
616 g_return_val_if_fail (HDY_IS_ACTION_ROW (self), NULL);
617
618 priv = hdy_action_row_get_instance_private (self);
619
620 return priv->activatable_widget;
621 }
622
623 static void
activatable_widget_weak_notify(gpointer data,GObject * where_the_object_was)624 activatable_widget_weak_notify (gpointer data,
625 GObject *where_the_object_was)
626 {
627 HdyActionRow *self = HDY_ACTION_ROW (data);
628 HdyActionRowPrivate *priv = hdy_action_row_get_instance_private (self);
629
630 priv->activatable_widget = NULL;
631
632 g_object_notify_by_pspec (G_OBJECT (self), props[PROP_ACTIVATABLE_WIDGET]);
633 }
634
635 /**
636 * hdy_action_row_set_activatable_widget:
637 * @self: a #HdyActionRow
638 * @widget: (nullable): the target #GtkWidget, or %NULL to unset
639 *
640 * Sets the widget to activate when @self is activated, either by clicking
641 * on it, by calling hdy_action_row_activate(), or via mnemonics in the title or
642 * the subtitle. See the “use_underline” property to enable mnemonics.
643 *
644 * The target widget will be activated by emitting the
645 * GtkWidget::mnemonic-activate signal on it.
646 *
647 * Since: 0.0.7
648 */
649 void
hdy_action_row_set_activatable_widget(HdyActionRow * self,GtkWidget * widget)650 hdy_action_row_set_activatable_widget (HdyActionRow *self,
651 GtkWidget *widget)
652 {
653 HdyActionRowPrivate *priv;
654
655 g_return_if_fail (HDY_IS_ACTION_ROW (self));
656
657 priv = hdy_action_row_get_instance_private (self);
658
659 if (priv->activatable_widget == widget)
660 return;
661
662 if (widget != NULL)
663 g_return_if_fail (GTK_IS_WIDGET (widget));
664
665 if (priv->activatable_widget)
666 g_object_weak_unref (G_OBJECT (priv->activatable_widget),
667 activatable_widget_weak_notify,
668 self);
669
670 priv->activatable_widget = widget;
671
672 if (priv->activatable_widget != NULL)
673 g_object_weak_ref (G_OBJECT (priv->activatable_widget),
674 activatable_widget_weak_notify,
675 self);
676
677 g_object_notify_by_pspec (G_OBJECT (self), props[PROP_ACTIVATABLE_WIDGET]);
678 }
679
680 /**
681 * hdy_action_row_get_use_underline:
682 * @self: a #HdyActionRow
683 *
684 * Gets whether an embedded underline in the text of the title and subtitle
685 * labels indicates a mnemonic. See hdy_action_row_set_use_underline().
686 *
687 * Returns: %TRUE if an embedded underline in the title and subtitle labels
688 * indicates the mnemonic accelerator keys.
689 *
690 * Since: 0.0.6
691 */
692 gboolean
hdy_action_row_get_use_underline(HdyActionRow * self)693 hdy_action_row_get_use_underline (HdyActionRow *self)
694 {
695 HdyActionRowPrivate *priv;
696
697 g_return_val_if_fail (HDY_IS_ACTION_ROW (self), FALSE);
698
699 priv = hdy_action_row_get_instance_private (self);
700
701 return priv->use_underline;
702 }
703
704 /**
705 * hdy_action_row_set_use_underline:
706 * @self: a #HdyActionRow
707 * @use_underline: %TRUE if underlines in the text indicate mnemonics
708 *
709 * If true, an underline in the text of the title and subtitle labels indicates
710 * the next character should be used for the mnemonic accelerator key.
711 *
712 * Since: 0.0.6
713 */
714 void
hdy_action_row_set_use_underline(HdyActionRow * self,gboolean use_underline)715 hdy_action_row_set_use_underline (HdyActionRow *self,
716 gboolean use_underline)
717 {
718 HdyActionRowPrivate *priv;
719
720 g_return_if_fail (HDY_IS_ACTION_ROW (self));
721
722 priv = hdy_action_row_get_instance_private (self);
723
724 if (priv->use_underline == !!use_underline)
725 return;
726
727 priv->use_underline = !!use_underline;
728 hdy_preferences_row_set_use_underline (HDY_PREFERENCES_ROW (self), priv->use_underline);
729 gtk_label_set_use_underline (priv->title, priv->use_underline);
730 gtk_label_set_use_underline (priv->subtitle, priv->use_underline);
731 gtk_label_set_mnemonic_widget (priv->title, GTK_WIDGET (self));
732 gtk_label_set_mnemonic_widget (priv->subtitle, GTK_WIDGET (self));
733
734 g_object_notify_by_pspec (G_OBJECT (self), props[PROP_USE_UNDERLINE]);
735 }
736
737 /**
738 * hdy_action_row_add_action:
739 * @self: a #HdyActionRow
740 * @widget: (allow-none): the action widget
741 *
742 * Adds an action widget to @self.
743 *
744 * Since: 0.0.6
745 */
746 void
hdy_action_row_add_action(HdyActionRow * self,GtkWidget * widget)747 hdy_action_row_add_action (HdyActionRow *self,
748 GtkWidget *widget)
749 {
750 HdyActionRowPrivate *priv;
751
752 g_return_if_fail (HDY_IS_ACTION_ROW (self));
753
754 priv = hdy_action_row_get_instance_private (self);
755
756 gtk_box_pack_end (priv->header, widget, FALSE, TRUE, 0);
757 }
758
759 /**
760 * hdy_action_row_add_prefix:
761 * @self: a #HdyActionRow
762 * @widget: (allow-none): the prefix widget
763 *
764 * Adds a prefix widget to @self.
765 *
766 * Since: 0.0.6
767 */
768 void
hdy_action_row_add_prefix(HdyActionRow * self,GtkWidget * widget)769 hdy_action_row_add_prefix (HdyActionRow *self,
770 GtkWidget *widget)
771 {
772 HdyActionRowPrivate *priv;
773
774 g_return_if_fail (HDY_IS_ACTION_ROW (self));
775
776 priv = hdy_action_row_get_instance_private (self);
777
778 gtk_box_pack_start (priv->prefixes, widget, FALSE, TRUE, 0);
779 gtk_widget_show (GTK_WIDGET (priv->prefixes));
780 }
781
782 void
hdy_action_row_activate(HdyActionRow * self)783 hdy_action_row_activate (HdyActionRow *self)
784 {
785 g_return_if_fail (HDY_IS_ACTION_ROW (self));
786
787 HDY_ACTION_ROW_GET_CLASS (self)->activate (self);
788 }
789