mirror of
https://gitlab.gnome.org/GNOME/gtk.git
synced 2024-12-26 21:51:08 +00:00
386b63b85d
In 99.9% of all cases, these are just NULL, NULL. So just do away with these arguments, people can use the setters for the rare cases where they want the scrolled window to use a different adjustment.
394 lines
12 KiB
C
394 lines
12 KiB
C
/* List Box
|
|
*
|
|
* GtkListBox allows lists with complicated layouts, using
|
|
* regular widgets supporting sorting and filtering.
|
|
*
|
|
*/
|
|
|
|
#include <gtk/gtk.h>
|
|
#include <stdlib.h>
|
|
#include <string.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))
|
|
#define GTK_IS_MESSAGE_ROW(message_row) (G_TYPE_CHECK_INSTANCE_TYPE ((message_row), GTK_TYPE_MESSAGE_ROW))
|
|
#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;
|
|
|
|
GtkMessageRowPrivate *priv;
|
|
};
|
|
|
|
struct _GtkMessageRowClass
|
|
{
|
|
GtkListBoxRowClass parent_class;
|
|
};
|
|
|
|
struct _GtkMessageRowPrivate
|
|
{
|
|
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;
|
|
};
|
|
|
|
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)
|
|
{
|
|
GtkMessageRowPrivate *priv = row->priv;
|
|
GDateTime *t;
|
|
char *s;
|
|
|
|
gtk_label_set_text (priv->source_name, priv->message->sender_name);
|
|
gtk_label_set_text (priv->source_nick, priv->message->sender_nick);
|
|
gtk_label_set_text (priv->content_label, priv->message->message);
|
|
t = g_date_time_new_from_unix_utc (priv->message->time);
|
|
s = g_date_time_format (t, "%e %b %y");
|
|
gtk_label_set_text (priv->short_time_label, s);
|
|
g_free (s);
|
|
s = g_date_time_format (t, "%X - %e %b %Y");
|
|
gtk_label_set_text (priv->detailed_time_label, s);
|
|
g_free (s);
|
|
g_date_time_unref (t);
|
|
|
|
gtk_widget_set_visible (GTK_WIDGET(priv->n_favorites_label),
|
|
priv->message->n_favorites != 0);
|
|
s = g_strdup_printf ("<b>%d</b>\nFavorites", priv->message->n_favorites);
|
|
gtk_label_set_markup (priv->n_favorites_label, s);
|
|
g_free (s);
|
|
|
|
gtk_widget_set_visible (GTK_WIDGET(priv->n_reshares_label),
|
|
priv->message->n_reshares != 0);
|
|
s = g_strdup_printf ("<b>%d</b>\nReshares", priv->message->n_reshares);
|
|
gtk_label_set_markup (priv->n_reshares_label, s);
|
|
g_free (s);
|
|
|
|
gtk_widget_set_visible (GTK_WIDGET (priv->resent_box), priv->message->resent_by != NULL);
|
|
if (priv->message->resent_by)
|
|
gtk_button_set_label (GTK_BUTTON (priv->resent_by_button), priv->message->resent_by);
|
|
|
|
if (strcmp (priv->message->sender_nick, "@GTKtoolkit") == 0)
|
|
{
|
|
gtk_image_set_from_icon_name (priv->avatar_image, "gtk3-demo");
|
|
gtk_image_set_icon_size (priv->avatar_image, GTK_ICON_SIZE_LARGE);
|
|
}
|
|
else
|
|
gtk_image_set_from_pixbuf (priv->avatar_image, avatar_pixbuf_other);
|
|
|
|
}
|
|
|
|
static void
|
|
gtk_message_row_expand (GtkMessageRow *row)
|
|
{
|
|
GtkMessageRowPrivate *priv = row->priv;
|
|
gboolean expand;
|
|
|
|
expand = !gtk_revealer_get_reveal_child (priv->details_revealer);
|
|
|
|
gtk_revealer_set_reveal_child (priv->details_revealer, expand);
|
|
if (expand)
|
|
gtk_button_set_label (priv->expand_button, "Hide");
|
|
else
|
|
gtk_button_set_label (priv->expand_button, "Expand");
|
|
}
|
|
|
|
static void
|
|
expand_clicked (GtkMessageRow *row,
|
|
GtkButton *button)
|
|
{
|
|
gtk_message_row_expand (row);
|
|
}
|
|
|
|
static void
|
|
reshare_clicked (GtkMessageRow *row,
|
|
GtkButton *button)
|
|
{
|
|
GtkMessageRowPrivate *priv = row->priv;
|
|
|
|
priv->message->n_reshares++;
|
|
gtk_message_row_update (row);
|
|
}
|
|
|
|
static void
|
|
favorite_clicked (GtkMessageRow *row,
|
|
GtkButton *button)
|
|
{
|
|
GtkMessageRowPrivate *priv = row->priv;
|
|
|
|
priv->message->n_favorites++;
|
|
gtk_message_row_update (row);
|
|
}
|
|
|
|
static void
|
|
gtk_message_row_state_flags_changed (GtkWidget *widget,
|
|
GtkStateFlags previous_state_flags)
|
|
{
|
|
GtkMessageRowPrivate *priv = GTK_MESSAGE_ROW (widget)->priv;
|
|
GtkStateFlags flags;
|
|
gboolean visible;
|
|
|
|
flags = gtk_widget_get_state_flags (widget);
|
|
|
|
visible = flags & (GTK_STATE_FLAG_PRELIGHT | GTK_STATE_FLAG_SELECTED) ? TRUE : FALSE;
|
|
gtk_widget_set_visible (priv->extra_buttons_box, visible);
|
|
|
|
GTK_WIDGET_CLASS (gtk_message_row_parent_class)->state_flags_changed (widget, previous_state_flags);
|
|
}
|
|
|
|
static void
|
|
gtk_message_row_finalize (GObject *obj)
|
|
{
|
|
GtkMessageRowPrivate *priv = GTK_MESSAGE_ROW (obj)->priv;
|
|
g_object_unref (priv->message);
|
|
G_OBJECT_CLASS (gtk_message_row_parent_class)->finalize(obj);
|
|
}
|
|
|
|
static void
|
|
gtk_message_row_class_init (GtkMessageRowClass *klass)
|
|
{
|
|
GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (klass);
|
|
GObjectClass *object_class = G_OBJECT_CLASS (klass);
|
|
|
|
object_class->finalize = gtk_message_row_finalize;
|
|
|
|
gtk_widget_class_set_template_from_resource (widget_class, "/listbox/listbox.ui");
|
|
gtk_widget_class_bind_template_child_private (widget_class, GtkMessageRow, content_label);
|
|
gtk_widget_class_bind_template_child_private (widget_class, GtkMessageRow, source_name);
|
|
gtk_widget_class_bind_template_child_private (widget_class, GtkMessageRow, source_nick);
|
|
gtk_widget_class_bind_template_child_private (widget_class, GtkMessageRow, short_time_label);
|
|
gtk_widget_class_bind_template_child_private (widget_class, GtkMessageRow, detailed_time_label);
|
|
gtk_widget_class_bind_template_child_private (widget_class, GtkMessageRow, extra_buttons_box);
|
|
gtk_widget_class_bind_template_child_private (widget_class, GtkMessageRow, details_revealer);
|
|
gtk_widget_class_bind_template_child_private (widget_class, GtkMessageRow, avatar_image);
|
|
gtk_widget_class_bind_template_child_private (widget_class, GtkMessageRow, resent_box);
|
|
gtk_widget_class_bind_template_child_private (widget_class, GtkMessageRow, resent_by_button);
|
|
gtk_widget_class_bind_template_child_private (widget_class, GtkMessageRow, n_reshares_label);
|
|
gtk_widget_class_bind_template_child_private (widget_class, GtkMessageRow, n_favorites_label);
|
|
gtk_widget_class_bind_template_child_private (widget_class, GtkMessageRow, 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_message_row_state_flags_changed;
|
|
}
|
|
|
|
static void
|
|
gtk_message_row_init (GtkMessageRow *row)
|
|
{
|
|
row->priv = gtk_message_row_get_instance_private (row);
|
|
|
|
gtk_widget_init_template (GTK_WIDGET (row));
|
|
}
|
|
|
|
static GtkMessageRow *
|
|
gtk_message_row_new (GtkMessage *message)
|
|
{
|
|
GtkMessageRow *row;
|
|
|
|
row = g_object_new (gtk_message_row_get_type (), NULL);
|
|
row->priv->message = message;
|
|
gtk_message_row_update (row);
|
|
|
|
return row;
|
|
}
|
|
|
|
static int
|
|
gtk_message_row_sort (GtkMessageRow *a, GtkMessageRow *b, gpointer data)
|
|
{
|
|
return b->priv->message->time - a->priv->message->time;
|
|
}
|
|
|
|
static void
|
|
row_activated (GtkListBox *listbox, GtkListBoxRow *row)
|
|
{
|
|
gtk_message_row_expand (GTK_MESSAGE_ROW (row));
|
|
}
|
|
|
|
GtkWidget *
|
|
do_listbox (GtkWidget *do_widget)
|
|
{
|
|
GtkWidget *scrolled, *listbox, *vbox, *label;
|
|
GtkMessage *message;
|
|
GtkMessageRow *row;
|
|
GBytes *data;
|
|
char **lines;
|
|
int i;
|
|
|
|
if (!window)
|
|
{
|
|
avatar_pixbuf_other = gdk_pixbuf_new_from_resource_at_scale ("/listbox/apple-red.png", 32, 32, FALSE, NULL);
|
|
|
|
window = gtk_window_new ();
|
|
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);
|
|
g_object_add_weak_pointer (G_OBJECT (window), (gpointer *)&window);
|
|
|
|
vbox = gtk_box_new (GTK_ORIENTATION_VERTICAL, 12);
|
|
gtk_window_set_child (GTK_WINDOW (window), vbox);
|
|
label = gtk_label_new ("Messages from GTK and friends");
|
|
gtk_box_append (GTK_BOX (vbox), label);
|
|
scrolled = gtk_scrolled_window_new ();
|
|
gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (scrolled), GTK_POLICY_NEVER, GTK_POLICY_AUTOMATIC);
|
|
gtk_widget_set_vexpand (scrolled, TRUE);
|
|
gtk_box_append (GTK_BOX (vbox), scrolled);
|
|
listbox = gtk_list_box_new ();
|
|
gtk_scrolled_window_set_child (GTK_SCROLLED_WINDOW (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_list_box_insert (GTK_LIST_BOX (listbox), GTK_WIDGET (row), -1);
|
|
}
|
|
|
|
g_strfreev (lines);
|
|
g_bytes_unref (data);
|
|
}
|
|
|
|
if (!gtk_widget_get_visible (window))
|
|
gtk_widget_show (window);
|
|
else
|
|
gtk_window_destroy (GTK_WINDOW (window));
|
|
|
|
return window;
|
|
}
|