[gtk/emoji-grid: 134/136] Add an emoji list
- From: Matthias Clasen <matthiasc src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [gtk/emoji-grid: 134/136] Add an emoji list
- Date: Sat, 26 Feb 2022 23:56:17 +0000 (UTC)
commit 36faf9257d46ae2e93c379daa872685cacebc28b
Author: Matthias Clasen <mclasen redhat com>
Date: Fri Feb 25 14:15:00 2022 -0500
Add an emoji list
Add a list model that contains Emoji, grouped
into sections.
gtk/gtk.h | 1 +
gtk/gtkemojilist.c | 385 +++++++++++++++++++++++++++++++++++++++++++++++++++++
gtk/gtkemojilist.h | 81 +++++++++++
gtk/meson.build | 2 +
4 files changed, 469 insertions(+)
---
diff --git a/gtk/gtk.h b/gtk/gtk.h
index 8afb5b6195..f07a4cdd6d 100644
--- a/gtk/gtk.h
+++ b/gtk/gtk.h
@@ -104,6 +104,7 @@
#include <gtk/gtkeditable.h>
#include <gtk/gtkeditablelabel.h>
#include <gtk/gtkemojichooser.h>
+#include <gtk/gtkemojilist.h>
#include <gtk/gtkentry.h>
#include <gtk/gtkentrybuffer.h>
#include <gtk/gtkentrycompletion.h>
diff --git a/gtk/gtkemojilist.c b/gtk/gtkemojilist.c
new file mode 100644
index 0000000000..637bbd7fa8
--- /dev/null
+++ b/gtk/gtkemojilist.c
@@ -0,0 +1,385 @@
+/*
+ * Copyright © 2022 Red Hat, Inc.
+ *
+ * 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 "gtkemojilist.h"
+
+#include "gtkintl.h"
+#include "gtkprivate.h"
+#include "gtktypebuiltins.h"
+#include "gtksectionmodel.h"
+
+#define GDK_ARRAY_ELEMENT_TYPE GtkEmojiObject *
+#define GDK_ARRAY_NAME objects
+#define GDK_ARRAY_TYPE_NAME Objects
+#define GDK_ARRAY_FREE_FUNC g_object_unref
+#include "gdk/gdkarrayimpl.c"
+
+struct _GtkEmojiObject
+{
+ GObject parent_instance;
+ GVariant *data;
+};
+
+enum {
+ PROP_NAME = 1,
+ PROP_GROUP,
+ PROP_NUM_PROPERTIES
+};
+
+G_DEFINE_TYPE (GtkEmojiObject, gtk_emoji_object, G_TYPE_OBJECT);
+
+static void
+gtk_emoji_object_init (GtkEmojiObject *object)
+{
+}
+
+static void
+gtk_emoji_object_finalize (GObject *object)
+{
+ GtkEmojiObject *self = GTK_EMOJI_OBJECT (object);
+
+ g_variant_unref (self->data);
+
+ G_OBJECT_CLASS (gtk_emoji_object_parent_class)->finalize (object);
+}
+
+static void
+gtk_emoji_object_get_property (GObject *object,
+ guint property_id,
+ GValue *value,
+ GParamSpec *pspec)
+{
+ GtkEmojiObject *self = GTK_EMOJI_OBJECT (object);
+
+ switch (property_id)
+ {
+ case PROP_NAME:
+ g_value_set_string (value, gtk_emoji_object_get_name (self));
+ break;
+
+ case PROP_GROUP:
+ g_value_set_enum (value, gtk_emoji_object_get_group (self));
+ break;
+
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
+ break;
+ }
+}
+
+static void
+gtk_emoji_object_class_init (GtkEmojiObjectClass *class)
+{
+ GObjectClass *object_class = G_OBJECT_CLASS (class);
+ GParamSpec *pspec;
+
+ object_class->finalize = gtk_emoji_object_finalize;
+ object_class->get_property = gtk_emoji_object_get_property;
+
+ /**
+ * GtkEmojiObject:name: (attributes org.gtk.Property.get=gtk_emoji_object_get_name)
+ *
+ * The name.
+ */
+ pspec = g_param_spec_string ("name", "Name", "Name",
+ NULL,
+ G_PARAM_READABLE | G_PARAM_STATIC_STRINGS);
+
+ g_object_class_install_property (object_class, PROP_NAME, pspec);
+
+ pspec = g_param_spec_enum ("group", "Group", "Group",
+ GTK_TYPE_EMOJI_GROUP, GTK_EMOJI_GROUP_SMILEYS,
+ G_PARAM_READABLE | G_PARAM_STATIC_STRINGS);
+
+ g_object_class_install_property (object_class, PROP_GROUP, pspec);
+
+}
+
+static GtkEmojiObject *
+gtk_emoji_object_new (GVariant *data)
+{
+ GtkEmojiObject *obj;
+
+ obj = g_object_new (GTK_TYPE_EMOJI_OBJECT, NULL);
+ obj->data = g_variant_ref (data);
+
+ return obj;
+}
+
+/**
+ * gtk_emoji_object_get_emoji: (attributes org.gtk.Method.get_property=emoji)
+ * @self: a `GtkEmojiObject`
+ *
+ * Returns the emoji contained in a `GtkEmojiObject`.
+ *
+ * Returns: the emoji of @self
+ */
+void
+gtk_emoji_object_get_text (GtkEmojiObject *self,
+ char *buffer,
+ int length,
+ gunichar modifier)
+{
+ g_return_if_fail (GTK_IS_EMOJI_OBJECT (self));
+ GVariant *codes;
+ char *p = buffer;
+
+ codes = g_variant_get_child_value (self->data, 0);
+ for (int i = 0; i < g_variant_n_children (codes); i++)
+ {
+ gunichar code;
+
+ g_variant_get_child (codes, i, "u", &code);
+ if (code == 0)
+ code = modifier;
+ if (code != 0)
+ p += g_unichar_to_utf8 (code, p);
+ }
+ g_variant_unref (codes);
+ p += g_unichar_to_utf8 (0xFE0F, p); /* U+FE0F is the Emoji variation selector */
+ p[0] = 0;
+}
+
+GtkEmojiGroup
+gtk_emoji_object_get_group (GtkEmojiObject *self)
+{
+ GtkEmojiGroup group;
+
+ g_return_val_if_fail (GTK_IS_EMOJI_OBJECT (self), GTK_EMOJI_GROUP_SMILEYS);
+
+ g_variant_get_child (self->data, 3, "u", &group);
+
+ return group;
+}
+
+const char *
+gtk_emoji_object_get_name (GtkEmojiObject *self)
+{
+ const char *name;
+
+ g_return_val_if_fail (GTK_IS_EMOJI_OBJECT (self), NULL);
+
+ g_variant_get_child (self->data, 1, "s", &name);
+
+ return name;
+}
+
+const char **
+gtk_emoji_object_get_keywords (GtkEmojiObject *self)
+{
+ const char **keywords;
+
+ g_return_val_if_fail (GTK_IS_EMOJI_OBJECT (self), NULL);
+
+ g_variant_get_child (self->data, 2, "^a&s", &keywords);
+
+ return keywords;
+}
+
+struct _GtkEmojiList
+{
+ GObject parent_instance;
+
+ GVariant *data;
+ Objects items;
+
+ int section[GTK_EMOJI_GROUP_FLAGS];
+};
+
+struct _GtkEmojiListClass
+{
+ GObjectClass parent_class;
+};
+
+static GType
+gtk_emoji_list_get_item_type (GListModel *list)
+{
+ return G_TYPE_OBJECT;
+}
+
+static guint
+gtk_emoji_list_get_n_items (GListModel *list)
+{
+ GtkEmojiList *self = GTK_EMOJI_LIST (list);
+
+ return objects_get_size (&self->items);
+}
+
+static gpointer
+gtk_emoji_list_get_item (GListModel *list,
+ guint position)
+{
+ GtkEmojiList *self = GTK_EMOJI_LIST (list);
+
+ if (position >= objects_get_size (&self->items))
+ return NULL;
+
+ return g_object_ref (objects_get (&self->items, position));
+}
+
+static void
+gtk_emoji_list_model_init (GListModelInterface *iface)
+{
+ iface->get_item_type = gtk_emoji_list_get_item_type;
+ iface->get_n_items = gtk_emoji_list_get_n_items;
+ iface->get_item = gtk_emoji_list_get_item;
+}
+
+static void
+gtk_emoji_list_get_section (GtkSectionModel *model,
+ guint position,
+ guint *out_start,
+ guint *out_end)
+{
+ GtkEmojiList *self = GTK_EMOJI_LIST (model);
+ GtkEmojiObject *obj;
+ GtkEmojiGroup group;
+
+ if (objects_get_size (&self->items) <= position)
+ {
+ *out_start = objects_get_size (&self->items);
+ *out_end = G_MAXUINT;
+ return;
+ }
+
+ obj = objects_get (&self->items, position);
+ group = gtk_emoji_object_get_group (obj);
+
+ *out_end = self->section[group];
+ if (group > 0)
+ *out_start = self->section[group - 1];
+ else
+ *out_start = 0;
+
+ g_assert (*out_start <= position);
+ g_assert (position <= *out_end);
+}
+
+static void
+gtk_emoji_list_section_model_init (GtkSectionModelInterface *iface)
+{
+ iface->get_section = gtk_emoji_list_get_section;
+}
+
+G_DEFINE_TYPE_WITH_CODE (GtkEmojiList, gtk_emoji_list, G_TYPE_OBJECT,
+ G_IMPLEMENT_INTERFACE (G_TYPE_LIST_MODEL,
+ gtk_emoji_list_model_init)
+ G_IMPLEMENT_INTERFACE (GTK_TYPE_SECTION_MODEL,
+ gtk_emoji_list_section_model_init))
+
+
+static void
+gtk_emoji_list_dispose (GObject *object)
+{
+ GtkEmojiList *self = GTK_EMOJI_LIST (object);
+
+ objects_clear (&self->items);
+ g_variant_unref (self->data);
+
+ G_OBJECT_CLASS (gtk_emoji_list_parent_class)->dispose (object);
+}
+
+static void
+gtk_emoji_list_class_init (GtkEmojiListClass *class)
+{
+ GObjectClass *gobject_class = G_OBJECT_CLASS (class);
+
+ gobject_class->dispose = gtk_emoji_list_dispose;
+}
+
+static void
+gtk_emoji_list_init (GtkEmojiList *self)
+{
+ objects_init (&self->items);
+}
+
+static void
+gtk_emoji_list_populate (GtkEmojiList *self)
+{
+ GBytes *bytes;
+ GVariantIter *iter;
+ GVariant *item;
+ int pos = 0;
+
+ bytes = get_emoji_data ();
+ self->data = g_variant_ref_sink (g_variant_new_from_bytes (G_VARIANT_TYPE ("a(ausasu)"), bytes, TRUE));
+ g_bytes_unref (bytes);
+
+ iter = g_variant_iter_new (self->data);
+ while ((item = g_variant_iter_next_value (iter)))
+ {
+ GtkEmojiObject *emoji = gtk_emoji_object_new (item);
+ GtkEmojiGroup group;
+
+ pos++;
+
+ group = gtk_emoji_object_get_group (emoji);
+ self->section[group] = MAX (self->section[group], pos);
+
+ objects_append (&self->items, emoji);
+ g_variant_unref (item);
+ }
+}
+
+/**
+ * gtk_emoji_list_new:
+ *
+ * Creates a new `GtkEmojiList` with the given @emojis.
+ *
+ * Returns: a new `GtkEmojiList`
+ */
+GtkEmojiList *
+gtk_emoji_list_new (void)
+{
+ GtkEmojiList *self;
+
+ self = g_object_new (GTK_TYPE_EMOJI_LIST, NULL);
+
+ gtk_emoji_list_populate (self);
+
+ return self;
+}
+
+/**
+ * gtk_emoji_list_get_emoji:
+ * @self: a `GtkEmojiList`
+ * @position: the position to get the emoji for
+ *
+ * Gets the emoji that is at @position in @self.
+ *
+ * If @self does not contain @position items, %NULL is returned.
+ *
+ * This function returns the const char *. To get the
+ * object wrapping it, use g_list_model_get_item().
+ *
+ * Returns: (nullable): the emoji at the given position
+ */
+GtkEmojiObject *
+gtk_emoji_list_get_emoji (GtkEmojiList *self,
+ guint position)
+{
+ g_return_val_if_fail (GTK_IS_EMOJI_LIST (self), NULL);
+
+ if (position >= objects_get_size (&self->items))
+ return NULL;
+
+ return objects_get (&self->items, position);
+}
diff --git a/gtk/gtkemojilist.h b/gtk/gtkemojilist.h
new file mode 100644
index 0000000000..7d131c04e7
--- /dev/null
+++ b/gtk/gtkemojilist.h
@@ -0,0 +1,81 @@
+/*
+ * Copyright © 2022 Red Hat, Inc.
+ *
+ * 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_EMOJI_LIST_H__
+#define __GTK_EMOJI_LIST_H__
+
+
+#if !defined (__GTK_H_INSIDE__) && !defined (GTK_COMPILATION)
+#error "Only <gtk/gtk.h> can be included directly."
+#endif
+
+#include <gio/gio.h>
+/* for GDK_AVAILABLE_IN_ALL */
+#include <gdk/gdk.h>
+
+
+G_BEGIN_DECLS
+
+#define GTK_TYPE_EMOJI_OBJECT (gtk_emoji_object_get_type ())
+GDK_AVAILABLE_IN_ALL
+G_DECLARE_FINAL_TYPE (GtkEmojiObject, gtk_emoji_object, GTK, EMOJI_OBJECT, GObject)
+
+GDK_AVAILABLE_IN_ALL
+void gtk_emoji_object_get_text (GtkEmojiObject *self,
+ char *buffer,
+ int length,
+ gunichar modifier);
+
+typedef enum {
+ GTK_EMOJI_GROUP_SMILEYS,
+ GTK_EMOJI_GROUP_BODY,
+ GTK_EMOJI_GROUP_COMPONENT,
+ GTK_EMOJI_GROUP_NATURE,
+ GTK_EMOJI_GROUP_FOOD,
+ GTK_EMOJI_GROUP_PLACES,
+ GTK_EMOJI_GROUP_ACTIVITIES,
+ GTK_EMOJI_GROUP_OBJECTS,
+ GTK_EMOJI_GROUP_SYMBOLS,
+ GTK_EMOJI_GROUP_FLAGS
+} GtkEmojiGroup;
+
+GDK_AVAILABLE_IN_ALL
+GtkEmojiGroup gtk_emoji_object_get_group (GtkEmojiObject *self);
+
+GDK_AVAILABLE_IN_ALL
+const char * gtk_emoji_object_get_name (GtkEmojiObject *self);
+
+GDK_AVAILABLE_IN_ALL
+const char ** gtk_emoji_object_get_keywords (GtkEmojiObject *self);
+
+#define GTK_TYPE_EMOJI_LIST (gtk_emoji_list_get_type ())
+
+GDK_AVAILABLE_IN_ALL
+G_DECLARE_FINAL_TYPE (GtkEmojiList, gtk_emoji_list, GTK, EMOJI_LIST, GObject)
+
+GDK_AVAILABLE_IN_ALL
+GtkEmojiList * gtk_emoji_list_new (void);
+
+GDK_AVAILABLE_IN_ALL
+GtkEmojiObject *gtk_emoji_list_get_emoji (GtkEmojiList *self,
+ guint position);
+
+G_END_DECLS
+
+#endif /* __GTK_EMOJI_LIST_H__ */
diff --git a/gtk/meson.build b/gtk/meson.build
index 7879f4839a..a5b8a61cef 100644
--- a/gtk/meson.build
+++ b/gtk/meson.build
@@ -14,6 +14,7 @@ gtk_cargs = [
# List of sources that do not contain public API, and should not be
# introspected
gtk_private_sources = files([
+ 'gtkemojilist.c',
'fnmatch.c',
'gdkpixbufutils.c',
'gsettings-mapping.c',
@@ -520,6 +521,7 @@ gtk_public_headers = files([
'gtkeditable.h',
'gtkeditablelabel.h',
'gtkemojichooser.h',
+ 'gtkemojilist.h',
'gtkentry.h',
'gtkentrybuffer.h',
'gtkentrycompletion.h',
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]