Verified Commit 6fadb1f8 authored by Zander Brown's avatar Zander Brown
Browse files

switcher: Add documentation

parent 5f344652
Pipeline #4704 failed with stage
in 4 minutes and 7 seconds
......@@ -103,6 +103,11 @@
<xi:include href="xml/api-index-0.0.8.xml"><xi:fallback /></xi:include>
</index>
<index id="api-index-0-0-9" role="0.0.9">
<title>Index of new symbols in 0.0.9</title>
<xi:include href="xml/api-index-0.0.9.xml"><xi:fallback /></xi:include>
</index>
<index id="annotations-glossary">
<title>Annotations glossary</title>
<xi:include href="xml/annotation-glossary.xml"><xi:fallback /></xi:include>
......
......@@ -11,6 +11,7 @@ private_headers = [
images = [
'images/arrows.png',
'images/dialer.png',
'images/switchers.png',
]
content_files = [
......
This diff is collapsed.
......@@ -277,7 +277,7 @@ dialog_action_clicked_cb (GtkButton *btn,
static void
switcher_demo_clicked_cb (GtkButton *btn,
ExampleWindow *self)
HdyDemoWindow *self)
{
GtkBuilder *builder;
GtkWidget *win, *pswitch;
......
......@@ -24,7 +24,9 @@
</glade-widget-class>
<glade-widget-class name="HdyLeaflet" generic-name="leaflet" title="Leaflet"/>
<glade-widget-class name="HdySearchBar" generic-name="searchbar" title="Search Bar" since="0.0.6"/>
<glade-widget-class name="HdySwitcher" generic-name="switcher" title="Switcher" since="0.0.8"/>
<glade-widget-class name="HdySwitcherBar" generic-name="switcherbar" title="Switcher Bar" since="0.0.9"/>
<glade-widget-class name="HdyPrimarySwitcher" generic-name="primaryswitcher" title="Primary Switcher" since="0.0.9"/>
<glade-widget-class name="HdySecondarySwitcher" generic-name="secondaryswitcher" title="Secondary Switcher" since="0.0.9"/>
<glade-widget-class name="HdyTitleBar" generic-name="titlebar" title="Title Bar"/>
</glade-widget-classes>
......
......@@ -14,34 +14,41 @@
* @short_description: An adaptive switcher
* @title: HdyPrimarySwitcher
*
* An alternative #GtkStackSwitcher
* An applications main switcher. Intended to be used in a #GtkHeaderBar with
* gtk_header_bar_set_custom_title()
*
* C Usage
* |[<!-- language="C" -->
* GtkWidget *stack, *switcher;
* GtkWidget *hb, *stack, *switcher;
*
* hb = gtk_header_bar_new ();
* stack = gtk_stack_new ();
* switcher = hdy_primary_switcher_new ();
* gtk_header_bar_set_custom_title (GTK_HEADER_BAR (hb), switcher);
* hdy_switcher_set_stack (HDY_SWITCHER (switcher), GTK_STACK (stack));
* ]|
*
* Vala Usage
* |[<!-- language="Vala" -->
* var hb = new Gtk.HeaderBar ();
* var stack = new Gtk.Stack ();
* var switcher = new Hdy.PrimarySwitcher ();
* hb.custom_title = switcher;
* switcher.stack = stack;
* ]|
*
* Python Usage
* |[<!-- language="Python" -->
* hb = Gtk.HeaderBar ()
* stack = Gtk.Stack ()
* switcher = Handy.PrimarySwitcher ()
* hb.props.custom_title = switcher
* switcher.props.stack = stack
* ]|
*
* Design Information: [GitLab Issue](https://source.puri.sm/Librem5/libhandy/issues/64)
*
* Since: 0.0.8
* Since: 0.0.9
*/
......@@ -50,6 +57,8 @@ typedef struct {
GtkWidget *label;
HdySecondarySwitcher *secondary;
gboolean secondary_active;
gulong size_handler;
GBinding *secondary_active_binding;
} HdyPrimarySwitcherPrivate;
enum {
......@@ -74,46 +83,79 @@ hdy_primary_switcher_init (HdyPrimarySwitcher *self)
priv = hdy_primary_switcher_get_instance_private (self);
priv->secondary_active = FALSE;
priv->size_handler = 0;
/* The switcher and label are different widths but should
* act as if they have the same height */
gtk_stack_set_hhomogeneous (GTK_STACK (self), FALSE);
gtk_stack_set_vhomogeneous (GTK_STACK (self), FALSE);
gtk_stack_set_vhomogeneous (GTK_STACK (self), TRUE);
gtk_widget_set_halign (GTK_WIDGET (self), GTK_ALIGN_CENTER);
/* The 'real' switcher */
priv->switcher = hdy_switcher_bar_new ();
gtk_widget_show (priv->switcher);
gtk_stack_add_named (GTK_STACK (self), priv->switcher, "switcher");
/* Label used for mobile view */
priv->label = gtk_label_new (NULL);
context = gtk_widget_get_style_context (priv->label);
gtk_style_context_add_class (context, "title");
gtk_widget_set_halign (priv->label, GTK_ALIGN_CENTER);
gtk_widget_set_valign (priv->label, GTK_ALIGN_CENTER);
gtk_label_set_ellipsize (GTK_LABEL (priv->label), PANGO_ELLIPSIZE_END);
g_object_bind_property (self, "title", priv->label, "label", G_BINDING_SYNC_CREATE);
gtk_widget_show (priv->label);
gtk_stack_add_named (GTK_STACK (self), priv->label, "label");
/* We use the switcher by default */
gtk_stack_set_visible_child (GTK_STACK (self), priv->switcher);
gtk_widget_set_focus_on_click (GTK_WIDGET (self), FALSE);
}
/* The secondary switcher is lost, presumably it was destroyed */
static void
lost_secondary_cb (gpointer data,
GObject *where_the_object_was)
{
HdyPrimarySwitcherPrivate *priv;
g_return_if_fail (HDY_IS_PRIMARY_SWITCHER (data));
priv = hdy_primary_switcher_get_instance_private (HDY_PRIMARY_SWITCHER (data));
priv->secondary = NULL;
g_clear_object (&priv->secondary_active_binding);
hdy_primary_switcher_set_secondary_active (HDY_PRIMARY_SWITCHER (data), FALSE);
}
static void
hdy_primary_switcher_dispose (GObject *object)
{
HdyPrimarySwitcher *self = HDY_PRIMARY_SWITCHER (object);
/* Release the secondary switcher */
hdy_primary_switcher_set_secondary (self, NULL);
G_OBJECT_CLASS (hdy_primary_switcher_parent_class)->dispose (object);
}
static void
hdy_primary_switcher_get_property (GObject *object,
guint prop_id,
GValue *value,
GParamSpec *pspec)
guint prop_id,
GValue *value,
GParamSpec *pspec)
{
HdyPrimarySwitcher *self = HDY_PRIMARY_SWITCHER (object);
HdyPrimarySwitcherPrivate *priv = hdy_primary_switcher_get_instance_private (self);
switch (prop_id) {
case PROP_ICON_SIZE:
/* Pass though to the switcher */
g_object_get_property (G_OBJECT (priv->switcher), "icon-size", value);
break;
case PROP_STACK:
/* Pass though to the switcher */
g_object_get_property (G_OBJECT (priv->switcher), "stack", value);
break;
......@@ -122,11 +164,11 @@ hdy_primary_switcher_get_property (GObject *object,
break;
case PROP_SECONDARY_ACTIVE:
g_value_set_boolean (value, priv->secondary_active);
g_value_set_boolean (value, hdy_primary_switcher_get_secondary_active (self));
break;
case PROP_TITLE:
g_object_get_property (G_OBJECT (priv->label), "label", value);
g_value_set_string (value, hdy_primary_switcher_get_title (self));
break;
default:
......@@ -158,16 +200,11 @@ hdy_primary_switcher_set_property (GObject *object,
break;
case PROP_SECONDARY_ACTIVE:
priv->secondary_active = g_value_get_boolean (value);
if (priv->secondary_active) {
gtk_stack_set_visible_child (GTK_STACK (self), priv->label);
} else {
gtk_stack_set_visible_child (GTK_STACK (self), priv->switcher);
}
hdy_primary_switcher_set_secondary_active (self, g_value_get_boolean (value));
break;
case PROP_TITLE:
g_object_set_property (G_OBJECT (priv->label), "label", value);
hdy_primary_switcher_set_title (self, g_value_get_string (value));
break;
default:
......@@ -182,14 +219,18 @@ hdy_primary_switcher_class_init (HdyPrimarySwitcherClass *klass)
GObjectClass *object_class = G_OBJECT_CLASS (klass);
GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (klass);
object_class->dispose = hdy_primary_switcher_dispose;
object_class->get_property = hdy_primary_switcher_get_property;
object_class->set_property = hdy_primary_switcher_set_property;
/**
* HdyPrimarySwitcher:title:
*
* Title shown in mobile view
*
* See: hdy_primary_switcher_set_title()
*
* Since: 0.0.8
* Since: 0.0.9
*/
g_object_class_install_property (object_class,
PROP_TITLE,
......@@ -203,8 +244,11 @@ hdy_primary_switcher_class_init (HdyPrimarySwitcherClass *klass)
/**
* HdyPrimarySwitcher:secondary:
*
* The #HdySecondarySwitcher to use
*
* See: hdy_primary_switcher_set_secondary()
*
* Since: 0.0.8
* Since: 0.0.9
*/
g_object_class_install_property (object_class,
PROP_SECONDARY,
......@@ -219,8 +263,11 @@ hdy_primary_switcher_class_init (HdyPrimarySwitcherClass *klass)
/**
* HdyPrimarySwitcher:secondary-active:
*
* Indicates the secondary switcher is active
*
* You shouldn't set this directly but you can observe it with #GObject::notify
*
* Since: 0.0.8
* Since: 0.0.9
*/
g_object_class_install_property (object_class,
PROP_SECONDARY_ACTIVE,
......@@ -242,10 +289,20 @@ hdy_primary_switcher_class_init (HdyPrimarySwitcherClass *klass)
gtk_widget_class_set_css_name (widget_class, "hdyprimaryswitcher");
}
static void
secondary_allocate_cb (GtkWidget *secondary,
GdkRectangle *allocation,
HdyPrimarySwitcher *self)
/**
* hdy_primary_switcher_set_title:
* @self: a #HdyPrimarySwitcher
* @title: the new title
*
* Set the title used when #HdyPrimarySwitcher:secondary is in use
*
* Generally this should be in sync with the title of your #GtkWindow/#GtkHeaderBar
*
* Since: 0.0.9
*/
void
hdy_primary_switcher_set_title (HdyPrimarySwitcher *self,
const gchar *title)
{
HdyPrimarySwitcherPrivate *priv;
......@@ -253,11 +310,69 @@ secondary_allocate_cb (GtkWidget *secondary,
priv = hdy_primary_switcher_get_instance_private (self);
/* Set the contents of the label */
g_object_set (priv->label,
"label", title,
NULL);
g_object_notify (G_OBJECT (self), "title");
}
/**
* hdy_primary_switcher_get_title:
* @self: a #HdyPrimarySwitcher
*
* Get the title used when #HdyPrimarySwitcher:secondary is in use
*
* See: hdy_primary_switcher_set_title()
*
* Returns: (nullable) (transfer none): the title, or %NULL if none has been set
*
* Since: 0.0.9
*/
gchar *
hdy_primary_switcher_get_title (HdyPrimarySwitcher *self)
{
HdyPrimarySwitcherPrivate *priv;
gchar *title;
g_return_val_if_fail (HDY_IS_PRIMARY_SWITCHER (self), NULL);
priv = hdy_primary_switcher_get_instance_private (self);
/* Get the contents of the label */
g_object_get (priv->label,
"label", &title,
NULL);
return title;
}
/* size of secondary switcher (potentially) changed */
static void
secondary_allocate_cb (GtkWidget *secondary,
GdkRectangle *allocation,
HdyPrimarySwitcher *self)
{
g_return_if_fail (HDY_IS_PRIMARY_SWITCHER (self));
/* If the size is less/equal to 400 switch to secondary */
g_object_set (self,
"secondary-active", allocation->width <= 400,
NULL);
}
/**
* hdy_primary_switcher_set_secondary:
* @self: a #HdyPrimarySwitcher
* @secondary: the #HdySecondarySwitcher for mobile view
*
* Set the #HdySecondarySwitcher this switcher will defer to in mobile view
*
* For best results the switcher should have a #HdyPrimarySwitcher:title set
*
* Since: 0.0.9
*/
void
hdy_primary_switcher_set_secondary (HdyPrimarySwitcher *self,
HdySecondarySwitcher *secondary)
......@@ -269,12 +384,34 @@ hdy_primary_switcher_set_secondary (HdyPrimarySwitcher *self,
priv = hdy_primary_switcher_get_instance_private (self);
priv->secondary = secondary;
/* Ignore attemts to set the current switcher */
if (priv->secondary == secondary)
return;
/* Disconnect the old one */
if (priv->secondary) {
g_signal_connect (priv->secondary, "size-allocate",
G_CALLBACK (secondary_allocate_cb), self);
g_object_bind_property (self, "secondary-active", priv->secondary, "active", G_BINDING_SYNC_CREATE);
g_signal_handler_disconnect (G_OBJECT (priv->secondary), priv->size_handler);
g_object_weak_unref (G_OBJECT (priv->secondary), lost_secondary_cb, self);
g_clear_object (&priv->secondary_active_binding);
priv->secondary = NULL;
}
/* Connect the new one */
if (secondary) {
priv->secondary = secondary;
g_object_weak_ref (G_OBJECT (priv->secondary), lost_secondary_cb, self);
/* HACK: Make mobile size switch based on the size of secondary not primary */
priv->size_handler = g_signal_connect (priv->secondary, "size-allocate",
G_CALLBACK (secondary_allocate_cb),
self);
/* Bind 'active' of the secondary switcher with 'secondary-active' of this one */
priv->secondary_active_binding = g_object_bind_property (self,
"secondary-active",
priv->secondary,
"active",
G_BINDING_SYNC_CREATE);
}
g_object_notify (G_OBJECT (self), "secondary");
......@@ -284,13 +421,13 @@ hdy_primary_switcher_set_secondary (HdyPrimarySwitcher *self,
* hdy_primary_switcher_get_secondary:
* @self: a #HdyPrimarySwitcher
*
* Get the #GtkStack being controlled by the #HdySwitcher
* Get the #HdySecondarySwitcher used for mobile views
*
* See: hdy_primary_switcher_set_secondary()
*
* Returns: (nullable) (transfer none): the #HdySecondarySwitcher, or %NULL if none has been set
*
* Since: 0.0.8
* Since: 0.0.9
*/
HdySecondarySwitcher *
hdy_primary_switcher_get_secondary (HdyPrimarySwitcher *self)
......@@ -304,6 +441,90 @@ hdy_primary_switcher_get_secondary (HdyPrimarySwitcher *self)
return priv->secondary;
}
/**
* hdy_primary_switcher_set_secondary_active:
* @self: a #HdyPrimarySwitcher
* @active: state of the secondary switcher
*
* This is included for completeness, you almost certainly shouldn't be
* using this function
*
* See: hdy_primary_switcher_get_secondary_active()
*
* Since: 0.0.9
*/
void
hdy_primary_switcher_set_secondary_active (HdyPrimarySwitcher *self,
gboolean active)
{
HdyPrimarySwitcherPrivate *priv;
g_return_if_fail (HDY_IS_PRIMARY_SWITCHER (self));
priv = hdy_primary_switcher_get_instance_private (self);
/* Ignore change if it's actually the current state */
if (priv->secondary_active == active)
return;
priv->secondary_active = active;
if (active) {
gtk_stack_set_visible_child (GTK_STACK (self), priv->label);
} else {
gtk_stack_set_visible_child (GTK_STACK (self), priv->switcher);
}
g_object_notify (G_OBJECT (self), "secondary-active");
}
/**
* hdy_primary_switcher_get_secondary_active:
* @self: a #HdyPrimarySwitcher
*
* Get the #HdySecondartSwitcher:active state
*
* Returns: %TRUE if the secondary is active
*
* Since: 0.0.9
*/
gboolean
hdy_primary_switcher_get_secondary_active (HdyPrimarySwitcher *self)
{
HdyPrimarySwitcherPrivate *priv;
g_return_val_if_fail (HDY_IS_PRIMARY_SWITCHER (self), FALSE);
priv = hdy_primary_switcher_get_instance_private (self);
return priv->secondary_active;
}
/**
* hdy_primary_switcher_new:
*
* Create a #HdyPrimarySwitcher
*
* Should be used with a #HdySecondarySwitcher (#HdyPrimarySwitcher:secondary) and
* gernerally with #HdyPrimarySwitcher:title bound to #GtkWindow
* #GtkWindow:title (g_object_bind_property())
*
* C Usage
* |[<!-- language="C" -->
* GtkWidget *switcher = hdy_primary_switcher_new ();
* ]|
*
* Vala Usage
* |[<!-- language="Vala" -->
* var switcher = new Hdy.PrimarySwitcher ();
* ]|
*
* Python Usage
* |[<!-- language="Python" -->
* switcher = Handy.PrimarySwitcher ()
* ]|
*
* Since: 0.0.9
*/
GtkWidget *
hdy_primary_switcher_new (void)
{
......
......@@ -25,9 +25,15 @@ struct _HdyPrimarySwitcherClass {
G_DECLARE_DERIVABLE_TYPE (HdyPrimarySwitcher, hdy_primary_switcher, HDY, PRIMARY_SWITCHER, GtkStack)
GtkWidget *hdy_primary_switcher_new (void);
void hdy_primary_switcher_set_secondary (HdyPrimarySwitcher *self,
HdySecondarySwitcher *secondary);
HdySecondarySwitcher *hdy_primary_switcher_get_secondary (HdyPrimarySwitcher *self);
GtkWidget *hdy_primary_switcher_new (void);
void hdy_primary_switcher_set_title (HdyPrimarySwitcher *self,
const gchar *title);
gchar *hdy_primary_switcher_get_title (HdyPrimarySwitcher *self);
void hdy_primary_switcher_set_secondary (HdyPrimarySwitcher *self,
HdySecondarySwitcher *secondary);
HdySecondarySwitcher *hdy_primary_switcher_get_secondary (HdyPrimarySwitcher *self);
void hdy_primary_switcher_set_secondary_active (HdyPrimarySwitcher *self,
gboolean active);
gboolean hdy_primary_switcher_get_secondary_active (HdyPrimarySwitcher *self);
G_END_DECLS
......@@ -45,7 +45,7 @@
*
* Design Information: [GitLab Issue](https://source.puri.sm/Librem5/libhandy/issues/64)
*
* Since: 0.0.8
* Since: 0.0.9
*/
#define TIMEOUT_EXPAND 500
......@@ -593,9 +593,6 @@ static void
hdy_switcher_bar_dispose (GObject *object)
{
HdySwitcherBar *self = HDY_SWITCHER_BAR (object);
//HdySwitcherBarPrivate *priv;
//priv = hdy_switcher_bar_get_instance_private (self);
remove_switch_timer (self);
hdy_switcher_bar_set_stack (self, NULL);
......@@ -622,49 +619,63 @@ hdy_switcher_bar_get_preferred_width (GtkWidget *widget,
gint *nat)
{
HdySwitcherBar *self = HDY_SWITCHER_BAR (widget);
/* the greatest button width when vertical */
gint widest_v = 0;
/* the greatest button width when horizontal */
gint widest_h = 0;
/* number of buttons, used instead of g_list_length
* to avoid multiple iterations of the list */
gint count = 0;
/* for each button */
for (GList *l = gtk_container_get_children (GTK_CONTAINER (self)); l != NULL; l = g_list_next (l)) {
/* get the buttons minimum width for each orientation */
gint v_min = 0;
gint h_nat = 0;
hdy_switcher_button_get_size (HDY_SWITCHER_BUTTON (l->data), &v_min, NULL, &h_nat);
if (v_min > widest_v)
widest_v = v_min;
if (h_nat > widest_h)
widest_h = h_nat;
/* Update the widest if necessary */
widest_v = MAX (v_min, widest_v);
widest_h = MAX (h_nat, widest_h);
count++;
}
/* The minimum width is the widest vertical button * number of button */
*min = widest_v * count;
/* Natural width is the same but when horizintal */
*nat = widest_h * count;
}
/* Work out if a given width should be horizintal or verical */
static gint
is_narrow (HdySwitcherBar *self,
gint width)
{
gint widest_h = 0;
/* The widest button in horizontal mode */
gint widest_h = 0;
gint count = 0;
/* for each button */
for (GList *l = gtk_container_get_children (GTK_CONTAINER (self)); l != NULL; l = g_list_next (l)) {
gint h_min = 0;
/* Get the horizontal minimum */
hdy_switcher_button_get_size (HDY_SWITCHER_BUTTON (l->data), NULL, &h_min, NULL);
/* Update the widest */
widest_h = MAX (widest_h, h_min);
count++;
}
/* We are narrow if we can't fit the required number of buttons
* at the minimum width of the widest button in the given width */
return (widest_h * count) > width;
}
/* figure out how we will use the size we have been given */
static void
hdy_switcher_bar_size_allocate (GtkWidget *widget,
GtkAllocation *allocation)
......@@ -709,7 +720,7 @@ hdy_switcher_bar_class_init (HdySwitcherBarClass *class)
gtk_widget_class_set_css_name (widget_class, "hdyswitcher");
/* Load the styles for the widget, this feels very hacky */
/* Load the styles for the widget, doing this here feels very hacky */
provider = gtk_css_provider_new ();
gtk_css_provider_load_from_resource (provider, "/sm/puri/handy/styles/hdy-switcher.css");
gtk_style_context_add_provider_for_screen (gdk_screen_get_default (),
......@@ -721,7 +732,7 @@ hdy_switcher_bar_class_init (HdySwitcherBarClass *class)
/**
* hdy_switcher_bar_new:
*
* Create a #HdySwitcherBar with #GtkWindow:transient-for set to parent
* Create a #HdySwitcherBar, set #HdySwitcher:stack to use it
*
* C Usage
* |[<!-- language="C" -->
......@@ -738,7 +749,7 @@ hdy_switcher_bar_class_init (HdySwitcherBarClass *class)
* switcher = Handy.SwitcherBar ()
* ]|
*