[gnome-bluetooth: 1/4] lib: Add BluetoothHdyColumn



commit 543b34a22dbecb71f495ab28c30f6636e38f49fd
Author: Adrien Plazas <kekun plazas laposte net>
Date:   Tue Feb 5 13:08:36 2019 +0100

    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.

 docs/reference/libgnome-bluetooth/meson.build |   1 +
 lib/bluetooth-hdy-column.c                    | 368 ++++++++++++++++++++++++++
 lib/bluetooth-hdy-column.h                    |  25 ++
 lib/meson.build                               |   1 +
 po/POTFILES.in                                |   1 +
 5 files changed, 396 insertions(+)
---
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


[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]