[gtk/wip/otte/listview: 17/158] Add GtkNumericSorter
- From: Benjamin Otte <otte src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [gtk/wip/otte/listview: 17/158] Add GtkNumericSorter
- Date: Tue, 4 Feb 2020 22:21:54 +0000 (UTC)
commit 2ad847f2e68c82d11bbcc6e856d854c36e523036
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 | 420 +++++++++++++++++++++++++++++++++++
gtk/gtknumericsorter.h | 53 +++++
gtk/meson.build | 2 +
7 files changed, 497 insertions(+)
---
diff --git a/docs/reference/gtk/gtk4-docs.xml b/docs/reference/gtk/gtk4-docs.xml
index ab30f17937..5b8bff4db2 100644
--- a/docs/reference/gtk/gtk4-docs.xml
+++ b/docs/reference/gtk/gtk4-docs.xml
@@ -60,6 +60,7 @@
<xi:include href="xml/gtksorter.xml" />
<xi:include href="xml/gtkcustomsorter.xml" />
<xi:include href="xml/gtkstringsorter.xml" />
+ <xi:include href="xml/gtknumericsorter.xml" />
<xi:include href="xml/gtkmultisorter.xml" />
</section>
<xi:include href="xml/gtkselectionmodel.xml" />
diff --git a/docs/reference/gtk/gtk4-sections.txt b/docs/reference/gtk/gtk4-sections.txt
index d5d66a3c53..1c9d23ea1a 100644
--- a/docs/reference/gtk/gtk4-sections.txt
+++ b/docs/reference/gtk/gtk4-sections.txt
@@ -2597,6 +2597,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_order
+gtk_numeric_sorter_set_sort_order
+<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 81e5dd9373..cbbd789e1a 100644
--- a/docs/reference/gtk/gtk4.types.in
+++ b/docs/reference/gtk/gtk4.types.in
@@ -137,6 +137,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 2eee2c826a..e4750080b9 100644
--- a/gtk/gtk.h
+++ b/gtk/gtk.h
@@ -170,6 +170,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..253fd201d7
--- /dev/null
+++ b/gtk/gtknumericsorter.c
@@ -0,0 +1,420 @@
+/*
+ * 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"
+
+#include <math.h>
+#include "fallback-c89.c"
+
+/**
+ * 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;
+
+ GtkSortType sort_order;
+
+ GtkExpression *expression;
+};
+
+enum {
+ PROP_0,
+ PROP_EXPRESSION,
+ PROP_SORT_ORDER,
+ NUM_PROPERTIES
+};
+
+G_DEFINE_TYPE (GtkNumericSorter, gtk_numeric_sorter, GTK_TYPE_SORTER)
+
+static GParamSpec *properties[NUM_PROPERTIES] = { NULL, };
+
+#define DO_COMPARISON(_result, _type, _getter, _order) G_STMT_START{ \
+ _type num1 = _getter (&value1); \
+ _type num2 = _getter (&value2); \
+\
+ if (num1 < num2) \
+ _result = _order == GTK_SORT_ASCENDING ? GTK_ORDERING_SMALLER : GTK_ORDERING_LARGER; \
+ else if (num1 > num2) \
+ _result = _order == GTK_SORT_ASCENDING ? GTK_ORDERING_LARGER : GTK_ORDERING_SMALLER; \
+ else \
+ _result = GTK_ORDERING_EQUAL; \
+}G_STMT_END
+
+static GtkOrdering
+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;
+ gboolean res1, res2;
+ GtkOrdering result;
+
+ if (self->expression == NULL)
+ return GTK_ORDERING_EQUAL;
+
+ res1 = gtk_expression_evaluate (self->expression, item1, &value1);
+ res2 = gtk_expression_evaluate (self->expression, item2, &value2);
+
+ /* If items don't evaluate, order them at the end, so they aren't
+ * in the way. */
+ if (!res1)
+ {
+ result = res2 ? GTK_ORDERING_LARGER : GTK_ORDERING_EQUAL;
+ goto out;
+ }
+ else if (!res2)
+ {
+ result = GTK_ORDERING_SMALLER;
+ goto out;
+ }
+
+ switch (g_type_fundamental (G_VALUE_TYPE (&value1)))
+ {
+ case G_TYPE_BOOLEAN:
+ DO_COMPARISON (result, gboolean, g_value_get_boolean, self->sort_order);
+ break;
+
+ case G_TYPE_CHAR:
+ DO_COMPARISON (result, char, g_value_get_char, self->sort_order);
+ break;
+
+ case G_TYPE_UCHAR:
+ DO_COMPARISON (result, guchar, g_value_get_uchar, self->sort_order);
+ break;
+
+ case G_TYPE_INT:
+ DO_COMPARISON (result, int, g_value_get_int, self->sort_order);
+ break;
+
+ case G_TYPE_UINT:
+ DO_COMPARISON (result, guint, g_value_get_uint, self->sort_order);
+ break;
+
+ case G_TYPE_FLOAT:
+ {
+ float num1 = g_value_get_float (&value1);
+ float num2 = g_value_get_float (&value2);
+
+ if (isnanf (num1) && isnanf (num2))
+ result = GTK_ORDERING_EQUAL;
+ else if (isnanf (num1))
+ result = self->sort_order == GTK_SORT_ASCENDING ? GTK_ORDERING_LARGER : GTK_ORDERING_SMALLER;
+ else if (isnanf (num2))
+ result = self->sort_order == GTK_SORT_ASCENDING ? GTK_ORDERING_SMALLER : GTK_ORDERING_LARGER;
+ else if (num1 < num2)
+ result = self->sort_order == GTK_SORT_ASCENDING ? GTK_ORDERING_SMALLER : GTK_ORDERING_LARGER;
+ else if (num1 > num2)
+ result = self->sort_order == GTK_SORT_ASCENDING ? GTK_ORDERING_LARGER : GTK_ORDERING_SMALLER;
+ else
+ result = GTK_ORDERING_EQUAL;
+ break;
+ }
+
+ case G_TYPE_DOUBLE:
+ {
+ double num1 = g_value_get_double (&value1);
+ double num2 = g_value_get_double (&value2);
+
+ if (isnan (num1) && isnan (num2))
+ result = GTK_ORDERING_EQUAL;
+ else if (isnan (num1))
+ result = self->sort_order == GTK_SORT_ASCENDING ? GTK_ORDERING_LARGER : GTK_ORDERING_SMALLER;
+ else if (isnan (num2))
+ result = self->sort_order == GTK_SORT_ASCENDING ? GTK_ORDERING_SMALLER : GTK_ORDERING_LARGER;
+ else if (num1 < num2)
+ result = self->sort_order == GTK_SORT_ASCENDING ? GTK_ORDERING_SMALLER : GTK_ORDERING_LARGER;
+ else if (num1 > num2)
+ result = self->sort_order == GTK_SORT_ASCENDING ? GTK_ORDERING_LARGER : GTK_ORDERING_SMALLER;
+ else
+ result = GTK_ORDERING_EQUAL;
+ break;
+ }
+
+ case G_TYPE_LONG:
+ DO_COMPARISON (result, long, g_value_get_long, self->sort_order);
+ break;
+
+ case G_TYPE_ULONG:
+ DO_COMPARISON (result, gulong, g_value_get_ulong, self->sort_order);
+ break;
+
+ case G_TYPE_INT64:
+ DO_COMPARISON (result, gint64, g_value_get_int64, self->sort_order);
+ break;
+
+ case G_TYPE_UINT64:
+ DO_COMPARISON (result, guint64, g_value_get_uint64, self->sort_order);
+ break;
+
+ default:
+ g_critical ("Invalid value type %s for expression\n", g_type_name (gtk_expression_get_value_type
(self->expression)));
+ result = GTK_ORDERING_EQUAL;
+ break;
+ }
+
+out:
+ g_value_unset (&value1);
+ g_value_unset (&value2);
+
+ return result;
+}
+
+static GtkSorterOrder
+gtk_numeric_sorter_get_order (GtkSorter *sorter)
+{
+ GtkNumericSorter *self = GTK_NUMERIC_SORTER (sorter);
+
+ if (self->expression == NULL)
+ return GTK_SORTER_ORDER_NONE;
+
+ return GTK_SORTER_ORDER_PARTIAL;
+}
+
+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_ORDER:
+ gtk_numeric_sorter_set_sort_order (self, g_value_get_enum (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_ORDER:
+ g_value_set_enum (value, self->sort_order);
+ 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;
+ sorter_class->get_order = gtk_numeric_sorter_get_order;
+
+ 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 items to get a number 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-order:
+ *
+ * Whether the sorter will sort smaller numbers first
+ */
+ properties[PROP_SORT_ORDER] =
+ g_param_spec_enum ("sort-order",
+ P_("Sort order"),
+ P_("Whether to sort smaller numbers first"),
+ GTK_TYPE_SORT_TYPE,
+ GTK_SORT_ASCENDING,
+ 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_order = GTK_SORT_ASCENDING;
+}
+
+/**
+ * gtk_numeric_sorter_new:
+ * @expression: (transfer full) (nullable): The expression to evaluate
+ *
+ * Creates a new numeric sorter using the given @expression.
+ *
+ * Smaller numbers will be sorted first. You can call
+ * gtk_numeric_sorter_set_sort_order() to change this.
+ *
+ * Returns: a new #GtkSorter
+ */
+GtkSorter *
+gtk_numeric_sorter_new (GtkExpression *expression)
+{
+ GtkSorter *result;
+
+ result = g_object_new (GTK_TYPE_NUMERIC_SORTER,
+ "expression", expression,
+ NULL);
+
+ g_clear_pointer (&expression, gtk_expression_unref);
+
+ return result;
+}
+
+/**
+ * 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.
+ *
+ * Unless an expression is set on @self, the sorter will always
+ * compare items as invalid.
+ *
+ * The expression must have a return type that can be compared
+ * numerically, such as #G_TYPE_INT or #G_TYPE_DOUBLE.
+ */
+void
+gtk_numeric_sorter_set_expression (GtkNumericSorter *self,
+ GtkExpression *expression)
+{
+ g_return_if_fail (GTK_IS_NUMERIC_SORTER (self));
+
+ if (self->expression == expression)
+ return;
+
+ g_clear_pointer (&self->expression, gtk_expression_unref);
+ if (expression)
+ self->expression = gtk_expression_ref (expression);
+
+ 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_order:
+ * @self: a #GtkNumericSorter
+ * @sort_order: whether to sort smaller numbers first
+ *
+ * Sets whether to sort smaller numbers before larger ones.
+ */
+void
+gtk_numeric_sorter_set_sort_order (GtkNumericSorter *self,
+ GtkSortType sort_order)
+{
+ g_return_if_fail (GTK_IS_NUMERIC_SORTER (self));
+
+ if (self->sort_order == sort_order)
+ return;
+
+ self->sort_order = sort_order;
+
+ gtk_sorter_changed (GTK_SORTER (self), GTK_SORTER_CHANGE_INVERTED);
+
+ g_object_notify_by_pspec (G_OBJECT (self), properties[PROP_SORT_ORDER]);
+}
+
+/**
+ * gtk_numeric_sorter_get_sort_order:
+ * @self: a #GtkNumericSorter
+ *
+ * Gets whether this sorter will sort smaller numbers first.
+ *
+ * Returns: the order of the numbers
+ */
+GtkSortType
+gtk_numeric_sorter_get_sort_order (GtkNumericSorter *self)
+{
+ g_return_val_if_fail (GTK_IS_NUMERIC_SORTER (self), GTK_SORT_ASCENDING);
+
+ return self->sort_order;
+}
diff --git a/gtk/gtknumericsorter.h b/gtk/gtknumericsorter.h
new file mode 100644
index 0000000000..39bb48e212
--- /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 (GtkExpression *expression);
+
+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
+GtkSortType gtk_numeric_sorter_get_sort_order (GtkNumericSorter *self);
+GDK_AVAILABLE_IN_ALL
+void gtk_numeric_sorter_set_sort_order (GtkNumericSorter *self,
+ GtkSortType sort_order);
+
+G_END_DECLS
+
+#endif /* __GTK_NUMERIC_SORTER_H__ */
diff --git a/gtk/meson.build b/gtk/meson.build
index 234d0801a7..c616a13772 100644
--- a/gtk/meson.build
+++ b/gtk/meson.build
@@ -295,6 +295,7 @@ gtk_public_sources = files([
'gtknomediafile.c',
'gtknoselection.c',
'gtknotebook.c',
+ 'gtknumericsorter.c',
'gtkorientable.c',
'gtkoverlay.c',
'gtkoverlaylayout.c',
@@ -556,6 +557,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]