diff options
author | Adrien Plazas <kekun.plazas@laposte.net> | 2019-02-05 13:08:36 +0100 |
---|---|---|
committer | Bastien Nocera <hadess@hadess.net> | 2019-02-06 17:54:26 +0100 |
commit | 543b34a22dbecb71f495ab28c30f6636e38f49fd (patch) | |
tree | 77082c7b60215d706e24dd97c49ed107de9dab08 | |
parent | c201fa71898c271a59a77d07fc2a96334faa446b (diff) | |
download | gnome-bluetooth-543b34a22dbecb71f495ab28c30f6636e38f49fd.tar.gz |
lib: Add BluetoothHdyColumn
This is a fork of HdyColumn introduced to fix a name collision in GNOME
Settings as is has both gnome-bluetooth's version of HdyColumn and its
own in parallel.
The widget couldn't be named BluetoothColumn as the name was already
taken.
-rw-r--r-- | docs/reference/libgnome-bluetooth/meson.build | 1 | ||||
-rw-r--r-- | lib/bluetooth-hdy-column.c | 368 | ||||
-rw-r--r-- | lib/bluetooth-hdy-column.h | 25 | ||||
-rw-r--r-- | lib/meson.build | 1 | ||||
-rw-r--r-- | po/POTFILES.in | 1 |
5 files changed, 396 insertions, 0 deletions
diff --git a/docs/reference/libgnome-bluetooth/meson.build b/docs/reference/libgnome-bluetooth/meson.build index 67e030de..51ad8089 100644 --- a/docs/reference/libgnome-bluetooth/meson.build +++ b/docs/reference/libgnome-bluetooth/meson.build @@ -7,6 +7,7 @@ private_headers = [ 'bluetooth-settings-obexpush.h', 'bluetooth-settings-row.h', 'gnome-bluetooth-enum-types.h', + 'bluetooth-hdy-column.h', ] version_conf = configuration_data() diff --git a/lib/bluetooth-hdy-column.c b/lib/bluetooth-hdy-column.c new file mode 100644 index 00000000..77b5eead --- /dev/null +++ b/lib/bluetooth-hdy-column.c @@ -0,0 +1,368 @@ +/* + * Copyright (C) 2018 Purism SPC + * + * SPDX-License-Identifier: LGPL-2.1+ + */ + +#include "bluetooth-hdy-column.h" + +#include <glib/gi18n.h> +#include <math.h> + +/* + * SECTION:bluetooth-hdy-column + * @short_description: A container letting its child grow up to a given width. + * @Title: BluetoothHdyColumn + * + * The #BluetoothHdyColumn widget limits the size of the widget it contains to a + * given maximum width. The expansion of the child from its minimum to its + * maximum size is eased out for a smooth transition. + * + * If the child requires more than the requested maximum width, it will be + * allocated the minimum width it can fit in instead. + */ + +#define BLUETOOTH_EASE_OUT_TAN_CUBIC 3 + +enum { + PROP_0, + PROP_MAXIMUM_WIDTH, + PROP_LINEAR_GROWTH_WIDTH, + LAST_PROP, +}; + +struct _BluetoothHdyColumn +{ + GtkBin parent_instance; + + gint maximum_width; + gint linear_growth_width; +}; + +static GParamSpec *props[LAST_PROP]; + +G_DEFINE_TYPE (BluetoothHdyColumn, bluetooth_hdy_column, GTK_TYPE_BIN) + +static gdouble +ease_out_cubic (gdouble progress) +{ + gdouble tmp = progress - 1; + + return tmp * tmp * tmp + 1; +} + +static void +bluetooth_hdy_column_get_property (GObject *object, + guint prop_id, + GValue *value, + GParamSpec *pspec) +{ + BluetoothHdyColumn *self = BLUETOOTH_HDY_COLUMN (object); + + switch (prop_id) { + case PROP_MAXIMUM_WIDTH: + g_value_set_int (value, bluetooth_hdy_column_get_maximum_width (self)); + break; + case PROP_LINEAR_GROWTH_WIDTH: + g_value_set_int (value, bluetooth_hdy_column_get_linear_growth_width (self)); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); + } +} + +static void +bluetooth_hdy_column_set_property (GObject *object, + guint prop_id, + const GValue *value, + GParamSpec *pspec) +{ + BluetoothHdyColumn *self = BLUETOOTH_HDY_COLUMN (object); + + switch (prop_id) { + case PROP_MAXIMUM_WIDTH: + bluetooth_hdy_column_set_maximum_width (self, g_value_get_int (value)); + break; + case PROP_LINEAR_GROWTH_WIDTH: + bluetooth_hdy_column_set_linear_growth_width (self, g_value_get_int (value)); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); + } +} + +static gint +get_child_width (BluetoothHdyColumn *self, + gint width) +{ + GtkBin *bin = GTK_BIN (self); + GtkWidget *child; + gint minimum_width = 0, maximum_width; + gdouble amplitude, threshold, progress; + + child = gtk_bin_get_child (bin); + if (child == NULL) + return 0; + + if (gtk_widget_get_visible (child)) + gtk_widget_get_preferred_width (child, &minimum_width, NULL); + + /* Sanitize the minimum width to use for computations. */ + minimum_width = MIN (MAX (minimum_width, self->linear_growth_width), self->maximum_width); + + if (width <= minimum_width) + return width; + + /* Sanitize the maximum width to use for computations. */ + maximum_width = MAX (minimum_width, self->maximum_width); + amplitude = maximum_width - minimum_width; + threshold = (BLUETOOTH_EASE_OUT_TAN_CUBIC * amplitude + (gdouble) minimum_width); + + if (width >= threshold) + return maximum_width; + + progress = (width - minimum_width) / (threshold - minimum_width); + + return ease_out_cubic (progress) * amplitude + minimum_width; +} + +/* This private method is prefixed by the call name because it will be a virtual + * method in GTK+ 4. + */ +static void +bluetooth_hdy_column_measure (GtkWidget *widget, + GtkOrientation orientation, + int for_size, + int *minimum, + int *natural, + int *minimum_baseline, + int *natural_baseline) +{ + GtkBin *bin = GTK_BIN (widget); + GtkWidget *child; + + if (minimum) + *minimum = 0; + if (natural) + *natural = 0; + if (minimum_baseline) + *minimum_baseline = -1; + if (natural_baseline) + *natural_baseline = -1; + + child = gtk_bin_get_child (bin); + if (!(child && gtk_widget_get_visible (child))) + return; + + if (orientation == GTK_ORIENTATION_HORIZONTAL) + gtk_widget_get_preferred_width (child, minimum, natural); + else { + gint child_width = get_child_width (BLUETOOTH_HDY_COLUMN (widget), for_size); + + gtk_widget_get_preferred_height_and_baseline_for_width (child, + child_width, + minimum, + natural, + minimum_baseline, + natural_baseline); + } +} + +static void +bluetooth_hdy_column_get_preferred_width (GtkWidget *widget, + gint *minimum, + gint *natural) +{ + bluetooth_hdy_column_measure (widget, GTK_ORIENTATION_HORIZONTAL, -1, + minimum, natural, NULL, NULL); +} + +static void +bluetooth_hdy_column_get_preferred_height_and_baseline_for_width (GtkWidget *widget, + gint width, + gint *minimum, + gint *natural, + gint *minimum_baseline, + gint *natural_baseline) +{ + bluetooth_hdy_column_measure (widget, GTK_ORIENTATION_VERTICAL, width, + minimum, natural, minimum_baseline, natural_baseline); +} + +static void +bluetooth_hdy_column_get_preferred_height (GtkWidget *widget, + gint *minimum, + gint *natural) +{ + bluetooth_hdy_column_measure (widget, GTK_ORIENTATION_VERTICAL, -1, + minimum, natural, NULL, NULL); +} + +static void +bluetooth_hdy_column_size_allocate (GtkWidget *widget, + GtkAllocation *allocation) +{ + BluetoothHdyColumn *self = BLUETOOTH_HDY_COLUMN (widget); + GtkBin *bin = GTK_BIN (widget); + GtkAllocation child_allocation; + gint baseline; + GtkWidget *child; + + gtk_widget_set_allocation (widget, allocation); + + child = gtk_bin_get_child (bin); + if (child == NULL) + return; + + child_allocation.width = get_child_width (self, allocation->width); + child_allocation.height = allocation->height; + + if (!gtk_widget_get_has_window (widget)) { + /* This allways center the child vertically. */ + child_allocation.x = allocation->x + (allocation->width - child_allocation.width) / 2; + child_allocation.y = allocation->y; + } + else { + child_allocation.x = 0; + child_allocation.y = 0; + } + + baseline = gtk_widget_get_allocated_baseline (widget); + gtk_widget_size_allocate_with_baseline (child, &child_allocation, baseline); +} + +static void +bluetooth_hdy_column_class_init (BluetoothHdyColumnClass *klass) +{ + GObjectClass *object_class = G_OBJECT_CLASS (klass); + GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (klass); + GtkContainerClass *container_class = GTK_CONTAINER_CLASS (klass); + + object_class->get_property = bluetooth_hdy_column_get_property; + object_class->set_property = bluetooth_hdy_column_set_property; + + widget_class->get_preferred_width = bluetooth_hdy_column_get_preferred_width; + widget_class->get_preferred_height = bluetooth_hdy_column_get_preferred_height; + widget_class->get_preferred_height_and_baseline_for_width = bluetooth_hdy_column_get_preferred_height_and_baseline_for_width; + widget_class->size_allocate = bluetooth_hdy_column_size_allocate; + + gtk_container_class_handle_border_width (container_class); + + /** + * BluetoothHdyColumn:maximum_width: + * + * The maximum width to allocate to the child. + */ + props[PROP_MAXIMUM_WIDTH] = + g_param_spec_int ("maximum-width", + _("Maximum width"), + _("The maximum width allocated to the child"), + 0, G_MAXINT, 0, + G_PARAM_READWRITE | G_PARAM_EXPLICIT_NOTIFY); + + /** + * BluetoothHdyColumn:linear_growth_width: + * + * The width up to which the child will be allocated all the width. + */ + props[PROP_LINEAR_GROWTH_WIDTH] = + g_param_spec_int ("linear-growth-width", + _("Linear growth width"), + _("The width up to which the child will be allocated all the width"), + 0, G_MAXINT, 0, + G_PARAM_READWRITE | G_PARAM_EXPLICIT_NOTIFY); + + g_object_class_install_properties (object_class, LAST_PROP, props); + + gtk_widget_class_set_css_name (widget_class, "bluetoothcolumn"); +} + +static void +bluetooth_hdy_column_init (BluetoothHdyColumn *self) +{ +} + +/** + * bluetooth_hdy_column_new: + * + * Creates a new #BluetoothHdyColumn. + * + * Returns: a new #BluetoothHdyColumn + */ +BluetoothHdyColumn * +bluetooth_hdy_column_new (void) +{ + return g_object_new (BLUETOOTH_TYPE_HDY_COLUMN, NULL); +} + +/** + * bluetooth_hdy_column_get_maximum_width: + * @self: a #BluetoothHdyColumn + * + * Gets the maximum width to allocate to the contained child. + * + * Returns: the maximum width to allocate to the contained child. + */ +gint +bluetooth_hdy_column_get_maximum_width (BluetoothHdyColumn *self) +{ + g_return_val_if_fail (BLUETOOTH_IS_HDY_COLUMN (self), 0); + + return self->maximum_width; +} + +/** + * bluetooth_hdy_column_set_maximum_width: + * @self: a #BluetoothHdyColumn + * @maximum_width: the maximum width + * + * Sets the maximum width to allocate to the contained child. + */ +void +bluetooth_hdy_column_set_maximum_width (BluetoothHdyColumn *self, + gint maximum_width) +{ + g_return_if_fail (BLUETOOTH_IS_HDY_COLUMN (self)); + + self->maximum_width = maximum_width; +} + +/** + * bluetooth_hdy_column_get_linear_growth_width: + * @self: a #BluetoothHdyColumn + * + * Gets the width up to which the child will be allocated all the available + * width and starting from which it will be allocated a portion of the available + * width. In bith cases the allocated width won't exceed the declared maximum. + * + * Returns: the width up to which the child will be allocated all the available + * width. + */ +gint +bluetooth_hdy_column_get_linear_growth_width (BluetoothHdyColumn *self) +{ + g_return_val_if_fail (BLUETOOTH_IS_HDY_COLUMN (self), 0); + + return self->linear_growth_width; +} + +/** + * bluetooth_hdy_column_set_linear_growth_width: + * @self: a #BluetoothHdyColumn + * @linear_growth_width: the linear growth width + * + * Sets the width up to which the child will be allocated all the available + * width and starting from which it will be allocated a portion of the available + * width. In bith cases the allocated width won't exceed the declared maximum. + * + */ +void +bluetooth_hdy_column_set_linear_growth_width (BluetoothHdyColumn *self, + gint linear_growth_width) +{ + g_return_if_fail (BLUETOOTH_IS_HDY_COLUMN (self)); + + self->linear_growth_width = linear_growth_width; + + gtk_widget_queue_resize (GTK_WIDGET (self)); +} diff --git a/lib/bluetooth-hdy-column.h b/lib/bluetooth-hdy-column.h new file mode 100644 index 00000000..2ed80bc3 --- /dev/null +++ b/lib/bluetooth-hdy-column.h @@ -0,0 +1,25 @@ +/* + * Copyright (C) 2018 Purism SPC + * + * SPDX-License-Identifier: LGPL-2.1+ + */ + +#pragma once + +#include <gtk/gtk.h> + +G_BEGIN_DECLS + +#define BLUETOOTH_TYPE_HDY_COLUMN (bluetooth_hdy_column_get_type()) + +G_DECLARE_FINAL_TYPE (BluetoothHdyColumn, bluetooth_hdy_column, BLUETOOTH, HDY_COLUMN, GtkBin) + +BluetoothHdyColumn *bluetooth_hdy_column_new (void); +gint bluetooth_hdy_column_get_maximum_width (BluetoothHdyColumn *self); +void bluetooth_hdy_column_set_maximum_width (BluetoothHdyColumn *self, + gint maximum_width); +gint bluetooth_hdy_column_get_linear_growth_width (BluetoothHdyColumn *self); +void bluetooth_hdy_column_set_linear_growth_width (BluetoothHdyColumn *self, + gint linear_growth_width); + +G_END_DECLS diff --git a/lib/meson.build b/lib/meson.build index 258ff28f..52afd22a 100644 --- a/lib/meson.build +++ b/lib/meson.build @@ -23,6 +23,7 @@ sources = files( 'bluetooth-chooser-button.c', 'bluetooth-chooser-combo.c', 'bluetooth-client.c', + 'bluetooth-hdy-column.c', 'bluetooth-filter-widget.c', 'bluetooth-pairing-dialog.c', 'bluetooth-settings-obexpush.c', diff --git a/po/POTFILES.in b/po/POTFILES.in index ffdf6a16..e2b74e55 100644 --- a/po/POTFILES.in +++ b/po/POTFILES.in @@ -3,6 +3,7 @@ lib/bluetooth-chooser.c lib/bluetooth-chooser-combo.c lib/bluetooth-client.c lib/bluetooth-filter-widget.c +lib/bluetooth-hdy-column.c lib/bluetooth-pairing-dialog.c lib/bluetooth-settings-row.c lib/bluetooth-settings-row.ui |