1 /*
2  * Copyright (C) 2018 Purism SPC
3  *
4  * SPDX-License-Identifier: LGPL-2.1+
5  */
6 
7 #include "config.h"
8 #include "hdy-expander-row.h"
9 
10 #include <glib/gi18n-lib.h>
11 #include "hdy-action-row.h"
12 
13 /**
14  * SECTION:hdy-expander-row
15  * @short_description: A #GtkListBox row used to reveal widgets.
16  * @Title: HdyExpanderRow
17  *
18  * The #HdyExpanderRow allows the user to reveal or hide widgets below it. It
19  * also allows the user to enable the expansion of the row, allowing to disable
20  * all that the row contains.
21  *
22  * It also supports adding a child as an action widget by specifying “action” as
23  * the “type” attribute of a &lt;child&gt; element. It also supports setting a
24  * child as a prefix widget by specifying “prefix” as the “type” attribute of a
25  * &lt;child&gt; element.
26  *
27  * # CSS nodes
28  *
29  * #HdyExpanderRow has a main CSS node with name row, and the .expander style
30  * class. It has the .empty style class when it contains no children.
31  *
32  * It contains the subnodes row.header for its main embedded row, list.nested
33  * for the list it can expand, and image.expander-row-arrow for its arrow.
34  *
35  * When expanded, #HdyExpanderRow will add the
36  * .checked-expander-row-previous-sibling style class to its previous sibling,
37  * and remove it when retracted.
38  *
39  * Since: 0.0.6
40  */
41 
42 typedef struct
43 {
44   GtkBox *box;
45   GtkBox *actions;
46   GtkBox *prefixes;
47   GtkListBox *list;
48   HdyActionRow *action_row;
49   GtkSwitch *enable_switch;
50   GtkImage *image;
51 
52   gboolean expanded;
53   gboolean enable_expansion;
54   gboolean show_enable_switch;
55 } HdyExpanderRowPrivate;
56 
57 static void hdy_expander_row_buildable_init (GtkBuildableIface *iface);
58 
59 G_DEFINE_TYPE_WITH_CODE (HdyExpanderRow, hdy_expander_row, HDY_TYPE_PREFERENCES_ROW,
60                          G_ADD_PRIVATE (HdyExpanderRow)
61                          G_IMPLEMENT_INTERFACE (GTK_TYPE_BUILDABLE,
62                          hdy_expander_row_buildable_init))
63 
64 static GtkBuildableIface *parent_buildable_iface;
65 
66 enum {
67   PROP_0,
68   PROP_SUBTITLE,
69   PROP_USE_UNDERLINE,
70   PROP_ICON_NAME,
71   PROP_EXPANDED,
72   PROP_ENABLE_EXPANSION,
73   PROP_SHOW_ENABLE_SWITCH,
74   LAST_PROP,
75 };
76 
77 static GParamSpec *props[LAST_PROP];
78 
79 static void
update_arrow(HdyExpanderRow * self)80 update_arrow (HdyExpanderRow *self)
81 {
82   HdyExpanderRowPrivate *priv = hdy_expander_row_get_instance_private (self);
83   GtkWidget *parent = gtk_widget_get_parent (GTK_WIDGET (self));
84   GtkWidget *previous_sibling = NULL;
85 
86   if (parent) {
87     g_autoptr (GList) siblings = gtk_container_get_children (GTK_CONTAINER (parent));
88     GList *l;
89 
90     for (l = siblings; l != NULL && l->next != NULL && l->next->data != self; l = l->next);
91 
92     if (l && l->next && l->next->data == self)
93       previous_sibling = l->data;
94   }
95 
96   if (priv->expanded)
97     gtk_widget_set_state_flags (GTK_WIDGET (self), GTK_STATE_FLAG_CHECKED, FALSE);
98   else
99     gtk_widget_unset_state_flags (GTK_WIDGET (self), GTK_STATE_FLAG_CHECKED);
100 
101   if (previous_sibling) {
102     GtkStyleContext *previous_sibling_context = gtk_widget_get_style_context (previous_sibling);
103 
104     if (priv->expanded)
105       gtk_style_context_add_class (previous_sibling_context, "checked-expander-row-previous-sibling");
106     else
107       gtk_style_context_remove_class (previous_sibling_context, "checked-expander-row-previous-sibling");
108   }
109 }
110 
111 static void
hdy_expander_row_get_property(GObject * object,guint prop_id,GValue * value,GParamSpec * pspec)112 hdy_expander_row_get_property (GObject    *object,
113                                guint       prop_id,
114                                GValue     *value,
115                                GParamSpec *pspec)
116 {
117   HdyExpanderRow *self = HDY_EXPANDER_ROW (object);
118 
119   switch (prop_id) {
120   case PROP_SUBTITLE:
121     g_value_set_string (value, hdy_expander_row_get_subtitle (self));
122     break;
123   case PROP_USE_UNDERLINE:
124     g_value_set_boolean (value, hdy_expander_row_get_use_underline (self));
125     break;
126   case PROP_ICON_NAME:
127     g_value_set_string (value, hdy_expander_row_get_icon_name (self));
128     break;
129   case PROP_EXPANDED:
130     g_value_set_boolean (value, hdy_expander_row_get_expanded (self));
131     break;
132   case PROP_ENABLE_EXPANSION:
133     g_value_set_boolean (value, hdy_expander_row_get_enable_expansion (self));
134     break;
135   case PROP_SHOW_ENABLE_SWITCH:
136     g_value_set_boolean (value, hdy_expander_row_get_show_enable_switch (self));
137     break;
138   default:
139     G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
140   }
141 }
142 
143 static void
hdy_expander_row_set_property(GObject * object,guint prop_id,const GValue * value,GParamSpec * pspec)144 hdy_expander_row_set_property (GObject      *object,
145                                guint         prop_id,
146                                const GValue *value,
147                                GParamSpec   *pspec)
148 {
149   HdyExpanderRow *self = HDY_EXPANDER_ROW (object);
150 
151   switch (prop_id) {
152   case PROP_SUBTITLE:
153     hdy_expander_row_set_subtitle (self, g_value_get_string (value));
154     break;
155   case PROP_USE_UNDERLINE:
156     hdy_expander_row_set_use_underline (self, g_value_get_boolean (value));
157     break;
158   case PROP_ICON_NAME:
159     hdy_expander_row_set_icon_name (self, g_value_get_string (value));
160     break;
161   case PROP_EXPANDED:
162     hdy_expander_row_set_expanded (self, g_value_get_boolean (value));
163     break;
164   case PROP_ENABLE_EXPANSION:
165     hdy_expander_row_set_enable_expansion (self, g_value_get_boolean (value));
166     break;
167   case PROP_SHOW_ENABLE_SWITCH:
168     hdy_expander_row_set_show_enable_switch (self, g_value_get_boolean (value));
169     break;
170   default:
171     G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
172   }
173 }
174 
175 static void
hdy_expander_row_forall(GtkContainer * container,gboolean include_internals,GtkCallback callback,gpointer callback_data)176 hdy_expander_row_forall (GtkContainer *container,
177                          gboolean      include_internals,
178                          GtkCallback   callback,
179                          gpointer      callback_data)
180 {
181   HdyExpanderRow *self = HDY_EXPANDER_ROW (container);
182   HdyExpanderRowPrivate *priv = hdy_expander_row_get_instance_private (self);
183 
184   if (include_internals)
185     GTK_CONTAINER_CLASS (hdy_expander_row_parent_class)->forall (container,
186                                                                  include_internals,
187                                                                  callback,
188                                                                  callback_data);
189   else {
190     if (priv->prefixes)
191       gtk_container_foreach (GTK_CONTAINER (priv->prefixes), callback, callback_data);
192     if (priv->actions)
193       gtk_container_foreach (GTK_CONTAINER (priv->actions), callback, callback_data);
194     if (priv->list)
195       gtk_container_foreach (GTK_CONTAINER (priv->list), callback, callback_data);
196   }
197 }
198 
199 static void
activate_cb(HdyExpanderRow * self)200 activate_cb (HdyExpanderRow *self)
201 {
202   HdyExpanderRowPrivate *priv = hdy_expander_row_get_instance_private (self);
203 
204   hdy_expander_row_set_expanded (self, !priv->expanded);
205 }
206 
207 static void
count_children_cb(GtkWidget * widget,gint * count)208 count_children_cb (GtkWidget *widget,
209                    gint      *count)
210 {
211   (*count)++;
212 }
213 
214 static void
list_children_changed_cb(HdyExpanderRow * self)215 list_children_changed_cb (HdyExpanderRow *self)
216 {
217   HdyExpanderRowPrivate *priv = hdy_expander_row_get_instance_private (self);
218   GtkStyleContext *context = gtk_widget_get_style_context (GTK_WIDGET (self));
219   gint count = 0;
220 
221   gtk_container_foreach (GTK_CONTAINER (priv->list), (GtkCallback) count_children_cb, &count);
222 
223   if (count == 0)
224     gtk_style_context_add_class (context, "empty");
225   else
226     gtk_style_context_remove_class (context, "empty");
227 }
228 
229 static void
hdy_expander_row_add(GtkContainer * container,GtkWidget * child)230 hdy_expander_row_add (GtkContainer *container,
231                       GtkWidget    *child)
232 {
233   HdyExpanderRow *self = HDY_EXPANDER_ROW (container);
234   HdyExpanderRowPrivate *priv = hdy_expander_row_get_instance_private (self);
235 
236   /* When constructing the widget, we want the box to be added as the child of
237    * the GtkListBoxRow, as an implementation detail.
238    */
239   if (priv->box == NULL)
240     GTK_CONTAINER_CLASS (hdy_expander_row_parent_class)->add (container, child);
241   else
242     gtk_container_add (GTK_CONTAINER (priv->list), child);
243 }
244 
245 static void
hdy_expander_row_remove(GtkContainer * container,GtkWidget * child)246 hdy_expander_row_remove (GtkContainer *container,
247                          GtkWidget    *child)
248 {
249   HdyExpanderRow *self = HDY_EXPANDER_ROW (container);
250   HdyExpanderRowPrivate *priv = hdy_expander_row_get_instance_private (self);
251 
252   if (child == GTK_WIDGET (priv->box))
253     GTK_CONTAINER_CLASS (hdy_expander_row_parent_class)->remove (container, child);
254   else if (gtk_widget_get_parent (child) == GTK_WIDGET (priv->actions))
255     gtk_container_remove (GTK_CONTAINER (priv->actions), child);
256   else if (gtk_widget_get_parent (child) == GTK_WIDGET (priv->prefixes))
257     gtk_container_remove (GTK_CONTAINER (priv->prefixes), child);
258   else
259     gtk_container_remove (GTK_CONTAINER (priv->list), child);
260 }
261 
262 static void
hdy_expander_row_class_init(HdyExpanderRowClass * klass)263 hdy_expander_row_class_init (HdyExpanderRowClass *klass)
264 {
265   GObjectClass *object_class = G_OBJECT_CLASS (klass);
266   GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (klass);
267   GtkContainerClass *container_class = GTK_CONTAINER_CLASS (klass);
268 
269   object_class->get_property = hdy_expander_row_get_property;
270   object_class->set_property = hdy_expander_row_set_property;
271 
272   container_class->add = hdy_expander_row_add;
273   container_class->remove = hdy_expander_row_remove;
274   container_class->forall = hdy_expander_row_forall;
275 
276   /**
277    * HdyExpanderRow:subtitle:
278    *
279    * The subtitle for this row.
280    *
281    * Since: 1.0
282    */
283   props[PROP_SUBTITLE] =
284     g_param_spec_string ("subtitle",
285                          _("Subtitle"),
286                          _("The subtitle for this row"),
287                          "",
288                          G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS | G_PARAM_EXPLICIT_NOTIFY);
289 
290   /**
291    * HdyExpanderRow:use-underline:
292    *
293    * Whether an embedded underline in the text of the title and subtitle labels
294    * indicates a mnemonic.
295    *
296    * Since: 1.0
297    */
298   props[PROP_USE_UNDERLINE] =
299     g_param_spec_boolean ("use-underline",
300                           _("Use underline"),
301                           _("If set, an underline in the text indicates the next character should be used for the mnemonic accelerator key"),
302                           FALSE,
303                           G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS | G_PARAM_EXPLICIT_NOTIFY);
304 
305   /**
306    * HdyExpanderRow:icon-name:
307    *
308    * The icon name for this row.
309    *
310    * Since: 1.0
311    */
312   props[PROP_ICON_NAME] =
313     g_param_spec_string ("icon-name",
314                          _("Icon name"),
315                          _("Icon name"),
316                          "",
317                          G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS | G_PARAM_EXPLICIT_NOTIFY);
318 
319   /**
320    * HdyExpanderRow:expanded:
321    *
322    * %TRUE if the row is expanded.
323    */
324   props[PROP_EXPANDED] =
325     g_param_spec_boolean ("expanded",
326                           _("Expanded"),
327                           _("Whether the row is expanded"),
328                           FALSE,
329                           G_PARAM_READWRITE | G_PARAM_EXPLICIT_NOTIFY);
330 
331   /**
332    * HdyExpanderRow:enable-expansion:
333    *
334    * %TRUE if the expansion is enabled.
335    */
336   props[PROP_ENABLE_EXPANSION] =
337     g_param_spec_boolean ("enable-expansion",
338                           _("Enable expansion"),
339                           _("Whether the expansion is enabled"),
340                           TRUE,
341                           G_PARAM_READWRITE | G_PARAM_EXPLICIT_NOTIFY);
342 
343   /**
344    * HdyExpanderRow:show-enable-switch:
345    *
346    * %TRUE if the switch enabling the expansion is visible.
347    */
348   props[PROP_SHOW_ENABLE_SWITCH] =
349     g_param_spec_boolean ("show-enable-switch",
350                           _("Show enable switch"),
351                           _("Whether the switch enabling the expansion is visible"),
352                           FALSE,
353                           G_PARAM_READWRITE | G_PARAM_EXPLICIT_NOTIFY);
354 
355   g_object_class_install_properties (object_class, LAST_PROP, props);
356 
357   gtk_widget_class_set_template_from_resource (widget_class,
358                                                "/sm/puri/handy/ui/hdy-expander-row.ui");
359   gtk_widget_class_bind_template_child_private (widget_class, HdyExpanderRow, action_row);
360   gtk_widget_class_bind_template_child_private (widget_class, HdyExpanderRow, box);
361   gtk_widget_class_bind_template_child_private (widget_class, HdyExpanderRow, actions);
362   gtk_widget_class_bind_template_child_private (widget_class, HdyExpanderRow, list);
363   gtk_widget_class_bind_template_child_private (widget_class, HdyExpanderRow, image);
364   gtk_widget_class_bind_template_child_private (widget_class, HdyExpanderRow, enable_switch);
365   gtk_widget_class_bind_template_callback (widget_class, activate_cb);
366   gtk_widget_class_bind_template_callback (widget_class, list_children_changed_cb);
367 }
368 
369 #define NOTIFY(func, prop) \
370 static void \
371 func (gpointer this) { \
372   g_object_notify_by_pspec (G_OBJECT (this), props[prop]); \
373 } \
374 
375 NOTIFY (notify_subtitle_cb, PROP_SUBTITLE);
376 NOTIFY (notify_use_underline_cb, PROP_USE_UNDERLINE);
377 NOTIFY (notify_icon_name_cb, PROP_ICON_NAME);
378 
379 static void
hdy_expander_row_init(HdyExpanderRow * self)380 hdy_expander_row_init (HdyExpanderRow *self)
381 {
382   HdyExpanderRowPrivate *priv = hdy_expander_row_get_instance_private (self);
383 
384   priv->prefixes = NULL;
385 
386   gtk_widget_init_template (GTK_WIDGET (self));
387 
388   hdy_expander_row_set_enable_expansion (self, TRUE);
389   hdy_expander_row_set_expanded (self, FALSE);
390 
391   g_signal_connect_object (priv->action_row, "notify::subtitle", G_CALLBACK (notify_subtitle_cb), self, G_CONNECT_SWAPPED);
392   g_signal_connect_object (priv->action_row, "notify::use-underline", G_CALLBACK (notify_use_underline_cb), self, G_CONNECT_SWAPPED);
393   g_signal_connect_object (priv->action_row, "notify::icon-name", G_CALLBACK (notify_icon_name_cb), self, G_CONNECT_SWAPPED);
394 }
395 
396 static void
hdy_expander_row_buildable_add_child(GtkBuildable * buildable,GtkBuilder * builder,GObject * child,const gchar * type)397 hdy_expander_row_buildable_add_child (GtkBuildable *buildable,
398                                       GtkBuilder   *builder,
399                                       GObject      *child,
400                                       const gchar  *type)
401 {
402   HdyExpanderRow *self = HDY_EXPANDER_ROW (buildable);
403   HdyExpanderRowPrivate *priv = hdy_expander_row_get_instance_private (self);
404 
405   if (priv->box == NULL || !type)
406     gtk_container_add (GTK_CONTAINER (self), GTK_WIDGET (child));
407   else if (type && strcmp (type, "action") == 0)
408     hdy_expander_row_add_action (self, GTK_WIDGET (child));
409   else if (type && strcmp (type, "prefix") == 0)
410     hdy_expander_row_add_prefix (self, GTK_WIDGET (child));
411   else
412     GTK_BUILDER_WARN_INVALID_CHILD_TYPE (self, type);
413 }
414 
415 static void
hdy_expander_row_buildable_init(GtkBuildableIface * iface)416 hdy_expander_row_buildable_init (GtkBuildableIface *iface)
417 {
418   parent_buildable_iface = g_type_interface_peek_parent (iface);
419   iface->add_child = hdy_expander_row_buildable_add_child;
420 }
421 
422 /**
423  * hdy_expander_row_new:
424  *
425  * Creates a new #HdyExpanderRow.
426  *
427  * Returns: a new #HdyExpanderRow
428  *
429  * Since: 0.0.6
430  */
431 GtkWidget *
hdy_expander_row_new(void)432 hdy_expander_row_new (void)
433 {
434   return g_object_new (HDY_TYPE_EXPANDER_ROW, NULL);
435 }
436 
437 /**
438  * hdy_expander_row_get_subtitle:
439  * @self: a #HdyExpanderRow
440  *
441  * Gets the subtitle for @self.
442  *
443  * Returns: (transfer none) (nullable): the subtitle for @self, or %NULL.
444  *
445  * Since: 1.0
446  */
447 const gchar *
hdy_expander_row_get_subtitle(HdyExpanderRow * self)448 hdy_expander_row_get_subtitle (HdyExpanderRow *self)
449 {
450   HdyExpanderRowPrivate *priv;
451 
452   g_return_val_if_fail (HDY_IS_EXPANDER_ROW (self), NULL);
453 
454   priv = hdy_expander_row_get_instance_private (self);
455 
456   return hdy_action_row_get_subtitle (priv->action_row);
457 }
458 
459 /**
460  * hdy_expander_row_set_subtitle:
461  * @self: a #HdyExpanderRow
462  * @subtitle: (nullable): the subtitle
463  *
464  * Sets the subtitle for @self.
465  *
466  * Since: 1.0
467  */
468 void
hdy_expander_row_set_subtitle(HdyExpanderRow * self,const gchar * subtitle)469 hdy_expander_row_set_subtitle (HdyExpanderRow *self,
470                                const gchar    *subtitle)
471 {
472   HdyExpanderRowPrivate *priv;
473 
474   g_return_if_fail (HDY_IS_EXPANDER_ROW (self));
475 
476   priv = hdy_expander_row_get_instance_private (self);
477 
478   hdy_action_row_set_subtitle (priv->action_row, subtitle);
479 }
480 
481 /**
482  * hdy_expander_row_get_use_underline:
483  * @self: a #HdyExpanderRow
484  *
485  * Gets whether an embedded underline in the text of the title and subtitle
486  * labels indicates a mnemonic. See hdy_expander_row_set_use_underline().
487  *
488  * Returns: %TRUE if an embedded underline in the title and subtitle labels
489  *          indicates the mnemonic accelerator keys.
490  *
491  * Since: 1.0
492  */
493 gboolean
hdy_expander_row_get_use_underline(HdyExpanderRow * self)494 hdy_expander_row_get_use_underline (HdyExpanderRow *self)
495 {
496   HdyExpanderRowPrivate *priv;
497 
498   g_return_val_if_fail (HDY_IS_EXPANDER_ROW (self), FALSE);
499 
500   priv = hdy_expander_row_get_instance_private (self);
501 
502   return hdy_action_row_get_use_underline (priv->action_row);
503 }
504 
505 /**
506  * hdy_expander_row_set_use_underline:
507  * @self: a #HdyExpanderRow
508  * @use_underline: %TRUE if underlines in the text indicate mnemonics
509  *
510  * If true, an underline in the text of the title and subtitle labels indicates
511  * the next character should be used for the mnemonic accelerator key.
512  *
513  * Since: 1.0
514  */
515 void
hdy_expander_row_set_use_underline(HdyExpanderRow * self,gboolean use_underline)516 hdy_expander_row_set_use_underline (HdyExpanderRow *self,
517                                     gboolean        use_underline)
518 {
519   HdyExpanderRowPrivate *priv;
520 
521   g_return_if_fail (HDY_IS_EXPANDER_ROW (self));
522 
523   priv = hdy_expander_row_get_instance_private (self);
524 
525   hdy_action_row_set_use_underline (priv->action_row, use_underline);
526 }
527 
528 /**
529  * hdy_expander_row_get_icon_name:
530  * @self: a #HdyExpanderRow
531  *
532  * Gets the icon name for @self.
533  *
534  * Returns: the icon name for @self.
535  *
536  * Since: 1.0
537  */
538 const gchar *
hdy_expander_row_get_icon_name(HdyExpanderRow * self)539 hdy_expander_row_get_icon_name (HdyExpanderRow *self)
540 {
541   HdyExpanderRowPrivate *priv;
542 
543   g_return_val_if_fail (HDY_IS_EXPANDER_ROW (self), NULL);
544 
545   priv = hdy_expander_row_get_instance_private (self);
546 
547   return hdy_action_row_get_icon_name (priv->action_row);
548 }
549 
550 /**
551  * hdy_expander_row_set_icon_name:
552  * @self: a #HdyExpanderRow
553  * @icon_name: the icon name
554  *
555  * Sets the icon name for @self.
556  *
557  * Since: 1.0
558  */
559 void
hdy_expander_row_set_icon_name(HdyExpanderRow * self,const gchar * icon_name)560 hdy_expander_row_set_icon_name (HdyExpanderRow *self,
561                                 const gchar    *icon_name)
562 {
563   HdyExpanderRowPrivate *priv;
564 
565   g_return_if_fail (HDY_IS_EXPANDER_ROW (self));
566 
567   priv = hdy_expander_row_get_instance_private (self);
568 
569   hdy_action_row_set_icon_name (priv->action_row, icon_name);
570 }
571 
572 gboolean
hdy_expander_row_get_expanded(HdyExpanderRow * self)573 hdy_expander_row_get_expanded (HdyExpanderRow *self)
574 {
575   HdyExpanderRowPrivate *priv;
576 
577   g_return_val_if_fail (HDY_IS_EXPANDER_ROW (self), FALSE);
578 
579   priv = hdy_expander_row_get_instance_private (self);
580 
581   return priv->expanded;
582 }
583 
584 void
hdy_expander_row_set_expanded(HdyExpanderRow * self,gboolean expanded)585 hdy_expander_row_set_expanded (HdyExpanderRow *self,
586                                gboolean        expanded)
587 {
588   HdyExpanderRowPrivate *priv;
589 
590   g_return_if_fail (HDY_IS_EXPANDER_ROW (self));
591 
592   priv = hdy_expander_row_get_instance_private (self);
593 
594   expanded = !!expanded && priv->enable_expansion;
595 
596   if (priv->expanded == expanded)
597     return;
598 
599   priv->expanded = expanded;
600 
601   update_arrow (self);
602 
603   g_object_notify_by_pspec (G_OBJECT (self), props[PROP_EXPANDED]);
604 }
605 
606 /**
607  * hdy_expander_row_get_enable_expansion:
608  * @self: a #HdyExpanderRow
609  *
610  * Gets whether the expansion of @self is enabled.
611  *
612  * Returns: whether the expansion of @self is enabled.
613  *
614  * Since: 0.0.6
615  */
616 gboolean
hdy_expander_row_get_enable_expansion(HdyExpanderRow * self)617 hdy_expander_row_get_enable_expansion (HdyExpanderRow *self)
618 {
619   HdyExpanderRowPrivate *priv;
620 
621   g_return_val_if_fail (HDY_IS_EXPANDER_ROW (self), FALSE);
622 
623   priv = hdy_expander_row_get_instance_private (self);
624 
625   return priv->enable_expansion;
626 }
627 
628 /**
629  * hdy_expander_row_set_enable_expansion:
630  * @self: a #HdyExpanderRow
631  * @enable_expansion: %TRUE to enable the expansion
632  *
633  * Sets whether the expansion of @self is enabled.
634  *
635  * Since: 0.0.6
636  */
637 void
hdy_expander_row_set_enable_expansion(HdyExpanderRow * self,gboolean enable_expansion)638 hdy_expander_row_set_enable_expansion (HdyExpanderRow *self,
639                                        gboolean        enable_expansion)
640 {
641   HdyExpanderRowPrivate *priv;
642 
643   g_return_if_fail (HDY_IS_EXPANDER_ROW (self));
644 
645   priv = hdy_expander_row_get_instance_private (self);
646 
647   enable_expansion = !!enable_expansion;
648 
649   if (priv->enable_expansion == enable_expansion)
650     return;
651 
652   priv->enable_expansion = enable_expansion;
653 
654   hdy_expander_row_set_expanded (self, priv->enable_expansion);
655 
656   g_object_notify_by_pspec (G_OBJECT (self), props[PROP_ENABLE_EXPANSION]);
657 }
658 
659 /**
660  * hdy_expander_row_get_show_enable_switch:
661  * @self: a #HdyExpanderRow
662  *
663  * Gets whether the switch enabling the expansion of @self is visible.
664  *
665  * Returns: whether the switch enabling the expansion of @self is visible.
666  *
667  * Since: 0.0.6
668  */
669 gboolean
hdy_expander_row_get_show_enable_switch(HdyExpanderRow * self)670 hdy_expander_row_get_show_enable_switch (HdyExpanderRow *self)
671 {
672   HdyExpanderRowPrivate *priv;
673 
674   g_return_val_if_fail (HDY_IS_EXPANDER_ROW (self), FALSE);
675 
676   priv = hdy_expander_row_get_instance_private (self);
677 
678   return priv->show_enable_switch;
679 }
680 
681 /**
682  * hdy_expander_row_set_show_enable_switch:
683  * @self: a #HdyExpanderRow
684  * @show_enable_switch: %TRUE to show the switch enabling the expansion
685  *
686  * Sets whether the switch enabling the expansion of @self is visible.
687  *
688  * Since: 0.0.6
689  */
690 void
hdy_expander_row_set_show_enable_switch(HdyExpanderRow * self,gboolean show_enable_switch)691 hdy_expander_row_set_show_enable_switch (HdyExpanderRow *self,
692                                          gboolean        show_enable_switch)
693 {
694   HdyExpanderRowPrivate *priv;
695 
696   g_return_if_fail (HDY_IS_EXPANDER_ROW (self));
697 
698   priv = hdy_expander_row_get_instance_private (self);
699 
700   show_enable_switch = !!show_enable_switch;
701 
702   if (priv->show_enable_switch == show_enable_switch)
703     return;
704 
705   priv->show_enable_switch = show_enable_switch;
706 
707   g_object_notify_by_pspec (G_OBJECT (self), props[PROP_SHOW_ENABLE_SWITCH]);
708 }
709 
710 /**
711  * hdy_expander_row_add_action:
712  * @self: a #HdyExpanderRow
713  * @widget: the action widget
714  *
715  * Adds an action widget to @self.
716  *
717  * Since: 1.0
718  */
719 void
hdy_expander_row_add_action(HdyExpanderRow * self,GtkWidget * widget)720 hdy_expander_row_add_action (HdyExpanderRow *self,
721                              GtkWidget      *widget)
722 {
723   HdyExpanderRowPrivate *priv;
724 
725   g_return_if_fail (HDY_IS_EXPANDER_ROW (self));
726   g_return_if_fail (GTK_IS_WIDGET (self));
727 
728   priv = hdy_expander_row_get_instance_private (self);
729 
730   gtk_box_pack_start (priv->actions, widget, FALSE, TRUE, 0);
731   gtk_widget_show (GTK_WIDGET (priv->actions));
732 }
733 
734 /**
735  * hdy_expander_row_add_prefix:
736  * @self: a #HdyExpanderRow
737  * @widget: the prefix widget
738  *
739  * Adds a prefix widget to @self.
740  *
741  * Since: 1.0
742  */
743 void
hdy_expander_row_add_prefix(HdyExpanderRow * self,GtkWidget * widget)744 hdy_expander_row_add_prefix (HdyExpanderRow *self,
745                              GtkWidget      *widget)
746 {
747   HdyExpanderRowPrivate *priv;
748 
749   g_return_if_fail (HDY_IS_EXPANDER_ROW (self));
750   g_return_if_fail (GTK_IS_WIDGET (widget));
751 
752   priv = hdy_expander_row_get_instance_private (self);
753 
754   if (priv->prefixes == NULL) {
755     priv->prefixes = GTK_BOX (gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 12));
756     gtk_widget_set_no_show_all (GTK_WIDGET (priv->prefixes), TRUE);
757     gtk_widget_set_can_focus (GTK_WIDGET (priv->prefixes), FALSE);
758     hdy_action_row_add_prefix (HDY_ACTION_ROW (priv->action_row), GTK_WIDGET (priv->prefixes));
759   }
760   gtk_box_pack_start (priv->prefixes, widget, FALSE, TRUE, 0);
761   gtk_widget_show (GTK_WIDGET (priv->prefixes));
762 }
763