[gtk/prop-list: 4/21] Add GtkNumericSorter



commit 93e2e5e171d937140a3379d0147333e5becd73af
Author: Matthias Clasen <mclasen redhat com>
Date:   Sun Dec 8 14:37:20 2019 -0500

    Add GtkNumericSorter
    
    This sorter compares numbers obtained from items
    by evaluating an expression.

 docs/reference/gtk/gtk4-docs.xml     |   1 +
 docs/reference/gtk/gtk4-sections.txt |  19 ++
 docs/reference/gtk/gtk4.types.in     |   1 +
 gtk/gtk.h                            |   1 +
 gtk/gtknumericsorter.c               | 360 +++++++++++++++++++++++++++++++++++
 gtk/gtknumericsorter.h               |  53 ++++++
 gtk/meson.build                      |   2 +
 7 files changed, 437 insertions(+)
---
diff --git a/docs/reference/gtk/gtk4-docs.xml b/docs/reference/gtk/gtk4-docs.xml
index 5a55fee5d0..98fd5c90fb 100644
--- a/docs/reference/gtk/gtk4-docs.xml
+++ b/docs/reference/gtk/gtk4-docs.xml
@@ -51,6 +51,7 @@
       <xi:include href="xml/gtkslicelistmodel.xml" />
       <xi:include href="xml/gtksorter.xml" />
       <xi:include href="xml/gtkstringsorter.xml" />
+      <xi:include href="xml/gtknumericsorter.xml" />
       <xi:include href="xml/gtkcustomsorter.xml" />
       <xi:include href="xml/gtkmultisorter.xml" />
       <xi:include href="xml/gtksortlistmodel.xml" />
diff --git a/docs/reference/gtk/gtk4-sections.txt b/docs/reference/gtk/gtk4-sections.txt
index 714a49d9bd..678399ea82 100644
--- a/docs/reference/gtk/gtk4-sections.txt
+++ b/docs/reference/gtk/gtk4-sections.txt
@@ -2892,6 +2892,25 @@ GTK_STRING_SORTER_GET_CLASS
 gtk_string_sorter_get_type
 </SECTION>
 
+<SECTION>
+<FILE>gtknumericsorter</FILE>
+<TITLE>GtkNumericSorter</TITLE>
+GtkNumericSorter
+gtk_numeric_sorter_new
+gtk_numeric_sorter_get_expression
+gtk_numeric_sorter_set_expression
+gtk_numeric_sorter_get_sort_increasing
+gtk_numeric_sorter_set_sort_increasing
+<SUBSECTION Standard>
+GTK_NUMERIC_SORTER
+GTK_IS_NUMERIC_SORTER
+GTK_TYPE_NUMERIC_SORTER
+GTK_IS_NUMERIC_SORTER_CLASS
+GTK_NUMERIC_SORTER_GET_CLASS
+<SUBSECTION Private>
+gtk_numeric_sorter_get_type
+</SECTION>
+
 <SECTION>
 <FILE>gtkcustomsorter</FILE>
 <TITLE>GtkCustomSorter</TITLE>
diff --git a/docs/reference/gtk/gtk4.types.in b/docs/reference/gtk/gtk4.types.in
index d3a73beb1f..b9f1bde8a9 100644
--- a/docs/reference/gtk/gtk4.types.in
+++ b/docs/reference/gtk/gtk4.types.in
@@ -130,6 +130,7 @@ gtk_native_get_type
 gtk_no_selection_get_type
 gtk_notebook_get_type
 gtk_notebook_page_get_type
+gtk_numeric_sorter_get_type
 gtk_orientable_get_type
 gtk_overlay_get_type
 gtk_pad_controller_get_type
diff --git a/gtk/gtk.h b/gtk/gtk.h
index 7a8d076a53..f74d1a4b0a 100644
--- a/gtk/gtk.h
+++ b/gtk/gtk.h
@@ -184,6 +184,7 @@
 #include <gtk/gtknativedialog.h>
 #include <gtk/gtknoselection.h>
 #include <gtk/gtknotebook.h>
+#include <gtk/gtknumericsorter.h>
 #include <gtk/gtkorientable.h>
 #include <gtk/gtkoverlay.h>
 #include <gtk/gtkpadcontroller.h>
