[gtk/wip/otte/listview] gtk-demo: Add a listview demo
- From: Matthias Clasen <matthiasc src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [gtk/wip/otte/listview] gtk-demo: Add a listview demo
- Date: Sun, 6 Jan 2019 02:14:50 +0000 (UTC)
commit dfd280acd0225181a80b884d9afd2ee00232da80
Author: Matthias Clasen <mclasen redhat com>
Date: Sat Jan 5 21:13:26 2019 -0500
gtk-demo: Add a listview demo
Duplicate the listbox demo with GtkListView,
and give both demos a "more messages" button,
to demonstrate scalability.
demos/gtk-demo/demo.gresource.xml | 6 +
demos/gtk-demo/listbox.c | 183 +++++++--------------
demos/gtk-demo/listview.c | 323 ++++++++++++++++++++++++++++++++++++++
demos/gtk-demo/listview.ui | 302 +++++++++++++++++++++++++++++++++++
demos/gtk-demo/meson.build | 3 +-
demos/gtk-demo/message.c | 79 ++++++++++
demos/gtk-demo/message.h | 34 ++++
7 files changed, 803 insertions(+), 127 deletions(-)
---
diff --git a/demos/gtk-demo/demo.gresource.xml b/demos/gtk-demo/demo.gresource.xml
index bbf603e1ad..4d47a5f626 100644
--- a/demos/gtk-demo/demo.gresource.xml
+++ b/demos/gtk-demo/demo.gresource.xml
@@ -179,6 +179,7 @@
<file>links.c</file>
<file>listbox.c</file>
<file>list_store.c</file>
+ <file>listview.c</file>
<file>markup.c</file>
<file>menus.c</file>
<file>modelbutton.c</file>
@@ -223,6 +224,11 @@
<file>messages.txt</file>
<file>apple-red.png</file>
</gresource>
+ <gresource prefix="/listview">
+ <file>listview.ui</file>
+ <file>messages.txt</file>
+ <file>apple-red.png</file>
+ </gresource>
<gresource prefix="/popover">
<file>popover.ui</file>
</gresource>
diff --git a/demos/gtk-demo/listbox.c b/demos/gtk-demo/listbox.c
index c1dc9ef6a7..e09bd097e2 100644
--- a/demos/gtk-demo/listbox.c
+++ b/demos/gtk-demo/listbox.c
@@ -9,16 +9,11 @@
#include <stdlib.h>
#include <string.h>
+#include "message.h"
+
static GdkPixbuf *avatar_pixbuf_other;
static GtkWidget *window = NULL;
-#define GTK_TYPE_MESSAGE (gtk_message_get_type ())
-#define GTK_MESSAGE(message) (G_TYPE_CHECK_INSTANCE_CAST ((message), GTK_TYPE_MESSAGE,
GtkMessage))
-#define GTK_MESSAGE_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), GTK_TYPE_MESSAGE,
GtkMessageClass))
-#define GTK_IS_MESSAGE(message) (G_TYPE_CHECK_INSTANCE_TYPE ((message), GTK_TYPE_MESSAGE))
-#define GTK_IS_MESSAGE_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), GTK_TYPE_MESSAGE))
-#define GTK_MESSAGE_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), GTK_TYPE_MESSAGE,
GtkMessageClass))
-
#define GTK_TYPE_MESSAGE_ROW (gtk_message_row_get_type ())
#define GTK_MESSAGE_ROW(message_row) (G_TYPE_CHECK_INSTANCE_CAST ((message_row),
GTK_TYPE_MESSAGE_ROW, GtkMessageRow))
#define GTK_MESSAGE_ROW_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), GTK_TYPE_MESSAGE_ROW,
GtkMessageRowClass))
@@ -26,33 +21,10 @@ static GtkWidget *window = NULL;
#define GTK_IS_MESSAGE_ROW_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), GTK_TYPE_MESSAGE_ROW))
#define GTK_MESSAGE_ROW_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), GTK_TYPE_MESSAGE_ROW,
GtkMessageRowClass))
-typedef struct _GtkMessage GtkMessage;
-typedef struct _GtkMessageClass GtkMessageClass;
typedef struct _GtkMessageRow GtkMessageRow;
typedef struct _GtkMessageRowClass GtkMessageRowClass;
typedef struct _GtkMessageRowPrivate GtkMessageRowPrivate;
-
-struct _GtkMessage
-{
- GObject parent;
-
- guint id;
- char *sender_name;
- char *sender_nick;
- char *message;
- gint64 time;
- guint reply_to;
- char *resent_by;
- int n_favorites;
- int n_reshares;
-};
-
-struct _GtkMessageClass
-{
- GObjectClass parent_class;
-};
-
struct _GtkMessageRow
{
GtkListBoxRow parent;
@@ -83,84 +55,10 @@ struct _GtkMessageRowPrivate
GtkButton *expand_button;
};
-GType gtk_message_get_type (void) G_GNUC_CONST;
GType gtk_message_row_get_type (void) G_GNUC_CONST;
-G_DEFINE_TYPE (GtkMessage, gtk_message, G_TYPE_OBJECT);
-
-static void
-gtk_message_finalize (GObject *obj)
-{
- GtkMessage *msg = GTK_MESSAGE (obj);
-
- g_free (msg->sender_name);
- g_free (msg->sender_nick);
- g_free (msg->message);
- g_free (msg->resent_by);
-
- G_OBJECT_CLASS (gtk_message_parent_class)->finalize (obj);
-}
-static void
-gtk_message_class_init (GtkMessageClass *klass)
-{
- GObjectClass *object_class = G_OBJECT_CLASS (klass);
- object_class->finalize = gtk_message_finalize;
-}
-
-static void
-gtk_message_init (GtkMessage *msg)
-{
-}
-
-static void
-gtk_message_parse (GtkMessage *msg, const char *str)
-{
- char **strv;
- int i;
-
- strv = g_strsplit (str, "|", 0);
-
- i = 0;
- msg->id = strtol (strv[i++], NULL, 10);
- msg->sender_name = g_strdup (strv[i++]);
- msg->sender_nick = g_strdup (strv[i++]);
- msg->message = g_strdup (strv[i++]);
- msg->time = strtol (strv[i++], NULL, 10);
- if (strv[i])
- {
- msg->reply_to = strtol (strv[i++], NULL, 10);
- if (strv[i])
- {
- if (*strv[i])
- msg->resent_by = g_strdup (strv[i]);
- i++;
- if (strv[i])
- {
- msg->n_favorites = strtol (strv[i++], NULL, 10);
- if (strv[i])
- {
- msg->n_reshares = strtol (strv[i++], NULL, 10);
- }
-
- }
- }
- }
-
- g_strfreev (strv);
-}
-
-static GtkMessage *
-gtk_message_new (const char *str)
-{
- GtkMessage *msg;
- msg = g_object_new (gtk_message_get_type (), NULL);
- gtk_message_parse (msg, str);
- return msg;
-}
-
G_DEFINE_TYPE_WITH_PRIVATE (GtkMessageRow, gtk_message_row, GTK_TYPE_LIST_BOX_ROW);
-
static void
gtk_message_row_update (GtkMessageRow *row)
{
@@ -333,16 +231,49 @@ row_activated (GtkListBox *listbox, GtkListBoxRow *row)
gtk_message_row_expand (GTK_MESSAGE_ROW (row));
}
-GtkWidget *
-do_listbox (GtkWidget *do_widget)
+static void
+update_count (GtkListBox *listbox, GtkLabel *label)
+{
+ GList *children = gtk_container_get_children (GTK_CONTAINER (listbox));
+ guint n_items = g_list_length (children);
+ g_list_free (children);
+
+ char *text = g_strdup_printf ("%u rows", n_items);
+ gtk_label_set_label (label, text);
+ g_free (text);
+}
+
+static GtkWidget *header_label;
+
+static void
+add_more (GtkListBox *listbox)
{
- GtkWidget *scrolled, *listbox, *vbox, *label;
- GtkMessage *message;
- GtkMessageRow *row;
GBytes *data;
char **lines;
int i;
+ data = g_resources_lookup_data ("/listbox/messages.txt", 0, NULL);
+ lines = g_strsplit (g_bytes_get_data (data, NULL), "\n", 0);
+
+ for (i = 0; lines[i] != NULL && *lines[i]; i++)
+ {
+ GtkMessage *message = gtk_message_new (lines[i]);
+ GtkMessageRow *row = gtk_message_row_new (message);
+ gtk_container_add (GTK_CONTAINER (listbox), GTK_WIDGET (row));
+ }
+
+ g_strfreev (lines);
+ g_bytes_unref (data);
+
+ update_count (listbox, GTK_LABEL (header_label));
+}
+
+GtkWidget *
+do_listbox (GtkWidget *do_widget)
+{
+ GtkWidget *scrolled, *listbox, *vbox, *label;
+ GtkWidget *header, *more;
+
if (!window)
{
avatar_pixbuf_other = gdk_pixbuf_new_from_resource_at_scale ("/listbox/apple-red.png", 32, 32, FALSE,
NULL);
@@ -350,15 +281,27 @@ do_listbox (GtkWidget *do_widget)
window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
gtk_window_set_display (GTK_WINDOW (window),
gtk_widget_get_display (do_widget));
- gtk_window_set_title (GTK_WINDOW (window), "List Box");
- gtk_window_set_default_size (GTK_WINDOW (window),
- 400, 600);
+ gtk_window_set_default_size (GTK_WINDOW (window), 400, 600);
/* NULL window variable when window is closed */
g_signal_connect (window, "destroy",
G_CALLBACK (gtk_widget_destroyed),
&window);
+ listbox = gtk_list_box_new ();
+
+ header = gtk_header_bar_new ();
+ gtk_header_bar_set_show_title_buttons (GTK_HEADER_BAR (header), TRUE);
+ gtk_header_bar_set_title (GTK_HEADER_BAR (header), "List View");
+ header_label = gtk_label_new ("");
+ gtk_header_bar_pack_start (GTK_HEADER_BAR (header), header_label);
+ more = gtk_button_new_from_icon_name ("list-add");
+
+ g_signal_connect_swapped (more, "clicked", G_CALLBACK (add_more), listbox);
+
+ gtk_header_bar_pack_start (GTK_HEADER_BAR (header), more);
+ gtk_window_set_titlebar (GTK_WINDOW (window), header);
+
vbox = gtk_box_new (GTK_ORIENTATION_VERTICAL, 12);
gtk_container_add (GTK_CONTAINER (window), vbox);
label = gtk_label_new ("Messages from Gtk+ and friends");
@@ -367,26 +310,14 @@ do_listbox (GtkWidget *do_widget)
gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (scrolled), GTK_POLICY_NEVER,
GTK_POLICY_AUTOMATIC);
gtk_widget_set_vexpand (scrolled, TRUE);
gtk_box_pack_start (GTK_BOX (vbox), scrolled);
- listbox = gtk_list_box_new ();
gtk_container_add (GTK_CONTAINER (scrolled), listbox);
gtk_list_box_set_sort_func (GTK_LIST_BOX (listbox), (GtkListBoxSortFunc)gtk_message_row_sort, listbox,
NULL);
gtk_list_box_set_activate_on_single_click (GTK_LIST_BOX (listbox), FALSE);
g_signal_connect (listbox, "row-activated", G_CALLBACK (row_activated), NULL);
- data = g_resources_lookup_data ("/listbox/messages.txt", 0, NULL);
- lines = g_strsplit (g_bytes_get_data (data, NULL), "\n", 0);
-
- for (i = 0; lines[i] != NULL && *lines[i]; i++)
- {
- message = gtk_message_new (lines[i]);
- row = gtk_message_row_new (message);
- gtk_widget_show (GTK_WIDGET (row));
- gtk_container_add (GTK_CONTAINER (listbox), GTK_WIDGET (row));
- }
-
- g_strfreev (lines);
- g_bytes_unref (data);
+ add_more (listbox);
+ update_count (listbox, header_label);
}
if (!gtk_widget_get_visible (window))
diff --git a/demos/gtk-demo/listview.c b/demos/gtk-demo/listview.c
new file mode 100644
index 0000000000..900b04eb1b
--- /dev/null
+++ b/demos/gtk-demo/listview.c
@@ -0,0 +1,323 @@
+/* List View
+ *
+ * GtkListView allows lists with complicated layouts, using
+ * models to hold the data, and creating rows on demand.
+ */
+
+#include <gtk/gtk.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "message.h"
+
+static GdkPixbuf *avatar_pixbuf_other;
+static GtkWidget *window = NULL;
+
+#define GTK_TYPE_MSG_ROW (gtk_msg_row_get_type ())
+#define GTK_MSG_ROW(msg_row) (G_TYPE_CHECK_INSTANCE_CAST ((msg_row), GTK_TYPE_MSG_ROW,
GtkMsgRow))
+#define GTK_MSG_ROW_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), GTK_TYPE_MSG_ROW,
GtkMsgRowClass))
+#define GTK_IS_MSG_ROW(msg_row) (G_TYPE_CHECK_INSTANCE_TYPE ((msg_row), GTK_TYPE_MSG_ROW))
+#define GTK_IS_MSG_ROW_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), GTK_TYPE_MSG_ROW))
+#define GTK_MSG_ROW_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), GTK_TYPE_MSG_ROW,
GtkMsgRowClass))
+
+typedef struct _GtkMsgRow GtkMsgRow;
+typedef struct _GtkMsgRowClass GtkMsgRowClass;
+
+struct _GtkMsgRow
+{
+ GtkBin parent;
+
+ GtkMessage *message;
+ GtkRevealer *details_revealer;
+ GtkImage *avatar_image;
+ GtkWidget *extra_buttons_box;
+ GtkLabel *content_label;
+ GtkLabel *source_name;
+ GtkLabel *source_nick;
+ GtkLabel *short_time_label;
+ GtkLabel *detailed_time_label;
+ GtkBox *resent_box;
+ GtkLinkButton *resent_by_button;
+ GtkLabel *n_favorites_label;
+ GtkLabel *n_reshares_label;
+ GtkButton *expand_button;
+};
+
+struct _GtkMsgRowClass
+{
+ GtkBinClass parent_class;
+};
+
+static GType gtk_msg_row_get_type (void) G_GNUC_CONST;
+
+G_DEFINE_TYPE (GtkMsgRow, gtk_msg_row, GTK_TYPE_BIN);
+
+static void
+gtk_msg_row_update (GtkMsgRow *row)
+{
+ GDateTime *t;
+ char *s;
+
+ gtk_label_set_text (row->source_name, row->message->sender_name);
+ gtk_label_set_text (row->source_nick, row->message->sender_nick);
+ gtk_label_set_text (row->content_label, row->message->message);
+ t = g_date_time_new_from_unix_utc (row->message->time);
+ s = g_date_time_format (t, "%e %b %y");
+ gtk_label_set_text (row->short_time_label, s);
+ g_free (s);
+ s = g_date_time_format (t, "%X - %e %b %Y");
+ gtk_label_set_text (row->detailed_time_label, s);
+ g_free (s);
+ g_date_time_unref (t);
+
+ gtk_widget_set_visible (GTK_WIDGET(row->n_favorites_label),
+ row->message->n_favorites != 0);
+ s = g_strdup_printf ("<b>%d</b>\nFavorites", row->message->n_favorites);
+ gtk_label_set_markup (row->n_favorites_label, s);
+ g_free (s);
+
+ gtk_widget_set_visible (GTK_WIDGET(row->n_reshares_label),
+ row->message->n_reshares != 0);
+ s = g_strdup_printf ("<b>%d</b>\nReshares", row->message->n_reshares);
+ gtk_label_set_markup (row->n_reshares_label, s);
+ g_free (s);
+
+ gtk_widget_set_visible (GTK_WIDGET (row->resent_box), row->message->resent_by != NULL);
+ if (row->message->resent_by)
+ gtk_button_set_label (GTK_BUTTON (row->resent_by_button), row->message->resent_by);
+
+ if (strcmp (row->message->sender_nick, "@GTKtoolkit") == 0)
+ {
+ gtk_image_set_from_icon_name (row->avatar_image, "gtk3-demo");
+ gtk_image_set_icon_size (row->avatar_image, GTK_ICON_SIZE_LARGE);
+ }
+ else
+ gtk_image_set_from_pixbuf (row->avatar_image, avatar_pixbuf_other);
+
+}
+
+static void
+gtk_msg_row_expand (GtkMsgRow *row)
+{
+ gboolean expand;
+
+ expand = !gtk_revealer_get_reveal_child (row->details_revealer);
+
+ gtk_revealer_set_reveal_child (row->details_revealer, expand);
+ if (expand)
+ gtk_button_set_label (row->expand_button, "Hide");
+ else
+ gtk_button_set_label (row->expand_button, "Expand");
+}
+
+static void
+expand_clicked (GtkMsgRow *row,
+ GtkButton *button)
+{
+ gtk_msg_row_expand (row);
+}
+
+static void
+reshare_clicked (GtkMsgRow *row,
+ GtkButton *button)
+{
+ row->message->n_reshares++;
+ gtk_msg_row_update (row);
+
+}
+
+static void
+favorite_clicked (GtkMsgRow *row,
+ GtkButton *button)
+{
+ row->message->n_favorites++;
+ gtk_msg_row_update (row);
+}
+
+static void
+gtk_msg_row_state_flags_changed (GtkWidget *widget,
+ GtkStateFlags previous_state_flags)
+{
+ GtkMsgRow *row = GTK_MSG_ROW (widget);
+ GtkStateFlags flags;
+
+ flags = gtk_widget_get_state_flags (widget);
+
+ gtk_widget_set_visible (row->extra_buttons_box,
+ flags & (GTK_STATE_FLAG_PRELIGHT | GTK_STATE_FLAG_SELECTED));
+
+ GTK_WIDGET_CLASS (gtk_msg_row_parent_class)->state_flags_changed (widget, previous_state_flags);
+}
+
+static void
+gtk_msg_row_finalize (GObject *obj)
+{
+ G_OBJECT_CLASS (gtk_msg_row_parent_class)->finalize(obj);
+}
+
+static void
+gtk_msg_row_class_init (GtkMsgRowClass *klass)
+{
+ GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (klass);
+ GObjectClass *object_class = G_OBJECT_CLASS (klass);
+
+ object_class->finalize = gtk_msg_row_finalize;
+
+ gtk_widget_class_set_template_from_resource (widget_class, "/listview/listview.ui");
+ gtk_widget_class_bind_template_child (widget_class, GtkMsgRow, content_label);
+ gtk_widget_class_bind_template_child (widget_class, GtkMsgRow, source_name);
+ gtk_widget_class_bind_template_child (widget_class, GtkMsgRow, source_nick);
+ gtk_widget_class_bind_template_child (widget_class, GtkMsgRow, short_time_label);
+ gtk_widget_class_bind_template_child (widget_class, GtkMsgRow, detailed_time_label);
+ gtk_widget_class_bind_template_child (widget_class, GtkMsgRow, extra_buttons_box);
+ gtk_widget_class_bind_template_child (widget_class, GtkMsgRow, details_revealer);
+ gtk_widget_class_bind_template_child (widget_class, GtkMsgRow, avatar_image);
+ gtk_widget_class_bind_template_child (widget_class, GtkMsgRow, resent_box);
+ gtk_widget_class_bind_template_child (widget_class, GtkMsgRow, resent_by_button);
+ gtk_widget_class_bind_template_child (widget_class, GtkMsgRow, n_reshares_label);
+ gtk_widget_class_bind_template_child (widget_class, GtkMsgRow, n_favorites_label);
+ gtk_widget_class_bind_template_child (widget_class, GtkMsgRow, expand_button);
+ gtk_widget_class_bind_template_callback (widget_class, expand_clicked);
+ gtk_widget_class_bind_template_callback (widget_class, reshare_clicked);
+ gtk_widget_class_bind_template_callback (widget_class, favorite_clicked);
+
+ widget_class->state_flags_changed = gtk_msg_row_state_flags_changed;
+}
+
+static void
+row_activated (GtkGestureMultiPress *gesture,
+ int n_press,
+ double x,
+ double y,
+ GtkMsgRow *row)
+{
+ if (n_press == 2)
+ gtk_msg_row_expand (row);
+}
+
+static void
+gtk_msg_row_init (GtkMsgRow *row)
+{
+ GtkGesture *double_click;
+
+ gtk_widget_init_template (GTK_WIDGET (row));
+
+ double_click = gtk_gesture_multi_press_new ();
+ g_signal_connect (double_click, "pressed", G_CALLBACK (row_activated), row);
+ gtk_widget_add_controller (GTK_WIDGET (row), GTK_EVENT_CONTROLLER (double_click));
+}
+
+static int
+gtk_message_sort (gconstpointer a, gconstpointer b, gpointer data)
+{
+ return ((const GtkMessage *)b)->time - ((const GtkMessage *)a)->time;
+}
+
+static void
+bind_msg_row (GObject *list_item, GParamSpec *pspec, gpointer data)
+{
+ GtkMessage *message = (GtkMessage *)gtk_list_item_get_item (GTK_LIST_ITEM (list_item));
+ GtkMsgRow *row = (GtkMsgRow *) gtk_bin_get_child (GTK_BIN (list_item));
+
+ row->message = message;
+ if (message)
+ gtk_msg_row_update (row);
+}
+
+static void
+setup_row (GtkListItem *item,
+ gpointer data)
+{
+ g_signal_connect (item, "notify::item", G_CALLBACK (bind_msg_row), data);
+ gtk_container_add (GTK_CONTAINER (item), g_object_new (gtk_msg_row_get_type (), NULL));
+}
+
+static void
+update_count (GListModel *model, guint position, guint removed, guint added, GtkLabel *label)
+{
+ guint n_items = g_list_model_get_n_items (model);
+ char *text = g_strdup_printf ("%u rows", n_items);
+ gtk_label_set_label (label, text);
+ g_free (text);
+}
+
+static void
+add_more (GListModel *model)
+{
+ GBytes *data;
+ char **lines;
+ int i;
+
+ data = g_resources_lookup_data ("/listview/messages.txt", 0, NULL);
+ lines = g_strsplit (g_bytes_get_data (data, NULL), "\n", 0);
+
+ for (i = 0; lines[i] != NULL && *lines[i]; i++)
+ {
+ GtkMessage *message = gtk_message_new (lines[i]);
+ g_list_store_append (G_LIST_STORE (model), message);
+ }
+
+ g_strfreev (lines);
+ g_bytes_unref (data);
+}
+
+GtkWidget *
+do_listview (GtkWidget *do_widget)
+{
+ GtkWidget *scrolled, *listview, *vbox, *label;
+ GtkWidget *header, *header_label, *more;
+ GListModel *model;
+
+ if (!window)
+ {
+ avatar_pixbuf_other = gdk_pixbuf_new_from_resource_at_scale ("/listbox/apple-red.png", 32, 32, FALSE,
NULL);
+
+ model = G_LIST_MODEL (g_list_store_new (gtk_message_get_type ()));
+
+ window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
+ gtk_window_set_display (GTK_WINDOW (window),
+ gtk_widget_get_display (do_widget));
+ gtk_window_set_default_size (GTK_WINDOW (window), 400, 600);
+
+ /* NULL window variable when window is closed */
+ g_signal_connect (window, "destroy",
+ G_CALLBACK (gtk_widget_destroyed),
+ &window);
+
+ header = gtk_header_bar_new ();
+ gtk_header_bar_set_show_title_buttons (GTK_HEADER_BAR (header), TRUE);
+ gtk_header_bar_set_title (GTK_HEADER_BAR (header), "List View");
+ header_label = gtk_label_new ("");
+ gtk_header_bar_pack_start (GTK_HEADER_BAR (header), header_label);
+ more = gtk_button_new_from_icon_name ("list-add");
+
+ g_signal_connect_swapped (more, "clicked", G_CALLBACK (add_more), model);
+ g_signal_connect (model, "items-changed", G_CALLBACK (update_count), header_label);
+
+ gtk_header_bar_pack_start (GTK_HEADER_BAR (header), more);
+ gtk_window_set_titlebar (GTK_WINDOW (window), header);
+
+ vbox = gtk_box_new (GTK_ORIENTATION_VERTICAL, 12);
+ gtk_container_add (GTK_CONTAINER (window), vbox);
+ label = gtk_label_new ("Messages from Gtk+ and friends");
+ gtk_box_pack_start (GTK_BOX (vbox), label);
+ scrolled = gtk_scrolled_window_new (NULL, NULL);
+ gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (scrolled), GTK_POLICY_NEVER,
GTK_POLICY_AUTOMATIC);
+ gtk_widget_set_vexpand (scrolled, TRUE);
+ gtk_box_pack_start (GTK_BOX (vbox), scrolled);
+ listview = gtk_list_view_new ();
+ gtk_container_add (GTK_CONTAINER (scrolled), listview);
+
+ gtk_list_view_set_functions (GTK_LIST_VIEW (listview), setup_row, NULL, NULL, NULL);
+ gtk_list_view_set_model (GTK_LIST_VIEW (listview), G_LIST_MODEL (gtk_sort_list_model_new (model,
gtk_message_sort, NULL, NULL)));
+
+ add_more (model);
+ }
+
+ if (!gtk_widget_get_visible (window))
+ gtk_widget_show (window);
+ else
+ gtk_widget_destroy (window);
+
+ return window;
+}
diff --git a/demos/gtk-demo/listview.ui b/demos/gtk-demo/listview.ui
new file mode 100644
index 0000000000..08d836cf2b
--- /dev/null
+++ b/demos/gtk-demo/listview.ui
@@ -0,0 +1,302 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<interface domain="gtk40">
+ <!-- interface-requires gtk+ 3.10 -->
+ <!-- interface-requires gtkdemo 3.10 -->
+ <object class="GtkMenu" id="menu1">
+ <child>
+ <object class="GtkMenuItem" id="menuitem1">
+ <property name="label" translatable="yes">Email message</property>
+ <property name="use-underline">1</property>
+ </object>
+ </child>
+ <child>
+ <object class="GtkMenuItem" id="menuitem2">
+ <property name="label" translatable="yes">Embed message</property>
+ <property name="use-underline">1</property>
+ </object>
+ </child>
+ </object>
+ <template class="GtkMsgRow" parent="GtkBin">
+ <child>
+ <object class="GtkGrid" id="grid1">
+ <property name="hexpand">1</property>
+ <child>
+ <object class="GtkImage" id="avatar_image">
+ <property name="width-request">32</property>
+ <property name="height-request">32</property>
+ <property name="halign">center</property>
+ <property name="valign">start</property>
+ <property name="margin-top">8</property>
+ <property name="margin-bottom">8</property>
+ <property name="margin-start">8</property>
+ <property name="margin-end">8</property>
+ <property name="icon-name">image-missing</property>
+ </object>
+ <packing>
+ <property name="left-attach">0</property>
+ <property name="top-attach">0</property>
+ <property name="height">5</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkBox" id="box1">
+ <property name="hexpand">1</property>
+ <property name="baseline-position">top</property>
+ <child>
+ <object class="GtkButton" id="button2">
+ <property name="can-focus">1</property>
+ <property name="receives-default">1</property>
+ <property name="valign">baseline</property>
+ <property name="relief">none</property>
+ <child>
+ <object class="GtkLabel" id="source_name">
+ <property name="valign">baseline</property>
+ <property name="label" translatable="0">Username</property>
+ <attributes>
+ <attribute name="weight" value="bold"/>
+ </attributes>
+ </object>
+ </child>
+ </object>
+ </child>
+ <child>
+ <object class="GtkLabel" id="source_nick">
+ <property name="valign">baseline</property>
+ <property name="label" translatable="0">@nick</property>
+ <style>
+ <class name="dim-label"/>
+ </style>
+ </object>
+ <packing>
+ <property name="position">1</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkLabel" id="short_time_label">
+ <property name="valign">baseline</property>
+ <property name="label" translatable="yes">38m</property>
+ <style>
+ <class name="dim-label"/>
+ </style>
+ </object>
+ <packing>
+ <property name="pack-type">end</property>
+ <property name="position">2</property>
+ </packing>
+ </child>
+ </object>
+ <packing>
+ <property name="left-attach">1</property>
+ <property name="top-attach">0</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkLabel" id="content_label">
+ <property name="halign">start</property>
+ <property name="valign">start</property>
+ <property name="xalign">0</property>
+ <property name="yalign">0</property>
+ <property name="label" translatable="0">Message</property>
+ <property name="wrap">1</property>
+ <accessibility>
+ <role type="static"/>
+ </accessibility>
+ </object>
+ <packing>
+ <property name="left-attach">1</property>
+ <property name="top-attach">1</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkBox" id="resent_box">
+ <child>
+ <object class="GtkImage" id="image2">
+ <property name="icon-name">media-playlist-repeat</property>
+ </object>
+ </child>
+ <child>
+ <object class="GtkLabel" id="label4">
+ <property name="label" translatable="yes">Resent by</property>
+ </object>
+ <packing>
+ <property name="position">1</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkLinkButton" id="resent_by_button">
+ <property name="label" translatable="0">reshareer</property>
+ <property name="can-focus">1</property>
+ <property name="receives-default">1</property>
+ <property name="relief">none</property>
+ <property name="uri">http://www.gtk.org</property>
+ </object>
+ <packing>
+ <property name="position">2</property>
+ </packing>
+ </child>
+ </object>
+ <packing>
+ <property name="left-attach">1</property>
+ <property name="top-attach">2</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkBox" id="box3">
+ <property name="spacing">6</property>
+ <child>
+ <object class="GtkButton" id="expand_button">
+ <property name="label" translatable="yes">Expand</property>
+ <property name="can-focus">1</property>
+ <property name="receives-default">1</property>
+ <property name="relief">none</property>
+ <signal name="clicked" handler="expand_clicked" swapped="yes"/>
+ </object>
+ </child>
+ <child>
+ <object class="GtkBox" id="extra_buttons_box">
+ <property name="visible">0</property>
+ <property name="spacing">6</property>
+ <child>
+ <object class="GtkButton" id="reply-button">
+ <property name="label" translatable="yes">Reply</property>
+ <property name="can-focus">1</property>
+ <property name="receives-default">1</property>
+ <property name="relief">none</property>
+ </object>
+ </child>
+ <child>
+ <object class="GtkButton" id="reshare-button">
+ <property name="label" translatable="yes">Reshare</property>
+ <property name="can-focus">1</property>
+ <property name="receives-default">1</property>
+ <property name="relief">none</property>
+ <signal name="clicked" handler="reshare_clicked" swapped="yes"/>
+ </object>
+ <packing>
+ <property name="position">1</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkButton" id="favorite-buttton">
+ <property name="label" translatable="yes">Favorite</property>
+ <property name="can-focus">1</property>
+ <property name="receives-default">1</property>
+ <property name="relief">none</property>
+ <signal name="clicked" handler="favorite_clicked" swapped="yes"/>
+ </object>
+ <packing>
+ <property name="position">2</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkMenuButton" id="more-button">
+ <property name="can-focus">1</property>
+ <property name="receives-default">1</property>
+ <property name="relief">none</property>
+ <property name="popup">menu1</property>
+ <child>
+ <object class="GtkLabel" id="label7">
+ <property name="label" translatable="yes">More...</property>
+ </object>
+ </child>
+ </object>
+ <packing>
+ <property name="position">3</property>
+ </packing>
+ </child>
+ </object>
+ <packing>
+ <property name="position">1</property>
+ </packing>
+ </child>
+ </object>
+ <packing>
+ <property name="left-attach">1</property>
+ <property name="top-attach">3</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkRevealer" id="details_revealer">
+ <child>
+ <object class="GtkBox" id="box5">
+ <property name="orientation">vertical</property>
+ <child>
+ <object class="GtkBox" id="box7">
+ <property name="margin-top">2</property>
+ <property name="margin-bottom">2</property>
+ <property name="spacing">8</property>
+ <child>
+ <object class="GtkFrame" id="frame1">
+ <property name="shadow-type">none</property>
+ <child>
+ <object class="GtkLabel" id="n_reshares_label">
+ <property name="label" translatable="0"><b>2</b>
+Reshares</property>
+ <property name="use-markup">1</property>
+ </object>
+ </child>
+ <child type="label_item"/>
+ </object>
+ </child>
+ <child>
+ <object class="GtkFrame" id="frame2">
+ <property name="shadow-type">none</property>
+ <child>
+ <object class="GtkLabel" id="n_favorites_label">
+ <property name="label" translatable="0"><b>2</b>
+FAVORITES</property>
+ <property name="use-markup">1</property>
+ </object>
+ </child>
+ <child type="label_item"/>
+ </object>
+ <packing>
+ <property name="position">1</property>
+ </packing>
+ </child>
+ </object>
+ <packing>
+ <property name="position">1</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkBox" id="box6">
+ <child>
+ <object class="GtkLabel" id="detailed_time_label">
+ <property name="label" translatable="0">4:25 AM - 14 Jun 13 </property>
+ <style>
+ <class name="dim-label"/>
+ </style>
+ </object>
+ </child>
+ <child>
+ <object class="GtkButton" id="button5">
+ <property name="label" translatable="yes">Details</property>
+ <property name="can-focus">1</property>
+ <property name="receives-default">1</property>
+ <property name="relief">none</property>
+ <style>
+ <class name="dim-label"/>
+ </style>
+ </object>
+ <packing>
+ <property name="position">1</property>
+ </packing>
+ </child>
+ </object>
+ <packing>
+ <property name="position">2</property>
+ </packing>
+ </child>
+ </object>
+ </child>
+ </object>
+ <packing>
+ <property name="left-attach">1</property>
+ <property name="top-attach">4</property>
+ </packing>
+ </child>
+ </object>
+ </child>
+ </template>
+</interface>
diff --git a/demos/gtk-demo/meson.build b/demos/gtk-demo/meson.build
index 93c2902575..b03ce6f7bb 100644
--- a/demos/gtk-demo/meson.build
+++ b/demos/gtk-demo/meson.build
@@ -36,6 +36,7 @@ demos = files([
'infobar.c',
'links.c',
'listbox.c',
+ 'listview.c',
'flowbox.c',
'list_store.c',
'markup.c',
@@ -76,7 +77,7 @@ demos = files([
gtkdemo_deps = [ libgtk_dep, ]
-extra_demo_sources = files(['main.c', 'gtkfishbowl.c', 'fontplane.c', 'gtkgears.c', 'puzzlepiece.c'])
+extra_demo_sources = files(['main.c', 'gtkfishbowl.c', 'fontplane.c', 'gtkgears.c', 'puzzlepiece.c',
'message.c'])
if harfbuzz_dep.found() and pangoft_dep.found()
demos += files('font_features.c')
diff --git a/demos/gtk-demo/message.c b/demos/gtk-demo/message.c
new file mode 100644
index 0000000000..64566d4c17
--- /dev/null
+++ b/demos/gtk-demo/message.c
@@ -0,0 +1,79 @@
+
+#include <gtk/gtk.h>
+#include "message.h"
+
+#include <stdlib.h>
+#include <string.h>
+
+G_DEFINE_TYPE (GtkMessage, gtk_message, G_TYPE_OBJECT);
+
+static void
+gtk_message_finalize (GObject *obj)
+{
+ GtkMessage *msg = GTK_MESSAGE (obj);
+
+ g_free (msg->sender_name);
+ g_free (msg->sender_nick);
+ g_free (msg->message);
+ g_free (msg->resent_by);
+
+ G_OBJECT_CLASS (gtk_message_parent_class)->finalize (obj);
+}
+
+static void
+gtk_message_class_init (GtkMessageClass *klass)
+{
+ GObjectClass *object_class = G_OBJECT_CLASS (klass);
+ object_class->finalize = gtk_message_finalize;
+}
+
+static void
+gtk_message_init (GtkMessage *msg)
+{
+}
+
+static void
+gtk_message_parse (GtkMessage *msg, const char *str)
+{
+ char **strv;
+ int i;
+
+ strv = g_strsplit (str, "|", 0);
+
+ i = 0;
+ msg->id = strtol (strv[i++], NULL, 10);
+ msg->sender_name = g_strdup (strv[i++]);
+ msg->sender_nick = g_strdup (strv[i++]);
+ msg->message = g_strdup (strv[i++]);
+ msg->time = strtol (strv[i++], NULL, 10);
+ if (strv[i])
+ {
+ msg->reply_to = strtol (strv[i++], NULL, 10);
+ if (strv[i])
+ {
+ if (*strv[i])
+ msg->resent_by = g_strdup (strv[i]);
+ i++;
+ if (strv[i])
+ {
+ msg->n_favorites = strtol (strv[i++], NULL, 10);
+ if (strv[i])
+ {
+ msg->n_reshares = strtol (strv[i++], NULL, 10);
+ }
+
+ }
+ }
+ }
+
+ g_strfreev (strv);
+}
+
+GtkMessage *
+gtk_message_new (const char *str)
+{
+ GtkMessage *msg;
+ msg = g_object_new (gtk_message_get_type (), NULL);
+ gtk_message_parse (msg, str);
+ return msg;
+}
diff --git a/demos/gtk-demo/message.h b/demos/gtk-demo/message.h
new file mode 100644
index 0000000000..66ff37588f
--- /dev/null
+++ b/demos/gtk-demo/message.h
@@ -0,0 +1,34 @@
+#pragma once
+
+#define GTK_TYPE_MESSAGE (gtk_message_get_type ())
+#define GTK_MESSAGE(message) (G_TYPE_CHECK_INSTANCE_CAST ((message), GTK_TYPE_MESSAGE,
GtkMessage))
+#define GTK_MESSAGE_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), GTK_TYPE_MESSAGE,
GtkMessageClass))
+#define GTK_IS_MESSAGE(message) (G_TYPE_CHECK_INSTANCE_TYPE ((message), GTK_TYPE_MESSAGE))
+#define GTK_IS_MESSAGE_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), GTK_TYPE_MESSAGE))
+#define GTK_MESSAGE_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), GTK_TYPE_MESSAGE,
GtkMessageClass))
+
+typedef struct _GtkMessage GtkMessage;
+typedef struct _GtkMessageClass GtkMessageClass;
+
+struct _GtkMessage
+{
+ GObject parent;
+
+ guint id;
+ char *sender_name;
+ char *sender_nick;
+ char *message;
+ gint64 time;
+ guint reply_to;
+ char *resent_by;
+ int n_favorites;
+ int n_reshares;
+};
+
+struct _GtkMessageClass
+{
+ GObjectClass parent_class;
+};
+
+GType gtk_message_get_type (void) G_GNUC_CONST;
+GtkMessage * gtk_message_new (const char *str);
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]