diff --git a/gtk/gtknumericsorter.c b/gtk/gtknumericsorter.c
new file mode 100644
index 0000000000..277842f176
--- /dev/null
+++ b/gtk/gtknumericsorter.c
@@ -0,0 +1,360 @@
+/*
+ * Copyright © 2019 Matthias Clasen
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library. If not, see <http://www.gnu.org/licenses/>.
+ *
+ * Authors: Matthias Clasen <mclasen redhat com>
+ */
+
+#include "config.h"
+
+#include "gtknumericsorter.h"
+
+#include "gtkintl.h"
+#include "gtktypebuiltins.h"
+
+/**
+ * SECTION:gtknumericsorter
+ * @Title: GtkNumericSorter
+ * @Short_description: Sort by comparing numbers 
+ * @See_also: #GtkExpression
+ *
+ * GtkNumericSorter is a #GtkSorter that compares numbers.
+ *
+ * To obtain the numbers to compare, this sorter evaluates a #GtkExpression.
+ */
+
+struct _GtkNumericSorter
+{
+  GtkSorter parent_instance;
+
+  gboolean sort_increasing;
+
+  GtkExpression *expression;
+  GType target_type;
+};
+
+enum {
+  PROP_0,
+  PROP_EXPRESSION,
+  PROP_SORT_INCREASING,
+  NUM_PROPERTIES
+};
+
+G_DEFINE_TYPE (GtkNumericSorter, gtk_numeric_sorter, GTK_TYPE_SORTER)
+
+static GParamSpec *properties[NUM_PROPERTIES] = { NULL, };
+
+static int
+gtk_numeric_sorter_compare (GtkSorter *sorter,
+                           gpointer   item1,
+                           gpointer   item2)
+{
+  GtkNumericSorter *self = GTK_NUMERIC_SORTER (sorter);
+  GValue value1 = G_VALUE_INIT;
+  GValue value2 = G_VALUE_INIT;
+  GValue dst = G_VALUE_INIT;
+  int result = 0;
+
+  if (self->expression == NULL ||
+      !gtk_expression_evaluate (self->expression, item1, &value1) ||
+      !gtk_expression_evaluate (self->expression, item2, &value2))
+    goto out;
+
+  switch (self->target_type)
+    {
+    case G_TYPE_INT64:
+      {
+        gint64 v1, v2;
+
+        g_value_init (&dst, G_TYPE_INT64);
+        g_value_transform (&value1, &dst);
+        v1 = g_value_get_int64 (&dst);
+        g_value_transform (&value2, &dst);
+        v2 = g_value_get_int64 (&dst);
+
+        if (v1 > v2)
+          result = 1;
+        else if (v1 < v2)
+          result = -1;
+        else
+          result = 0;
+      }
+      break;
+
+    case G_TYPE_UINT64:
+      {
+        guint64 v1, v2;
+
+        g_value_init (&dst, G_TYPE_UINT64);
+        g_value_transform (&value1, &dst);
+        v1 = g_value_get_uint64 (&dst);
+        g_value_transform (&value2, &dst);
+        v2 = g_value_get_uint64 (&dst);
+
+        if (v1 > v2)
+          result = 1;
+        else if (v1 < v2)
+          result = -1;
+        else
+          result = 0;
+      }
+      break;
+
+    case G_TYPE_DOUBLE:
+      {
+        double v1, v2;
+
+        g_value_init (&dst, G_TYPE_DOUBLE);
+        g_value_transform (&value1, &dst);
+        v1 = g_value_get_double (&dst);
+        g_value_transform (&value2, &dst);
+        v2 = g_value_get_double (&dst);
+
+        if (v1 > v2)
+          result = 1;
+        else if (v1 < v2)
+          result = -1;
+        else
+          result = 0;
+      }
+      break;
+
+    default:
+      g_assert_not_reached ();
+      break;
+    }
+
+out:
+  g_value_unset (&value1);
+  g_value_unset (&value2);
+
+  if (!self->sort_increasing)
+    result = - result;
+
+  return result;
+}
+
+static void
+gtk_numeric_sorter_set_property (GObject      *object,
+                                guint         prop_id,
+                                const GValue *value,
+                                GParamSpec   *pspec)
+{
+  GtkNumericSorter *self = GTK_NUMERIC_SORTER (object);
+
+  switch (prop_id)
+    {
+    case PROP_EXPRESSION:
+      gtk_numeric_sorter_set_expression (self, g_value_get_boxed (value));
+      break;
+
+    case PROP_SORT_INCREASING:
+      gtk_numeric_sorter_set_sort_increasing (self, g_value_get_boolean (value));
+      break;
+
+    default:
+      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+      break;
+    }
+}
+
+static void 
+gtk_numeric_sorter_get_property (GObject     *object,
+                                guint        prop_id,
+                                GValue      *value,
+                                GParamSpec  *pspec)
+{
+  GtkNumericSorter *self = GTK_NUMERIC_SORTER (object);
+
+  switch (prop_id)
+    {
+    case PROP_EXPRESSION:
+      g_value_set_boxed (value, self->expression);
+      break;
+
+    case PROP_SORT_INCREASING:
+      g_value_set_boolean (value, self->sort_increasing);
+      break;
+
+    default:
+      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+      break;
+    }
+}
+
+static void
+gtk_numeric_sorter_dispose (GObject *object)
+{
+  GtkNumericSorter *self = GTK_NUMERIC_SORTER (object);
+
+  g_clear_pointer (&self->expression, gtk_expression_unref);
+
+  G_OBJECT_CLASS (gtk_numeric_sorter_parent_class)->dispose (object);
+}
+
+static void
+gtk_numeric_sorter_class_init (GtkNumericSorterClass *class)
+{
+  GtkSorterClass *sorter_class = GTK_SORTER_CLASS (class);
+  GObjectClass *object_class = G_OBJECT_CLASS (class);
+
+  sorter_class->compare = gtk_numeric_sorter_compare;
+
+  object_class->get_property = gtk_numeric_sorter_get_property;
+  object_class->set_property = gtk_numeric_sorter_set_property;
+  object_class->dispose = gtk_numeric_sorter_dispose;
+
+  /**
+   * GtkNumericSorter:expression:
+   *
+   * The expression to evalute on item to get a numeric to compare with
+   */
+  properties[PROP_EXPRESSION] =
+      g_param_spec_boxed ("expression",
+                          P_("Expression"),
+                          P_("Expression to compare with"),
+                          GTK_TYPE_EXPRESSION,
+                          G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS | G_PARAM_EXPLICIT_NOTIFY);
+
+  /**
+   * GtkNumericSorter:sort-increasing:
+   *
+   * Whether the sorter will sort smaller numbers first
+   */
+  properties[PROP_SORT_INCREASING] =
+      g_param_spec_boolean ("sort-increasing",
+                            P_("Sort increasing"),
+                            P_("Whether to sort smaller numbers first"),
+                            TRUE,
+                            G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS | G_PARAM_EXPLICIT_NOTIFY);
+
+  g_object_class_install_properties (object_class, NUM_PROPERTIES, properties);
+
+}
+
+static void
+gtk_numeric_sorter_init (GtkNumericSorter *self)
+{
+  self->sort_increasing = TRUE;
+}
+
+/**
+ * gtk_numeric_sorter_new:
+ *
+ * Creates a new numeric sorter.
+ *
+ * Until an expression is set on it, this sorter will always
+ * compare items as equal.
+ *
+ * Returns: a new #GtkSorter
+ */
+GtkSorter *
+gtk_numeric_sorter_new (void)
+{
+  return g_object_new (GTK_TYPE_NUMERIC_SORTER, NULL);
+}
+
+/**
+ * gtk_numeric_sorter_get_expression:
+ * @self: a #GtkNumericSorter
+ *
+ * Gets the expression that is evaluated to obtain numbers from items.
+ *
+ * Returns: (nullable): a #GtkExpression, or %NULL
+ */
+GtkExpression *
+gtk_numeric_sorter_get_expression (GtkNumericSorter *self)
+{
+  g_return_val_if_fail (GTK_IS_NUMERIC_SORTER (self), NULL);
+
+  return self->expression;
+}
+
+/**
+ * gtk_numeric_sorter_set_expression:
+ * @self: a #GtkNumericSorter
+ * @expression: (nullable) (transfer none): a #GtkExpression, or %NULL
+ *
+ * Sets the expression that is evaluated to obtain numbers from items.
+ *
+ * The expression must have a type that can be transformed to G_TYPE_INT64,
+ * G_TYPE_UINT64 or G_TYPE_DOUBLE.
+ */
+void
+gtk_numeric_sorter_set_expression (GtkNumericSorter *self,
+                                  GtkExpression   *expression)
+{
+  g_return_if_fail (GTK_IS_NUMERIC_SORTER (self));
+  g_return_if_fail (expression == NULL ||
+                    g_value_type_transformable (gtk_expression_get_value_type (expression), G_TYPE_INT64) ||
+                    g_value_type_transformable (gtk_expression_get_value_type (expression), G_TYPE_UINT64) ||
+                    g_value_type_transformable (gtk_expression_get_value_type (expression), G_TYPE_DOUBLE));
+
+  if (self->expression == expression)
+    return;
+
+  g_clear_pointer (&self->expression, gtk_expression_unref);
+  self->expression = gtk_expression_ref (expression);
+
+  if (g_value_type_transformable (gtk_expression_get_value_type (expression), G_TYPE_INT64))
+    self->target_type = G_TYPE_INT64;
+  else if (g_value_type_transformable (gtk_expression_get_value_type (expression), G_TYPE_UINT64))
+    self->target_type = G_TYPE_UINT64;
+  else 
+    self->target_type = G_TYPE_DOUBLE;
+
+  gtk_sorter_changed (GTK_SORTER (self), GTK_SORTER_CHANGE_DIFFERENT);
+
+  g_object_notify_by_pspec (G_OBJECT (self), properties[PROP_EXPRESSION]);
+}
+
+/**
+ * gtk_numeric_sorter_set_sort_increasing:
+ * @self: a #GtkNumericSorter
+ * @sort_increasing: whether to sort smaller numbers first
+ *
+ * Sets whether to sort smaller numbers before larger ones.
+ */
+void
+gtk_numeric_sorter_set_sort_increasing (GtkNumericSorter *self,
+                                        gboolean          sort_increasing)
+{
+  g_return_if_fail (GTK_IS_NUMERIC_SORTER (self));
+
+  if (self->sort_increasing == sort_increasing)
+    return;
+
+  self->sort_increasing = sort_increasing;
+
+  gtk_sorter_changed (GTK_SORTER (self), GTK_SORTER_CHANGE_INVERTED);
+
+  g_object_notify_by_pspec (G_OBJECT (self), properties[PROP_SORT_INCREASING]);
+}
+
+/**
+ * gtk_numeric_sorter_get_sort_increasing:
+ * @self: a #GtkNumericSorter
+ *
+ * Gets whether this sorter will sort smaller numbers first.
+ *
+ * Returns: %TRUE if smaller numbers are sorted first
+ */
+gboolean
+gtk_numeric_sorter_get_sort_increasing (GtkNumericSorter *self)
+{
+  g_return_val_if_fail (GTK_IS_NUMERIC_SORTER (self), TRUE);
+
+  return self->sort_increasing;
+}
diff --git a/gtk/gtknumericsorter.h b/gtk/gtknumericsorter.h
new file mode 100644
index 0000000000..9668c32ffc
--- /dev/null
+++ b/gtk/gtknumericsorter.h
@@ -0,0 +1,53 @@
+/*
+ * Copyright © 2019 Matthias Clasen
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library. If not, see <http://www.gnu.org/licenses/>.
+ *
+ * Authors: Matthias Clasen <mclasen redhat com>
+ */
+
+#ifndef __GTK_NUMERIC_SORTER_H__
+#define __GTK_NUMERIC_SORTER_H__
+
+#if !defined (__GTK_H_INSIDE__) && !defined (GTK_COMPILATION)
+#error "Only <gtk/gtk.h> can be included directly."
+#endif
+
+#include <gtk/gtkexpression.h>
+#include <gtk/gtksorter.h>
+
+G_BEGIN_DECLS
+
+#define GTK_TYPE_NUMERIC_SORTER             (gtk_numeric_sorter_get_type ())
+GDK_AVAILABLE_IN_ALL
+G_DECLARE_FINAL_TYPE (GtkNumericSorter, gtk_numeric_sorter, GTK, NUMERIC_SORTER, GtkSorter)
+
+GDK_AVAILABLE_IN_ALL
+GtkSorter *             gtk_numeric_sorter_new                   (void);
+
+GDK_AVAILABLE_IN_ALL
+GtkExpression *         gtk_numeric_sorter_get_expression        (GtkNumericSorter       *self);
+GDK_AVAILABLE_IN_ALL
+void                    gtk_numeric_sorter_set_expression        (GtkNumericSorter       *self,
+                                                                  GtkExpression          *expression);
+
+GDK_AVAILABLE_IN_ALL
+gboolean                gtk_numeric_sorter_get_sort_increasing   (GtkNumericSorter       *self);
+GDK_AVAILABLE_IN_ALL
+void                    gtk_numeric_sorter_set_sort_increasing   (GtkNumericSorter       *self,
+                                                                  gboolean                sort_increasing);
+
+G_END_DECLS
+
+#endif /* __GTK_NUMERIC_SORTER_H__ */
diff --git a/gtk/meson.build b/gtk/meson.build
index 7235fd4e43..6b26237e4a 100644
--- a/gtk/meson.build
+++ b/gtk/meson.build
@@ -321,6 +321,7 @@ gtk_public_sources = files([
   'gtknomediafile.c',
   'gtknoselection.c',
   'gtknotebook.c',
+  'gtknumericsorter.c',
   'gtkorientable.c',
   'gtkoverlay.c',
   'gtkoverlaylayout.c',
@@ -601,6 +602,7 @@ gtk_public_headers = files([
   'gtknativedialog.h',
   'gtknoselection.h',
   'gtknotebook.h',
+  'gtknumericsorter.h',
   'gtkorientable.h',
   'gtkoverlay.h',
   'gtkpadcontroller.h',


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